fix: Replace teams endpoint for bitbucket connector

Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
This commit is contained in:
m.nabokikh 2020-10-03 12:50:10 +03:00
parent d4c3a3505d
commit 4b94469547
3 changed files with 15 additions and 11 deletions

View file

@ -10,7 +10,7 @@ When a client redeems a refresh token through dex, dex will re-query Bitbucket t
Register a new OAuth consumer with [Bitbucket](https://confluence.atlassian.com/bitbucket/oauth-on-bitbucket-cloud-238027431.html) ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`. Register a new OAuth consumer with [Bitbucket](https://confluence.atlassian.com/bitbucket/oauth-on-bitbucket-cloud-238027431.html) ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`.
The application requires the user to grant the `Read Account` and `Read Team membership` permissions. The latter is required only if group membership is a desired claim. The application requires the user to grant only the `Read Account` permission.
The following is an example of a configuration for `examples/config-dev.yaml`: The following is an example of a configuration for `examples/config-dev.yaml`:

View file

@ -362,10 +362,14 @@ func (b *bitbucketConnector) getGroups(ctx context.Context, client *http.Client,
return nil, nil return nil, nil
} }
type team struct { type teamName struct {
Name string `json:"username"` // The "username" from Bitbucket Cloud is actually the team name here Name string `json:"username"` // The "username" from Bitbucket Cloud is actually the team name here
} }
type team struct {
Team teamName `json:"team"`
}
type userTeamsResponse struct { type userTeamsResponse struct {
pagedResponse pagedResponse
Values []team Values []team
@ -373,18 +377,18 @@ 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) {
var teams []string var teams []string
apiURL := b.apiURL + "/teams?role=member" apiURL := b.apiURL + "/user/permissions/teams"
for { for {
// https://developer.atlassian.com/bitbucket/api/2/reference/resource/teams // https://developer.atlassian.com/bitbucket/api/2/reference/resource/user/permissions/teams
var response userTeamsResponse var response userTeamsResponse
if err := get(ctx, client, apiURL, &response); err != nil { if err := get(ctx, client, apiURL, &response); err != nil {
return nil, fmt.Errorf("bitbucket: get user teams: %v", err) return nil, fmt.Errorf("bitbucket: get user teams: %v", err)
} }
for _, team := range response.Values { for _, value := range response.Values {
teams = append(teams, team.Name) teams = append(teams, value.Team.Name)
} }
if response.Next == nil { if response.Next == nil {

View file

@ -21,14 +21,14 @@ func TestUserGroups(t *testing.T) {
PageLen: 10, PageLen: 10,
}, },
Values: []team{ Values: []team{
{Name: "team-1"}, {Team: teamName{Name: "team-1"}},
{Name: "team-2"}, {Team: teamName{Name: "team-2"}},
{Name: "team-3"}, {Team: teamName{Name: "team-3"}},
}, },
} }
s := newTestServer(map[string]interface{}{ s := newTestServer(map[string]interface{}{
"/teams?role=member": teamsResponse, "/user/permissions/teams": teamsResponse,
}) })
connector := bitbucketConnector{apiURL: s.URL} connector := bitbucketConnector{apiURL: s.URL}
@ -46,7 +46,7 @@ func TestUserGroups(t *testing.T) {
func TestUserWithoutTeams(t *testing.T) { func TestUserWithoutTeams(t *testing.T) {
s := newTestServer(map[string]interface{}{ s := newTestServer(map[string]interface{}{
"/teams?role=member": userTeamsResponse{}, "/user/permissions/teams": userTeamsResponse{},
}) })
connector := bitbucketConnector{apiURL: s.URL} connector := bitbucketConnector{apiURL: s.URL}