Commit d26e23c1 authored by Ed Tan's avatar Ed Tan

Make suggested code changes

parent 2c024d8c
......@@ -14,7 +14,7 @@ The following is an example of a configuration for `examples/config-dev.yaml`:
```yaml
connectors:
- type: bitbucket
- type: bitbucket-cloud
# Required field for connector id.
id: bitbucket
# Required field for connector name.
......@@ -22,9 +22,11 @@ connectors:
config:
# Credentials can be string literals or pulled from the environment.
clientID: $BITBUCKET_CLIENT_ID
clientSecret: BITBUCKET_CLIENT_SECRET
clientSecret: $BITBUCKET_CLIENT_SECRET
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:
- my-team
```
// Package bitbucket provides authentication strategies using Bitbucket.
package bitbucket
// Package bitbucketcloud provides authentication strategies using Bitbucket Cloud.
package bitbucketcloud
import (
"context"
......@@ -71,8 +71,7 @@ type bitbucketConnector struct {
clientID string
clientSecret string
logger logrus.FieldLogger
// apiURL defaults to "https://api.bitbucket.org/2.0"
apiURL string
apiURL string
// the following are used only for tests
hostName string
......@@ -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 {
return u, err
return user{}, err
}
if u.Email, err = b.userEmail(ctx, client); err != nil {
return u, err
return user{}, err
}
return u, nil
......@@ -309,7 +308,6 @@ func (b *bitbucketConnector) user(ctx context.Context, client *http.Client) (use
type userEmail struct {
IsPrimary bool `json:"is_primary"`
IsConfirmed bool `json:"is_confirmed"`
Type string `json:"type"`
Email string `json:"email"`
}
......@@ -356,7 +354,7 @@ func (b *bitbucketConnector) getGroups(ctx context.Context, client *http.Client,
if len(b.teams) > 0 {
filteredTeams := filterTeams(bitbucketTeams, b.teams)
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
} 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.
func filterTeams(userTeams, configTeams []string) (teams []string) {
func filterTeams(userTeams, configTeams []string) []string {
teams := []string{}
teamFilter := make(map[string]struct{})
for _, team := range configTeams {
if _, ok := teamFilter[team]; !ok {
teamFilter[team] = struct{}{}
}
teamFilter[team] = struct{}{}
}
for _, team := range userTeams {
if _, ok := teamFilter[team]; ok {
teams = append(teams, team)
}
}
return
return teams
}
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 {
......@@ -392,7 +389,10 @@ type userTeamsResponse struct {
}
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 {
// https://developer.atlassian.com/bitbucket/api/2/reference/resource/teams
var response userTeamsResponse
......@@ -402,7 +402,7 @@ func (b *bitbucketConnector) userTeams(ctx context.Context, client *http.Client)
}
for _, team := range response.Values {
teams = append(teams, team.Username)
teams = append(teams, team.Name)
}
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 {
body, err := ioutil.ReadAll(resp.Body)
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)
}
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
......
package bitbucket
package bitbucketcloud
import (
"context"
......@@ -22,9 +22,9 @@ func TestUserGroups(t *testing.T) {
PageLen: 10,
},
Values: []team{
{Username: "team-1"},
{Username: "team-2"},
{Username: "team-3"},
{Name: "team-1"},
{Name: "team-2"},
{Name: "team-3"},
},
}
......@@ -113,12 +113,12 @@ func newClient() *http.Client {
func expectNil(t *testing.T, a interface{}) {
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{}) {
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/authproxy"
"github.com/dexidp/dex/connector/bitbucket"
"github.com/dexidp/dex/connector/bitbucketcloud"
"github.com/dexidp/dex/connector/github"
"github.com/dexidp/dex/connector/gitlab"
"github.com/dexidp/dex/connector/ldap"
......@@ -430,17 +430,17 @@ 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{
"mockCallback": func() ConnectorConfig { return new(mock.CallbackConfig) },
"mockPassword": func() ConnectorConfig { return new(mock.PasswordConfig) },
"ldap": func() ConnectorConfig { return new(ldap.Config) },
"github": func() ConnectorConfig { return new(github.Config) },
"gitlab": func() ConnectorConfig { return new(gitlab.Config) },
"oidc": func() ConnectorConfig { return new(oidc.Config) },
"saml": func() ConnectorConfig { return new(saml.Config) },
"authproxy": func() ConnectorConfig { return new(authproxy.Config) },
"linkedin": func() ConnectorConfig { return new(linkedin.Config) },
"microsoft": func() ConnectorConfig { return new(microsoft.Config) },
"bitbucket": func() ConnectorConfig { return new(bitbucket.Config) },
"mockCallback": func() ConnectorConfig { return new(mock.CallbackConfig) },
"mockPassword": func() ConnectorConfig { return new(mock.PasswordConfig) },
"ldap": func() ConnectorConfig { return new(ldap.Config) },
"github": func() ConnectorConfig { return new(github.Config) },
"gitlab": func() ConnectorConfig { return new(gitlab.Config) },
"oidc": func() ConnectorConfig { return new(oidc.Config) },
"saml": func() ConnectorConfig { return new(saml.Config) },
"authproxy": func() ConnectorConfig { return new(authproxy.Config) },
"linkedin": func() ConnectorConfig { return new(linkedin.Config) },
"microsoft": func() ConnectorConfig { return new(microsoft.Config) },
"bitbucket-cloud": func() ConnectorConfig { return new(bitbucketcloud.Config) },
// Keep around for backwards compatibility.
"samlExperimental": func() ConnectorConfig { return new(saml.Config) },
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment