@@ -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,49 @@ 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 sends some user information only via POST in the first request
206+ if "user" in context .request :
207+ userinfo = json .load (context .request ["user" ])
208+ userinfo ["name" ] = " " .join (
209+ filter (
210+ None ,
211+ [
212+ userinfo .get ("firstName" , "" ),
213+ userinfo .get ("middleName" , "" ),
214+ userinfo .get ("lastName" , "" ),
215+ ],
216+ )
217+ )
218+ else :
219+ # Apple has no userinfo endpoint
220+ userinfo = {}
221+
222+ authn_resp = self .client .parse_response (
223+ AuthorizationResponse , info = context .request , sformat = "dict"
224+ )
196225 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 )
226+ msg = "Missing or invalid state in authn response for state: {}" .format (
227+ backend_state
228+ )
229+ logline = lu .LOG_FMT .format (
230+ id = lu .get_session_id (context .state ), message = msg
231+ )
199232 logger .debug (logline )
200- raise SATOSAAuthenticationError (context .state , "Missing or invalid state in authn response" )
233+ raise SATOSAAuthenticationError (
234+ context .state , "Missing or invalid state in authn response"
235+ )
201236
202237 self ._check_error_response (authn_resp , context )
203238 access_token , id_token_claims = self ._get_tokens (authn_resp , context )
204239 if not id_token_claims :
205240 id_token_claims = {}
206241
207- # Apple has no userinfo endpoint
208- userinfo = {}
209-
210242 if not id_token_claims and not userinfo :
211243 msg = "No id_token or userinfo, nothing to do.."
212- logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
244+ logline = lu .LOG_FMT .format (
245+ id = lu .get_session_id (context .state ), message = msg
246+ )
213247 logger .error (logline )
214248 raise SATOSAAuthenticationError (context .state , "No user info available." )
215249
@@ -218,7 +252,9 @@ def response_endpoint(self, context, *args):
218252 logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
219253 logger .debug (logline )
220254 del context .state [self .name ]
221- internal_resp = self ._translate_response (all_user_claims , self .client .authorization_endpoint )
255+ internal_resp = self ._translate_response (
256+ all_user_claims , self .client .authorization_endpoint
257+ )
222258 return self .auth_callback_func (context , internal_resp )
223259
224260 def _translate_response (self , response , issuer ):
@@ -245,7 +281,9 @@ def get_metadata_desc(self):
245281 See satosa.backends.oauth.get_metadata_desc
246282 :rtype: satosa.metadata_creation.description.MetadataDescription
247283 """
248- return get_metadata_desc_for_oauth_backend (self .config ["provider_metadata" ]["issuer" ], self .config )
284+ return get_metadata_desc_for_oauth_backend (
285+ self .config ["provider_metadata" ]["issuer" ], self .config
286+ )
249287
250288
251289def _create_client (provider_metadata , client_metadata , verify_ssl = True ):
@@ -258,15 +296,15 @@ def _create_client(provider_metadata, client_metadata, verify_ssl=True):
258296 :return: client instance to use for communicating with the configured provider
259297 :rtype: oic.oic.Client
260298 """
261- client = oic .Client (
262- client_authn_method = CLIENT_AUTHN_METHOD , verify_ssl = verify_ssl
263- )
299+ client = oic .Client (client_authn_method = CLIENT_AUTHN_METHOD , verify_ssl = verify_ssl )
264300
265301 # Provider configuration information
266302 if "authorization_endpoint" in provider_metadata :
267303 # no dynamic discovery necessary
268- client .handle_provider_config (ProviderConfigurationResponse (** provider_metadata ),
269- provider_metadata ["issuer" ])
304+ client .handle_provider_config (
305+ ProviderConfigurationResponse (** provider_metadata ),
306+ provider_metadata ["issuer" ],
307+ )
270308 else :
271309 # do dynamic discovery
272310 client .provider_config (provider_metadata ["issuer" ])
@@ -277,9 +315,12 @@ def _create_client(provider_metadata, client_metadata, verify_ssl=True):
277315 client .store_registration_info (RegistrationRequest (** client_metadata ))
278316 else :
279317 # do dynamic registration
280- client .register (client .provider_info ['registration_endpoint' ],
281- ** client_metadata )
318+ client .register (
319+ client .provider_info ["registration_endpoint" ], ** client_metadata
320+ )
282321
283- client .subject_type = (client .registration_response .get ("subject_type" ) or
284- client .provider_info ["subject_types_supported" ][0 ])
322+ client .subject_type = (
323+ client .registration_response .get ("subject_type" )
324+ or client .provider_info ["subject_types_supported" ][0 ]
325+ )
285326 return client
0 commit comments