@@ -97,6 +97,9 @@ type FakeIDP struct {
97
97
deviceCode * syncmap.Map [string , deviceFlow ]
98
98
99
99
// hooks
100
+ // hookWellKnown allows mutating the returned .well-known/configuration JSON.
101
+ // Using this can break the IDP configuration, so be careful.
102
+ hookWellKnown func (r * http.Request , j * ProviderJSON ) error
100
103
// hookValidRedirectURL can be used to reject a redirect url from the
101
104
// IDP -> Application. Almost all IDPs have the concept of
102
105
// "Authorized Redirect URLs". This can be used to emulate that.
@@ -151,6 +154,12 @@ func WithMiddlewares(mws ...func(http.Handler) http.Handler) func(*FakeIDP) {
151
154
}
152
155
}
153
156
157
+ func WithHookWellKnown (hook func (r * http.Request , j * ProviderJSON ) error ) func (* FakeIDP ) {
158
+ return func (f * FakeIDP ) {
159
+ f .hookWellKnown = hook
160
+ }
161
+ }
162
+
154
163
// WithRefresh is called when a refresh token is used. The email is
155
164
// the email of the user that is being refreshed assuming the claims are correct.
156
165
func WithRefresh (hook func (email string ) error ) func (* FakeIDP ) {
@@ -753,7 +762,16 @@ func (f *FakeIDP) httpHandler(t testing.TB) http.Handler {
753
762
mux .Get ("/.well-known/openid-configuration" , func (rw http.ResponseWriter , r * http.Request ) {
754
763
f .logger .Info (r .Context (), "http OIDC config" , slogRequestFields (r )... )
755
764
756
- _ = json .NewEncoder (rw ).Encode (f .provider )
765
+ cpy := f .provider
766
+ if f .hookWellKnown != nil {
767
+ err := f .hookWellKnown (r , & cpy )
768
+ if err != nil {
769
+ http .Error (rw , err .Error (), http .StatusInternalServerError )
770
+ return
771
+ }
772
+ }
773
+
774
+ _ = json .NewEncoder (rw ).Encode (cpy )
757
775
})
758
776
759
777
// Authorize is called when the user is redirected to the IDP to login.
@@ -1371,8 +1389,11 @@ func (f *FakeIDP) AppCredentials() (clientID string, clientSecret string) {
1371
1389
return f .clientID , f .clientSecret
1372
1390
}
1373
1391
1374
- // OIDCConfig returns the OIDC config to use for Coderd.
1375
- func (f * FakeIDP ) OIDCConfig (t testing.TB , scopes []string , opts ... func (cfg * coderd.OIDCConfig )) * coderd.OIDCConfig {
1392
+ func (f * FakeIDP ) PublicKey () crypto.PublicKey {
1393
+ return f .key .Public ()
1394
+ }
1395
+
1396
+ func (f * FakeIDP ) OauthConfig (t testing.TB , scopes []string ) * oauth2.Config {
1376
1397
t .Helper ()
1377
1398
1378
1399
if len (scopes ) == 0 {
@@ -1391,22 +1412,50 @@ func (f *FakeIDP) OIDCConfig(t testing.TB, scopes []string, opts ...func(cfg *co
1391
1412
RedirectURL : "https://redirect.com" ,
1392
1413
Scopes : scopes ,
1393
1414
}
1415
+ f .cfg = oauthCfg
1394
1416
1395
- ctx := oidc .ClientContext (context .Background (), f .HTTPClient (nil ))
1417
+ return oauthCfg
1418
+ }
1419
+
1420
+ func (f * FakeIDP ) OIDCConfigSkipIssuerChecks (t testing.TB , scopes []string , opts ... func (cfg * coderd.OIDCConfig )) * coderd.OIDCConfig {
1421
+ ctx := oidc .InsecureIssuerURLContext (context .Background (), f .issuer )
1422
+
1423
+ return f .oidcConfig (ctx , t , scopes , func (config * oidc.Config ) {
1424
+ config .SkipIssuerCheck = true
1425
+ }, opts ... )
1426
+ }
1427
+
1428
+ func (f * FakeIDP ) OIDCConfig (t testing.TB , scopes []string , opts ... func (cfg * coderd.OIDCConfig )) * coderd.OIDCConfig {
1429
+ return f .oidcConfig (context .Background (), t , scopes , nil , opts ... )
1430
+ }
1431
+
1432
+ // OIDCConfig returns the OIDC config to use for Coderd.
1433
+ func (f * FakeIDP ) oidcConfig (ctx context.Context , t testing.TB , scopes []string , verifierOpt func (config * oidc.Config ), opts ... func (cfg * coderd.OIDCConfig )) * coderd.OIDCConfig {
1434
+ t .Helper ()
1435
+
1436
+ oauthCfg := f .OauthConfig (t , scopes )
1437
+
1438
+ ctx = oidc .ClientContext (ctx , f .HTTPClient (nil ))
1396
1439
p , err := oidc .NewProvider (ctx , f .provider .Issuer )
1397
1440
require .NoError (t , err , "failed to create OIDC provider" )
1441
+
1442
+ verifierConfig := & oidc.Config {
1443
+ ClientID : oauthCfg .ClientID ,
1444
+ SupportedSigningAlgs : []string {
1445
+ "RS256" ,
1446
+ },
1447
+ // Todo: add support for Now()
1448
+ }
1449
+ if verifierOpt != nil {
1450
+ verifierOpt (verifierConfig )
1451
+ }
1452
+
1398
1453
cfg := & coderd.OIDCConfig {
1399
1454
OAuth2Config : oauthCfg ,
1400
1455
Provider : p ,
1401
1456
Verifier : oidc .NewVerifier (f .provider .Issuer , & oidc.StaticKeySet {
1402
1457
PublicKeys : []crypto.PublicKey {f .key .Public ()},
1403
- }, & oidc.Config {
1404
- ClientID : oauthCfg .ClientID ,
1405
- SupportedSigningAlgs : []string {
1406
- "RS256" ,
1407
- },
1408
- // Todo: add support for Now()
1409
- }),
1458
+ }, verifierConfig ),
1410
1459
UsernameField : "preferred_username" ,
1411
1460
EmailField : "email" ,
1412
1461
AuthURLParams : map [string ]string {"access_type" : "offline" },
@@ -1419,13 +1468,12 @@ func (f *FakeIDP) OIDCConfig(t testing.TB, scopes []string, opts ...func(cfg *co
1419
1468
opt (cfg )
1420
1469
}
1421
1470
1422
- f .cfg = oauthCfg
1423
1471
return cfg
1424
1472
}
1425
1473
1426
1474
func (f * FakeIDP ) getClaims (m * syncmap.Map [string , jwt.MapClaims ], key string ) (jwt.MapClaims , bool ) {
1427
1475
v , ok := m .Load (key )
1428
- if ! ok {
1476
+ if ! ok || v == nil {
1429
1477
if f .defaultIDClaims != nil {
1430
1478
return f .defaultIDClaims , true
1431
1479
}
0 commit comments