@@ -123,7 +123,11 @@ class OpenIdConnectConfiguration(BaseAuthenticatorConfiguration):
123
123
)
124
124
125
125
JWT_ALGORITHMS = ListField (
126
- help_text = _ ("The algorithm(s) for decoding JWT responses from the IDP." ),
126
+ help_text = _ (
127
+ "The algorithm(s) for decoding JWT responses from the IDP. "
128
+ "Leave blank to extract from the .well-known configuration (if that fails we will attempt the default algorithms). "
129
+ "Set to ['none'] to not use encrypted tokens (the provider must send unencrypted tokens for this to work)"
130
+ ),
127
131
default = None ,
128
132
allow_null = True ,
129
133
validators = [JWTAlgorithmListFieldValidator ()],
@@ -263,6 +267,28 @@ def public_key(self):
263
267
)
264
268
return None
265
269
270
+ def _get_jwt_algorithms (self ) -> list [str ]:
271
+ """
272
+ Get the JWT algorithms to pass to the decode
273
+ """
274
+ if self .setting ("JWT_ALGORITHMS" ):
275
+ # If the admin specified the algorithms then use them
276
+ return self .setting ("JWT_ALGORITHMS" )
277
+ else :
278
+ # Try to get the algorithms from the .well-known/openid-configuration
279
+ try :
280
+ logger .debug ("Attempting to get the JWT algorithms from the .well-known/openid-configuration" )
281
+ config = self .oidc_config ()
282
+ idp_algorithms = config .get ("id_token_encryption_alg_values_supported" )
283
+ if idp_algorithms :
284
+ logger .debug (f"JWT algorithms supported by the IDP: { idp_algorithms } " )
285
+ return idp_algorithms
286
+ except Exception as e :
287
+ # In controller 2.4 we did not have the ability to set the JWT algorithms so we will use the default algorithms
288
+ lib_defaults = super ().JWT_ALGORITHMS
289
+ logger .error (f"Unable to get JWT algorithms from the .well-known/openid-configuration, defaulting to { lib_defaults } : { e } " )
290
+ return lib_defaults
291
+
266
292
def user_data (self , access_token , * args , ** kwargs ):
267
293
"""
268
294
This function overrides the one in social auth class OpenIdConnectAuth, since
@@ -277,18 +303,25 @@ def user_data(self, access_token, *args, **kwargs):
277
303
# If the content type is application/jwt than we can assume that the token is encrypted. Otherwise it should be application/json
278
304
pubkey = self .public_key ()
279
305
if not pubkey :
280
- logger .error (_ ( "OIDC client sent encrypted user info response, but no public key found." ) )
306
+ logger .error ("OIDC client sent encrypted user info response, but no public key found." )
281
307
return None
308
+ # Get the algorithms to pass to the decode
309
+ algorithms = self ._get_jwt_algorithms ()
310
+ options = {}
311
+ if algorithms == ['none' ]:
312
+ logger .info ("JWT decryption algorithm is set to ['none'], will proceed but this is insecure" )
313
+ options ['verify_signature' ] = False
282
314
try :
283
315
data = jwt .decode (
284
316
access_token ,
285
317
key = pubkey ,
286
- algorithms = self . setting ( "JWT_ALGORITHMS" ) ,
318
+ algorithms = algorithms ,
287
319
audience = self .setting ("KEY" ),
320
+ options = options ,
288
321
)
289
322
return data
290
323
except PyJWTError as e :
291
- logger .error (_ ( f"Unable to decode user info response JWT: { e } " ) )
324
+ logger .error (f"Unable to decode user info response JWT: { e } " )
292
325
return None
293
326
return user_data .json ()
294
327
0 commit comments