1use std::{collections::HashMap, ops::Deref};
20
21use chrono::{DateTime, Duration, Utc};
22use language_tags::LanguageTag;
23use mas_iana::{
24 jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
25 oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
26};
27use mas_jose::jwk::PublicJsonWebKeySet;
28use serde::{Deserialize, Serialize};
29use serde_with::{serde_as, skip_serializing_none, TimestampSeconds};
30use thiserror::Error;
31use url::Url;
32
33use crate::{
34 oidc::{ApplicationType, SubjectType},
35 requests::GrantType,
36 response_type::ResponseType,
37};
38
39mod client_metadata_serde;
40use client_metadata_serde::ClientMetadataSerdeHelper;
41
42pub const DEFAULT_RESPONSE_TYPES: [OAuthAuthorizationEndpointResponseType; 1] =
44 [OAuthAuthorizationEndpointResponseType::Code];
45
46pub const DEFAULT_GRANT_TYPES: &[GrantType] = &[GrantType::AuthorizationCode];
48
49pub const DEFAULT_APPLICATION_TYPE: ApplicationType = ApplicationType::Web;
51
52pub const DEFAULT_TOKEN_AUTH_METHOD: &OAuthClientAuthenticationMethod =
54 &OAuthClientAuthenticationMethod::ClientSecretBasic;
55
56pub const DEFAULT_SIGNING_ALGORITHM: &JsonWebSignatureAlg = &JsonWebSignatureAlg::Rs256;
58
59pub const DEFAULT_ENCRYPTION_ENC_ALGORITHM: &JsonWebEncryptionEnc =
61 &JsonWebEncryptionEnc::A128CbcHs256;
62
63#[derive(Debug, Clone, PartialEq, Eq)]
67pub struct Localized<T> {
68 non_localized: T,
69 localized: HashMap<LanguageTag, T>,
70}
71
72impl<T> Localized<T> {
73 pub fn new(non_localized: T, localized: impl IntoIterator<Item = (LanguageTag, T)>) -> Self {
76 Self {
77 non_localized,
78 localized: localized.into_iter().collect(),
79 }
80 }
81
82 #[allow(clippy::len_without_is_empty)]
84 pub fn len(&self) -> usize {
85 self.localized.len() + 1
86 }
87
88 pub fn non_localized(&self) -> &T {
90 &self.non_localized
91 }
92
93 pub fn to_non_localized(self) -> T {
95 self.non_localized
96 }
97
98 pub fn get(&self, language: Option<&LanguageTag>) -> Option<&T> {
100 match language {
101 Some(lang) => self.localized.get(lang),
102 None => Some(&self.non_localized),
103 }
104 }
105
106 pub fn iter(&self) -> impl Iterator<Item = (Option<&LanguageTag>, &T)> {
108 Some(&self.non_localized)
109 .into_iter()
110 .map(|val| (None, val))
111 .chain(self.localized.iter().map(|(lang, val)| (Some(lang), val)))
112 }
113}
114
115impl<T> From<(T, HashMap<LanguageTag, T>)> for Localized<T> {
116 fn from(t: (T, HashMap<LanguageTag, T>)) -> Self {
117 Localized {
118 non_localized: t.0,
119 localized: t.1,
120 }
121 }
122}
123
124#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Default)]
130#[serde(from = "ClientMetadataSerdeHelper")]
131pub struct ClientMetadata {
132 pub redirect_uris: Option<Vec<Url>>,
142
143 pub response_types: Option<Vec<ResponseType>>,
154
155 pub grant_types: Option<Vec<GrantType>>,
170
171 pub application_type: Option<ApplicationType>,
175
176 pub contacts: Option<Vec<String>>,
178
179 pub client_name: Option<Localized<String>>,
181
182 pub logo_uri: Option<Localized<Url>>,
184
185 pub client_uri: Option<Localized<Url>>,
187
188 pub policy_uri: Option<Localized<Url>>,
191
192 pub tos_uri: Option<Localized<Url>>,
195
196 pub jwks_uri: Option<Url>,
207
208 pub jwks: Option<PublicJsonWebKeySet>,
217
218 pub software_id: Option<String>,
225
226 pub software_version: Option<String>,
229
230 pub sector_identifier_uri: Option<Url>,
237
238 pub subject_type: Option<SubjectType>,
242
243 pub token_endpoint_auth_method: Option<OAuthClientAuthenticationMethod>,
252
253 pub token_endpoint_auth_signing_alg: Option<JsonWebSignatureAlg>,
265
266 pub id_token_signed_response_alg: Option<JsonWebSignatureAlg>,
277
278 pub id_token_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
285
286 pub id_token_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
294
295 pub userinfo_signed_response_alg: Option<JsonWebSignatureAlg>,
299
300 pub userinfo_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
309
310 pub userinfo_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
320
321 pub request_object_signing_alg: Option<JsonWebSignatureAlg>,
328
329 pub request_object_encryption_alg: Option<JsonWebEncryptionAlg>,
336
337 pub request_object_encryption_enc: Option<JsonWebEncryptionEnc>,
345
346 pub default_max_age: Option<Duration>,
354
355 pub require_auth_time: Option<bool>,
359
360 pub default_acr_values: Option<Vec<String>>,
362
363 pub initiate_login_uri: Option<Url>,
369
370 pub request_uris: Option<Vec<Url>>,
384
385 pub require_signed_request_object: Option<bool>,
392
393 pub require_pushed_authorization_requests: Option<bool>,
400
401 pub introspection_signed_response_alg: Option<JsonWebSignatureAlg>,
407
408 pub introspection_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
420
421 pub introspection_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
433
434 pub post_logout_redirect_uris: Option<Vec<Url>>,
439}
440
441impl ClientMetadata {
442 #[allow(clippy::too_many_lines)]
451 pub fn validate(self) -> Result<VerifiedClientMetadata, ClientMetadataVerificationError> {
452 let grant_types = self.grant_types();
453 let has_implicit = grant_types.contains(&GrantType::Implicit);
454 let has_authorization_code = grant_types.contains(&GrantType::AuthorizationCode);
455 let has_both = has_implicit && has_authorization_code;
456
457 if let Some(uris) = &self.redirect_uris {
458 if let Some(uri) = uris.iter().find(|uri| uri.fragment().is_some()) {
459 return Err(ClientMetadataVerificationError::RedirectUriWithFragment(
460 uri.clone(),
461 ));
462 }
463 } else if has_authorization_code || has_implicit {
464 return Err(ClientMetadataVerificationError::MissingRedirectUris);
466 }
467
468 let response_type_code = [OAuthAuthorizationEndpointResponseType::Code.into()];
469 let response_types = match &self.response_types {
470 Some(types) => &types[..],
471 None if has_authorization_code || has_implicit => &response_type_code[..],
473 None => &[],
474 };
475
476 for response_type in response_types {
477 let has_code = response_type.has_code();
478 let has_id_token = response_type.has_id_token();
479 let has_token = response_type.has_token();
480 let is_ok = has_code && has_both
481 || !has_code && has_implicit
482 || has_authorization_code && !has_id_token && !has_token
483 || !has_code && !has_id_token && !has_token;
484
485 if !is_ok {
486 return Err(ClientMetadataVerificationError::IncoherentResponseType(
487 response_type.clone(),
488 ));
489 }
490 }
491
492 if self.jwks_uri.is_some() && self.jwks.is_some() {
493 return Err(ClientMetadataVerificationError::JwksUriAndJwksMutuallyExclusive);
494 }
495
496 if let Some(url) = self
497 .sector_identifier_uri
498 .as_ref()
499 .filter(|url| url.scheme() != "https")
500 {
501 return Err(ClientMetadataVerificationError::UrlNonHttpsScheme(
502 "sector_identifier_uri",
503 url.clone(),
504 ));
505 }
506
507 if *self.token_endpoint_auth_method() == OAuthClientAuthenticationMethod::PrivateKeyJwt
508 && self.jwks_uri.is_none()
509 && self.jwks.is_none()
510 {
511 return Err(ClientMetadataVerificationError::MissingJwksForTokenMethod);
512 }
513
514 if let Some(alg) = &self.token_endpoint_auth_signing_alg {
515 if *alg == JsonWebSignatureAlg::None {
516 return Err(ClientMetadataVerificationError::UnauthorizedSigningAlgNone(
517 "token_endpoint",
518 ));
519 }
520 } else if matches!(
521 self.token_endpoint_auth_method(),
522 OAuthClientAuthenticationMethod::PrivateKeyJwt
523 | OAuthClientAuthenticationMethod::ClientSecretJwt
524 ) {
525 return Err(ClientMetadataVerificationError::MissingAuthSigningAlg(
526 "token_endpoint",
527 ));
528 }
529
530 if *self.id_token_signed_response_alg() == JsonWebSignatureAlg::None
531 && response_types.iter().any(ResponseType::has_id_token)
532 {
533 return Err(ClientMetadataVerificationError::IdTokenSigningAlgNone);
534 }
535
536 if self.id_token_encrypted_response_enc.is_some() {
537 self.id_token_encrypted_response_alg.as_ref().ok_or(
538 ClientMetadataVerificationError::MissingEncryptionAlg("id_token"),
539 )?;
540 }
541
542 if self.userinfo_encrypted_response_enc.is_some() {
543 self.userinfo_encrypted_response_alg.as_ref().ok_or(
544 ClientMetadataVerificationError::MissingEncryptionAlg("userinfo"),
545 )?;
546 }
547
548 if self.request_object_encryption_enc.is_some() {
549 self.request_object_encryption_alg.as_ref().ok_or(
550 ClientMetadataVerificationError::MissingEncryptionAlg("request_object"),
551 )?;
552 }
553
554 if let Some(url) = self
555 .initiate_login_uri
556 .as_ref()
557 .filter(|url| url.scheme() != "https")
558 {
559 return Err(ClientMetadataVerificationError::UrlNonHttpsScheme(
560 "initiate_login_uri",
561 url.clone(),
562 ));
563 }
564
565 if self.introspection_encrypted_response_enc.is_some() {
566 self.introspection_encrypted_response_alg.as_ref().ok_or(
567 ClientMetadataVerificationError::MissingEncryptionAlg("introspection"),
568 )?;
569 }
570
571 Ok(VerifiedClientMetadata { inner: self })
572 }
573
574 #[must_use]
585 pub fn response_types(&self) -> Vec<ResponseType> {
586 self.response_types.clone().unwrap_or_else(|| {
587 DEFAULT_RESPONSE_TYPES
588 .into_iter()
589 .map(ResponseType::from)
590 .collect()
591 })
592 }
593
594 #[must_use]
607 pub fn grant_types(&self) -> &[GrantType] {
608 self.grant_types.as_deref().unwrap_or(DEFAULT_GRANT_TYPES)
609 }
610
611 #[must_use]
615 pub fn application_type(&self) -> ApplicationType {
616 self.application_type
617 .clone()
618 .unwrap_or(DEFAULT_APPLICATION_TYPE)
619 }
620
621 #[must_use]
627 pub fn token_endpoint_auth_method(&self) -> &OAuthClientAuthenticationMethod {
628 self.token_endpoint_auth_method
629 .as_ref()
630 .unwrap_or(DEFAULT_TOKEN_AUTH_METHOD)
631 }
632
633 #[must_use]
644 pub fn id_token_signed_response_alg(&self) -> &JsonWebSignatureAlg {
645 self.id_token_signed_response_alg
646 .as_ref()
647 .unwrap_or(DEFAULT_SIGNING_ALGORITHM)
648 }
649
650 #[must_use]
659 pub fn id_token_encrypted_response(
660 &self,
661 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
662 self.id_token_encrypted_response_alg.as_ref().map(|alg| {
663 (
664 alg,
665 self.id_token_encrypted_response_enc
666 .as_ref()
667 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
668 )
669 })
670 }
671
672 #[must_use]
681 pub fn userinfo_encrypted_response(
682 &self,
683 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
684 self.userinfo_encrypted_response_alg.as_ref().map(|alg| {
685 (
686 alg,
687 self.userinfo_encrypted_response_enc
688 .as_ref()
689 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
690 )
691 })
692 }
693
694 #[must_use]
703 pub fn request_object_encryption(
704 &self,
705 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
706 self.request_object_encryption_alg.as_ref().map(|alg| {
707 (
708 alg,
709 self.request_object_encryption_enc
710 .as_ref()
711 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
712 )
713 })
714 }
715
716 #[must_use]
720 pub fn require_auth_time(&self) -> bool {
721 self.require_auth_time.unwrap_or_default()
722 }
723
724 #[must_use]
731 pub fn require_signed_request_object(&self) -> bool {
732 self.require_signed_request_object.unwrap_or_default()
733 }
734
735 #[must_use]
742 pub fn require_pushed_authorization_requests(&self) -> bool {
743 self.require_pushed_authorization_requests
744 .unwrap_or_default()
745 }
746
747 #[must_use]
757 pub fn introspection_encrypted_response(
758 &self,
759 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
760 self.introspection_encrypted_response_alg
761 .as_ref()
762 .map(|alg| {
763 (
764 alg,
765 self.introspection_encrypted_response_enc
766 .as_ref()
767 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
768 )
769 })
770 }
771}
772
773#[derive(Serialize, Debug, PartialEq, Eq, Clone)]
809#[serde(into = "ClientMetadataSerdeHelper")]
810pub struct VerifiedClientMetadata {
811 inner: ClientMetadata,
812}
813
814impl VerifiedClientMetadata {
815 #[must_use]
823 pub fn redirect_uris(&self) -> &[Url] {
824 match &self.redirect_uris {
825 Some(v) => v,
826 None => &[],
827 }
828 }
829}
830
831impl Deref for VerifiedClientMetadata {
832 type Target = ClientMetadata;
833
834 fn deref(&self) -> &Self::Target {
835 &self.inner
836 }
837}
838
839#[derive(Debug, Error)]
841pub enum ClientMetadataVerificationError {
842 #[error("redirect URIs are missing")]
844 MissingRedirectUris,
845
846 #[error("redirect URI with fragment: {0}")]
848 RedirectUriWithFragment(Url),
849
850 #[error("'{0}' response type not compatible with grant types")]
852 IncoherentResponseType(ResponseType),
853
854 #[error("jwks_uri and jwks are mutually exclusive")]
857 JwksUriAndJwksMutuallyExclusive,
858
859 #[error("{0}'s URL doesn't use a https scheme: {1}")]
861 UrlNonHttpsScheme(&'static str, Url),
862
863 #[error("missing JWK Set for token auth method")]
865 MissingJwksForTokenMethod,
866
867 #[error("none signing alg unauthorized for {0}")]
869 UnauthorizedSigningAlgNone(&'static str),
870
871 #[error("{0} missing auth signing algorithm")]
875 MissingAuthSigningAlg(&'static str),
876
877 #[error("ID Token signing alg is none")]
880 IdTokenSigningAlgNone,
881
882 #[error("{0} missing encryption alg value")]
884 MissingEncryptionAlg(&'static str),
885}
886
887#[serde_as]
889#[skip_serializing_none]
890#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
891pub struct ClientRegistrationResponse {
892 pub client_id: String,
894
895 #[serde(default)]
897 pub client_secret: Option<String>,
898
899 #[serde(default)]
901 #[serde_as(as = "Option<TimestampSeconds<i64>>")]
902 pub client_id_issued_at: Option<DateTime<Utc>>,
903
904 #[serde(default)]
908 #[serde_as(as = "Option<TimestampSeconds<i64>>")]
909 pub client_secret_expires_at: Option<DateTime<Utc>>,
910}
911
912#[cfg(test)]
913mod tests {
914 use assert_matches::assert_matches;
915 use mas_iana::{
916 jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
917 oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
918 };
919 use mas_jose::jwk::PublicJsonWebKeySet;
920 use url::Url;
921
922 use super::{ClientMetadata, ClientMetadataVerificationError};
923 use crate::{requests::GrantType, response_type::ResponseType};
924
925 fn valid_client_metadata() -> ClientMetadata {
926 ClientMetadata {
927 redirect_uris: Some(vec![Url::parse("http://localhost/oidc").unwrap()]),
928 ..Default::default()
929 }
930 }
931
932 fn jwks() -> PublicJsonWebKeySet {
933 serde_json::from_value(serde_json::json!({
934 "keys": [
935 {
936 "alg": "RS256",
937 "kty": "RSA",
938 "n": "tCwhHOxX_ylh5kVwfVqW7QIBTIsPjkjCjVCppDrynuF_3msEdtEaG64eJUz84ODFNMCC0BQ57G7wrKQVWkdSDxWUEqGk2BixBiHJRWZdofz1WOBTdPVicvHW5Zl_aIt7uXWMdOp_SODw-O2y2f05EqbFWFnR2-1y9K8KbiOp82CD72ny1Jbb_3PxTs2Z0F4ECAtTzpDteaJtjeeueRjr7040JAjQ-5fpL5D1g8x14LJyVIo-FL_y94NPFbMp7UCi69CIfVHXFO8WYFz949og-47mWRrID5lS4zpx-QLuvNhUb_lSqmylUdQB3HpRdOcYdj3xwy4MHJuu7tTaf0AmCQ",
939 "use": "sig",
940 "kid": "d98f49bc6ca4581eae8dfadd494fce10ea23aab0",
941 "e": "AQAB"
942 }
943 ]
944 })).unwrap()
945 }
946
947 #[test]
948 fn validate_required_metadata() {
949 let metadata = valid_client_metadata();
950 metadata.validate().unwrap();
951 }
952
953 #[test]
954 fn validate_redirect_uris() {
955 let mut metadata = ClientMetadata::default();
956
957 assert_matches!(
959 metadata.clone().validate(),
960 Err(ClientMetadataVerificationError::MissingRedirectUris)
961 );
962
963 let wrong_uri = Url::parse("http://localhost/#fragment").unwrap();
965 metadata.redirect_uris = Some(vec![
966 Url::parse("http://localhost/").unwrap(),
967 wrong_uri.clone(),
968 ]);
969 let uri = assert_matches!(
970 metadata.clone().validate(),
971 Err(ClientMetadataVerificationError::RedirectUriWithFragment(uri)) => uri
972 );
973 assert_eq!(uri, wrong_uri);
974
975 metadata.redirect_uris = Some(vec![
977 Url::parse("http://localhost/").unwrap(),
978 Url::parse("http://localhost/oidc").unwrap(),
979 Url::parse("http://localhost/?oidc").unwrap(),
980 Url::parse("http://localhost/my-client?oidc").unwrap(),
981 ]);
982 metadata.validate().unwrap();
983 }
984
985 #[test]
986 #[allow(clippy::too_many_lines)]
987 fn validate_response_types() {
988 let mut metadata = valid_client_metadata();
989
990 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
993 metadata.clone().validate().unwrap();
994
995 let response_type: ResponseType =
997 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
998 metadata.response_types = Some(vec![response_type.clone()]);
999 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1000 assert_eq!(res, response_type);
1001
1002 let response_type: ResponseType =
1004 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1005 metadata.response_types = Some(vec![response_type.clone()]);
1006 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1007 assert_eq!(res, response_type);
1008
1009 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1011 metadata.response_types = Some(vec![response_type.clone()]);
1012 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1013 assert_eq!(res, response_type);
1014
1015 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::IdToken.into();
1017 metadata.response_types = Some(vec![response_type.clone()]);
1018 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1019 assert_eq!(res, response_type);
1020
1021 let response_type: ResponseType =
1023 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1024 metadata.response_types = Some(vec![response_type.clone()]);
1025 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1026 assert_eq!(res, response_type);
1027
1028 let response_type: ResponseType =
1030 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1031 metadata.response_types = Some(vec![response_type.clone()]);
1032 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1033 assert_eq!(res, response_type);
1034
1035 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1037 metadata.clone().validate().unwrap();
1038
1039 metadata.grant_types = Some(vec![GrantType::Implicit]);
1041 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Code.into();
1043 metadata.response_types = Some(vec![response_type.clone()]);
1044 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1045 assert_eq!(res, response_type);
1046
1047 let response_type: ResponseType =
1049 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1050 metadata.response_types = Some(vec![response_type.clone()]);
1051 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1052 assert_eq!(res, response_type);
1053
1054 let response_type: ResponseType =
1056 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1057 metadata.response_types = Some(vec![response_type.clone()]);
1058 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1059 assert_eq!(res, response_type);
1060
1061 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1063 metadata.response_types = Some(vec![response_type.clone()]);
1064 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1065 assert_eq!(res, response_type);
1066
1067 metadata.response_types =
1069 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1070 metadata.clone().validate().unwrap();
1071
1072 metadata.response_types = Some(vec![
1074 OAuthAuthorizationEndpointResponseType::IdTokenToken.into()
1075 ]);
1076 metadata.clone().validate().unwrap();
1077
1078 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Token.into()]);
1080 metadata.clone().validate().unwrap();
1081
1082 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1084 metadata.clone().validate().unwrap();
1085
1086 metadata.grant_types = Some(vec![GrantType::AuthorizationCode, GrantType::Implicit]);
1088 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
1090 metadata.clone().validate().unwrap();
1091
1092 metadata.response_types = Some(vec![
1094 OAuthAuthorizationEndpointResponseType::CodeIdToken.into()
1095 ]);
1096 metadata.clone().validate().unwrap();
1097
1098 metadata.response_types = Some(vec![
1100 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into(),
1101 ]);
1102 metadata.clone().validate().unwrap();
1103
1104 metadata.response_types = Some(vec![
1106 OAuthAuthorizationEndpointResponseType::CodeToken.into()
1107 ]);
1108 metadata.clone().validate().unwrap();
1109
1110 metadata.response_types =
1112 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1113 metadata.clone().validate().unwrap();
1114
1115 metadata.response_types = Some(vec![
1117 OAuthAuthorizationEndpointResponseType::IdTokenToken.into()
1118 ]);
1119 metadata.clone().validate().unwrap();
1120
1121 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Token.into()]);
1123 metadata.clone().validate().unwrap();
1124
1125 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1127 metadata.clone().validate().unwrap();
1128
1129 metadata.grant_types = Some(vec![GrantType::RefreshToken, GrantType::ClientCredentials]);
1131 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Code.into();
1133 metadata.response_types = Some(vec![response_type.clone()]);
1134 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1135 assert_eq!(res, response_type);
1136
1137 let response_type: ResponseType =
1139 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1140 metadata.response_types = Some(vec![response_type.clone()]);
1141 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1142 assert_eq!(res, response_type);
1143
1144 let response_type: ResponseType =
1146 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1147 metadata.response_types = Some(vec![response_type.clone()]);
1148 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1149 assert_eq!(res, response_type);
1150
1151 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1153 metadata.response_types = Some(vec![response_type.clone()]);
1154 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1155 assert_eq!(res, response_type);
1156
1157 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::IdToken.into();
1159 metadata.response_types = Some(vec![response_type.clone()]);
1160 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1161 assert_eq!(res, response_type);
1162
1163 let response_type: ResponseType =
1165 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1166 metadata.response_types = Some(vec![response_type.clone()]);
1167 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1168 assert_eq!(res, response_type);
1169
1170 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Token.into();
1172 metadata.response_types = Some(vec![response_type.clone()]);
1173 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1174 assert_eq!(res, response_type);
1175
1176 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1178 metadata.validate().unwrap();
1179 }
1180
1181 #[test]
1182 fn validate_jwks() {
1183 let mut metadata = valid_client_metadata();
1184
1185 metadata.jwks_uri = Some(Url::parse("http://localhost/jwks").unwrap());
1187 metadata.clone().validate().unwrap();
1188
1189 metadata.jwks = Some(jwks());
1191 assert_matches!(
1192 metadata.clone().validate(),
1193 Err(ClientMetadataVerificationError::JwksUriAndJwksMutuallyExclusive)
1194 );
1195
1196 metadata.jwks_uri = None;
1198 metadata.validate().unwrap();
1199 }
1200
1201 #[test]
1202 fn validate_sector_identifier_uri() {
1203 let mut metadata = valid_client_metadata();
1204
1205 let identifier_uri = Url::parse("http://localhost/").unwrap();
1207 metadata.sector_identifier_uri = Some(identifier_uri.clone());
1208 let (field, url) = assert_matches!(
1209 metadata.clone().validate(),
1210 Err(ClientMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1211 );
1212 assert_eq!(field, "sector_identifier_uri");
1213 assert_eq!(url, identifier_uri);
1214
1215 metadata.sector_identifier_uri = Some(Url::parse("https://localhost/").unwrap());
1217 metadata.validate().unwrap();
1218 }
1219
1220 #[test]
1221 fn validate_token_endpoint_auth_method() {
1222 let mut metadata = valid_client_metadata();
1223
1224 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::None);
1226 let field = assert_matches!(
1227 metadata.clone().validate(),
1228 Err(ClientMetadataVerificationError::UnauthorizedSigningAlgNone(field)) => field
1229 );
1230 assert_eq!(field, "token_endpoint");
1231
1232 metadata.token_endpoint_auth_method = Some(OAuthClientAuthenticationMethod::PrivateKeyJwt);
1234 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::Rs256);
1235
1236 assert_matches!(
1238 metadata.clone().validate(),
1239 Err(ClientMetadataVerificationError::MissingJwksForTokenMethod)
1240 );
1241
1242 metadata.jwks_uri = Some(Url::parse("https://localhost/jwks").unwrap());
1244 metadata.clone().validate().unwrap();
1245
1246 metadata.jwks_uri = None;
1248 metadata.jwks = Some(jwks());
1249 metadata.clone().validate().unwrap();
1250
1251 metadata.token_endpoint_auth_signing_alg = None;
1253 let field = assert_matches!(
1254 metadata.clone().validate(),
1255 Err(ClientMetadataVerificationError::MissingAuthSigningAlg(field)) => field
1256 );
1257 assert_eq!(field, "token_endpoint");
1258
1259 metadata.token_endpoint_auth_method =
1261 Some(OAuthClientAuthenticationMethod::ClientSecretJwt);
1262 metadata.jwks = None;
1263
1264 let field = assert_matches!(
1266 metadata.clone().validate(),
1267 Err(ClientMetadataVerificationError::MissingAuthSigningAlg(field)) => field
1268 );
1269 assert_eq!(field, "token_endpoint");
1270
1271 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::Rs256);
1273 metadata.validate().unwrap();
1274 }
1275
1276 #[test]
1277 fn validate_id_token_signed_response_alg() {
1278 let mut metadata = valid_client_metadata();
1279 metadata.id_token_signed_response_alg = Some(JsonWebSignatureAlg::None);
1280 metadata.grant_types = Some(vec![GrantType::AuthorizationCode, GrantType::Implicit]);
1281
1282 metadata.response_types = Some(vec![
1284 OAuthAuthorizationEndpointResponseType::CodeIdToken.into()
1285 ]);
1286 assert_matches!(
1287 metadata.clone().validate(),
1288 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1289 );
1290
1291 metadata.response_types = Some(vec![
1293 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into(),
1294 ]);
1295 assert_matches!(
1296 metadata.clone().validate(),
1297 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1298 );
1299
1300 metadata.response_types =
1302 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1303 assert_matches!(
1304 metadata.clone().validate(),
1305 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1306 );
1307
1308 metadata.response_types = Some(vec![
1310 OAuthAuthorizationEndpointResponseType::IdTokenToken.into()
1311 ]);
1312 assert_matches!(
1313 metadata.clone().validate(),
1314 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1315 );
1316
1317 metadata.response_types = Some(vec![
1319 OAuthAuthorizationEndpointResponseType::Code.into(),
1320 OAuthAuthorizationEndpointResponseType::CodeToken.into(),
1321 OAuthAuthorizationEndpointResponseType::Token.into(),
1322 OAuthAuthorizationEndpointResponseType::None.into(),
1323 ]);
1324 metadata.validate().unwrap();
1325 }
1326
1327 #[test]
1328 fn validate_id_token_encrypted_response() {
1329 let mut metadata = valid_client_metadata();
1330 metadata.id_token_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1331
1332 let field = assert_matches!(
1334 metadata.clone().validate(),
1335 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1336 );
1337 assert_eq!(field, "id_token");
1338
1339 metadata.id_token_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1341 metadata.validate().unwrap();
1342 }
1343
1344 #[test]
1345 fn validate_userinfo_encrypted_response() {
1346 let mut metadata = valid_client_metadata();
1347 metadata.userinfo_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1348
1349 let field = assert_matches!(
1351 metadata.clone().validate(),
1352 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1353 );
1354 assert_eq!(field, "userinfo");
1355
1356 metadata.userinfo_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1358 metadata.validate().unwrap();
1359 }
1360
1361 #[test]
1362 fn validate_request_object_encryption() {
1363 let mut metadata = valid_client_metadata();
1364 metadata.request_object_encryption_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1365
1366 let field = assert_matches!(
1368 metadata.clone().validate(),
1369 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1370 );
1371 assert_eq!(field, "request_object");
1372
1373 metadata.request_object_encryption_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1375 metadata.validate().unwrap();
1376 }
1377
1378 #[test]
1379 fn validate_initiate_login_uri() {
1380 let mut metadata = valid_client_metadata();
1381
1382 let initiate_uri = Url::parse("http://localhost/").unwrap();
1384 metadata.initiate_login_uri = Some(initiate_uri.clone());
1385 let (field, url) = assert_matches!(
1386 metadata.clone().validate(),
1387 Err(ClientMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1388 );
1389 assert_eq!(field, "initiate_login_uri");
1390 assert_eq!(url, initiate_uri);
1391
1392 metadata.initiate_login_uri = Some(Url::parse("https://localhost/").unwrap());
1394 metadata.validate().unwrap();
1395 }
1396
1397 #[test]
1398 fn validate_introspection_encrypted_response() {
1399 let mut metadata = valid_client_metadata();
1400 metadata.introspection_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1401
1402 let field = assert_matches!(
1404 metadata.clone().validate(),
1405 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1406 );
1407 assert_eq!(field, "introspection");
1408
1409 metadata.introspection_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1411 metadata.validate().unwrap();
1412 }
1413}