keystone: test cases, refactoring and cleanup
This commit is contained in:
		
				
					committed by
					
						 Krzysztof Balka
						Krzysztof Balka
					
				
			
			
				
	
			
			
			
						parent
						
							a965365a2b
						
					
				
				
					commit
					88d1e2b041
				
			| @@ -13,13 +13,14 @@ services: | ||||
|   - docker | ||||
|  | ||||
| env: | ||||
|   - DEX_POSTGRES_DATABASE=postgres DEX_POSTGRES_USER=postgres DEX_POSTGRES_HOST="localhost" DEX_ETCD_ENDPOINTS=http://localhost:2379 DEX_LDAP_TESTS=1 DEBIAN_FRONTEND=noninteractive | ||||
|   - DEX_POSTGRES_DATABASE=postgres DEX_POSTGRES_USER=postgres DEX_POSTGRES_HOST="localhost" DEX_ETCD_ENDPOINTS=http://localhost:2379 DEX_LDAP_TESTS=1 DEBIAN_FRONTEND=noninteractive DEX_KEYSTONE_URL=http://localhost:5000 DEX_KEYSTONE_ADMIN_URL=http://localhost:35357 | ||||
|  | ||||
| install: | ||||
|   - sudo -E apt-get install -y --force-yes slapd time ldap-utils | ||||
|   - sudo /etc/init.d/slapd stop | ||||
|   - docker run -d --net=host gcr.io/etcd-development/etcd:v3.2.9 | ||||
|  | ||||
|   - docker run -d -p 0.0.0.0:5000:5000 -p 0.0.0.0:35357:35357 openio/openstack-keystone | ||||
|   - sleep 60s | ||||
|  | ||||
| script: | ||||
|   - make testall | ||||
|   | ||||
| @@ -11,12 +11,15 @@ FROM alpine:3.8 | ||||
| # experience when this doesn't work out of the box. | ||||
| # | ||||
| # OpenSSL is required so wget can query HTTPS endpoints for health checking. | ||||
| RUN apk add --update ca-certificates openssl bash | ||||
| RUN apk add --update ca-certificates openssl | ||||
|  | ||||
| COPY --from=0 /go/bin/dex /usr/local/bin/dex | ||||
|  | ||||
| # Import frontend assets and set the correct CWD directory so the assets | ||||
| # are in the default path. | ||||
| COPY web /web | ||||
| WORKDIR / | ||||
|  | ||||
| EXPOSE 5500-5600 | ||||
| CMD ["bash"] | ||||
| ENTRYPOINT ["dex"] | ||||
|  | ||||
| CMD ["version"] | ||||
|   | ||||
| @@ -35,7 +35,6 @@ type Identity struct { | ||||
| 	// | ||||
| 	// This data is never shared with end users, OAuth clients, or through the API. | ||||
| 	ConnectorData []byte | ||||
| 	Password string | ||||
| } | ||||
|  | ||||
| // PasswordConnector is an interface implemented by connectors which take a | ||||
|   | ||||
| @@ -2,163 +2,186 @@ | ||||
| package keystone | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"github.com/dexidp/dex/connector" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"encoding/json" | ||||
| 	"net/http" | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/sirupsen/logrus" | ||||
|  | ||||
| 	"github.com/dexidp/dex/connector" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	_ connector.PasswordConnector = &Connector{} | ||||
|   	_ connector.RefreshConnector = &Connector{} | ||||
| 	_ connector.PasswordConnector = &keystoneConnector{} | ||||
| 	_ connector.RefreshConnector  = &keystoneConnector{} | ||||
| ) | ||||
|  | ||||
| // Open returns an authentication strategy using Keystone. | ||||
| func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) { | ||||
| 	return &Connector{c.Domain, c.KeystoneHost, | ||||
| 	c.KeystoneUsername, c.KeystonePassword, logger}, nil | ||||
| 	return &keystoneConnector{c.Domain, c.KeystoneHost, | ||||
| 		c.KeystoneUsername, c.KeystonePassword, logger}, nil | ||||
| } | ||||
|  | ||||
| func (p Connector) Close() error { return nil } | ||||
| func (p *keystoneConnector) Close() error { return nil } | ||||
|  | ||||
| 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) | ||||
| func (p *keystoneConnector) Login(ctx context.Context, s connector.Scopes, username, password string) ( | ||||
| 	identity connector.Identity, validPassword bool, err error) { | ||||
| 	resp, err := p.getTokenResponse(ctx, username, password) | ||||
| 	if err != nil { | ||||
| 		return identity, false, fmt.Errorf("keystone: error %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// 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) | ||||
| 	if resp.StatusCode == 201 { | ||||
| 		token := resp.Header.Get("X-Subject-Token") | ||||
| 		data, err := ioutil.ReadAll(resp.Body) | ||||
| 		if err != nil { | ||||
| 			return identity, false, err | ||||
| 		} | ||||
| 		defer resp.Body.Close() | ||||
|  | ||||
|     	var tokenResponse = new(TokenResponse) | ||||
|     	err := json.Unmarshal(data, &tokenResponse) | ||||
| 		var tokenResp = new(tokenResponse) | ||||
| 		err = json.Unmarshal(data, &tokenResp) | ||||
| 		if err != nil { | ||||
| 			return identity, false, fmt.Errorf("keystone: invalid token response: %v", err) | ||||
| 		} | ||||
| 		groups, err := p.getUserGroups(ctx, tokenResp.Token.User.ID, token) | ||||
| 		if err != nil { | ||||
| 			return identity, false, err | ||||
| 		} | ||||
|  | ||||
|     	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 | ||||
| 		identity.Username = username | ||||
| 		identity.UserID = tokenResp.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 | ||||
| } | ||||
|  | ||||
| func (p Connector) Prompt() string { return "username" } | ||||
| func (p *keystoneConnector) Prompt() string { return "username" } | ||||
|  | ||||
| func (p Connector) Refresh( | ||||
| func (p *keystoneConnector) 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(ctx) | ||||
| 	if err != nil { | ||||
| 		return identity, fmt.Errorf("keystone: failed to obtain admin token: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	token, err := p.getAdminToken() | ||||
| 	ok, err := p.checkIfUserExists(ctx, identity.UserID, token) | ||||
| 	if err != nil { | ||||
| 		return identity, err | ||||
| 	} | ||||
| 	if !ok { | ||||
| 		return identity, fmt.Errorf("keystone: user %q does not exist", identity.UserID) | ||||
| 	} | ||||
|  | ||||
|   	if err != nil { | ||||
|     	fmt.Printf("keystone: failed to obtain admin token") | ||||
|     	return identity, err | ||||
|   	} | ||||
| 	groups, err := p.getUserGroups(ctx, identity.UserID, token) | ||||
| 	if err != nil { | ||||
| 		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) | ||||
| 	identity.Groups = groups | ||||
| 	return identity, nil | ||||
| } | ||||
|  | ||||
|  | ||||
| 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}, | ||||
| 						Password: password, | ||||
| func (p *keystoneConnector) getTokenResponse(ctx context.Context, username, pass string) (response *http.Response, err error) { | ||||
| 	client := &http.Client{} | ||||
| 	jsonData := loginRequestData{ | ||||
| 		auth: auth{ | ||||
| 			Identity: identity{ | ||||
| 				Methods: []string{"password"}, | ||||
| 				Password: password{ | ||||
| 					User: user{ | ||||
| 						Name:     username, | ||||
| 						Domain:   domain{ID: p.Domain}, | ||||
| 						Password: pass, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	jsonValue, _ := json.Marshal(jsonData) | ||||
|   	loginURI := p.KeystoneHost + "/v3/auth/tokens" | ||||
| 	return http.Post(loginURI, "application/json", bytes.NewBuffer(jsonValue)) | ||||
| 	jsonValue, err := json.Marshal(jsonData) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	authTokenURL := p.KeystoneHost + "/v3/auth/tokens/" | ||||
| 	req, err := http.NewRequest("POST", authTokenURL, bytes.NewBuffer(jsonValue)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| 	req = req.WithContext(ctx) | ||||
|  | ||||
| 	return client.Do(req) | ||||
| } | ||||
|  | ||||
| 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 *keystoneConnector) getAdminToken(ctx context.Context) (string, error) { | ||||
| 	resp, err := p.getTokenResponse(ctx, p.KeystoneUsername, p.KeystonePassword) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	token := resp.Header.Get("X-Subject-Token") | ||||
| 	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 *keystoneConnector) checkIfUserExists(ctx context.Context, userID string, token string) (bool, error) { | ||||
| 	userURL := p.KeystoneHost + "/v3/users/" + userID | ||||
| 	client := &http.Client{} | ||||
| 	req, err := http.NewRequest("GET", userURL, nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
|  | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	req = req.WithContext(ctx) | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
|  | ||||
| 	if resp.StatusCode == 200 { | ||||
| 		return true, nil | ||||
| 	} | ||||
| 	return false, err | ||||
| } | ||||
|  | ||||
| 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) | ||||
| func (p *keystoneConnector) getUserGroups(ctx context.Context, userID string, token string) ([]string, error) { | ||||
| 	client := &http.Client{} | ||||
| 	groupsURL := p.KeystoneHost + "/v3/users/" + userID + "/groups" | ||||
|  | ||||
|   	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 | ||||
| 	req, err := http.NewRequest("GET", groupsURL, nil) | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	req = req.WithContext(ctx) | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		p.Logger.Errorf("keystone: error while fetching user %q groups\n", userID) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	data, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	var groupsResp = new(groupsResponse) | ||||
|  | ||||
| 	err = json.Unmarshal(data, &groupsResp) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	groups := make([]string, len(groupsResp.Groups)) | ||||
| 	for i, group := range groupsResp.Groups { | ||||
| 		groups[i] = group.Name | ||||
| 	} | ||||
| 	return groups, nil | ||||
| } | ||||
|   | ||||
| @@ -1,275 +1,358 @@ | ||||
| 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" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/dexidp/dex/connector" | ||||
| ) | ||||
|  | ||||
| const dockerCliVersion = "1.37" | ||||
| const ( | ||||
| 	adminUser   = "demo" | ||||
| 	adminPass   = "DEMO_PASS" | ||||
| 	invalidPass = "WRONG_PASS" | ||||
|  | ||||
| const exposedKeystonePort = "5000" | ||||
| const exposedKeystonePortAdmin = "35357" | ||||
| 	testUser   = "test_user" | ||||
| 	testPass   = "test_pass" | ||||
| 	testEmail  = "test@example.com" | ||||
| 	testGroup  = "test_group" | ||||
| 	testDomain = "default" | ||||
| ) | ||||
|  | ||||
| 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/" | ||||
| var ( | ||||
| 	keystoneURL      = "" | ||||
| 	keystoneAdminURL = "" | ||||
| 	authTokenURL     = "" | ||||
| 	usersURL         = "" | ||||
| 	groupsURL        = "" | ||||
| ) | ||||
|  | ||||
| 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 | ||||
| type userResponse struct { | ||||
| 	User struct { | ||||
| 		ID string `json:"id"` | ||||
| 	} `json:"user"` | ||||
| } | ||||
|  | ||||
| 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) | ||||
| 	} | ||||
| type groupResponse struct { | ||||
| 	Group struct { | ||||
| 		ID string `json:"id"` | ||||
| 	} `json:"group"` | ||||
| } | ||||
|  | ||||
| func getAdminToken(admin_name, admin_pass string) (token string) { | ||||
| func getAdminToken(t *testing.T, adminName, adminPass string) (token, id string) { | ||||
| 	t.Helper() | ||||
| 	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, | ||||
| 	jsonData := loginRequestData{ | ||||
| 		auth: auth{ | ||||
| 			Identity: identity{ | ||||
| 				Methods: []string{"password"}, | ||||
| 				Password: password{ | ||||
| 					User: user{ | ||||
| 						Name:     adminName, | ||||
| 						Domain:   domain{ID: testDomain}, | ||||
| 						Password: adminPass, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	body, _ := json.Marshal(jsonData) | ||||
| 	body, err := json.Marshal(jsonData) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	req, _ := http.NewRequest("POST", authTokenURL, bytes.NewBuffer(body)) | ||||
| 	req, err := http.NewRequest("POST", authTokenURL, bytes.NewBuffer(body)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("keystone: failed to obtain admin token: %v\n", err) | ||||
| 	} | ||||
|  | ||||
| 	req.Header.Set("Content-Type", "application/json") | ||||
| 	resp, _ := client.Do(req) | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	token = resp.Header["X-Subject-Token"][0] | ||||
| 	return token | ||||
| 	token = resp.Header.Get("X-Subject-Token") | ||||
|  | ||||
| 	data, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	var tokenResp = new(tokenResponse) | ||||
| 	err = json.Unmarshal(data, &tokenResp) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	return token, tokenResp.Token.User.ID | ||||
| } | ||||
|  | ||||
| func createUser(token, user_name, user_email, user_pass string) (string){ | ||||
| func createUser(t *testing.T, token, userName, userEmail, userPass string) string { | ||||
| 	t.Helper() | ||||
| 	client := &http.Client{} | ||||
|  | ||||
| 	createUserData := CreateUserRequest{ | ||||
| 		CreateUser: CreateUserForm{ | ||||
| 			Name: user_name, | ||||
| 			Email: user_email, | ||||
| 			Enabled: true, | ||||
| 			Password: user_pass, | ||||
| 			Roles: []string{"admin"}, | ||||
| 	createUserData := map[string]interface{}{ | ||||
| 		"user": map[string]interface{}{ | ||||
| 			"name":     userName, | ||||
| 			"email":    userEmail, | ||||
| 			"enabled":  true, | ||||
| 			"password": userPass, | ||||
| 			"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) | ||||
| 	body, err := json.Marshal(createUserData) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 		t.Fatal(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, err := http.NewRequest("POST", usersURL, bytes.NewBuffer(body)) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	resp, _ := client.Do(req) | ||||
| 	fmt.Println(resp) | ||||
| 	req.Header.Add("Content-Type", "application/json") | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	data, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	var userResp = new(userResponse) | ||||
| 	err = json.Unmarshal(data, &userResp) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	return userResp.User.ID | ||||
| } | ||||
|  | ||||
| func createGroup(token, description, name string) string{ | ||||
| // delete group or user | ||||
| func delete(t *testing.T, token, id, uri string) { | ||||
| 	t.Helper() | ||||
| 	client := &http.Client{} | ||||
|  | ||||
| 	createGroupData := CreateGroup{ | ||||
| 		CreateGroupForm{ | ||||
| 			Description: description, | ||||
| 			Name: name, | ||||
| 	deleteURI := uri + id | ||||
| 	req, err := http.NewRequest("DELETE", deleteURI, nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("error: %v", err) | ||||
| 	} | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	client.Do(req) | ||||
| } | ||||
|  | ||||
| func createGroup(t *testing.T, token, description, name string) string { | ||||
| 	t.Helper() | ||||
| 	client := &http.Client{} | ||||
|  | ||||
| 	createGroupData := map[string]interface{}{ | ||||
| 		"group": map[string]interface{}{ | ||||
| 			"name":        name, | ||||
| 			"description": description, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	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) | ||||
| 	body, err := json.Marshal(createGroupData) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 		t.Fatal(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, err := http.NewRequest("POST", groupsURL, bytes.NewBuffer(body)) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	resp, _ := client.Do(req) | ||||
| 	fmt.Println(resp) | ||||
| 	req.Header.Add("Content-Type", "application/json") | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	data, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	var groupResp = new(groupResponse) | ||||
| 	err = json.Unmarshal(data, &groupResp) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	return groupResp.Group.ID | ||||
| } | ||||
|  | ||||
| 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 addUserToGroup(t *testing.T, token, groupID, userID string) error { | ||||
| 	t.Helper() | ||||
| 	uri := groupsURL + groupID + "/users/" + userID | ||||
| 	client := &http.Client{} | ||||
| 	req, err := http.NewRequest("PUT", uri, nil) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	req.Header.Set("X-Auth-Token", token) | ||||
| 	client.Do(req) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| 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) | ||||
| 	c := keystoneConnector{KeystoneHost: keystoneURL, Domain: testDomain, | ||||
| 		KeystoneUsername: adminUser, KeystonePassword: adminPass} | ||||
| 	s := connector.Scopes{OfflineAccess: true, Groups: true} | ||||
| 	_, validPW, err := c.Login(context.Background(), s, adminUser, invalidPass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
|  | ||||
|   	if validPW { | ||||
|   		t.Fail() | ||||
|   	} | ||||
| 	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) | ||||
| 	token, _ := getAdminToken(t, adminUser, adminPass) | ||||
| 	userID := createUser(t, token, testUser, testEmail, testPass) | ||||
| 	c := keystoneConnector{KeystoneHost: keystoneURL, Domain: testDomain, | ||||
| 		KeystoneUsername: adminUser, KeystonePassword: adminPass} | ||||
| 	s := connector.Scopes{OfflineAccess: true, Groups: true} | ||||
| 	identity, validPW, err := c.Login(context.Background(), s, testUser, testPass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
| 	t.Log(identity) | ||||
|  | ||||
| 	if !validPW { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| 	delete(t, token, userID, usersURL) | ||||
| } | ||||
|  | ||||
| func TestUseRefreshToken(t *testing.T) { | ||||
|   t.Fatal("Not implemented") | ||||
| 	token, adminID := getAdminToken(t, adminUser, adminPass) | ||||
| 	groupID := createGroup(t, token, "Test group description", testGroup) | ||||
| 	addUserToGroup(t, token, groupID, adminID) | ||||
|  | ||||
| 	c := keystoneConnector{KeystoneHost: keystoneURL, Domain: testDomain, | ||||
| 		KeystoneUsername: adminUser, KeystonePassword: adminPass} | ||||
| 	s := connector.Scopes{OfflineAccess: true, Groups: true} | ||||
|  | ||||
| 	identityLogin, _, err := c.Login(context.Background(), s, adminUser, adminPass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	identityRefresh, err := c.Refresh(context.Background(), s, identityLogin) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	delete(t, token, groupID, groupsURL) | ||||
|  | ||||
| 	expectEquals(t, 1, len(identityRefresh.Groups)) | ||||
| 	expectEquals(t, testGroup, string(identityRefresh.Groups[0])) | ||||
| } | ||||
|  | ||||
| func TestUseRefreshTokenUserDeleted(t *testing.T){ | ||||
|   t.Fatal("Not implemented") | ||||
| func TestUseRefreshTokenUserDeleted(t *testing.T) { | ||||
| 	token, _ := getAdminToken(t, adminUser, adminPass) | ||||
| 	userID := createUser(t, token, testUser, testEmail, testPass) | ||||
|  | ||||
| 	c := keystoneConnector{KeystoneHost: keystoneURL, Domain: testDomain, | ||||
| 		KeystoneUsername: adminUser, KeystonePassword: adminPass} | ||||
| 	s := connector.Scopes{OfflineAccess: true, Groups: true} | ||||
|  | ||||
| 	identityLogin, _, err := c.Login(context.Background(), s, testUser, testPass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	_, err = c.Refresh(context.Background(), s, identityLogin) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	delete(t, token, userID, usersURL) | ||||
| 	_, err = c.Refresh(context.Background(), s, identityLogin) | ||||
|  | ||||
| 	if !strings.Contains(err.Error(), "does not exist") { | ||||
| 		t.Errorf("unexpected error: %s", err.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestUseRefreshTokenGroupsChanged(t *testing.T){ | ||||
| 	t.Fatal("Not implemented") | ||||
| func TestUseRefreshTokenGroupsChanged(t *testing.T) { | ||||
| 	token, _ := getAdminToken(t, adminUser, adminPass) | ||||
| 	userID := createUser(t, token, testUser, testEmail, testPass) | ||||
|  | ||||
| 	c := keystoneConnector{KeystoneHost: keystoneURL, Domain: testDomain, | ||||
| 		KeystoneUsername: adminUser, KeystonePassword: adminPass} | ||||
| 	s := connector.Scopes{OfflineAccess: true, Groups: true} | ||||
|  | ||||
| 	identityLogin, _, err := c.Login(context.Background(), s, testUser, testPass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	identityRefresh, err := c.Refresh(context.Background(), s, identityLogin) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	expectEquals(t, 0, len(identityRefresh.Groups)) | ||||
|  | ||||
| 	groupID := createGroup(t, token, "Test group description", testGroup) | ||||
| 	addUserToGroup(t, token, groupID, userID) | ||||
|  | ||||
| 	identityRefresh, err = c.Refresh(context.Background(), s, identityLogin) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	delete(t, token, groupID, groupsURL) | ||||
| 	delete(t, token, userID, usersURL) | ||||
|  | ||||
| 	expectEquals(t, 1, len(identityRefresh.Groups)) | ||||
| } | ||||
|  | ||||
| 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 | ||||
| 	keystoneURLEnv := "DEX_KEYSTONE_URL" | ||||
| 	keystoneAdminURLEnv := "DEX_KEYSTONE_ADMIN_URL" | ||||
| 	keystoneURL = os.Getenv(keystoneURLEnv) | ||||
| 	if keystoneURL == "" { | ||||
| 		fmt.Printf("variable %q not set, skipping keystone connector tests\n", keystoneURLEnv) | ||||
| 		return | ||||
| 	} | ||||
| 	keystoneAdminURL := os.Getenv(keystoneAdminURLEnv) | ||||
| 	if keystoneAdminURL == "" { | ||||
| 		fmt.Printf("variable %q not set, skipping keystone connector tests\n", keystoneAdminURLEnv) | ||||
| 		return | ||||
| 	} | ||||
| 	authTokenURL = keystoneURL + "/v3/auth/tokens/" | ||||
| 	fmt.Printf("Auth token url %q\n", authTokenURL) | ||||
| 	fmt.Printf("Keystone URL %q\n", keystoneURL) | ||||
| 	usersURL = keystoneAdminURL + "/v3/users/" | ||||
| 	groupsURL = keystoneAdminURL + "/v3/groups/" | ||||
| 	// run all tests | ||||
| 	m.Run() | ||||
| } | ||||
|  | ||||
| func expectEquals(t *testing.T, a interface{}, b interface{}) { | ||||
| 	if !reflect.DeepEqual(a, b) { | ||||
| 		t.Errorf("Expected %v to be equal %v", a, b) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -4,133 +4,84 @@ import ( | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| type Connector struct { | ||||
| 	Domain 			 string | ||||
| 	KeystoneHost 	 string | ||||
| type keystoneConnector struct { | ||||
| 	Domain           string | ||||
| 	KeystoneHost     string | ||||
| 	KeystoneUsername string | ||||
| 	KeystonePassword string | ||||
| 	Logger 			 logrus.FieldLogger | ||||
| 	Logger           logrus.FieldLogger | ||||
| } | ||||
|  | ||||
| type ConnectorData struct { | ||||
| 	AccessToken string `json:"accessToken"` | ||||
| type userKeystone struct { | ||||
| 	Domain domainKeystone `json:"domain"` | ||||
| 	ID     string         `json:"id"` | ||||
| 	Name   string         `json:"name"` | ||||
| } | ||||
|  | ||||
| type KeystoneUser struct { | ||||
| 	Domain KeystoneDomain `json:"domain"` | ||||
| 	ID 	   string 		  `json:"id"` | ||||
| 	Name   string 		  `json:"name"` | ||||
| } | ||||
|  | ||||
| type KeystoneDomain struct { | ||||
| 	ID string   `json:"id"` | ||||
| type domainKeystone struct { | ||||
| 	ID   string `json:"id"` | ||||
| 	Name string `json:"name"` | ||||
| } | ||||
|  | ||||
| // Config holds the configuration parameters for Keystone connector. | ||||
| // Keystone should expose API v3 | ||||
| // An example config: | ||||
| //	connectors: | ||||
| //		type: keystone | ||||
| //		id: keystone | ||||
| //		name: Keystone | ||||
| //		config: | ||||
| //			keystoneHost: http://example:5000 | ||||
| //			domain: default | ||||
| //      keystoneUsername: demo | ||||
| //      keystonePassword: DEMO_PASS | ||||
| type Config struct { | ||||
| 	Domain 			 string `json:"domain"` | ||||
| 	KeystoneHost 	 string `json:"keystoneHost"` | ||||
| 	Domain           string `json:"domain"` | ||||
| 	KeystoneHost     string `json:"keystoneHost"` | ||||
| 	KeystoneUsername string `json:"keystoneUsername"` | ||||
| 	KeystonePassword string `json:"keystonePassword"` | ||||
| } | ||||
|  | ||||
| type LoginRequestData struct { | ||||
| 	Auth `json:"auth"` | ||||
| type loginRequestData struct { | ||||
| 	auth `json:"auth"` | ||||
| } | ||||
|  | ||||
| type Auth struct { | ||||
| 	Identity `json:"identity"` | ||||
| type auth struct { | ||||
| 	Identity identity `json:"identity"` | ||||
| } | ||||
|  | ||||
| type Identity struct { | ||||
| type identity struct { | ||||
| 	Methods  []string `json:"methods"` | ||||
| 	Password 		  `json:"password"` | ||||
| 	Password password `json:"password"` | ||||
| } | ||||
|  | ||||
| type Password struct { | ||||
| 	User `json:"user"` | ||||
| type password struct { | ||||
| 	User 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 { | ||||
| type user struct { | ||||
| 	Name     string `json:"name"` | ||||
| 	Email    string `json:"email"` | ||||
| 	Enabled  bool   `json:"enabled"` | ||||
| 	Domain   domain `json:"domain"` | ||||
| 	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 { | ||||
| type domain struct { | ||||
| 	ID string `json:"id"` | ||||
| } | ||||
|  | ||||
| type Links struct { | ||||
| 	Self string `json:"self"` | ||||
| 	Previous string `json:"previous"` | ||||
| 	Next string `json:"next"` | ||||
| type token struct { | ||||
| 	User userKeystone `json:"user"` | ||||
| } | ||||
|  | ||||
| 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 tokenResponse struct { | ||||
| 	Token token `json:"token"` | ||||
| } | ||||
|  | ||||
| type GroupsResponse struct { | ||||
| 	Links  Links   `json:"links"` | ||||
| 	Groups []Group `json:"groups"` | ||||
| type group struct { | ||||
| 	ID   string `json:"id"` | ||||
| 	Name string `json:"name"` | ||||
| } | ||||
|  | ||||
| type groupsResponse struct { | ||||
| 	Groups []group `json:"groups"` | ||||
| } | ||||
|   | ||||
| @@ -1,55 +0,0 @@ | ||||
| # The base path of dex and the external name of the OpenID Connect service. | ||||
| # This is the canonical URL that all clients MUST use to refer to dex. If a | ||||
| # path is provided, dex's HTTP service will listen at a non-root URL. | ||||
| issuer: http://0.0.0.0:5556/dex | ||||
|  | ||||
| # The storage configuration determines where dex stores its state. Supported | ||||
| # options include SQL flavors and Kubernetes third party resources. | ||||
| # | ||||
| # See the storage document at Documentation/storage.md for further information. | ||||
| storage: | ||||
|   type: sqlite3 | ||||
|   config: | ||||
|     file: examples/dex.db   #be in the dex directory, else change path here | ||||
|  | ||||
| # Configuration for the HTTP endpoints. | ||||
| web: | ||||
|   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: | ||||
|   http: 0.0.0.0:5558 | ||||
|  | ||||
| oauth2: | ||||
|   responseTypes: ["id_token"] | ||||
|  | ||||
| # Instead of reading from an external storage, use this list of clients. | ||||
| staticClients: | ||||
| - id: example-app | ||||
|   redirectURIs: | ||||
|   - 'http://127.0.0.1:5555/callback' | ||||
|   name: 'Example App' | ||||
|   secret: ZXhhbXBsZS1hcHAtc2VjcmV0 | ||||
|  | ||||
| #Provide Keystone connector and its config here | ||||
| # /v3/auth/tokens | ||||
| connectors: | ||||
| - type: keystone | ||||
|   id: keystone | ||||
|   name: Keystone | ||||
|   config: | ||||
|     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 | ||||
|  | ||||
| oauth2: | ||||
|   skipApprovalScreen: true | ||||
|  | ||||
| @@ -211,7 +211,6 @@ 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 { | ||||
| @@ -346,7 +345,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("2Failed to get auth request: %v", err) | ||||
| 		s.logger.Errorf("Failed to get auth request: %v", err) | ||||
| 		s.renderError(w, http.StatusInternalServerError, "Database error.") | ||||
| 		return | ||||
| 	} | ||||
| @@ -358,7 +357,6 @@ 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.") | ||||
| @@ -437,7 +435,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("3Failed to get auth request: %v", err) | ||||
| 		s.logger.Errorf("Failed to get auth request: %v", err) | ||||
| 		s.renderError(w, http.StatusInternalServerError, "Database error.") | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -27,6 +27,7 @@ import ( | ||||
| 	"github.com/dexidp/dex/connector/bitbucketcloud" | ||||
| 	"github.com/dexidp/dex/connector/github" | ||||
| 	"github.com/dexidp/dex/connector/gitlab" | ||||
| 	"github.com/dexidp/dex/connector/keystone" | ||||
| 	"github.com/dexidp/dex/connector/ldap" | ||||
| 	"github.com/dexidp/dex/connector/linkedin" | ||||
| 	"github.com/dexidp/dex/connector/microsoft" | ||||
| @@ -34,7 +35,6 @@ import ( | ||||
| 	"github.com/dexidp/dex/connector/oidc" | ||||
| 	"github.com/dexidp/dex/connector/saml" | ||||
| 	"github.com/dexidp/dex/storage" | ||||
|   "github.com/dexidp/dex/connector/keystone" | ||||
| ) | ||||
|  | ||||
| // LocalConnector is the local passwordDB connector which is an internal | ||||
| @@ -456,7 +456,7 @@ func openConnector(logger logrus.FieldLogger, conn storage.Connector) (connector | ||||
|  | ||||
| 	f, ok := ConnectorsConfig[conn.Type] | ||||
| 	if !ok { | ||||
| 		return c, fmt.Errorf("xunknown connector type %q", conn.Type) | ||||
| 		return c, fmt.Errorf("unknown connector type %q", conn.Type) | ||||
| 	} | ||||
|  | ||||
| 	connConfig := f() | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package storage | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user