git.iko.soy/typeable/oauth2-proxy
on master help sign in
Use global OIDC fields for Gitlab
commitd2ffef2c7e0a622295c42cb2fdd70ef14593d03c authorNick Meves <nick.meves@greenhouse.io> dateTue 1 Dec 2020, 17:50 (6 years ago) parent42f6cef
5 files changed+40−43
pkg/validation/options.go−1 providers/gitlab.go+11−14 providers/oidc.go+15−14 providers/provider_data.go+6−6 providers/util.go+8−8
pkg/validation/options.go−1
@@ -287,7 +287,6 @@ func parseProviderInfo(o *options.Options, msgs []string) []string {
287287 msgs = append(msgs, "oidc provider requires an oidc issuer URL")
288288 }
289289 case *providers.GitLabProvider:
290− p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
291290 p.Groups = o.GitLabGroup
292291 err := p.AddProjects(o.GitlabProjects)
293292 if err != nil {
providers/gitlab.go+11−14
@@ -20,8 +20,6 @@ type GitLabProvider struct {
2020
2121 Groups []string
2222 Projects []*GitlabProject
23−
24− AllowUnverifiedEmail bool
2523}
2624
2725// GitlabProject represents a Gitlab project constraint entity
@@ -103,7 +101,7 @@ func (p *GitLabProvider) Redeem(ctx context.Context, redirectURL, code string) (
103101 if err != nil {
104102 return nil, fmt.Errorf("token exchange: %v", err)
105103 }
106− s, err = p.createSessionState(ctx, token)
104+ s, err = p.createSession(ctx, token)
107105 if err != nil {
108106 return nil, fmt.Errorf("unable to update session: %v", err)
109107 }
@@ -162,7 +160,7 @@ func (p *GitLabProvider) redeemRefreshToken(ctx context.Context, s *sessions.Ses
162160 if err != nil {
163161 return fmt.Errorf("failed to get token: %v", err)
164162 }
165− newSession, err := p.createSessionState(ctx, token)
163+ newSession, err := p.createSession(ctx, token)
166164 if err != nil {
167165 return fmt.Errorf("unable to update session: %v", err)
168166 }
@@ -255,22 +253,21 @@ func (p *GitLabProvider) AddProjects(projects []string) error {
255253 return nil
256254}
257255
258−func (p *GitLabProvider) createSessionState(ctx context.Context, token *oauth2.Token) (*sessions.SessionState, error) {
259− rawIDToken, ok := token.Extra("id_token").(string)
260− if !ok {
261− return nil, fmt.Errorf("token response did not contain an id_token")
262− }
263−
264− // Parse and verify ID Token payload.
265− idToken, err := p.Verifier.Verify(ctx, rawIDToken)
256+func (p *GitLabProvider) createSession(ctx context.Context, token *oauth2.Token) (*sessions.SessionState, error) {
257+ idToken, err := p.verifyIDToken(ctx, token)
266258 if err != nil {
267− return nil, fmt.Errorf("could not verify id_token: %v", err)
259+ switch err {
260+ case ErrMissingIDToken:
261+ return nil, fmt.Errorf("token response did not contain an id_token")
262+ default:
263+ return nil, fmt.Errorf("could not verify id_token: %v", err)
264+ }
268265 }
269266
270267 created := time.Now()
271268 return &sessions.SessionState{
272269 AccessToken: token.AccessToken,
273− IDToken: rawIDToken,
270+ IDToken: getIDToken(token),
274271 RefreshToken: token.RefreshToken,
275272 CreatedAt: &created,
276273 ExpiresOn: &idToken.Expiry,
providers/oidc.go+15−14
@@ -49,7 +49,7 @@ func (p *OIDCProvider) Redeem(ctx context.Context, redirectURL, code string) (*s
4949 return p.createSession(ctx, token, false)
5050}
5151
52−// EnrichSessionState is called after Redeem to allow providers to enrich session fields
52+// EnrichSession is called after Redeem to allow providers to enrich session fields
5353// such as User, Email, Groups with provider specific API calls.
5454func (p *OIDCProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {
5555 if p.ProfileURL.String() == "" {
@@ -61,7 +61,7 @@ func (p *OIDCProvider) EnrichSession(ctx context.Context, s *sessions.SessionSta
6161
6262 // Try to get missing emails or groups from a profileURL
6363 if s.Email == "" || s.Groups == nil {
64− err := p.callProfileURL(ctx, s)
64+ err := p.enrichFromProfileURL(ctx, s)
6565 if err != nil {
6666 logger.Errorf("Warning: Profile URL request failed: %v", err)
6767 }
@@ -74,9 +74,9 @@ func (p *OIDCProvider) EnrichSession(ctx context.Context, s *sessions.SessionSta
7474 return nil
7575}
7676
77−// callProfileURL enriches a session's Email & Groups via the JSON response of
77+// enrichFromProfileURL enriches a session's Email & Groups via the JSON response of
7878// an OIDC profile URL
79−func (p *OIDCProvider) callProfileURL(ctx context.Context, s *sessions.SessionState) error {
79+func (p *OIDCProvider) enrichFromProfileURL(ctx context.Context, s *sessions.SessionState) error {
8080 respJSON, err := requests.New(p.ProfileURL.String()).
8181 WithContext(ctx).
8282 WithHeaders(makeOIDCHeader(s.AccessToken)).
@@ -91,22 +91,23 @@ func (p *OIDCProvider) callProfileURL(ctx context.Context, s *sessions.SessionSt
9191 s.Email = email
9292 }
9393
94− if len(s.Groups) == 0 {
95− for _, group := range coerceArray(respJSON, p.GroupsClaim) {
96− formatted, err := formatGroup(group)
97− if err != nil {
98− logger.Errorf("Warning: unable to format group of type %s with error %s",
99− reflect.TypeOf(group), err)
100− continue
101− }
102− s.Groups = append(s.Groups, formatted)
94+ if len(s.Groups) > 0 {
95+ return nil
96+ }
97+ for _, group := range coerceArray(respJSON, p.GroupsClaim) {
98+ formatted, err := formatGroup(group)
99+ if err != nil {
100+ logger.Errorf("Warning: unable to format group of type %s with error %s",
101+ reflect.TypeOf(group), err)
102+ continue
103103 }
104+ s.Groups = append(s.Groups, formatted)
104105 }
105106
106107 return nil
107108}
108109
109−// ValidateSessionState checks that the session's IDToken is still valid
110+// ValidateSession checks that the session's IDToken is still valid
110111func (p *OIDCProvider) ValidateSession(ctx context.Context, s *sessions.SessionState) bool {
111112 _, err := p.Verifier.Verify(ctx, s.IDToken)
112113 return err == nil
providers/provider_data.go+6−6
@@ -128,13 +128,13 @@ type OIDCClaims struct {
128128
129129func (p *ProviderData) verifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
130130 rawIDToken := getIDToken(token)
131− if strings.TrimSpace(rawIDToken) != "" {
132− if p.Verifier == nil {
133− return nil, ErrMissingOIDCVerifier
134− }
135− return p.Verifier.Verify(ctx, rawIDToken)
131+ if strings.TrimSpace(rawIDToken) == "" {
132+ return nil, ErrMissingIDToken
133+ }
134+ if p.Verifier == nil {
135+ return nil, ErrMissingOIDCVerifier
136136 }
137− return nil, ErrMissingIDToken
137+ return p.Verifier.Verify(ctx, rawIDToken)
138138}
139139
140140// buildSessionFromClaims uses IDToken claims to populate a fresh SessionState
providers/util.go+8−8
@@ -73,15 +73,15 @@ func getIDToken(token *oauth2.Token) string {
7373// formatGroup coerces an OIDC groups claim into a string
7474// If it is non-string, marshal it into JSON.
7575func formatGroup(rawGroup interface{}) (string, error) {
76− group, ok := rawGroup.(string)
77− if !ok {
78− jsonGroup, err := json.Marshal(rawGroup)
79− if err != nil {
80− return "", err
81− }
82− group = string(jsonGroup)
76+ if group, ok := rawGroup.(string); ok {
77+ return group, nil
78+ }
79+
80+ jsonGroup, err := json.Marshal(rawGroup)
81+ if err != nil {
82+ return "", err
8383 }
84− return group, nil
84+ return string(jsonGroup), nil
8585}
8686
8787// coerceArray extracts a field from simplejson.Json that might be a