@@ -76,10 +76,7 @@ def start_auth(self, context, request_info):
76
76
"""
77
77
oidc_nonce = rndstr ()
78
78
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 }
83
80
context .state [self .name ] = state_data
84
81
85
82
args = {
@@ -88,7 +85,7 @@ def start_auth(self, context, request_info):
88
85
"client_id" : self .client .client_id ,
89
86
"redirect_uri" : self .client .registration_response ["redirect_uris" ][0 ],
90
87
"state" : oidc_state ,
91
- "nonce" : oidc_nonce
88
+ "nonce" : oidc_nonce ,
92
89
}
93
90
args .update (self .config ["client" ]["auth_req_params" ])
94
91
auth_req = self .client .construct_AuthorizationRequest (request_args = args )
@@ -104,7 +101,9 @@ def register_endpoints(self):
104
101
:return: A list that can be used to map the request to SATOSA to this endpoint.
105
102
"""
106
103
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
108
107
if not redirect_path :
109
108
raise SATOSAError ("Missing path in redirect uri" )
110
109
@@ -122,10 +121,16 @@ def _verify_nonce(self, nonce, context):
122
121
"""
123
122
backend_state = context .state [self .name ]
124
123
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
+ )
127
130
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
+ )
129
134
130
135
def _get_tokens (self , authn_response , context ):
131
136
"""
@@ -142,22 +147,24 @@ def _get_tokens(self, authn_response, context):
142
147
"client_secret" : self .client .client_secret ,
143
148
"code" : authn_response ["code" ],
144
149
"grant_type" : "authorization_code" ,
145
- "redirect_uri" : self .client .registration_response [' redirect_uris' ][0 ],
150
+ "redirect_uri" : self .client .registration_response [" redirect_uris" ][0 ],
146
151
}
147
152
148
153
token_resp = requests .post (
149
154
"https://appleid.apple.com/auth/token" ,
150
155
data = args ,
151
- headers = {"Content-Type" : "application/x-www-form-urlencoded" }
152
- ).json ()
156
+ headers = {"Content-Type" : "application/x-www-form-urlencoded" },
157
+ ).json ()
153
158
154
159
logger .debug ("apple response received" )
155
160
logger .debug (token_resp )
156
161
157
162
self ._check_error_response (token_resp , context )
158
163
159
164
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
+ )
161
168
162
169
return token_resp ["access_token" ], id_token_claims
163
170
@@ -176,7 +183,9 @@ def _check_error_response(self, response, context):
176
183
error = response ["error" ],
177
184
description = response .get ("error_description" , "" ),
178
185
)
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
+ )
180
189
logger .debug (logline )
181
190
raise SATOSAAuthenticationError (context .state , "Access denied" )
182
191
@@ -192,24 +201,49 @@ def response_endpoint(self, context, *args):
192
201
:return:
193
202
"""
194
203
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
+ )
196
225
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
+ )
199
232
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
+ )
201
236
202
237
self ._check_error_response (authn_resp , context )
203
238
access_token , id_token_claims = self ._get_tokens (authn_resp , context )
204
239
if not id_token_claims :
205
240
id_token_claims = {}
206
241
207
- # Apple has no userinfo endpoint
208
- userinfo = {}
209
-
210
242
if not id_token_claims and not userinfo :
211
243
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
+ )
213
247
logger .error (logline )
214
248
raise SATOSAAuthenticationError (context .state , "No user info available." )
215
249
@@ -218,7 +252,9 @@ def response_endpoint(self, context, *args):
218
252
logline = lu .LOG_FMT .format (id = lu .get_session_id (context .state ), message = msg )
219
253
logger .debug (logline )
220
254
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
+ )
222
258
return self .auth_callback_func (context , internal_resp )
223
259
224
260
def _translate_response (self , response , issuer ):
@@ -245,7 +281,9 @@ def get_metadata_desc(self):
245
281
See satosa.backends.oauth.get_metadata_desc
246
282
:rtype: satosa.metadata_creation.description.MetadataDescription
247
283
"""
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
+ )
249
287
250
288
251
289
def _create_client (provider_metadata , client_metadata , verify_ssl = True ):
@@ -258,15 +296,15 @@ def _create_client(provider_metadata, client_metadata, verify_ssl=True):
258
296
:return: client instance to use for communicating with the configured provider
259
297
:rtype: oic.oic.Client
260
298
"""
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 )
264
300
265
301
# Provider configuration information
266
302
if "authorization_endpoint" in provider_metadata :
267
303
# 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
+ )
270
308
else :
271
309
# do dynamic discovery
272
310
client .provider_config (provider_metadata ["issuer" ])
@@ -277,9 +315,12 @@ def _create_client(provider_metadata, client_metadata, verify_ssl=True):
277
315
client .store_registration_info (RegistrationRequest (** client_metadata ))
278
316
else :
279
317
# 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
+ )
282
321
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
+ )
285
326
return client
0 commit comments