Merge pull request #1345 from concourse/pr/github-team-name-and-slug

Add 'both' option to use team name AND slug in TeamNameField

This allows the connector to be configured with both so that both team names and slugs can be returned in the groups. This makes configuring teams in an application a bit more foolproof; we would often have confusion over whether the team name or slug should be given by the user, so it's easier to just allow both, since collisions shouldn't be possible anyway.
This commit is contained in:
Stephan Renatus 2018-11-20 16:30:54 +01:00 committed by GitHub
commit d40043808b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 12 deletions

View file

@ -59,12 +59,13 @@ connectors:
# Flag which indicates that all user groups and teams should be loaded. # Flag which indicates that all user groups and teams should be loaded.
loadAllGroups: false loadAllGroups: false
# Optional choice between 'name' (default) or 'slug'. # Optional choice between 'name' (default), 'slug', or 'both'.
# #
# As an example, group claims for member of 'Site Reliability Engineers' in # As an example, group claims for member of 'Site Reliability Engineers' in
# Acme organization would yield: # Acme organization would yield:
# - ['acme:Site Reliability Engineers'] for 'name' # - ['acme:Site Reliability Engineers'] for 'name'
# - ['acme:site-reliability-engineers'] for 'slug' # - ['acme:site-reliability-engineers'] for 'slug'
# - ['acme:Site Reliability Engineers', 'acme:site-reliability-engineers'] for 'both'
teamNameField: slug teamNameField: slug
``` ```

View file

@ -16,11 +16,10 @@ import (
"strings" "strings"
"time" "time"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/github" "golang.org/x/oauth2/github"
"github.com/sirupsen/logrus"
"github.com/dexidp/dex/connector" "github.com/dexidp/dex/connector"
) )
@ -111,7 +110,7 @@ func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector
g.loadAllGroups = c.LoadAllGroups g.loadAllGroups = c.LoadAllGroups
switch c.TeamNameField { switch c.TeamNameField {
case "name", "slug", "": case "name", "slug", "both", "":
g.teamNameField = c.TeamNameField g.teamNameField = c.TeamNameField
default: default:
return nil, fmt.Errorf("invalid connector config: unsupported team name field value `%s`", c.TeamNameField) return nil, fmt.Errorf("invalid connector config: unsupported team name field value `%s`", c.TeamNameField)
@ -449,7 +448,7 @@ func (c *githubConnector) userOrgTeams(ctx context.Context, client *http.Client)
} }
for _, t := range teams { for _, t := range teams {
groups[t.Org.Login] = append(groups[t.Org.Login], c.teamGroupClaim(t)) groups[t.Org.Login] = append(groups[t.Org.Login], c.teamGroupClaims(t)...)
} }
if apiURL == "" { if apiURL == "" {
@ -686,7 +685,7 @@ func (c *githubConnector) teamsForOrg(ctx context.Context, client *http.Client,
for _, t := range teams { for _, t := range teams {
if t.Org.Login == orgName { if t.Org.Login == orgName {
groups = append(groups, c.teamGroupClaim(t)) groups = append(groups, c.teamGroupClaims(t)...)
} }
} }
@ -698,12 +697,16 @@ func (c *githubConnector) teamsForOrg(ctx context.Context, client *http.Client,
return groups, nil return groups, nil
} }
// teamGroupClaim returns team slag if 'teamNameField; option is set to 'slug' otherwise returns team name. // teamGroupClaims returns team slug if 'teamNameField' option is set to
func (c *githubConnector) teamGroupClaim(t team) string { // 'slug', returns the slug *and* name if set to 'both', otherwise returns team
// name.
func (c *githubConnector) teamGroupClaims(t team) []string {
switch c.teamNameField { switch c.teamNameField {
case "both":
return []string{t.Name, t.Slug}
case "slug": case "slug":
return t.Slug return []string{t.Slug}
default: default:
return t.Name return []string{t.Name}
} }
} }

View file

@ -64,7 +64,6 @@ func TestUserGroups(t *testing.T) {
} }
func TestUserGroupsWithoutOrgs(t *testing.T) { func TestUserGroupsWithoutOrgs(t *testing.T) {
s := newTestServer(map[string]testResponse{ s := newTestServer(map[string]testResponse{
"/user/orgs": {data: []org{}}, "/user/orgs": {data: []org{}},
"/user/teams": {data: []team{}}, "/user/teams": {data: []team{}},
@ -76,7 +75,6 @@ func TestUserGroupsWithoutOrgs(t *testing.T) {
expectNil(t, err) expectNil(t, err)
expectEquals(t, len(groups), 0) expectEquals(t, len(groups), 0)
} }
func TestUserGroupsWithTeamNameFieldConfig(t *testing.T) { func TestUserGroupsWithTeamNameFieldConfig(t *testing.T) {
@ -102,6 +100,30 @@ func TestUserGroupsWithTeamNameFieldConfig(t *testing.T) {
}) })
} }
func TestUserGroupsWithTeamNameAndSlugFieldConfig(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user/orgs": {
data: []org{{Login: "org-1"}},
},
"/user/teams": {
data: []team{
{Name: "Team 1", Slug: "team-1", Org: org{Login: "org-1"}},
},
},
})
defer s.Close()
c := githubConnector{apiURL: s.URL, teamNameField: "both"}
groups, err := c.userGroups(context.Background(), newClient())
expectNil(t, err)
expectEquals(t, groups, []string{
"org-1",
"org-1:Team 1",
"org-1:team-1",
})
}
func TestUsernameIncludedInFederatedIdentity(t *testing.T) { func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
s := newTestServer(map[string]testResponse{ s := newTestServer(map[string]testResponse{