keystone: refresh token and groups
This commit is contained in:
		| @@ -10,111 +10,155 @@ import ( | ||||
| 	"net/http" | ||||
| 	"bytes" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| ) | ||||
|  | ||||
| type KeystoneConnector struct { | ||||
| 	domain string | ||||
| 	keystoneURI string | ||||
| 	Logger   logrus.FieldLogger | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	_ connector.PasswordConnector = &KeystoneConnector{} | ||||
| 	_ connector.PasswordConnector = &Connector{} | ||||
|   	_ connector.RefreshConnector = &Connector{} | ||||
| ) | ||||
|  | ||||
| // Config holds the configuration parameters for Keystone connector. | ||||
| // An example config: | ||||
| //	connectors: | ||||
| //		type: ksconfig | ||||
| //		id: keystone | ||||
| //		name: Keystone | ||||
| //		config: | ||||
| //			keystoneURI: http://example:5000/v3/auth/tokens | ||||
| //			domain: default | ||||
|  | ||||
| type Config struct { | ||||
| 	Domain string `json:"domain"` | ||||
| 	KeystoneURI string `json:"keystoneURI"` | ||||
| } | ||||
|  | ||||
| // Open returns an authentication strategy using Keystone. | ||||
| func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) { | ||||
| 	return &KeystoneConnector{c.Domain,c.KeystoneURI,logger}, nil | ||||
| 	return &Connector{c.Domain, c.KeystoneHost, | ||||
| 	c.KeystoneUsername, c.KeystonePassword, logger}, nil | ||||
| } | ||||
|  | ||||
| func (p KeystoneConnector) Close() error { return nil } | ||||
| func (p Connector) Close() error { return nil } | ||||
|  | ||||
| // Declare KeystoneJson struct to get a token | ||||
| type KeystoneJson struct { | ||||
| 	Auth `json:"auth"` | ||||
| func (p Connector) Login(ctx context.Context, s connector.Scopes, username, password string) ( | ||||
| 		identity connector.Identity, validPassword bool, err error) { | ||||
| 	response, err := p.getTokenResponse(username, password) | ||||
|  | ||||
| 	// Providing wrong password or wrong keystone URI throws error | ||||
| 	if err == nil && response.StatusCode == 201 { | ||||
|     	token := response.Header["X-Subject-Token"][0] | ||||
| 		data, _ := ioutil.ReadAll(response.Body) | ||||
|  | ||||
|     	var tokenResponse = new(TokenResponse) | ||||
|     	err := json.Unmarshal(data, &tokenResponse) | ||||
|  | ||||
|     	if err != nil { | ||||
|       		fmt.Printf("keystone: invalid token response: %v", err) | ||||
|       		return identity, false, err | ||||
|     	} | ||||
|     	groups, err := p.getUserGroups(tokenResponse.Token.User.ID, token) | ||||
|  | ||||
|     	if err != nil { | ||||
|       		return identity, false, err | ||||
|     	} | ||||
|  | ||||
| 		identity.Username =	username | ||||
|     	identity.UserID = tokenResponse.Token.User.ID | ||||
|    	 	identity.Groups = groups | ||||
| 		return identity, true, nil | ||||
|  | ||||
| 	} else if err != nil { | ||||
|     	fmt.Printf("keystone: error %v", err) | ||||
| 		return identity, false, err | ||||
|  | ||||
| 	} else { | ||||
| 		data, _ := ioutil.ReadAll(response.Body) | ||||
| 		fmt.Println(string(data)) | ||||
| 		return identity, false, err | ||||
| 	} | ||||
| 	return identity, false, nil | ||||
| } | ||||
|  | ||||
| type Auth struct { | ||||
| 	Identity `json:"identity"` | ||||
| func (p Connector) Prompt() string { return "username" } | ||||
|  | ||||
| func (p Connector) Refresh( | ||||
| 	ctx context.Context, s connector.Scopes, identity connector.Identity) (connector.Identity, error) { | ||||
|  | ||||
|   	if len(identity.ConnectorData) == 0 { | ||||
|   		return identity, nil | ||||
| 	} | ||||
|  | ||||
| 	token, err := p.getAdminToken() | ||||
|  | ||||
|   	if err != nil { | ||||
|     	fmt.Printf("keystone: failed to obtain admin token") | ||||
|     	return identity, err | ||||
|   	} | ||||
|  | ||||
|   	ok := p.checkIfUserExists(identity.UserID, token) | ||||
|   	if !ok { | ||||
|   		fmt.Printf("keystone: user %q does not exist\n", identity.UserID) | ||||
|      	return identity, fmt.Errorf("keystone: user %q does not exist", identity.UserID) | ||||
|   	} | ||||
|  | ||||
|   	groups, err := p.getUserGroups(identity.UserID, token) | ||||
|   	if err != nil { | ||||
|     	fmt.Printf("keystone: Failed to fetch user %q groups", identity.UserID) | ||||
|     	return identity, fmt.Errorf("keystone: failed to fetch user %q groups", identity.UserID) | ||||
|   	} | ||||
|  | ||||
|   	identity.Groups = groups | ||||
|   	fmt.Printf("Identity data after use of refresh token: %v", identity) | ||||
| 	return identity, nil | ||||
| } | ||||
|  | ||||
| type Identity struct { | ||||
| 	Methods  []string `json:"methods"` | ||||
| 	Password `json:"password"` | ||||
| } | ||||
|  | ||||
| type Password struct { | ||||
| 	User `json:"user"` | ||||
| } | ||||
|  | ||||
| type User struct { | ||||
| 	Name   string `json:"name"` | ||||
| 	Domain `json:"domain"` | ||||
| 	Password string `json:"password"` | ||||
| } | ||||
|  | ||||
| type Domain struct { | ||||
| 	ID string `json:"id"` | ||||
| } | ||||
|  | ||||
| func (p KeystoneConnector) Login(ctx context.Context, s connector.Scopes, username, password string) (identity connector.Identity, validPassword bool, err error) { | ||||
| 	// Instantiate KeystoneJson struct type to get a token | ||||
| 	jsonData := KeystoneJson{ | ||||
| func (p Connector) getTokenResponse(username, password string) (response *http.Response, err error) { | ||||
| 	jsonData := LoginRequestData{ | ||||
| 		Auth: Auth{ | ||||
| 			Identity: Identity{ | ||||
| 				Methods:[]string{"password"}, | ||||
| 				Password: Password{ | ||||
| 					User: User{ | ||||
| 						Name: username, | ||||
| 						Domain: Domain{ID:p.domain}, | ||||
| 						Domain: Domain{ID:p.Domain}, | ||||
| 						Password: password, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	// Marshal jsonData | ||||
| 	jsonValue, _ := json.Marshal(jsonData) | ||||
|  | ||||
| 	// Make an http post request to Keystone URI | ||||
| 	response, err := http.Post(p.keystoneURI, "application/json", bytes.NewBuffer(jsonValue)) | ||||
|  | ||||
| 	// Providing wrong password or wrong keystone URI throws error | ||||
| 	if err == nil && response.StatusCode == 201 { | ||||
| 		data, _ := ioutil.ReadAll(response.Body) | ||||
| 		fmt.Println(string(data)) | ||||
| 		identity.Username =	username | ||||
| 		return identity, true, nil | ||||
|  | ||||
| 	} else if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 		return identity, false, err | ||||
|  | ||||
| 	} else { | ||||
| 		fmt.Printf("The HTTP request failed with error %v\n", response.StatusCode) | ||||
| 		data, _ := ioutil.ReadAll(response.Body) | ||||
| 		fmt.Println(string(data)) | ||||
| 		return identity, false, err | ||||
|  | ||||
| 	} | ||||
| 	return identity, false, nil | ||||
|   	loginURI := p.KeystoneHost + "/v3/auth/tokens" | ||||
| 	return http.Post(loginURI, "application/json", bytes.NewBuffer(jsonValue)) | ||||
| } | ||||
|  | ||||
| func (p KeystoneConnector) Prompt() string { return "username" } | ||||
| func (p Connector) getAdminToken()(string, error) { | ||||
|   	response, err := p.getTokenResponse(p.KeystoneUsername, p.KeystonePassword) | ||||
|   	if err!= nil { | ||||
|     	return "", err | ||||
|   	} | ||||
|   	token := response.Header["X-Subject-Token"][0] | ||||
|   	return token, nil | ||||
| } | ||||
|  | ||||
| func (p Connector) checkIfUserExists(userID string, token string) (bool) { | ||||
|   	groupsURI := p.KeystoneHost + "/v3/users/" + userID | ||||
|   	client := &http.Client{} | ||||
|   	req, _ := http.NewRequest("GET", groupsURI, nil) | ||||
|   	req.Header.Set("X-Auth-Token", token) | ||||
|   	response, err :=  client.Do(req) | ||||
|   	if err == nil && response.StatusCode == 200 { | ||||
|     	return true | ||||
|   	} | ||||
|   	return false | ||||
| } | ||||
|  | ||||
| func (p Connector) getUserGroups(userID string, token string) ([]string, error) { | ||||
|   	groupsURI := p.KeystoneHost + "/v3/users/" + userID + "/groups" | ||||
|   	client := &http.Client{} | ||||
|   	req, _ := http.NewRequest("GET", groupsURI, nil) | ||||
|   	req.Header.Set("X-Auth-Token", token) | ||||
|   	response, err :=  client.Do(req) | ||||
|  | ||||
|   	if err != nil { | ||||
|     	fmt.Printf("keystone: error while fetching user %q groups\n", userID) | ||||
|     	return nil, err | ||||
|   	} | ||||
|   	data, _ := ioutil.ReadAll(response.Body) | ||||
|   	var groupsResponse = new(GroupsResponse) | ||||
|   	err = json.Unmarshal(data, &groupsResponse) | ||||
|   	if err != nil { | ||||
|     	return nil, err | ||||
|   	} | ||||
|   	groups := []string{} | ||||
|   	for _, group := range groupsResponse.Groups { | ||||
|   		groups = append(groups, group.Name) | ||||
|   	} | ||||
|   	return groups, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										275
									
								
								connector/keystone/keystone_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								connector/keystone/keystone_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,275 @@ | ||||
| package keystone | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| 	"github.com/dexidp/dex/connector" | ||||
|  | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
|   	"time" | ||||
|   	"net/http" | ||||
|  | ||||
| 	"github.com/docker/docker/api/types" | ||||
| 	"github.com/docker/docker/api/types/container" | ||||
| 	"github.com/docker/docker/client" | ||||
|    	networktypes "github.com/docker/docker/api/types/network" | ||||
|   	"github.com/docker/go-connections/nat" | ||||
| 	"golang.org/x/net/context" | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"io/ioutil" | ||||
| ) | ||||
|  | ||||
| const dockerCliVersion = "1.37" | ||||
|  | ||||
| const exposedKeystonePort = "5000" | ||||
| const exposedKeystonePortAdmin = "35357" | ||||
|  | ||||
| const keystoneHost = "http://localhost" | ||||
| const keystoneURL = keystoneHost + ":" + exposedKeystonePort | ||||
| const keystoneAdminURL = keystoneHost + ":" + exposedKeystonePortAdmin | ||||
| const authTokenURL = keystoneURL + "/v3/auth/tokens/" | ||||
| const userURL = keystoneAdminURL + "/v3/users/" | ||||
| const groupURL = keystoneAdminURL + "/v3/groups/" | ||||
|  | ||||
| func startKeystoneContainer() string { | ||||
| 	ctx := context.Background() | ||||
| 	cli, err := client.NewClientWithOpts(client.WithVersion(dockerCliVersion)) | ||||
|  | ||||
| 	if err != nil { | ||||
|     	fmt.Printf("Error %v", err) | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	imageName := "openio/openstack-keystone" | ||||
| 	out, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{}) | ||||
| 	if err != nil { | ||||
|     	fmt.Printf("Error %v", err) | ||||
| 		return "" | ||||
| 	} | ||||
| 	io.Copy(os.Stdout, out) | ||||
|  | ||||
| 	resp, err := cli.ContainerCreate(ctx, &container.Config{ | ||||
| 		Image: imageName, | ||||
|     }, &container.HostConfig{ | ||||
|     		PortBindings: nat.PortMap{ | ||||
|         		"5000/tcp": []nat.PortBinding{ | ||||
|             		{ | ||||
|                 		HostIP:   "0.0.0.0", | ||||
|                 		HostPort: exposedKeystonePort, | ||||
|             		}, | ||||
|         		}, | ||||
| 				"35357/tcp": []nat.PortBinding{ | ||||
| 					{ | ||||
| 					HostIP:   "0.0.0.0", | ||||
| 					HostPort: exposedKeystonePortAdmin, | ||||
| 					}, | ||||
| 				}, | ||||
|     		}, | ||||
| 		}, &networktypes.NetworkingConfig{}, "dex_keystone_test") | ||||
|  | ||||
| 	if err != nil { | ||||
|     	fmt.Printf("Error %v", err) | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	fmt.Println(resp.ID) | ||||
|   	return resp.ID | ||||
| } | ||||
|  | ||||
| func cleanKeystoneContainer(ID string) { | ||||
| 	ctx := context.Background() | ||||
| 	cli, err := client.NewClientWithOpts(client.WithVersion(dockerCliVersion)) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error %v", err) | ||||
| 		return | ||||
| 	} | ||||
| 	duration := time.Duration(1) | ||||
| 	if err:= cli.ContainerStop(ctx, ID, &duration); err != nil { | ||||
| 		fmt.Printf("Error %v", err) | ||||
| 		return | ||||
| 	} | ||||
| 	if err:= cli.ContainerRemove(ctx, ID, types.ContainerRemoveOptions{}); err != nil { | ||||
| 		fmt.Printf("Error %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getAdminToken(admin_name, admin_pass string) (token string) { | ||||
| 	client := &http.Client{} | ||||
|  | ||||
| 	jsonData := LoginRequestData{ | ||||
| 		Auth: Auth{ | ||||
| 			Identity: Identity{ | ||||
| 				Methods:[]string{"password"}, | ||||
| 				Password: Password{ | ||||
| 					User: User{ | ||||
| 						Name: admin_name, | ||||
| 						Domain: Domain{ID: "default"}, | ||||
| 						Password: admin_pass, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	body, _ := json.Marshal(jsonData) | ||||
|  | ||||
| 	req, _ := http.NewRequest("POST", authTokenURL, bytes.NewBuffer(body)) | ||||
|  | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| 	resp, _ := client.Do(req) | ||||
|  | ||||
| 	token = resp.Header["X-Subject-Token"][0] | ||||
| 	return token | ||||
| } | ||||
|  | ||||
| func createUser(token, user_name, user_email, user_pass string) (string){ | ||||
| 	client := &http.Client{} | ||||
|  | ||||
| 	createUserData := CreateUserRequest{ | ||||
| 		CreateUser: CreateUserForm{ | ||||
| 			Name: user_name, | ||||
| 			Email: user_email, | ||||
| 			Enabled: true, | ||||
| 			Password: user_pass, | ||||
| 			Roles: []string{"admin"}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	body, _ := json.Marshal(createUserData) | ||||
|  | ||||
| 	req, _ := http.NewRequest("POST", userURL, bytes.NewBuffer(body)) | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	req.Header.Add("Content-Type", "application/json") | ||||
| 	resp, _ := client.Do(req) | ||||
|  | ||||
| 	data, _ := ioutil.ReadAll(resp.Body) | ||||
| 	var userResponse = new(UserResponse) | ||||
| 	err := json.Unmarshal(data, &userResponse) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 	} | ||||
|  | ||||
| 	fmt.Println(userResponse.User.ID) | ||||
| 	return userResponse.User.ID | ||||
|  | ||||
| } | ||||
|  | ||||
| func deleteUser(token, id string) { | ||||
| 	client := &http.Client{} | ||||
|  | ||||
| 	deleteUserURI := userURL + id | ||||
| 	fmt.Println(deleteUserURI) | ||||
| 	req, _ := http.NewRequest("DELETE", deleteUserURI, nil) | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	resp, _ := client.Do(req) | ||||
| 	fmt.Println(resp) | ||||
| } | ||||
|  | ||||
| func createGroup(token, description, name string) string{ | ||||
| 	client := &http.Client{} | ||||
|  | ||||
| 	createGroupData := CreateGroup{ | ||||
| 		CreateGroupForm{ | ||||
| 			Description: description, | ||||
| 			Name: name, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	body, _ := json.Marshal(createGroupData) | ||||
|  | ||||
| 	req, _ := http.NewRequest("POST", groupURL, bytes.NewBuffer(body)) | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	req.Header.Add("Content-Type", "application/json") | ||||
| 	resp, _ := client.Do(req) | ||||
| 	data, _ := ioutil.ReadAll(resp.Body) | ||||
|  | ||||
| 	var groupResponse = new(GroupID) | ||||
| 	err := json.Unmarshal(data, &groupResponse) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 	} | ||||
|  | ||||
| 	return groupResponse.Group.ID | ||||
| } | ||||
|  | ||||
| func addUserToGroup(token, groupId, userId string) { | ||||
| 	uri := groupURL + groupId + "/users/" + userId | ||||
| 	client := &http.Client{} | ||||
| 	req, _ := http.NewRequest("PUT", uri, nil) | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	resp, _ := client.Do(req) | ||||
| 	fmt.Println(resp) | ||||
| } | ||||
|  | ||||
| const adminUser = "demo" | ||||
| const adminPass = "DEMO_PASS" | ||||
| const invalidPass = "WRONG_PASS" | ||||
|  | ||||
| const testUser = "test_user" | ||||
| const testPass = "test_pass" | ||||
| const testEmail = "test@example.com" | ||||
|  | ||||
| const domain = "default" | ||||
|  | ||||
| func TestIncorrectCredentialsLogin(t *testing.T) { | ||||
|   	c := Connector{KeystoneHost: keystoneURL, Domain: domain, | ||||
|   				   KeystoneUsername: adminUser, KeystonePassword: adminPass} | ||||
|   	s := connector.Scopes{OfflineAccess: true, Groups: true} | ||||
|   	_, validPW, _ := c.Login(context.Background(), s, adminUser, invalidPass) | ||||
|  | ||||
|   	if validPW { | ||||
|   		t.Fail() | ||||
|   	} | ||||
| } | ||||
|  | ||||
| func TestValidUserLogin(t *testing.T) { | ||||
| 	token := getAdminToken(adminUser, adminPass) | ||||
| 	userID := createUser(token, testUser, testEmail, testPass) | ||||
|   	c := Connector{KeystoneHost: keystoneURL, Domain: domain, | ||||
|   				  KeystoneUsername: adminUser, KeystonePassword: adminPass} | ||||
|   	s := connector.Scopes{OfflineAccess: true, Groups: true} | ||||
|   	_, validPW, _ := c.Login(context.Background(), s, testUser, testPass) | ||||
|   	if !validPW { | ||||
|      	t.Fail() | ||||
|   	} | ||||
|   	deleteUser(token, userID) | ||||
| } | ||||
|  | ||||
| func TestUseRefreshToken(t *testing.T) { | ||||
|   t.Fatal("Not implemented") | ||||
| } | ||||
|  | ||||
| func TestUseRefreshTokenUserDeleted(t *testing.T){ | ||||
|   t.Fatal("Not implemented") | ||||
| } | ||||
|  | ||||
| func TestUseRefreshTokenGroupsChanged(t *testing.T){ | ||||
| 	t.Fatal("Not implemented") | ||||
| } | ||||
|  | ||||
| func TestMain(m *testing.M) { | ||||
| 	dockerID := startKeystoneContainer() | ||||
|   	repeats := 10 | ||||
|   	running := false | ||||
|   	for i := 0; i < repeats; i++ { | ||||
|    		_, err := http.Get(keystoneURL) | ||||
|    		if err == nil { | ||||
|      		running = true | ||||
|      		break | ||||
|    		} | ||||
|    		time.Sleep(10 * time.Second) | ||||
|   	} | ||||
|   	if !running { | ||||
|     	fmt.Printf("Failed to start keystone container") | ||||
|     	os.Exit(1) | ||||
|   	} | ||||
|   	defer cleanKeystoneContainer(dockerID) | ||||
|   	// run all tests | ||||
| 	m.Run() | ||||
| } | ||||
							
								
								
									
										136
									
								
								connector/keystone/types.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								connector/keystone/types.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | ||||
| package keystone | ||||
|  | ||||
| import ( | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| type Connector struct { | ||||
| 	Domain 			 string | ||||
| 	KeystoneHost 	 string | ||||
| 	KeystoneUsername string | ||||
| 	KeystonePassword string | ||||
| 	Logger 			 logrus.FieldLogger | ||||
| } | ||||
|  | ||||
| type ConnectorData struct { | ||||
| 	AccessToken string `json:"accessToken"` | ||||
| } | ||||
|  | ||||
| type KeystoneUser struct { | ||||
| 	Domain KeystoneDomain `json:"domain"` | ||||
| 	ID 	   string 		  `json:"id"` | ||||
| 	Name   string 		  `json:"name"` | ||||
| } | ||||
|  | ||||
| type KeystoneDomain struct { | ||||
| 	ID string   `json:"id"` | ||||
| 	Name string `json:"name"` | ||||
| } | ||||
|  | ||||
| type Config struct { | ||||
| 	Domain 			 string `json:"domain"` | ||||
| 	KeystoneHost 	 string `json:"keystoneHost"` | ||||
| 	KeystoneUsername string `json:"keystoneUsername"` | ||||
| 	KeystonePassword string `json:"keystonePassword"` | ||||
| } | ||||
|  | ||||
| type LoginRequestData struct { | ||||
| 	Auth `json:"auth"` | ||||
| } | ||||
|  | ||||
| type Auth struct { | ||||
| 	Identity `json:"identity"` | ||||
| } | ||||
|  | ||||
| type Identity struct { | ||||
| 	Methods  []string `json:"methods"` | ||||
| 	Password 		  `json:"password"` | ||||
| } | ||||
|  | ||||
| type Password struct { | ||||
| 	User `json:"user"` | ||||
| } | ||||
|  | ||||
| type User struct { | ||||
| 	Name   string 	`json:"name"` | ||||
| 	Domain 			`json:"domain"` | ||||
| 	Password string `json:"password"` | ||||
| } | ||||
|  | ||||
| type Domain struct { | ||||
| 	ID string `json:"id"` | ||||
| } | ||||
|  | ||||
| type Token struct { | ||||
| 	IssuedAt  string 	   			 `json:"issued_at"` | ||||
| 	Extras 	  map[string]interface{} `json:"extras"` | ||||
| 	Methods   []string 	   			 `json:"methods"` | ||||
| 	ExpiresAt string 	   			 `json:"expires_at"` | ||||
| 	User 	  KeystoneUser 			 `json:"user"` | ||||
| } | ||||
|  | ||||
| type TokenResponse struct { | ||||
| 	Token Token `json:"token"` | ||||
| } | ||||
|  | ||||
| type CreateUserRequest struct { | ||||
| 	CreateUser CreateUserForm  `json:"user"` | ||||
| } | ||||
|  | ||||
| type CreateUserForm struct { | ||||
| 	Name     string `json:"name"` | ||||
| 	Email    string `json:"email"` | ||||
| 	Enabled  bool   `json:"enabled"` | ||||
| 	Password string `json:"password"` | ||||
| 	Roles  []string `json:"roles"` | ||||
| } | ||||
|  | ||||
| type UserResponse struct { | ||||
| 	User CreateUserResponse `json:"user"` | ||||
| } | ||||
|  | ||||
| type CreateUserResponse struct { | ||||
| 	Username string   `json:"username"` | ||||
| 	Name 	 string   `json:"name"` | ||||
| 	Roles 	 []string `json:"roles"` | ||||
| 	Enabled  bool     `json:"enabled"` | ||||
| 	Options  string   `json:"options"` | ||||
| 	ID 		 string   `json:"id"` | ||||
| 	Email 	 string   `json:"email"` | ||||
| } | ||||
|  | ||||
| type CreateGroup struct { | ||||
| 	Group CreateGroupForm `json:"group"` | ||||
| } | ||||
|  | ||||
| type CreateGroupForm struct { | ||||
| 	Description string `json:"description"` | ||||
| 	Name 		string `json:"name"` | ||||
| } | ||||
|  | ||||
| type GroupID struct { | ||||
| 	Group GroupIDForm `json:"group"` | ||||
| } | ||||
|  | ||||
| type GroupIDForm struct { | ||||
| 	ID string `json:"id"` | ||||
| } | ||||
|  | ||||
| type Links struct { | ||||
| 	Self string `json:"self"` | ||||
| 	Previous string `json:"previous"` | ||||
| 	Next string `json:"next"` | ||||
| } | ||||
|  | ||||
| type Group struct { | ||||
| 	DomainID 	string `json:"domain_id` | ||||
| 	Description string `json:"description"` | ||||
| 	ID 			string `json:"id"` | ||||
| 	Links 		Links  `json:"links"` | ||||
| 	Name 		string `json:"name"` | ||||
| } | ||||
|  | ||||
| type GroupsResponse struct { | ||||
| 	Links  Links   `json:"links"` | ||||
| 	Groups []Group `json:"groups"` | ||||
| } | ||||
| @@ -14,7 +14,11 @@ storage: | ||||
|  | ||||
| # Configuration for the HTTP endpoints. | ||||
| web: | ||||
|   http: 0.0.0.0:5556 | ||||
|   https: 0.0.0.0:5556 | ||||
|   # Uncomment for HTTPS options. | ||||
|   # https: 127.0.0.1:5554 | ||||
|   tlsCert: ./ssl/dex.crt | ||||
|   tlsKey: ./ssl/dex.key | ||||
|  | ||||
| # Configuration for telemetry | ||||
| telemetry: | ||||
| @@ -32,13 +36,20 @@ staticClients: | ||||
|   secret: ZXhhbXBsZS1hcHAtc2VjcmV0 | ||||
|  | ||||
| #Provide Keystone connector and its config here | ||||
| # /v3/auth/tokens | ||||
| connectors: | ||||
| - type: ksconfig | ||||
| - type: keystone | ||||
|   id: keystone | ||||
|   name: Keystone | ||||
|   config: | ||||
|     keystoneURI: http://example:5000/v3/auth/tokens | ||||
|     keystoneHost: http://localhost:5000 | ||||
|     domain: default | ||||
|     keystoneUsername: demo | ||||
|     keystonePassword: DEMO_PASS | ||||
|  | ||||
| # Let dex keep a list of passwords which can be used to login to dex. | ||||
| enablePasswordDB: true | ||||
| enablePasswordDB: true | ||||
|  | ||||
| oauth2: | ||||
|   skipApprovalScreen: true | ||||
|  | ||||
|   | ||||
| @@ -211,6 +211,7 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) { | ||||
| 	} | ||||
|  | ||||
| 	authReqID := r.FormValue("req") | ||||
|   s.logger.Errorf("Auth req id %v", authReqID) | ||||
|  | ||||
| 	authReq, err := s.storage.GetAuthRequest(authReqID) | ||||
| 	if err != nil { | ||||
| @@ -345,7 +346,7 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request) | ||||
| 			s.renderError(w, http.StatusInternalServerError, "Requested resource does not exist.") | ||||
| 			return | ||||
| 		} | ||||
| 		s.logger.Errorf("Failed to get auth request: %v", err) | ||||
| 		s.logger.Errorf("2Failed to get auth request: %v", err) | ||||
| 		s.renderError(w, http.StatusInternalServerError, "Database error.") | ||||
| 		return | ||||
| 	} | ||||
| @@ -357,6 +358,7 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request) | ||||
| 	} | ||||
|  | ||||
| 	conn, err := s.getConnector(authReq.ConnectorID) | ||||
|   s.logger.Errorf("X Connector %v", conn) | ||||
| 	if err != nil { | ||||
| 		s.logger.Errorf("Failed to get connector with id %q : %v", authReq.ConnectorID, err) | ||||
| 		s.renderError(w, http.StatusInternalServerError, "Requested resource does not exist.") | ||||
| @@ -435,7 +437,7 @@ func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.Auth | ||||
| func (s *Server) handleApproval(w http.ResponseWriter, r *http.Request) { | ||||
| 	authReq, err := s.storage.GetAuthRequest(r.FormValue("req")) | ||||
| 	if err != nil { | ||||
| 		s.logger.Errorf("Failed to get auth request: %v", err) | ||||
| 		s.logger.Errorf("3Failed to get auth request: %v", err) | ||||
| 		s.renderError(w, http.StatusInternalServerError, "Database error.") | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -434,7 +434,7 @@ type ConnectorConfig interface { | ||||
| // ConnectorsConfig variable provides an easy way to return a config struct | ||||
| // depending on the connector type. | ||||
| var ConnectorsConfig = map[string]func() ConnectorConfig{ | ||||
| 	"ksconfig":        func() ConnectorConfig { return new(keystone.Config) }, | ||||
| 	"keystone":        func() ConnectorConfig { return new(keystone.Config) }, | ||||
| 	"mockCallback":    func() ConnectorConfig { return new(mock.CallbackConfig) }, | ||||
| 	"mockPassword":    func() ConnectorConfig { return new(mock.PasswordConfig) }, | ||||
| 	"ldap":            func() ConnectorConfig { return new(ldap.Config) }, | ||||
| @@ -456,7 +456,7 @@ func openConnector(logger logrus.FieldLogger, conn storage.Connector) (connector | ||||
|  | ||||
| 	f, ok := ConnectorsConfig[conn.Type] | ||||
| 	if !ok { | ||||
| 		return c, fmt.Errorf("unknown connector type %q", conn.Type) | ||||
| 		return c, fmt.Errorf("xunknown connector type %q", conn.Type) | ||||
| 	} | ||||
|  | ||||
| 	connConfig := f() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user