Make suggested code changes
This commit is contained in:
		| @@ -14,7 +14,7 @@ The following is an example of a configuration for `examples/config-dev.yaml`: | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| connectors: | connectors: | ||||||
| - type: bitbucket | - type: bitbucket-cloud | ||||||
|   # Required field for connector id. |   # Required field for connector id. | ||||||
|   id: bitbucket |   id: bitbucket | ||||||
|   # Required field for connector name. |   # Required field for connector name. | ||||||
| @@ -22,9 +22,11 @@ connectors: | |||||||
|   config: |   config: | ||||||
|     # Credentials can be string literals or pulled from the environment. |     # Credentials can be string literals or pulled from the environment. | ||||||
|     clientID: $BITBUCKET_CLIENT_ID |     clientID: $BITBUCKET_CLIENT_ID | ||||||
|     clientSecret: BITBUCKET_CLIENT_SECRET |     clientSecret: $BITBUCKET_CLIENT_SECRET | ||||||
|     redirectURI: http://127.0.0.1:5556/dex/callback |     redirectURI: http://127.0.0.1:5556/dex/callback | ||||||
|     # Optional teams, communicated through the "groups" scope. |     # Optional teams whitelist, communicated through the "groups" scope. | ||||||
|  |     # If `teams` is omitted, all of the user's Bitbucket teams are returned when the groups scope is present. | ||||||
|  |     # If `teams` is provided, this acts as a whitelist - only the user's Bitbucket teams that are in the configured `teams` below will go into the groups claim.  Conversely, if the user is not in any of the configured `teams`, the user will not be authenticated. | ||||||
|     teams: |     teams: | ||||||
|     - my-team |     - my-team | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| // Package bitbucket provides authentication strategies using Bitbucket. | // Package bitbucketcloud provides authentication strategies using Bitbucket Cloud. | ||||||
| package bitbucket | package bitbucketcloud | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| @@ -71,7 +71,6 @@ type bitbucketConnector struct { | |||||||
| 	clientID     string | 	clientID     string | ||||||
| 	clientSecret string | 	clientSecret string | ||||||
| 	logger       logrus.FieldLogger | 	logger       logrus.FieldLogger | ||||||
| 	// apiURL defaults to "https://api.bitbucket.org/2.0" |  | ||||||
| 	apiURL       string | 	apiURL       string | ||||||
|  |  | ||||||
| 	// the following are used only for tests | 	// the following are used only for tests | ||||||
| @@ -294,11 +293,11 @@ func (b *bitbucketConnector) user(ctx context.Context, client *http.Client) (use | |||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	if err = get(ctx, client, b.apiURL+"/user", &u); err != nil { | 	if err = get(ctx, client, b.apiURL+"/user", &u); err != nil { | ||||||
| 		return u, err | 		return user{}, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if u.Email, err = b.userEmail(ctx, client); err != nil { | 	if u.Email, err = b.userEmail(ctx, client); err != nil { | ||||||
| 		return u, err | 		return user{}, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return u, nil | 	return u, nil | ||||||
| @@ -309,7 +308,6 @@ func (b *bitbucketConnector) user(ctx context.Context, client *http.Client) (use | |||||||
| type userEmail struct { | type userEmail struct { | ||||||
| 	IsPrimary   bool   `json:"is_primary"` | 	IsPrimary   bool   `json:"is_primary"` | ||||||
| 	IsConfirmed bool   `json:"is_confirmed"` | 	IsConfirmed bool   `json:"is_confirmed"` | ||||||
| 	Type        string `json:"type"` |  | ||||||
| 	Email       string `json:"email"` | 	Email       string `json:"email"` | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -356,7 +354,7 @@ func (b *bitbucketConnector) getGroups(ctx context.Context, client *http.Client, | |||||||
| 	if len(b.teams) > 0 { | 	if len(b.teams) > 0 { | ||||||
| 		filteredTeams := filterTeams(bitbucketTeams, b.teams) | 		filteredTeams := filterTeams(bitbucketTeams, b.teams) | ||||||
| 		if len(filteredTeams) == 0 { | 		if len(filteredTeams) == 0 { | ||||||
| 			return nil, fmt.Errorf("bitbucket: user %q not in required teams", userLogin) | 			return nil, fmt.Errorf("bitbucket: user %q is not in any of the required teams", userLogin) | ||||||
| 		} | 		} | ||||||
| 		return filteredTeams, nil | 		return filteredTeams, nil | ||||||
| 	} else if groupScope { | 	} else if groupScope { | ||||||
| @@ -367,23 +365,22 @@ func (b *bitbucketConnector) getGroups(ctx context.Context, client *http.Client, | |||||||
| } | } | ||||||
|  |  | ||||||
| // Filter the users' team memberships by 'teams' from config. | // Filter the users' team memberships by 'teams' from config. | ||||||
| func filterTeams(userTeams, configTeams []string) (teams []string) { | func filterTeams(userTeams, configTeams []string) []string { | ||||||
|  | 	teams := []string{} | ||||||
| 	teamFilter := make(map[string]struct{}) | 	teamFilter := make(map[string]struct{}) | ||||||
| 	for _, team := range configTeams { | 	for _, team := range configTeams { | ||||||
| 		if _, ok := teamFilter[team]; !ok { |  | ||||||
| 		teamFilter[team] = struct{}{} | 		teamFilter[team] = struct{}{} | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 	for _, team := range userTeams { | 	for _, team := range userTeams { | ||||||
| 		if _, ok := teamFilter[team]; ok { | 		if _, ok := teamFilter[team]; ok { | ||||||
| 			teams = append(teams, team) | 			teams = append(teams, team) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return | 	return teams | ||||||
| } | } | ||||||
|  |  | ||||||
| type team struct { | type team struct { | ||||||
| 	Username string `json:"username"` // Username is actually the team name | 	Name string `json:"username"` // The "username" from Bitbucket Cloud is actually the team name here | ||||||
| } | } | ||||||
|  |  | ||||||
| type userTeamsResponse struct { | type userTeamsResponse struct { | ||||||
| @@ -392,7 +389,10 @@ type userTeamsResponse struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *bitbucketConnector) userTeams(ctx context.Context, client *http.Client) ([]string, error) { | func (b *bitbucketConnector) userTeams(ctx context.Context, client *http.Client) ([]string, error) { | ||||||
| 	apiURL, teams := b.apiURL+"/teams?role=member", []string{} |  | ||||||
|  | 	var teams []string | ||||||
|  | 	apiURL := b.apiURL + "/teams?role=member" | ||||||
|  |  | ||||||
| 	for { | 	for { | ||||||
| 		// https://developer.atlassian.com/bitbucket/api/2/reference/resource/teams | 		// https://developer.atlassian.com/bitbucket/api/2/reference/resource/teams | ||||||
| 		var response userTeamsResponse | 		var response userTeamsResponse | ||||||
| @@ -402,7 +402,7 @@ func (b *bitbucketConnector) userTeams(ctx context.Context, client *http.Client) | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		for _, team := range response.Values { | 		for _, team := range response.Values { | ||||||
| 			teams = append(teams, team.Username) | 			teams = append(teams, team.Name) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if response.Next == nil { | 		if response.Next == nil { | ||||||
| @@ -432,13 +432,13 @@ func get(ctx context.Context, client *http.Client, apiURL string, v interface{}) | |||||||
| 	if resp.StatusCode != http.StatusOK { | 	if resp.StatusCode != http.StatusOK { | ||||||
| 		body, err := ioutil.ReadAll(resp.Body) | 		body, err := ioutil.ReadAll(resp.Body) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("bitbucket: read body: %v", err) | 			return fmt.Errorf("bitbucket: read body: %s: %v", resp.Status, err) | ||||||
| 		} | 		} | ||||||
| 		return fmt.Errorf("%s: %s", resp.Status, body) | 		return fmt.Errorf("%s: %s", resp.Status, body) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := json.NewDecoder(resp.Body).Decode(v); err != nil { | 	if err := json.NewDecoder(resp.Body).Decode(v); err != nil { | ||||||
| 		return fmt.Errorf("failed to decode response: %v", err) | 		return fmt.Errorf("bitbucket: failed to decode response: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| package bitbucket | package bitbucketcloud | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| @@ -22,9 +22,9 @@ func TestUserGroups(t *testing.T) { | |||||||
| 			PageLen: 10, | 			PageLen: 10, | ||||||
| 		}, | 		}, | ||||||
| 		Values: []team{ | 		Values: []team{ | ||||||
| 			{Username: "team-1"}, | 			{Name: "team-1"}, | ||||||
| 			{Username: "team-2"}, | 			{Name: "team-2"}, | ||||||
| 			{Username: "team-3"}, | 			{Name: "team-3"}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -113,12 +113,12 @@ func newClient() *http.Client { | |||||||
|  |  | ||||||
| func expectNil(t *testing.T, a interface{}) { | func expectNil(t *testing.T, a interface{}) { | ||||||
| 	if a != nil { | 	if a != nil { | ||||||
| 		t.Errorf("Expected %+v to equal nil", a) | 		t.Fatalf("Expected %+v to equal nil", a) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func expectEquals(t *testing.T, a interface{}, b interface{}) { | func expectEquals(t *testing.T, a interface{}, b interface{}) { | ||||||
| 	if !reflect.DeepEqual(a, b) { | 	if !reflect.DeepEqual(a, b) { | ||||||
| 		t.Errorf("Expected %+v to equal %+v", a, b) | 		t.Fatalf("Expected %+v to equal %+v", a, b) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/dexidp/dex/connector" | 	"github.com/dexidp/dex/connector" | ||||||
| 	"github.com/dexidp/dex/connector/authproxy" | 	"github.com/dexidp/dex/connector/authproxy" | ||||||
| 	"github.com/dexidp/dex/connector/bitbucket" | 	"github.com/dexidp/dex/connector/bitbucketcloud" | ||||||
| 	"github.com/dexidp/dex/connector/github" | 	"github.com/dexidp/dex/connector/github" | ||||||
| 	"github.com/dexidp/dex/connector/gitlab" | 	"github.com/dexidp/dex/connector/gitlab" | ||||||
| 	"github.com/dexidp/dex/connector/ldap" | 	"github.com/dexidp/dex/connector/ldap" | ||||||
| @@ -440,7 +440,7 @@ var ConnectorsConfig = map[string]func() ConnectorConfig{ | |||||||
| 	"authproxy":       func() ConnectorConfig { return new(authproxy.Config) }, | 	"authproxy":       func() ConnectorConfig { return new(authproxy.Config) }, | ||||||
| 	"linkedin":        func() ConnectorConfig { return new(linkedin.Config) }, | 	"linkedin":        func() ConnectorConfig { return new(linkedin.Config) }, | ||||||
| 	"microsoft":       func() ConnectorConfig { return new(microsoft.Config) }, | 	"microsoft":       func() ConnectorConfig { return new(microsoft.Config) }, | ||||||
| 	"bitbucket":    func() ConnectorConfig { return new(bitbucket.Config) }, | 	"bitbucket-cloud": func() ConnectorConfig { return new(bitbucketcloud.Config) }, | ||||||
| 	// Keep around for backwards compatibility. | 	// Keep around for backwards compatibility. | ||||||
| 	"samlExperimental": func() ConnectorConfig { return new(saml.Config) }, | 	"samlExperimental": func() ConnectorConfig { return new(saml.Config) }, | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user