@@ -76,10 +76,7 @@ def start_auth(self, context, request_info):
7676 """
7777 oidc_nonce = rndstr ()
7878 oidc_state = rndstr ()
79- state_data = {
80- NONCE_KEY : oidc_nonce ,
81- STATE_KEY : oidc_state
82- }
79+ state_data = {NONCE_KEY : oidc_nonce , STATE_KEY : oidc_state }
8380 context .state [self .name ] = state_data
8481
8582 args = {
@@ -88,7 +85,7 @@ def start_auth(self, context, request_info):
8885 "client_id" : self .client .client_id ,
8986 "redirect_uri" : self .client .registration_response ["redirect_uris" ][0 ],
9087 "state" : oidc_state ,
91- "nonce" : oidc_nonce
88+ "nonce" : oidc_nonce ,
9289 }
9390 args .update (self .config ["client" ]["auth_req_params" ])
9491 auth_req = self .client .construct_AuthorizationRequest (request_args = args )
@@ -104,7 +101,9 @@ def register_endpoints(self):
104101 :return: A list that can be used to map the request to SATOSA to this endpoint.
105102 """
106103 url_map = []
107- redirect_path = urlparse (self .config ["client" ]["client_metadata" ]["redirect_uris" ][0 ]).path
104+ redirect_path = urlparse (
105+ self .config ["client" ]["client_metadata" ]["redirect_uris" ][0 ]
106+ ).path
108107 if not redirect_path :
109108 raise SATOSAError ("Missing path in redirect uri" )
110109
@@ -122,10 +121,16 @@ def _verify_nonce(self, nonce, context):
122121 """
123122 backend_state = context .state [self .name ]
124123 if nonce != backend_state [NONCE_KEY ]:
125- msg = "Missing or invalid nonce in authn response for state: {}" .format (backend_state )
126- logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
124+ msg = "Missing or invalid nonce in authn response for state: {}" .format (
125+ backend_state
126+ )
127+ logline = lu .LOG_FMT .format (
128+ id = lu .get_session_id (context .state ), message = msg
129+ )
127130 logger .debug (logline )
128- raise SATOSAAuthenticationError (context .state , "Missing or invalid nonce in authn response" )
131+ raise SATOSAAuthenticationError (
132+ context .state , "Missing or invalid nonce in authn response"
133+ )
129134
130135 def _get_tokens (self , authn_response , context ):
131136 """
@@ -142,22 +147,24 @@ def _get_tokens(self, authn_response, context):
142147 "client_secret" : self .client .client_secret ,
143148 "code" : authn_response ["code" ],
144149 "grant_type" : "authorization_code" ,
145- "redirect_uri" : self .client .registration_response [' redirect_uris' ][0 ],
150+ "redirect_uri" : self .client .registration_response [" redirect_uris" ][0 ],
146151 }
147152
148153 token_resp = requests .post (
149154 "https://appleid.apple.com/auth/token" ,
150155 data = args ,
151- headers = {"Content-Type" : "application/x-www-form-urlencoded" }
152- ).json ()
156+ headers = {"Content-Type" : "application/x-www-form-urlencoded" },
157+ ).json ()
153158
154159 logger .debug ("apple response received" )
155160 logger .debug (token_resp )
156161
157162 self ._check_error_response (token_resp , context )
158163
159164 keyjar = self .client .keyjar
160- id_token_claims = dict (Message ().from_jwt (token_resp ["id_token" ], keyjar = keyjar ))
165+ id_token_claims = dict (
166+ Message ().from_jwt (token_resp ["id_token" ], keyjar = keyjar )
167+ )
161168
162169 return token_resp ["access_token" ], id_token_claims
163170
@@ -176,7 +183,9 @@ def _check_error_response(self, response, context):
176183 error = response ["error" ],
177184 description = response .get ("error_description" , "" ),
178185 )
179- logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
186+ logline = lu .LOG_FMT .format (
187+ id = lu .get_session_id (context .state ), message = msg
188+ )
180189 logger .debug (logline )
181190 raise SATOSAAuthenticationError (context .state , "Access denied" )
182191
@@ -192,24 +201,44 @@ def response_endpoint(self, context, *args):
192201 :return:
193202 """
194203 backend_state = context .state [self .name ]
195- authn_resp = self .client .parse_response (AuthorizationResponse , info = context .request , sformat = "dict" )
204+
205+ # Apple has no userinfo endpoint
206+ # but may send some user information via POST in the first request.
207+ #
208+ # References:
209+ # - https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple
210+ # - https://developer.apple.com/documentation/sign_in_with_apple/namei
211+ try :
212+ userdata = context .request .get ("user" , "{}" )
213+ userinfo = json .load (userdata )
214+ except Exception as e :
215+ userinfo = {}
216+
217+ authn_resp = self .client .parse_response (
218+ AuthorizationResponse , info = context .request , sformat = "dict"
219+ )
196220 if backend_state [STATE_KEY ] != authn_resp ["state" ]:
197- msg = "Missing or invalid state in authn response for state: {}" .format (backend_state )
198- logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
221+ msg = "Missing or invalid state in authn response for state: {}" .format (
222+ backend_state
223+ )
224+ logline = lu .LOG_FMT .format (
225+ id = lu .get_session_id (context .state ), message = msg
226+ )
199227 logger .debug (logline )
200- raise SATOSAAuthenticationError (context .state , "Missing or invalid state in authn response" )
228+ raise SATOSAAuthenticationError (
229+ context .state , "Missing or invalid state in authn response"
230+ )
201231
202232 self ._check_error_response (authn_resp , context )
203233 access_token , id_token_claims = self ._get_tokens (authn_resp , context )
204234 if not id_token_claims :
205235 id_token_claims = {}
206236
207- # Apple has no userinfo endpoint
208- userinfo = {}
209-
210237 if not id_token_claims and not userinfo :
211238 msg = "No id_token or userinfo, nothing to do.."
212- logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
239+ logline = lu .LOG_FMT .format (
240+ id = lu .get_session_id (context .state ), message = msg
241+ )
213242 logger .error (logline )
214243 raise SATOSAAuthenticationError (context .state , "No user info available." )
215244
@@ -218,7 +247,9 @@ def response_endpoint(self, context, *args):
218247 logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
219248 logger .debug (logline )
220249 del context .state [self .name ]
221- internal_resp = self ._translate_response (all_user_claims , self .client .authorization_endpoint )
250+ internal_resp = self ._translate_response (
251+ all_user_claims , self .client .authorization_endpoint
252+ )
222253 return self .auth_callback_func (context , internal_resp )
223254
224255 def _translate_response (self , response , issuer ):
@@ -245,7 +276,9 @@ def get_metadata_desc(self):
245276 See satosa.backends.oauth.get_metadata_desc
246277 :rtype: satosa.metadata_creation.description.MetadataDescription
247278 """
248- return get_metadata_desc_for_oauth_backend (self .config ["provider_metadata" ]["issuer" ], self .config )
279+ return get_metadata_desc_for_oauth_backend (
280+ self .config ["provider_metadata" ]["issuer" ], self .config
281+ )
249282
250283
251284def _create_client (provider_metadata , client_metadata , verify_ssl = True ):
@@ -258,15 +291,15 @@ def _create_client(provider_metadata, client_metadata, verify_ssl=True):
258291 :return: client instance to use for communicating with the configured provider
259292 :rtype: oic.oic.Client
260293 """
261- client = oic .Client (
262- client_authn_method = CLIENT_AUTHN_METHOD , verify_ssl = verify_ssl
263- )
294+ client = oic .Client (client_authn_method = CLIENT_AUTHN_METHOD , verify_ssl = verify_ssl )
264295
265296 # Provider configuration information
266297 if "authorization_endpoint" in provider_metadata :
267298 # no dynamic discovery necessary
268- client .handle_provider_config (ProviderConfigurationResponse (** provider_metadata ),
269- provider_metadata ["issuer" ])
299+ client .handle_provider_config (
300+ ProviderConfigurationResponse (** provider_metadata ),
301+ provider_metadata ["issuer" ],
302+ )
270303 else :
271304 # do dynamic discovery
272305 client .provider_config (provider_metadata ["issuer" ])
@@ -277,9 +310,12 @@ def _create_client(provider_metadata, client_metadata, verify_ssl=True):
277310 client .store_registration_info (RegistrationRequest (** client_metadata ))
278311 else :
279312 # do dynamic registration
280- client .register (client .provider_info ['registration_endpoint' ],
281- ** client_metadata )
313+ client .register (
314+ client .provider_info ["registration_endpoint" ], ** client_metadata
315+ )
282316
283- client .subject_type = (client .registration_response .get ("subject_type" ) or
284- client .provider_info ["subject_types_supported" ][0 ])
317+ client .subject_type = (
318+ client .registration_response .get ("subject_type" )
319+ or client .provider_info ["subject_types_supported" ][0 ]
320+ )
285321 return client
0 commit comments