forked from mystiq/dex
connector/github: error if no groups scope without orgs
We should always check if a user is in any orgs or teams specified in config, and whether the groups scope is also included in client requests. If not, return an error, because dex wouldn't have required permissions to do the request anyway (need read:org).
This commit is contained in:
parent
20fd3163d9
commit
e92f38f38f
1 changed files with 35 additions and 42 deletions
|
@ -134,15 +134,14 @@ type githubConnector struct {
|
|||
}
|
||||
|
||||
func (c *githubConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
|
||||
var githubScopes []string
|
||||
if scopes.Groups {
|
||||
githubScopes = []string{scopeEmail, scopeOrgs}
|
||||
} else {
|
||||
githubScopes = []string{scopeEmail}
|
||||
// The GitHub API requires requires read:org scope to ensure users are members
|
||||
// of orgs and teams provided in configs.
|
||||
githubScopes := []string{scopeEmail}
|
||||
if len(c.orgs) > 0 || c.org != "" {
|
||||
githubScopes = append(githubScopes, scopeOrgs)
|
||||
}
|
||||
|
||||
endpoint := github.Endpoint
|
||||
|
||||
// case when it is a GitHub Enterprise account.
|
||||
if c.hostName != "" {
|
||||
endpoint = oauth2.Endpoint{
|
||||
|
@ -207,6 +206,22 @@ func newHTTPClient(rootCA string) (*http.Client, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// getGroups retrieves GitHub orgs and teams a user is in, if any.
|
||||
func (c *githubConnector) getGroups(ctx context.Context, client *http.Client, groupScope bool, userLogin string) (groups []string, err error) {
|
||||
// Org and team membership should always be checked if specified by config.
|
||||
if len(c.orgs) > 0 {
|
||||
if groups, err = c.listGroups(ctx, client, userLogin); err != nil {
|
||||
return groups, err
|
||||
}
|
||||
} else if groupScope && c.org != "" {
|
||||
// Do not check org membership here to preserve legacy behavior.
|
||||
if groups, err = c.teams(ctx, client, c.org); err != nil {
|
||||
return groups, fmt.Errorf("github: get teams: %v", err)
|
||||
}
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func (c *githubConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
|
||||
q := r.URL.Query()
|
||||
if errType := q.Get("error"); errType != "" {
|
||||
|
@ -244,24 +259,13 @@ func (c *githubConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
|
|||
EmailVerified: true,
|
||||
}
|
||||
|
||||
if s.Groups {
|
||||
var groups []string
|
||||
if len(c.orgs) > 0 {
|
||||
if groups, err = c.listGroups(ctx, client, user.Login); err != nil {
|
||||
return identity, err
|
||||
}
|
||||
} else if c.org != "" {
|
||||
inOrg, err := c.userInOrg(ctx, client, user.Login, c.org)
|
||||
groups, err := c.getGroups(ctx, client, s.Groups, user.Login)
|
||||
if err != nil {
|
||||
return identity, err
|
||||
}
|
||||
if !inOrg {
|
||||
return identity, fmt.Errorf("github: user %q not a member of org %q", user.Login, c.org)
|
||||
}
|
||||
if groups, err = c.teams(ctx, client, c.org); err != nil {
|
||||
return identity, fmt.Errorf("github: get teams: %v", err)
|
||||
}
|
||||
}
|
||||
// Preserve behavior of only setting identity.Groups if 'orgs' or groups scope
|
||||
// and 'org' are specified.
|
||||
if len(c.orgs) > 0 || (s.Groups && c.org != "") {
|
||||
identity.Groups = groups
|
||||
}
|
||||
|
||||
|
@ -300,24 +304,13 @@ func (c *githubConnector) Refresh(ctx context.Context, s connector.Scopes, ident
|
|||
identity.Username = username
|
||||
identity.Email = user.Email
|
||||
|
||||
if s.Groups {
|
||||
var groups []string
|
||||
if len(c.orgs) > 0 {
|
||||
if groups, err = c.listGroups(ctx, client, user.Login); err != nil {
|
||||
return identity, err
|
||||
}
|
||||
} else if c.org != "" {
|
||||
inOrg, err := c.userInOrg(ctx, client, user.Login, c.org)
|
||||
groups, err := c.getGroups(ctx, client, s.Groups, user.Login)
|
||||
if err != nil {
|
||||
return identity, err
|
||||
}
|
||||
if !inOrg {
|
||||
return identity, fmt.Errorf("github: user %q not a member of org %q", user.Login, c.org)
|
||||
}
|
||||
if groups, err = c.teams(ctx, client, c.org); err != nil {
|
||||
return identity, fmt.Errorf("github: get teams: %v", err)
|
||||
}
|
||||
}
|
||||
// Preserve behavior of only setting identity.Groups if 'orgs' or groups scope
|
||||
// and 'org' are specified.
|
||||
if len(c.orgs) > 0 || (s.Groups && c.org != "") {
|
||||
identity.Groups = groups
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue