4
4
"context"
5
5
"encoding/base64"
6
6
"encoding/binary"
7
+ "errors"
7
8
"fmt"
8
9
"net/http"
9
10
"strings"
@@ -79,13 +80,14 @@ type OIDCAuthenticator struct {
79
80
}
80
81
81
82
type OAuthArgs struct {
82
- ssl bool
83
- host string
84
- pathq string
85
- clientid string
83
+ ssl bool
84
+ host string
85
+ pathq string
86
+ clientid string
86
87
clientsecret string
87
- redirecturl string
88
- cookie string
88
+ redirecturl string
89
+ cookie string
90
+ tokenClaims []string
89
91
}
90
92
91
93
// NewOIDCAuthenticator create an instance of an OIDC authenticator
@@ -126,14 +128,14 @@ func NewOIDCAuthenticator(options OIDCAuthenticatorOptions) *OIDCAuthenticator {
126
128
http .HandleFunc (options .LogoutPath , oa .handleOAuth2Logout ())
127
129
logrus .Infof ("OIDC API is exposed on %s" , options .CallbackAddr )
128
130
http .HandleFunc (options .HealthCheckPath , handleHealthCheck )
129
- http .ListenAndServe (options .CallbackAddr , nil )
131
+ logrus . Fatalln ( http .ListenAndServe (options .CallbackAddr , nil ) )
130
132
}()
131
133
132
134
return oa
133
135
}
134
136
135
137
func handleHealthCheck (w http.ResponseWriter , r * http.Request ) {
136
- w .Write ([]byte ("OK" ))
138
+ _ , _ = w .Write ([]byte ("OK" ))
137
139
}
138
140
139
141
func (oa * OIDCAuthenticator ) withOAuth2Config (domain string , callback func (c oauth2.Config ) error ) error {
@@ -166,24 +168,25 @@ func (oa *OIDCAuthenticator) verifyIDToken(context context.Context, domain strin
166
168
// Parse and verify ID Token payload.
167
169
idToken , err := verifier .Verify (context , rawIDToken )
168
170
if err != nil {
169
- return nil , fmt .Errorf ("unable to verify ID Token: %v " , err )
171
+ return nil , fmt .Errorf ("unable to verify ID Token: %w " , err )
170
172
}
171
173
return idToken , nil
172
174
}
173
175
174
- func (oa * OIDCAuthenticator ) checkCookie (cookieValue string , domain string ) error {
176
+ func (oa * OIDCAuthenticator ) decryptCookie (cookieValue string , domain string ) ( * oidc. IDToken , error ) {
175
177
idToken , err := oa .encryptor .Decrypt (cookieValue )
176
178
if err != nil {
177
- return fmt .Errorf ("unable to decrypt session cookie: %v " , err )
179
+ return nil , fmt .Errorf ("unable to decrypt session cookie: %w " , err )
178
180
}
179
181
180
- _ , err = oa .verifyIDToken (context .Background (), domain , idToken )
181
- return err
182
+ token , err : = oa .verifyIDToken (context .Background (), domain , idToken )
183
+ return token , err
182
184
}
183
185
184
186
func extractOAuth2Args (msg * message.Message , readClientInfoFromMessages bool ) (OAuthArgs , error ) {
185
187
var cookie string
186
188
var clientid , clientsecret , redirecturl * string
189
+ var tokenClaims []string
187
190
188
191
// ssl
189
192
sslValue , ok := msg .KV .Get ("arg_ssl" )
@@ -225,6 +228,15 @@ func extractOAuth2Args(msg *message.Message, readClientInfoFromMessages bool) (O
225
228
cookieValue , ok := msg .KV .Get ("arg_cookie" )
226
229
if ok {
227
230
cookie , _ = cookieValue .(string )
231
+
232
+ // Token claims
233
+ tokenClaimsValue , ok := msg .KV .Get ("arg_token_claims" )
234
+ if ok {
235
+ strV , ok := tokenClaimsValue .(string )
236
+ if ok {
237
+ tokenClaims = strings .Split (strV , " " )
238
+ }
239
+ }
228
240
}
229
241
230
242
if readClientInfoFromMessages {
@@ -281,8 +293,9 @@ func extractOAuth2Args(msg *message.Message, readClientInfoFromMessages bool) (O
281
293
clientsecret = & temp
282
294
}
283
295
return OAuthArgs {ssl : ssl , host : host , pathq : pathq ,
284
- cookie : cookie , clientid : * clientid ,
285
- clientsecret : * clientsecret , redirecturl : * redirecturl },
296
+ cookie : cookie , clientid : * clientid ,
297
+ clientsecret : * clientsecret , redirecturl : * redirecturl ,
298
+ tokenClaims : tokenClaims },
286
299
nil
287
300
}
288
301
@@ -328,14 +341,47 @@ func (oa *OIDCAuthenticator) Authenticate(msg *message.Message) (bool, []action.
328
341
329
342
// Verify the cookie to make sure the user is authenticated
330
343
if oauthArgs .cookie != "" {
331
- err := oa .checkCookie (oauthArgs .cookie , extractDomainFromHost ( oauthArgs . host ) )
344
+ idToken , err := oa .decryptCookie (oauthArgs .cookie , domain )
332
345
if err != nil {
346
+ // CoreOS/go-oidc does not have error types, so the errors are handled using strings
347
+ // comparison.
348
+ if errors .Is (err , & oidc.TokenExpiredError {}) || strings .Contains (err .Error (), "oidc:" ) {
349
+ authorizationURL , e := oa .buildAuthorizationURL (domain , oauthArgs )
350
+ if e != nil {
351
+ return false , nil , e
352
+ }
353
+
354
+ logrus .Infof ("Authentication failed, redirecting to OIDC provider %s, reason: %s" , authorizationURL , err )
355
+
356
+ return false , []action.Action {BuildRedirectURLMessage (authorizationURL )}, nil
357
+ }
358
+
333
359
return false , nil , err
334
- } else {
360
+ }
361
+
362
+ if len (oauthArgs .tokenClaims ) == 0 {
335
363
return true , nil , nil
364
+ } else {
365
+ // Extract token claims.
366
+ actions , err := BuildTokenClaimsMessage (idToken , oauthArgs .tokenClaims )
367
+ if err != nil {
368
+ return false , nil , err
369
+ }
370
+
371
+ return true , actions , nil
336
372
}
373
+
337
374
}
338
375
376
+ authorizationURL , err := oa .buildAuthorizationURL (domain , oauthArgs )
377
+ if err != nil {
378
+ return false , nil , err
379
+ }
380
+
381
+ return false , []action.Action {BuildRedirectURLMessage (authorizationURL )}, nil
382
+ }
383
+
384
+ func (oa * OIDCAuthenticator ) buildAuthorizationURL (domain string , oauthArgs OAuthArgs ) (string , error ) {
339
385
currentTime := time .Now ()
340
386
341
387
var state State
@@ -346,7 +392,7 @@ func (oa *OIDCAuthenticator) Authenticate(msg *message.Message) (bool, []action.
346
392
347
393
stateBytes , err := msgpack .Marshal (state )
348
394
if err != nil {
349
- return false , nil , fmt .Errorf ("unable to marshal the state" )
395
+ return "" , fmt .Errorf ("unable to marshal the state" )
350
396
}
351
397
352
398
var authorizationURL string
@@ -355,10 +401,10 @@ func (oa *OIDCAuthenticator) Authenticate(msg *message.Message) (bool, []action.
355
401
return nil
356
402
})
357
403
if err != nil {
358
- return false , nil , fmt .Errorf ("unable to build authorize url: %w" , err )
404
+ return "" , fmt .Errorf ("unable to build authorize url: %w" , err )
359
405
}
360
406
361
- return false , []action. Action { BuildRedirectURLMessage ( authorizationURL )} , nil
407
+ return authorizationURL , nil
362
408
}
363
409
364
410
func (oa * OIDCAuthenticator ) handleOAuth2Logout () http.HandlerFunc {
0 commit comments