rp_certification_code.rs 19 KB

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