1 #![allow(clippy::expect_fun_call)]
2 extern crate env_logger;
3 extern crate http;
4 #[macro_use]
5 extern crate log;
6 extern crate openidconnect;
7 #[macro_use]
8 extern crate pretty_assertions;
9 extern crate reqwest_ as reqwest;
10 extern crate url;
11 
12 use std::collections::HashMap;
13 
14 use http::header::LOCATION;
15 use http::method::Method;
16 use reqwest::{blocking::Client, redirect::Policy};
17 use url::Url;
18 
19 use openidconnect::core::{
20     CoreClient, CoreClientAuthMethod, CoreClientRegistrationRequest,
21     CoreClientRegistrationResponse, CoreIdToken, CoreIdTokenClaims, CoreIdTokenVerifier,
22     CoreJsonWebKeySet, CoreJwsSigningAlgorithm, CoreProviderMetadata, CoreResponseType,
23     CoreUserInfoClaims,
24 };
25 use openidconnect::Nonce;
26 use openidconnect::{
27     AccessToken, AuthType, AuthenticationFlow, AuthorizationCode, ClaimsVerificationError,
28     CsrfToken, OAuth2TokenResponse, RequestTokenError, Scope, SignatureVerificationError,
29     UserInfoError,
30 };
31 
32 #[macro_use]
33 mod rp_common;
34 
35 use rp_common::{
36     get_provider_metadata, http_client, init_log, issuer_url, register_client, PanicIfFail,
37 };
38 
39 struct TestState {
40     access_token: Option<AccessToken>,
41     authorization_code: Option<AuthorizationCode>,
42     client: CoreClient,
43     id_token: Option<CoreIdToken>,
44     nonce: Option<Nonce>,
45     provider_metadata: CoreProviderMetadata,
46     registration_response: CoreClientRegistrationResponse,
47 }
48 impl TestState {
init<F>(test_id: &'static str, reg_request_fn: F) -> Self where F: FnOnce(CoreClientRegistrationRequest) -> CoreClientRegistrationRequest,49     pub fn init<F>(test_id: &'static str, reg_request_fn: F) -> Self
50     where
51         F: FnOnce(CoreClientRegistrationRequest) -> CoreClientRegistrationRequest,
52     {
53         init_log(test_id);
54 
55         let _issuer_url = issuer_url(test_id);
56         let provider_metadata = get_provider_metadata(test_id);
57         let registration_response = register_client(&provider_metadata, reg_request_fn);
58 
59         let redirect_uri = registration_response.redirect_uris()[0].clone();
60         let client: CoreClient = CoreClient::from_provider_metadata(
61             provider_metadata.clone(),
62             registration_response.client_id().to_owned(),
63             registration_response.client_secret().cloned(),
64         )
65         .set_redirect_uri(redirect_uri);
66 
67         TestState {
68             access_token: None,
69             authorization_code: None,
70             client,
71             id_token: None,
72             nonce: None,
73             provider_metadata,
74             registration_response,
75         }
76     }
77 
access_token(&self) -> &AccessToken78     pub fn access_token(&self) -> &AccessToken {
79         self.access_token.as_ref().expect("no access_token")
80     }
81 
authorize(mut self, scopes: &[Scope]) -> Self82     pub fn authorize(mut self, scopes: &[Scope]) -> Self {
83         let (authorization_code, nonce) = {
84             let mut authorization_request = self.client.authorize_url(
85                 AuthenticationFlow::AuthorizationCode::<CoreResponseType>,
86                 CsrfToken::new_random,
87                 Nonce::new_random,
88             );
89             authorization_request =
90                 scopes
91                     .iter()
92                     .fold(authorization_request, |mut authorization_request, scope| {
93                         authorization_request = authorization_request.add_scope(scope.clone());
94                         authorization_request
95                     });
96             let (url, state, nonce) = authorization_request.url();
97             log_debug!("Authorize URL: {:?}", url);
98 
99             let http_client = Client::builder().redirect(Policy::none()).build().unwrap();
100             let redirect_response = http_client
101                 .execute(
102                     http_client
103                         .request(Method::GET, url.as_str())
104                         .build()
105                         .unwrap(),
106                 )
107                 .unwrap();
108             assert!(redirect_response.status().is_redirection());
109             let redirected_url = Url::parse(
110                 redirect_response
111                     .headers()
112                     .get(LOCATION)
113                     .unwrap()
114                     .to_str()
115                     .unwrap(),
116             )
117             .unwrap();
118 
119             log_debug!("Authorization Server redirected to: {:?}", redirected_url);
120 
121             let mut query_params = HashMap::new();
122             redirected_url.query_pairs().for_each(|(key, value)| {
123                 query_params.insert(key, value);
124             });
125             log_debug!(
126                 "Authorization Server returned query params: {:?}",
127                 query_params
128             );
129 
130             assert_eq!(
131                 self.provider_metadata.issuer().as_str(),
132                 query_params.get("iss").unwrap()
133             );
134             assert_eq!(state.secret(), query_params.get("state").unwrap());
135 
136             log_info!("Successfully received authentication response from Authorization Server");
137 
138             let authorization_code =
139                 AuthorizationCode::new(query_params.get("code").unwrap().to_string());
140             log_debug!(
141                 "Authorization Server returned authorization code: {}",
142                 authorization_code.secret()
143             );
144 
145             (authorization_code, nonce)
146         };
147 
148         self.authorization_code = Some(authorization_code);
149         self.nonce = Some(nonce);
150 
151         self
152     }
153 
exchange_code(mut self) -> Self154     pub fn exchange_code(mut self) -> Self {
155         let token_response = self
156             .client
157             .exchange_code(
158                 self.authorization_code
159                     .take()
160                     .expect("no authorization_code"),
161             )
162             .request(http_client)
163             .panic_if_fail("failed to exchange authorization code for token");
164         log_debug!(
165             "Authorization Server returned token response: {:?}",
166             token_response
167         );
168 
169         self.access_token = Some(token_response.access_token().clone());
170 
171         let id_token = (*token_response
172             .extra_fields()
173             .id_token()
174             .expect("no id_token"))
175         .clone();
176         self.id_token = Some(id_token);
177 
178         self
179     }
180 
id_token(&self) -> &CoreIdToken181     pub fn id_token(&self) -> &CoreIdToken {
182         self.id_token.as_ref().expect("no id_token")
183     }
184 
id_token_verifier(&self, jwks: CoreJsonWebKeySet) -> CoreIdTokenVerifier185     pub fn id_token_verifier(&self, jwks: CoreJsonWebKeySet) -> CoreIdTokenVerifier {
186         CoreIdTokenVerifier::new_confidential_client(
187             self.registration_response.client_id().clone(),
188             self.registration_response
189                 .client_secret()
190                 .expect("no client_secret")
191                 .clone(),
192             self.provider_metadata.issuer().clone(),
193             jwks,
194         )
195     }
196 
id_token_claims(&self) -> &CoreIdTokenClaims197     pub fn id_token_claims(&self) -> &CoreIdTokenClaims {
198         let verifier = self.id_token_verifier(self.jwks());
199         self.id_token()
200             .claims(&verifier, self.nonce.as_ref().expect("no nonce"))
201             .panic_if_fail("failed to validate claims")
202     }
203 
id_token_claims_failure(&self) -> ClaimsVerificationError204     pub fn id_token_claims_failure(&self) -> ClaimsVerificationError {
205         let verifier = self.id_token_verifier(self.jwks());
206         self.id_token()
207             .claims(&verifier, self.nonce.as_ref().expect("no nonce"))
208             .expect_err("claims verification succeeded but was expected to fail")
209     }
210 
jwks(&self) -> CoreJsonWebKeySet211     pub fn jwks(&self) -> CoreJsonWebKeySet {
212         CoreJsonWebKeySet::fetch(self.provider_metadata.jwks_uri(), http_client)
213             .panic_if_fail("failed to fetch JWK set")
214     }
215 
set_auth_type(mut self, auth_type: AuthType) -> Self216     pub fn set_auth_type(mut self, auth_type: AuthType) -> Self {
217         self.client = self.client.set_auth_type(auth_type);
218         self
219     }
220 
user_info_claims(&self) -> CoreUserInfoClaims221     pub fn user_info_claims(&self) -> CoreUserInfoClaims {
222         self.client
223             .user_info(
224                 self.access_token().to_owned(),
225                 Some(self.id_token_claims().subject().clone()),
226             )
227             .unwrap()
228             .require_signed_response(false)
229             .request(http_client)
230             .panic_if_fail("failed to get UserInfo")
231     }
232 
user_info_claims_failure( &self, ) -> UserInfoError<openidconnect::reqwest::HttpClientError>233     pub fn user_info_claims_failure(
234         &self,
235     ) -> UserInfoError<openidconnect::reqwest::HttpClientError> {
236         let user_info_result: Result<CoreUserInfoClaims, _> = self
237             .client
238             .user_info(
239                 self.access_token().to_owned(),
240                 Some(self.id_token_claims().subject().clone()),
241             )
242             .unwrap()
243             .require_signed_response(false)
244             .request(http_client);
245         match user_info_result {
246             Err(err) => err,
247             _ => panic!("claims verification succeeded but was expected to fail"),
248         }
249     }
250 }
251 
252 #[test]
253 #[ignore]
rp_response_type_code()254 fn rp_response_type_code() {
255     let test_state = TestState::init("rp-response_type-code", |reg| reg).authorize(&[]);
256     assert!(
257         test_state
258             .authorization_code
259             .expect("no authorization_code")
260             .secret()
261             != ""
262     );
263     log_info!("SUCCESS");
264 }
265 
266 #[test]
267 #[ignore]
rp_scope_userinfo_claims()268 fn rp_scope_userinfo_claims() {
269     let user_info_scopes = vec!["profile", "email", "address", "phone"]
270         .iter()
271         .map(|scope| Scope::new((*scope).to_string()))
272         .collect::<Vec<_>>();
273     let test_state = TestState::init("rp-scope-userinfo-claims", |reg| reg)
274         .authorize(&user_info_scopes)
275         .exchange_code();
276     let id_token_claims = test_state.id_token_claims();
277     log_debug!("ID token: {:?}", id_token_claims);
278 
279     let user_info_claims = test_state.user_info_claims();
280     log_debug!("UserInfo response: {:?}", user_info_claims);
281 
282     assert_eq!(id_token_claims.subject(), user_info_claims.subject());
283     assert!(!user_info_claims
284         .email()
285         .expect("no email returned by UserInfo endpoint")
286         .is_empty());
287     assert!(!user_info_claims
288         .address()
289         .expect("no address returned by UserInfo endpoint")
290         .street_address
291         .as_ref()
292         .expect("no street address returned by UserInfo endpoint")
293         .is_empty());
294     assert!(!user_info_claims
295         .phone_number()
296         .expect("no phone_number returned by UserInfo endpoint")
297         .is_empty());
298 
299     log_info!("SUCCESS");
300 }
301 
302 #[test]
303 #[ignore]
rp_nonce_invalid()304 fn rp_nonce_invalid() {
305     let test_state = TestState::init("rp-nonce-invalid", |reg| reg)
306         .authorize(&[])
307         .exchange_code();
308 
309     match test_state.id_token_claims_failure() {
310         ClaimsVerificationError::InvalidNonce(_) => {
311             log_error!("ID token contains invalid nonce (expected result)")
312         }
313         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
314     }
315 
316     log_info!("SUCCESS");
317 }
318 
319 #[test]
320 #[ignore]
rp_token_endpoint_client_secret_basic()321 fn rp_token_endpoint_client_secret_basic() {
322     let test_state = TestState::init("rp-token_endpoint-client_secret_basic", |reg| {
323         reg.set_token_endpoint_auth_method(Some(CoreClientAuthMethod::ClientSecretBasic))
324     })
325     .set_auth_type(AuthType::BasicAuth)
326     .authorize(&[])
327     .exchange_code();
328 
329     let id_token_claims = test_state.id_token_claims();
330     log_debug!("ID token: {:?}", id_token_claims);
331 
332     log_info!("SUCCESS");
333 }
334 
335 #[test]
336 #[ignore]
rp_token_endpoint_client_secret_post()337 fn rp_token_endpoint_client_secret_post() {
338     let test_state = TestState::init("rp-token_endpoint-client_secret_post", |reg| {
339         reg.set_token_endpoint_auth_method(Some(CoreClientAuthMethod::ClientSecretPost))
340     })
341     .set_auth_type(AuthType::RequestBody)
342     .authorize(&[])
343     .exchange_code();
344 
345     let id_token_claims = test_state.id_token_claims();
346     log_debug!("ID token: {:?}", id_token_claims);
347 
348     log_info!("SUCCESS");
349 }
350 
351 #[test]
352 #[ignore]
rp_id_token_kid_absent_single_jwks()353 fn rp_id_token_kid_absent_single_jwks() {
354     let test_state = TestState::init("rp-id_token-kid-absent-single-jwks", |reg| reg)
355         .authorize(&[])
356         .exchange_code();
357 
358     let id_token_claims = test_state.id_token_claims();
359     log_debug!("ID token: {:?}", id_token_claims);
360 
361     log_info!("SUCCESS");
362 }
363 
364 #[test]
365 #[ignore]
rp_id_token_iat()366 fn rp_id_token_iat() {
367     let mut test_state = TestState::init("rp-id_token-iat", |reg| reg).authorize(&[]);
368 
369     let token_response = test_state
370         .client
371         .exchange_code(
372             test_state
373                 .authorization_code
374                 .take()
375                 .expect("no authorization_code"),
376         )
377         .request(http_client);
378 
379     match token_response {
380         Err(RequestTokenError::Parse(_, _)) => {
381             log_error!("ID token failed to parse without `iat` claim (expected result)")
382         }
383         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
384     }
385     log_info!("SUCCESS");
386 }
387 
388 #[test]
389 #[ignore]
rp_id_token_aud()390 fn rp_id_token_aud() {
391     let test_state = TestState::init("rp-id_token-aud", |reg| reg)
392         .authorize(&[])
393         .exchange_code();
394 
395     match test_state.id_token_claims_failure() {
396         ClaimsVerificationError::InvalidAudience(_) => {
397             log_error!("ID token has invalid audience (expected result)")
398         }
399         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
400     }
401 
402     log_info!("SUCCESS");
403 }
404 
405 #[test]
406 #[ignore]
rp_id_token_kid_absent_multiple_jwks()407 fn rp_id_token_kid_absent_multiple_jwks() {
408     let test_state = TestState::init("rp-id_token-kid-absent-multiple-jwks", |reg| reg)
409         .authorize(&[])
410         .exchange_code();
411 
412     match test_state.id_token_claims_failure() {
413         ClaimsVerificationError::SignatureVerification(
414             SignatureVerificationError::AmbiguousKeyId(_),
415         ) => log_error!("ID token has ambiguous key identification without KID (expected result)"),
416         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
417     }
418 
419     log_info!("SUCCESS");
420 }
421 
422 #[test]
423 #[ignore]
rp_id_token_sig_none()424 fn rp_id_token_sig_none() {
425     let test_state = TestState::init("rp-id_token-sig-none", |reg| reg)
426         .authorize(&[])
427         .exchange_code();
428 
429     let verifier = test_state
430         .id_token_verifier(test_state.jwks())
431         .insecure_disable_signature_check();
432 
433     let id_token_claims = test_state
434         .id_token()
435         .claims(&verifier, test_state.nonce.as_ref().expect("no nonce"))
436         .panic_if_fail("failed to validate claims");
437     log_debug!("ID token: {:?}", id_token_claims);
438 
439     log_info!("SUCCESS");
440 }
441 
442 #[test]
443 #[ignore]
rp_id_token_sig_rs256()444 fn rp_id_token_sig_rs256() {
445     let test_state = TestState::init("rp-id_token-sig-rs256", |reg| reg)
446         .authorize(&[])
447         .exchange_code();
448 
449     let id_token_claims = test_state.id_token_claims();
450     log_debug!("ID token: {:?}", id_token_claims);
451 
452     log_info!("SUCCESS");
453 }
454 
455 #[test]
456 #[ignore]
rp_id_token_sig_hs256()457 fn rp_id_token_sig_hs256() {
458     let test_state = TestState::init("rp-id_token-sig-hs256", |reg| reg)
459         .authorize(&[])
460         .exchange_code();
461 
462     let verifier = test_state
463         .id_token_verifier(test_state.jwks())
464         .set_allowed_algs(vec![CoreJwsSigningAlgorithm::HmacSha256]);
465     let id_token_claims = test_state
466         .id_token()
467         .claims(&verifier, test_state.nonce.as_ref().expect("no nonce"))
468         .panic_if_fail("failed to validate claims");
469     log_debug!("ID token: {:?}", id_token_claims);
470 
471     log_info!("SUCCESS");
472 }
473 
474 #[test]
475 #[ignore]
rp_id_token_sub()476 fn rp_id_token_sub() {
477     let mut test_state = TestState::init("rp-id_token-sub", |reg| reg).authorize(&[]);
478 
479     let token_response = test_state
480         .client
481         .exchange_code(
482             test_state
483                 .authorization_code
484                 .take()
485                 .expect("no authorization_code"),
486         )
487         .request(http_client);
488 
489     match token_response {
490         Err(RequestTokenError::Parse(_, _)) => {
491             log_error!("ID token failed to parse without `sub` claim (expected result)")
492         }
493         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
494     }
495     log_info!("SUCCESS");
496 }
497 
498 #[test]
499 #[ignore]
rp_id_token_bad_sig_rs256()500 fn rp_id_token_bad_sig_rs256() {
501     let test_state = TestState::init("rp-id_token-bad-sig-rs256", |reg| reg)
502         .authorize(&[])
503         .exchange_code();
504 
505     match test_state.id_token_claims_failure() {
506         ClaimsVerificationError::SignatureVerification(
507             SignatureVerificationError::CryptoError(_),
508         ) => log_error!("ID token has invalid signature (expected result)"),
509         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
510     }
511 
512     log_info!("SUCCESS");
513 }
514 
515 #[test]
516 #[ignore]
rp_id_token_bad_sig_hs256()517 fn rp_id_token_bad_sig_hs256() {
518     let test_state = TestState::init("rp-id_token-bad-sig-hs256", |reg| reg)
519         .authorize(&[])
520         .exchange_code();
521 
522     let verifier = test_state
523         .id_token_verifier(test_state.jwks())
524         .set_allowed_algs(vec![CoreJwsSigningAlgorithm::HmacSha256]);
525     let id_token_err = test_state
526         .id_token()
527         .claims(&verifier, test_state.nonce.as_ref().expect("no nonce"))
528         .expect_err("claims verification succeeded but was expected to fail");
529     match id_token_err {
530         ClaimsVerificationError::SignatureVerification(
531             SignatureVerificationError::CryptoError(_),
532         ) => log_error!("ID token has invalid signature (expected result)"),
533         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
534     }
535 
536     log_info!("SUCCESS");
537 }
538 
539 #[test]
540 #[ignore]
rp_id_token_issuer_mismatch()541 fn rp_id_token_issuer_mismatch() {
542     let test_state = TestState::init("rp-id_token-issuer-mismatch", |reg| reg)
543         .authorize(&[])
544         .exchange_code();
545 
546     match test_state.id_token_claims_failure() {
547         ClaimsVerificationError::InvalidIssuer(_) => {
548             log_error!("ID token has invalid issuer (expected result)")
549         }
550         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
551     }
552 
553     log_info!("SUCCESS");
554 }
555 
556 #[test]
557 #[ignore]
rp_userinfo_bad_sub_claim()558 fn rp_userinfo_bad_sub_claim() {
559     let test_state = TestState::init("rp-userinfo-bad-sub-claim", |reg| reg)
560         .authorize(&[Scope::new("profile".to_string())])
561         .exchange_code();
562     let id_token_claims = test_state.id_token_claims();
563     log_debug!("ID token: {:?}", id_token_claims);
564 
565     match test_state.user_info_claims_failure() {
566         UserInfoError::ClaimsVerification(ClaimsVerificationError::InvalidSubject(_)) => {
567             log_error!("UserInfo response has invalid subject (expected result)")
568         }
569         other => panic!("Unexpected result verifying ID token claims: {:?}", other),
570     }
571     log_info!("SUCCESS");
572 }
573 
574 #[test]
575 #[ignore]
rp_userinfo_bearer_header()576 fn rp_userinfo_bearer_header() {
577     let test_state = TestState::init("rp-userinfo-bearer-header", |reg| reg)
578         .authorize(&[Scope::new("profile".to_string())])
579         .exchange_code();
580     let id_token_claims = test_state.id_token_claims();
581     log_debug!("ID token: {:?}", id_token_claims);
582 
583     let user_info_claims = test_state.user_info_claims();
584     log_debug!("UserInfo response: {:?}", user_info_claims);
585     log_info!("SUCCESS");
586 }
587 
588 #[test]
589 #[ignore]
rp_userinfo_sig()590 fn rp_userinfo_sig() {
591     let test_state = TestState::init("rp-userinfo-sig", |reg| {
592         reg.set_userinfo_signed_response_alg(Some(CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256))
593     })
594     .authorize(&[Scope::new("profile".to_string())])
595     .exchange_code();
596     let id_token_claims = test_state.id_token_claims();
597     log_debug!("ID token: {:?}", id_token_claims);
598 
599     let user_info_claims: CoreUserInfoClaims = test_state
600         .client
601         .user_info(
602             test_state.access_token().to_owned(),
603             Some(id_token_claims.subject().clone()),
604         )
605         .unwrap()
606         // For some reason, the test suite omits these claims even though the Core spec says
607         // that the RP SHOULD verify these.
608         .require_audience_match(false)
609         .require_issuer_match(false)
610         .request(http_client)
611         .panic_if_fail("failed to get UserInfo");
612 
613     log_debug!("UserInfo response: {:?}", user_info_claims);
614     log_info!("SUCCESS");
615 }
616