1use std::ops::Deref;
12
13use chrono::{DateTime, Duration, Utc};
14use indexmap::IndexMap;
15use language_tags::LanguageTag;
16use mas_iana::{
17 jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
18 oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
19};
20use mas_jose::jwk::PublicJsonWebKeySet;
21use serde::{Deserialize, Serialize};
22use serde_with::{TimestampSeconds, serde_as, skip_serializing_none};
23use thiserror::Error;
24use url::Url;
25
26use crate::{
27 oidc::{ApplicationType, SubjectType},
28 requests::GrantType,
29 response_type::ResponseType,
30};
31
32mod client_metadata_serde;
33use client_metadata_serde::ClientMetadataSerdeHelper;
34
35pub const DEFAULT_RESPONSE_TYPES: [OAuthAuthorizationEndpointResponseType; 1] =
37 [OAuthAuthorizationEndpointResponseType::Code];
38
39pub const DEFAULT_GRANT_TYPES: &[GrantType] = &[GrantType::AuthorizationCode];
41
42pub const DEFAULT_APPLICATION_TYPE: ApplicationType = ApplicationType::Web;
44
45pub const DEFAULT_TOKEN_AUTH_METHOD: &OAuthClientAuthenticationMethod =
47 &OAuthClientAuthenticationMethod::ClientSecretBasic;
48
49pub const DEFAULT_SIGNING_ALGORITHM: &JsonWebSignatureAlg = &JsonWebSignatureAlg::Rs256;
51
52pub const DEFAULT_ENCRYPTION_ENC_ALGORITHM: &JsonWebEncryptionEnc =
54 &JsonWebEncryptionEnc::A128CbcHs256;
55
56#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct Localized<T> {
61 non_localized: T,
62 localized: IndexMap<LanguageTag, T>,
63}
64
65impl<T> Localized<T> {
66 pub fn new(non_localized: T, localized: impl IntoIterator<Item = (LanguageTag, T)>) -> Self {
69 Self {
70 non_localized,
71 localized: localized.into_iter().collect(),
72 }
73 }
74
75 #[allow(clippy::len_without_is_empty)]
77 pub fn len(&self) -> usize {
78 self.localized.len() + 1
79 }
80
81 pub fn non_localized(&self) -> &T {
83 &self.non_localized
84 }
85
86 pub fn to_non_localized(self) -> T {
88 self.non_localized
89 }
90
91 pub fn get(&self, language: Option<&LanguageTag>) -> Option<&T> {
93 match language {
94 Some(lang) => self.localized.get(lang),
95 None => Some(&self.non_localized),
96 }
97 }
98
99 pub fn iter(&self) -> impl Iterator<Item = (Option<&LanguageTag>, &T)> {
101 Some(&self.non_localized)
102 .into_iter()
103 .map(|val| (None, val))
104 .chain(self.localized.iter().map(|(lang, val)| (Some(lang), val)))
105 }
106}
107
108impl<T> From<(T, IndexMap<LanguageTag, T>)> for Localized<T> {
109 fn from(t: (T, IndexMap<LanguageTag, T>)) -> Self {
110 Localized {
111 non_localized: t.0,
112 localized: t.1,
113 }
114 }
115}
116
117#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
123#[serde(from = "ClientMetadataSerdeHelper", into = "ClientMetadataSerdeHelper")]
124pub struct ClientMetadata {
125 pub redirect_uris: Option<Vec<Url>>,
135
136 pub response_types: Option<Vec<ResponseType>>,
147
148 pub grant_types: Option<Vec<GrantType>>,
163
164 pub application_type: Option<ApplicationType>,
168
169 pub contacts: Option<Vec<String>>,
171
172 pub client_name: Option<Localized<String>>,
174
175 pub logo_uri: Option<Localized<Url>>,
177
178 pub client_uri: Option<Localized<Url>>,
180
181 pub policy_uri: Option<Localized<Url>>,
184
185 pub tos_uri: Option<Localized<Url>>,
188
189 pub jwks_uri: Option<Url>,
200
201 pub jwks: Option<PublicJsonWebKeySet>,
210
211 pub software_id: Option<String>,
218
219 pub software_version: Option<String>,
222
223 pub sector_identifier_uri: Option<Url>,
230
231 pub subject_type: Option<SubjectType>,
235
236 pub token_endpoint_auth_method: Option<OAuthClientAuthenticationMethod>,
245
246 pub token_endpoint_auth_signing_alg: Option<JsonWebSignatureAlg>,
258
259 pub id_token_signed_response_alg: Option<JsonWebSignatureAlg>,
270
271 pub id_token_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
278
279 pub id_token_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
287
288 pub userinfo_signed_response_alg: Option<JsonWebSignatureAlg>,
292
293 pub userinfo_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
302
303 pub userinfo_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
313
314 pub request_object_signing_alg: Option<JsonWebSignatureAlg>,
321
322 pub request_object_encryption_alg: Option<JsonWebEncryptionAlg>,
329
330 pub request_object_encryption_enc: Option<JsonWebEncryptionEnc>,
338
339 pub default_max_age: Option<Duration>,
347
348 pub require_auth_time: Option<bool>,
352
353 pub default_acr_values: Option<Vec<String>>,
355
356 pub initiate_login_uri: Option<Url>,
362
363 pub request_uris: Option<Vec<Url>>,
377
378 pub require_signed_request_object: Option<bool>,
385
386 pub require_pushed_authorization_requests: Option<bool>,
393
394 pub introspection_signed_response_alg: Option<JsonWebSignatureAlg>,
400
401 pub introspection_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
413
414 pub introspection_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
426
427 pub post_logout_redirect_uris: Option<Vec<Url>>,
432}
433
434impl ClientMetadata {
435 pub fn validate(self) -> Result<VerifiedClientMetadata, ClientMetadataVerificationError> {
444 let grant_types = self.grant_types();
445 let has_implicit = grant_types.contains(&GrantType::Implicit);
446 let has_authorization_code = grant_types.contains(&GrantType::AuthorizationCode);
447 let has_both = has_implicit && has_authorization_code;
448
449 if let Some(uris) = &self.redirect_uris {
450 if let Some(uri) = uris.iter().find(|uri| uri.fragment().is_some()) {
451 return Err(ClientMetadataVerificationError::RedirectUriWithFragment(
452 uri.clone(),
453 ));
454 }
455 } else if has_authorization_code || has_implicit {
456 return Err(ClientMetadataVerificationError::MissingRedirectUris);
458 }
459
460 let response_type_code = [OAuthAuthorizationEndpointResponseType::Code.into()];
461 let response_types = match &self.response_types {
462 Some(types) => &types[..],
463 None if has_authorization_code || has_implicit => &response_type_code[..],
465 None => &[],
466 };
467
468 for response_type in response_types {
469 let has_code = response_type.has_code();
470 let has_id_token = response_type.has_id_token();
471 let has_token = response_type.has_token();
472 let is_ok = has_code && has_both
473 || !has_code && has_implicit
474 || has_authorization_code && !has_id_token && !has_token
475 || !has_code && !has_id_token && !has_token;
476
477 if !is_ok {
478 return Err(ClientMetadataVerificationError::IncoherentResponseType(
479 response_type.clone(),
480 ));
481 }
482 }
483
484 if self.jwks_uri.is_some() && self.jwks.is_some() {
485 return Err(ClientMetadataVerificationError::JwksUriAndJwksMutuallyExclusive);
486 }
487
488 if let Some(url) = self
489 .sector_identifier_uri
490 .as_ref()
491 .filter(|url| url.scheme() != "https")
492 {
493 return Err(ClientMetadataVerificationError::UrlNonHttpsScheme(
494 "sector_identifier_uri",
495 url.clone(),
496 ));
497 }
498
499 if *self.token_endpoint_auth_method() == OAuthClientAuthenticationMethod::PrivateKeyJwt
500 && self.jwks_uri.is_none()
501 && self.jwks.is_none()
502 {
503 return Err(ClientMetadataVerificationError::MissingJwksForTokenMethod);
504 }
505
506 if let Some(alg) = &self.token_endpoint_auth_signing_alg {
507 if *alg == JsonWebSignatureAlg::None {
508 return Err(ClientMetadataVerificationError::UnauthorizedSigningAlgNone(
509 "token_endpoint",
510 ));
511 }
512 } else if matches!(
513 self.token_endpoint_auth_method(),
514 OAuthClientAuthenticationMethod::PrivateKeyJwt
515 | OAuthClientAuthenticationMethod::ClientSecretJwt
516 ) {
517 return Err(ClientMetadataVerificationError::MissingAuthSigningAlg(
518 "token_endpoint",
519 ));
520 }
521
522 if *self.id_token_signed_response_alg() == JsonWebSignatureAlg::None
523 && response_types.iter().any(ResponseType::has_id_token)
524 {
525 return Err(ClientMetadataVerificationError::IdTokenSigningAlgNone);
526 }
527
528 if self.id_token_encrypted_response_enc.is_some() {
529 self.id_token_encrypted_response_alg.as_ref().ok_or(
530 ClientMetadataVerificationError::MissingEncryptionAlg("id_token"),
531 )?;
532 }
533
534 if self.userinfo_encrypted_response_enc.is_some() {
535 self.userinfo_encrypted_response_alg.as_ref().ok_or(
536 ClientMetadataVerificationError::MissingEncryptionAlg("userinfo"),
537 )?;
538 }
539
540 if self.request_object_encryption_enc.is_some() {
541 self.request_object_encryption_alg.as_ref().ok_or(
542 ClientMetadataVerificationError::MissingEncryptionAlg("request_object"),
543 )?;
544 }
545
546 if let Some(url) = self
547 .initiate_login_uri
548 .as_ref()
549 .filter(|url| url.scheme() != "https")
550 {
551 return Err(ClientMetadataVerificationError::UrlNonHttpsScheme(
552 "initiate_login_uri",
553 url.clone(),
554 ));
555 }
556
557 if self.introspection_encrypted_response_enc.is_some() {
558 self.introspection_encrypted_response_alg.as_ref().ok_or(
559 ClientMetadataVerificationError::MissingEncryptionAlg("introspection"),
560 )?;
561 }
562
563 Ok(VerifiedClientMetadata { inner: self })
564 }
565
566 #[must_use]
569 pub fn sorted(mut self) -> Self {
570 if let Some(redirect_uris) = &mut self.redirect_uris {
572 redirect_uris.sort();
573 }
574 if let Some(response_types) = &mut self.response_types {
575 response_types.sort();
576 }
577 if let Some(grant_types) = &mut self.grant_types {
578 grant_types.sort();
579 }
580 if let Some(contacts) = &mut self.contacts {
581 contacts.sort();
582 }
583 if let Some(client_name) = &mut self.client_name {
584 client_name.sort();
585 }
586 if let Some(logo_uri) = &mut self.logo_uri {
587 logo_uri.sort();
588 }
589 if let Some(client_uri) = &mut self.client_uri {
590 client_uri.sort();
591 }
592 if let Some(policy_uri) = &mut self.policy_uri {
593 policy_uri.sort();
594 }
595 if let Some(tos_uri) = &mut self.tos_uri {
596 tos_uri.sort();
597 }
598 if let Some(default_acr_values) = &mut self.default_acr_values {
599 default_acr_values.sort();
600 }
601 if let Some(request_uris) = &mut self.request_uris {
602 request_uris.sort();
603 }
604 if let Some(post_logout_redirect_uris) = &mut self.post_logout_redirect_uris {
605 post_logout_redirect_uris.sort();
606 }
607
608 self
609 }
610
611 #[must_use]
622 pub fn response_types(&self) -> Vec<ResponseType> {
623 self.response_types.clone().unwrap_or_else(|| {
624 DEFAULT_RESPONSE_TYPES
625 .into_iter()
626 .map(ResponseType::from)
627 .collect()
628 })
629 }
630
631 #[must_use]
644 pub fn grant_types(&self) -> &[GrantType] {
645 self.grant_types.as_deref().unwrap_or(DEFAULT_GRANT_TYPES)
646 }
647
648 #[must_use]
652 pub fn application_type(&self) -> ApplicationType {
653 self.application_type
654 .clone()
655 .unwrap_or(DEFAULT_APPLICATION_TYPE)
656 }
657
658 #[must_use]
664 pub fn token_endpoint_auth_method(&self) -> &OAuthClientAuthenticationMethod {
665 self.token_endpoint_auth_method
666 .as_ref()
667 .unwrap_or(DEFAULT_TOKEN_AUTH_METHOD)
668 }
669
670 #[must_use]
681 pub fn id_token_signed_response_alg(&self) -> &JsonWebSignatureAlg {
682 self.id_token_signed_response_alg
683 .as_ref()
684 .unwrap_or(DEFAULT_SIGNING_ALGORITHM)
685 }
686
687 #[must_use]
696 pub fn id_token_encrypted_response(
697 &self,
698 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
699 self.id_token_encrypted_response_alg.as_ref().map(|alg| {
700 (
701 alg,
702 self.id_token_encrypted_response_enc
703 .as_ref()
704 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
705 )
706 })
707 }
708
709 #[must_use]
718 pub fn userinfo_encrypted_response(
719 &self,
720 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
721 self.userinfo_encrypted_response_alg.as_ref().map(|alg| {
722 (
723 alg,
724 self.userinfo_encrypted_response_enc
725 .as_ref()
726 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
727 )
728 })
729 }
730
731 #[must_use]
740 pub fn request_object_encryption(
741 &self,
742 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
743 self.request_object_encryption_alg.as_ref().map(|alg| {
744 (
745 alg,
746 self.request_object_encryption_enc
747 .as_ref()
748 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
749 )
750 })
751 }
752
753 #[must_use]
757 pub fn require_auth_time(&self) -> bool {
758 self.require_auth_time.unwrap_or_default()
759 }
760
761 #[must_use]
768 pub fn require_signed_request_object(&self) -> bool {
769 self.require_signed_request_object.unwrap_or_default()
770 }
771
772 #[must_use]
779 pub fn require_pushed_authorization_requests(&self) -> bool {
780 self.require_pushed_authorization_requests
781 .unwrap_or_default()
782 }
783
784 #[must_use]
794 pub fn introspection_encrypted_response(
795 &self,
796 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
797 self.introspection_encrypted_response_alg
798 .as_ref()
799 .map(|alg| {
800 (
801 alg,
802 self.introspection_encrypted_response_enc
803 .as_ref()
804 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
805 )
806 })
807 }
808}
809
810#[derive(Serialize, Debug, PartialEq, Eq, Clone)]
819#[serde(into = "ClientMetadataSerdeHelper")]
820pub struct VerifiedClientMetadata {
821 inner: ClientMetadata,
822}
823
824impl VerifiedClientMetadata {
825 #[must_use]
833 pub fn redirect_uris(&self) -> &[Url] {
834 match &self.redirect_uris {
835 Some(v) => v,
836 None => &[],
837 }
838 }
839}
840
841impl Deref for VerifiedClientMetadata {
842 type Target = ClientMetadata;
843
844 fn deref(&self) -> &Self::Target {
845 &self.inner
846 }
847}
848
849#[derive(Debug, Error)]
851pub enum ClientMetadataVerificationError {
852 #[error("redirect URIs are missing")]
854 MissingRedirectUris,
855
856 #[error("redirect URI with fragment: {0}")]
858 RedirectUriWithFragment(Url),
859
860 #[error("'{0}' response type not compatible with grant types")]
862 IncoherentResponseType(ResponseType),
863
864 #[error("jwks_uri and jwks are mutually exclusive")]
867 JwksUriAndJwksMutuallyExclusive,
868
869 #[error("{0}'s URL doesn't use a https scheme: {1}")]
871 UrlNonHttpsScheme(&'static str, Url),
872
873 #[error("missing JWK Set for token auth method")]
875 MissingJwksForTokenMethod,
876
877 #[error("none signing alg unauthorized for {0}")]
879 UnauthorizedSigningAlgNone(&'static str),
880
881 #[error("{0} missing auth signing algorithm")]
885 MissingAuthSigningAlg(&'static str),
886
887 #[error("ID Token signing alg is none")]
890 IdTokenSigningAlgNone,
891
892 #[error("{0} missing encryption alg value")]
894 MissingEncryptionAlg(&'static str),
895}
896
897#[serde_as]
899#[skip_serializing_none]
900#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
901pub struct ClientRegistrationResponse {
902 pub client_id: String,
904
905 #[serde(default)]
907 pub client_secret: Option<String>,
908
909 #[serde(default)]
911 #[serde_as(as = "Option<TimestampSeconds<i64>>")]
912 pub client_id_issued_at: Option<DateTime<Utc>>,
913
914 #[serde(default)]
918 #[serde_as(as = "Option<TimestampSeconds<i64>>")]
919 pub client_secret_expires_at: Option<DateTime<Utc>>,
920}
921
922#[cfg(test)]
923mod tests {
924 use assert_matches::assert_matches;
925 use mas_iana::{
926 jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
927 oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
928 };
929 use mas_jose::jwk::PublicJsonWebKeySet;
930 use url::Url;
931
932 use super::{ClientMetadata, ClientMetadataVerificationError};
933 use crate::{requests::GrantType, response_type::ResponseType};
934
935 fn valid_client_metadata() -> ClientMetadata {
936 ClientMetadata {
937 redirect_uris: Some(vec![Url::parse("http://localhost/oidc").unwrap()]),
938 ..Default::default()
939 }
940 }
941
942 fn jwks() -> PublicJsonWebKeySet {
943 serde_json::from_value(serde_json::json!({
944 "keys": [
945 {
946 "alg": "RS256",
947 "kty": "RSA",
948 "n": "tCwhHOxX_ylh5kVwfVqW7QIBTIsPjkjCjVCppDrynuF_3msEdtEaG64eJUz84ODFNMCC0BQ57G7wrKQVWkdSDxWUEqGk2BixBiHJRWZdofz1WOBTdPVicvHW5Zl_aIt7uXWMdOp_SODw-O2y2f05EqbFWFnR2-1y9K8KbiOp82CD72ny1Jbb_3PxTs2Z0F4ECAtTzpDteaJtjeeueRjr7040JAjQ-5fpL5D1g8x14LJyVIo-FL_y94NPFbMp7UCi69CIfVHXFO8WYFz949og-47mWRrID5lS4zpx-QLuvNhUb_lSqmylUdQB3HpRdOcYdj3xwy4MHJuu7tTaf0AmCQ",
949 "use": "sig",
950 "kid": "d98f49bc6ca4581eae8dfadd494fce10ea23aab0",
951 "e": "AQAB"
952 }
953 ]
954 })).unwrap()
955 }
956
957 #[test]
958 fn validate_required_metadata() {
959 let metadata = valid_client_metadata();
960 metadata.validate().unwrap();
961 }
962
963 #[test]
964 fn validate_redirect_uris() {
965 let mut metadata = ClientMetadata::default();
966
967 assert_matches!(
969 metadata.clone().validate(),
970 Err(ClientMetadataVerificationError::MissingRedirectUris)
971 );
972
973 let wrong_uri = Url::parse("http://localhost/#fragment").unwrap();
975 metadata.redirect_uris = Some(vec![
976 Url::parse("http://localhost/").unwrap(),
977 wrong_uri.clone(),
978 ]);
979 let uri = assert_matches!(
980 metadata.clone().validate(),
981 Err(ClientMetadataVerificationError::RedirectUriWithFragment(uri)) => uri
982 );
983 assert_eq!(uri, wrong_uri);
984
985 metadata.redirect_uris = Some(vec![
987 Url::parse("http://localhost/").unwrap(),
988 Url::parse("http://localhost/oidc").unwrap(),
989 Url::parse("http://localhost/?oidc").unwrap(),
990 Url::parse("http://localhost/my-client?oidc").unwrap(),
991 ]);
992 metadata.validate().unwrap();
993 }
994
995 #[test]
996 fn validate_response_types() {
997 let mut metadata = valid_client_metadata();
998
999 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
1002 metadata.clone().validate().unwrap();
1003
1004 let response_type: ResponseType =
1006 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1007 metadata.response_types = Some(vec![response_type.clone()]);
1008 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1009 assert_eq!(res, response_type);
1010
1011 let response_type: ResponseType =
1013 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1014 metadata.response_types = Some(vec![response_type.clone()]);
1015 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1016 assert_eq!(res, response_type);
1017
1018 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1020 metadata.response_types = Some(vec![response_type.clone()]);
1021 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1022 assert_eq!(res, response_type);
1023
1024 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::IdToken.into();
1026 metadata.response_types = Some(vec![response_type.clone()]);
1027 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1028 assert_eq!(res, response_type);
1029
1030 let response_type: ResponseType =
1032 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1033 metadata.response_types = Some(vec![response_type.clone()]);
1034 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1035 assert_eq!(res, response_type);
1036
1037 let response_type: ResponseType =
1039 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1040 metadata.response_types = Some(vec![response_type.clone()]);
1041 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1042 assert_eq!(res, response_type);
1043
1044 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1046 metadata.clone().validate().unwrap();
1047
1048 metadata.grant_types = Some(vec![GrantType::Implicit]);
1050 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Code.into();
1052 metadata.response_types = Some(vec![response_type.clone()]);
1053 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1054 assert_eq!(res, response_type);
1055
1056 let response_type: ResponseType =
1058 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1059 metadata.response_types = Some(vec![response_type.clone()]);
1060 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1061 assert_eq!(res, response_type);
1062
1063 let response_type: ResponseType =
1065 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1066 metadata.response_types = Some(vec![response_type.clone()]);
1067 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1068 assert_eq!(res, response_type);
1069
1070 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1072 metadata.response_types = Some(vec![response_type.clone()]);
1073 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1074 assert_eq!(res, response_type);
1075
1076 metadata.response_types =
1078 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1079 metadata.clone().validate().unwrap();
1080
1081 metadata.response_types = Some(vec![
1083 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1084 ]);
1085 metadata.clone().validate().unwrap();
1086
1087 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Token.into()]);
1089 metadata.clone().validate().unwrap();
1090
1091 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1093 metadata.clone().validate().unwrap();
1094
1095 metadata.grant_types = Some(vec![GrantType::AuthorizationCode, GrantType::Implicit]);
1097 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
1099 metadata.clone().validate().unwrap();
1100
1101 metadata.response_types = Some(vec![
1103 OAuthAuthorizationEndpointResponseType::CodeIdToken.into(),
1104 ]);
1105 metadata.clone().validate().unwrap();
1106
1107 metadata.response_types = Some(vec![
1109 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into(),
1110 ]);
1111 metadata.clone().validate().unwrap();
1112
1113 metadata.response_types = Some(vec![
1115 OAuthAuthorizationEndpointResponseType::CodeToken.into(),
1116 ]);
1117 metadata.clone().validate().unwrap();
1118
1119 metadata.response_types =
1121 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1122 metadata.clone().validate().unwrap();
1123
1124 metadata.response_types = Some(vec![
1126 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1127 ]);
1128 metadata.clone().validate().unwrap();
1129
1130 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Token.into()]);
1132 metadata.clone().validate().unwrap();
1133
1134 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1136 metadata.clone().validate().unwrap();
1137
1138 metadata.grant_types = Some(vec![GrantType::RefreshToken, GrantType::ClientCredentials]);
1140 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Code.into();
1142 metadata.response_types = Some(vec![response_type.clone()]);
1143 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1144 assert_eq!(res, response_type);
1145
1146 let response_type: ResponseType =
1148 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1149 metadata.response_types = Some(vec![response_type.clone()]);
1150 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1151 assert_eq!(res, response_type);
1152
1153 let response_type: ResponseType =
1155 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1156 metadata.response_types = Some(vec![response_type.clone()]);
1157 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1158 assert_eq!(res, response_type);
1159
1160 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1162 metadata.response_types = Some(vec![response_type.clone()]);
1163 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1164 assert_eq!(res, response_type);
1165
1166 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::IdToken.into();
1168 metadata.response_types = Some(vec![response_type.clone()]);
1169 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1170 assert_eq!(res, response_type);
1171
1172 let response_type: ResponseType =
1174 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1175 metadata.response_types = Some(vec![response_type.clone()]);
1176 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1177 assert_eq!(res, response_type);
1178
1179 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Token.into();
1181 metadata.response_types = Some(vec![response_type.clone()]);
1182 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1183 assert_eq!(res, response_type);
1184
1185 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1187 metadata.validate().unwrap();
1188 }
1189
1190 #[test]
1191 fn validate_jwks() {
1192 let mut metadata = valid_client_metadata();
1193
1194 metadata.jwks_uri = Some(Url::parse("http://localhost/jwks").unwrap());
1196 metadata.clone().validate().unwrap();
1197
1198 metadata.jwks = Some(jwks());
1200 assert_matches!(
1201 metadata.clone().validate(),
1202 Err(ClientMetadataVerificationError::JwksUriAndJwksMutuallyExclusive)
1203 );
1204
1205 metadata.jwks_uri = None;
1207 metadata.validate().unwrap();
1208 }
1209
1210 #[test]
1211 fn validate_sector_identifier_uri() {
1212 let mut metadata = valid_client_metadata();
1213
1214 let identifier_uri = Url::parse("http://localhost/").unwrap();
1216 metadata.sector_identifier_uri = Some(identifier_uri.clone());
1217 let (field, url) = assert_matches!(
1218 metadata.clone().validate(),
1219 Err(ClientMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1220 );
1221 assert_eq!(field, "sector_identifier_uri");
1222 assert_eq!(url, identifier_uri);
1223
1224 metadata.sector_identifier_uri = Some(Url::parse("https://localhost/").unwrap());
1226 metadata.validate().unwrap();
1227 }
1228
1229 #[test]
1230 fn validate_token_endpoint_auth_method() {
1231 let mut metadata = valid_client_metadata();
1232
1233 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::None);
1235 let field = assert_matches!(
1236 metadata.clone().validate(),
1237 Err(ClientMetadataVerificationError::UnauthorizedSigningAlgNone(field)) => field
1238 );
1239 assert_eq!(field, "token_endpoint");
1240
1241 metadata.token_endpoint_auth_method = Some(OAuthClientAuthenticationMethod::PrivateKeyJwt);
1243 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::Rs256);
1244
1245 assert_matches!(
1247 metadata.clone().validate(),
1248 Err(ClientMetadataVerificationError::MissingJwksForTokenMethod)
1249 );
1250
1251 metadata.jwks_uri = Some(Url::parse("https://localhost/jwks").unwrap());
1253 metadata.clone().validate().unwrap();
1254
1255 metadata.jwks_uri = None;
1257 metadata.jwks = Some(jwks());
1258 metadata.clone().validate().unwrap();
1259
1260 metadata.token_endpoint_auth_signing_alg = None;
1262 let field = assert_matches!(
1263 metadata.clone().validate(),
1264 Err(ClientMetadataVerificationError::MissingAuthSigningAlg(field)) => field
1265 );
1266 assert_eq!(field, "token_endpoint");
1267
1268 metadata.token_endpoint_auth_method =
1270 Some(OAuthClientAuthenticationMethod::ClientSecretJwt);
1271 metadata.jwks = None;
1272
1273 let field = assert_matches!(
1275 metadata.clone().validate(),
1276 Err(ClientMetadataVerificationError::MissingAuthSigningAlg(field)) => field
1277 );
1278 assert_eq!(field, "token_endpoint");
1279
1280 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::Rs256);
1282 metadata.validate().unwrap();
1283 }
1284
1285 #[test]
1286 fn validate_id_token_signed_response_alg() {
1287 let mut metadata = valid_client_metadata();
1288 metadata.id_token_signed_response_alg = Some(JsonWebSignatureAlg::None);
1289 metadata.grant_types = Some(vec![GrantType::AuthorizationCode, GrantType::Implicit]);
1290
1291 metadata.response_types = Some(vec![
1293 OAuthAuthorizationEndpointResponseType::CodeIdToken.into(),
1294 ]);
1295 assert_matches!(
1296 metadata.clone().validate(),
1297 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1298 );
1299
1300 metadata.response_types = Some(vec![
1302 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into(),
1303 ]);
1304 assert_matches!(
1305 metadata.clone().validate(),
1306 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1307 );
1308
1309 metadata.response_types =
1311 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1312 assert_matches!(
1313 metadata.clone().validate(),
1314 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1315 );
1316
1317 metadata.response_types = Some(vec![
1319 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1320 ]);
1321 assert_matches!(
1322 metadata.clone().validate(),
1323 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1324 );
1325
1326 metadata.response_types = Some(vec![
1328 OAuthAuthorizationEndpointResponseType::Code.into(),
1329 OAuthAuthorizationEndpointResponseType::CodeToken.into(),
1330 OAuthAuthorizationEndpointResponseType::Token.into(),
1331 OAuthAuthorizationEndpointResponseType::None.into(),
1332 ]);
1333 metadata.validate().unwrap();
1334 }
1335
1336 #[test]
1337 fn validate_id_token_encrypted_response() {
1338 let mut metadata = valid_client_metadata();
1339 metadata.id_token_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1340
1341 let field = assert_matches!(
1343 metadata.clone().validate(),
1344 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1345 );
1346 assert_eq!(field, "id_token");
1347
1348 metadata.id_token_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1350 metadata.validate().unwrap();
1351 }
1352
1353 #[test]
1354 fn validate_userinfo_encrypted_response() {
1355 let mut metadata = valid_client_metadata();
1356 metadata.userinfo_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1357
1358 let field = assert_matches!(
1360 metadata.clone().validate(),
1361 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1362 );
1363 assert_eq!(field, "userinfo");
1364
1365 metadata.userinfo_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1367 metadata.validate().unwrap();
1368 }
1369
1370 #[test]
1371 fn validate_request_object_encryption() {
1372 let mut metadata = valid_client_metadata();
1373 metadata.request_object_encryption_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1374
1375 let field = assert_matches!(
1377 metadata.clone().validate(),
1378 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1379 );
1380 assert_eq!(field, "request_object");
1381
1382 metadata.request_object_encryption_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1384 metadata.validate().unwrap();
1385 }
1386
1387 #[test]
1388 fn validate_initiate_login_uri() {
1389 let mut metadata = valid_client_metadata();
1390
1391 let initiate_uri = Url::parse("http://localhost/").unwrap();
1393 metadata.initiate_login_uri = Some(initiate_uri.clone());
1394 let (field, url) = assert_matches!(
1395 metadata.clone().validate(),
1396 Err(ClientMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1397 );
1398 assert_eq!(field, "initiate_login_uri");
1399 assert_eq!(url, initiate_uri);
1400
1401 metadata.initiate_login_uri = Some(Url::parse("https://localhost/").unwrap());
1403 metadata.validate().unwrap();
1404 }
1405
1406 #[test]
1407 fn validate_introspection_encrypted_response() {
1408 let mut metadata = valid_client_metadata();
1409 metadata.introspection_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1410
1411 let field = assert_matches!(
1413 metadata.clone().validate(),
1414 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1415 );
1416 assert_eq!(field, "introspection");
1417
1418 metadata.introspection_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1420 metadata.validate().unwrap();
1421 }
1422}