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)]
919 #[serde_as(as = "Option<TimestampSeconds<i64>>")]
920 pub client_secret_expires_at: Option<DateTime<Utc>>,
921}
922
923#[cfg(test)]
924mod tests {
925 use assert_matches::assert_matches;
926 use mas_iana::{
927 jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
928 oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
929 };
930 use mas_jose::jwk::PublicJsonWebKeySet;
931 use url::Url;
932
933 use super::{ClientMetadata, ClientMetadataVerificationError};
934 use crate::{requests::GrantType, response_type::ResponseType};
935
936 fn valid_client_metadata() -> ClientMetadata {
937 ClientMetadata {
938 redirect_uris: Some(vec![Url::parse("http://localhost/oidc").unwrap()]),
939 ..Default::default()
940 }
941 }
942
943 fn jwks() -> PublicJsonWebKeySet {
944 serde_json::from_value(serde_json::json!({
945 "keys": [
946 {
947 "alg": "RS256",
948 "kty": "RSA",
949 "n": "tCwhHOxX_ylh5kVwfVqW7QIBTIsPjkjCjVCppDrynuF_3msEdtEaG64eJUz84ODFNMCC0BQ57G7wrKQVWkdSDxWUEqGk2BixBiHJRWZdofz1WOBTdPVicvHW5Zl_aIt7uXWMdOp_SODw-O2y2f05EqbFWFnR2-1y9K8KbiOp82CD72ny1Jbb_3PxTs2Z0F4ECAtTzpDteaJtjeeueRjr7040JAjQ-5fpL5D1g8x14LJyVIo-FL_y94NPFbMp7UCi69CIfVHXFO8WYFz949og-47mWRrID5lS4zpx-QLuvNhUb_lSqmylUdQB3HpRdOcYdj3xwy4MHJuu7tTaf0AmCQ",
950 "use": "sig",
951 "kid": "d98f49bc6ca4581eae8dfadd494fce10ea23aab0",
952 "e": "AQAB"
953 }
954 ]
955 })).unwrap()
956 }
957
958 #[test]
959 fn validate_required_metadata() {
960 let metadata = valid_client_metadata();
961 metadata.validate().unwrap();
962 }
963
964 #[test]
965 fn validate_redirect_uris() {
966 let mut metadata = ClientMetadata::default();
967
968 assert_matches!(
970 metadata.clone().validate(),
971 Err(ClientMetadataVerificationError::MissingRedirectUris)
972 );
973
974 let wrong_uri = Url::parse("http://localhost/#fragment").unwrap();
976 metadata.redirect_uris = Some(vec![
977 Url::parse("http://localhost/").unwrap(),
978 wrong_uri.clone(),
979 ]);
980 let uri = assert_matches!(
981 metadata.clone().validate(),
982 Err(ClientMetadataVerificationError::RedirectUriWithFragment(uri)) => uri
983 );
984 assert_eq!(uri, wrong_uri);
985
986 metadata.redirect_uris = Some(vec![
988 Url::parse("http://localhost/").unwrap(),
989 Url::parse("http://localhost/oidc").unwrap(),
990 Url::parse("http://localhost/?oidc").unwrap(),
991 Url::parse("http://localhost/my-client?oidc").unwrap(),
992 ]);
993 metadata.validate().unwrap();
994 }
995
996 #[test]
997 fn validate_response_types() {
998 let mut metadata = valid_client_metadata();
999
1000 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
1003 metadata.clone().validate().unwrap();
1004
1005 let response_type: ResponseType =
1007 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1008 metadata.response_types = Some(vec![response_type.clone()]);
1009 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1010 assert_eq!(res, response_type);
1011
1012 let response_type: ResponseType =
1014 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1015 metadata.response_types = Some(vec![response_type.clone()]);
1016 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1017 assert_eq!(res, response_type);
1018
1019 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1021 metadata.response_types = Some(vec![response_type.clone()]);
1022 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1023 assert_eq!(res, response_type);
1024
1025 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::IdToken.into();
1027 metadata.response_types = Some(vec![response_type.clone()]);
1028 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1029 assert_eq!(res, response_type);
1030
1031 let response_type: ResponseType =
1033 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1034 metadata.response_types = Some(vec![response_type.clone()]);
1035 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1036 assert_eq!(res, response_type);
1037
1038 let response_type: ResponseType =
1040 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1041 metadata.response_types = Some(vec![response_type.clone()]);
1042 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1043 assert_eq!(res, response_type);
1044
1045 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1047 metadata.clone().validate().unwrap();
1048
1049 metadata.grant_types = Some(vec![GrantType::Implicit]);
1051 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Code.into();
1053 metadata.response_types = Some(vec![response_type.clone()]);
1054 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1055 assert_eq!(res, response_type);
1056
1057 let response_type: ResponseType =
1059 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1060 metadata.response_types = Some(vec![response_type.clone()]);
1061 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1062 assert_eq!(res, response_type);
1063
1064 let response_type: ResponseType =
1066 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1067 metadata.response_types = Some(vec![response_type.clone()]);
1068 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1069 assert_eq!(res, response_type);
1070
1071 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1073 metadata.response_types = Some(vec![response_type.clone()]);
1074 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1075 assert_eq!(res, response_type);
1076
1077 metadata.response_types =
1079 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1080 metadata.clone().validate().unwrap();
1081
1082 metadata.response_types = Some(vec![
1084 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1085 ]);
1086 metadata.clone().validate().unwrap();
1087
1088 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Token.into()]);
1090 metadata.clone().validate().unwrap();
1091
1092 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1094 metadata.clone().validate().unwrap();
1095
1096 metadata.grant_types = Some(vec![GrantType::AuthorizationCode, GrantType::Implicit]);
1098 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
1100 metadata.clone().validate().unwrap();
1101
1102 metadata.response_types = Some(vec![
1104 OAuthAuthorizationEndpointResponseType::CodeIdToken.into(),
1105 ]);
1106 metadata.clone().validate().unwrap();
1107
1108 metadata.response_types = Some(vec![
1110 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into(),
1111 ]);
1112 metadata.clone().validate().unwrap();
1113
1114 metadata.response_types = Some(vec![
1116 OAuthAuthorizationEndpointResponseType::CodeToken.into(),
1117 ]);
1118 metadata.clone().validate().unwrap();
1119
1120 metadata.response_types =
1122 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1123 metadata.clone().validate().unwrap();
1124
1125 metadata.response_types = Some(vec![
1127 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1128 ]);
1129 metadata.clone().validate().unwrap();
1130
1131 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Token.into()]);
1133 metadata.clone().validate().unwrap();
1134
1135 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1137 metadata.clone().validate().unwrap();
1138
1139 metadata.grant_types = Some(vec![GrantType::RefreshToken, GrantType::ClientCredentials]);
1141 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Code.into();
1143 metadata.response_types = Some(vec![response_type.clone()]);
1144 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1145 assert_eq!(res, response_type);
1146
1147 let response_type: ResponseType =
1149 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1150 metadata.response_types = Some(vec![response_type.clone()]);
1151 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1152 assert_eq!(res, response_type);
1153
1154 let response_type: ResponseType =
1156 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1157 metadata.response_types = Some(vec![response_type.clone()]);
1158 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1159 assert_eq!(res, response_type);
1160
1161 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1163 metadata.response_types = Some(vec![response_type.clone()]);
1164 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1165 assert_eq!(res, response_type);
1166
1167 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::IdToken.into();
1169 metadata.response_types = Some(vec![response_type.clone()]);
1170 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1171 assert_eq!(res, response_type);
1172
1173 let response_type: ResponseType =
1175 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1176 metadata.response_types = Some(vec![response_type.clone()]);
1177 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1178 assert_eq!(res, response_type);
1179
1180 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Token.into();
1182 metadata.response_types = Some(vec![response_type.clone()]);
1183 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1184 assert_eq!(res, response_type);
1185
1186 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1188 metadata.validate().unwrap();
1189 }
1190
1191 #[test]
1192 fn validate_jwks() {
1193 let mut metadata = valid_client_metadata();
1194
1195 metadata.jwks_uri = Some(Url::parse("http://localhost/jwks").unwrap());
1197 metadata.clone().validate().unwrap();
1198
1199 metadata.jwks = Some(jwks());
1201 assert_matches!(
1202 metadata.clone().validate(),
1203 Err(ClientMetadataVerificationError::JwksUriAndJwksMutuallyExclusive)
1204 );
1205
1206 metadata.jwks_uri = None;
1208 metadata.validate().unwrap();
1209 }
1210
1211 #[test]
1212 fn validate_sector_identifier_uri() {
1213 let mut metadata = valid_client_metadata();
1214
1215 let identifier_uri = Url::parse("http://localhost/").unwrap();
1217 metadata.sector_identifier_uri = Some(identifier_uri.clone());
1218 let (field, url) = assert_matches!(
1219 metadata.clone().validate(),
1220 Err(ClientMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1221 );
1222 assert_eq!(field, "sector_identifier_uri");
1223 assert_eq!(url, identifier_uri);
1224
1225 metadata.sector_identifier_uri = Some(Url::parse("https://localhost/").unwrap());
1227 metadata.validate().unwrap();
1228 }
1229
1230 #[test]
1231 fn validate_token_endpoint_auth_method() {
1232 let mut metadata = valid_client_metadata();
1233
1234 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::None);
1236 let field = assert_matches!(
1237 metadata.clone().validate(),
1238 Err(ClientMetadataVerificationError::UnauthorizedSigningAlgNone(field)) => field
1239 );
1240 assert_eq!(field, "token_endpoint");
1241
1242 metadata.token_endpoint_auth_method = Some(OAuthClientAuthenticationMethod::PrivateKeyJwt);
1244 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::Rs256);
1245
1246 assert_matches!(
1248 metadata.clone().validate(),
1249 Err(ClientMetadataVerificationError::MissingJwksForTokenMethod)
1250 );
1251
1252 metadata.jwks_uri = Some(Url::parse("https://localhost/jwks").unwrap());
1254 metadata.clone().validate().unwrap();
1255
1256 metadata.jwks_uri = None;
1258 metadata.jwks = Some(jwks());
1259 metadata.clone().validate().unwrap();
1260
1261 metadata.token_endpoint_auth_signing_alg = None;
1263 let field = assert_matches!(
1264 metadata.clone().validate(),
1265 Err(ClientMetadataVerificationError::MissingAuthSigningAlg(field)) => field
1266 );
1267 assert_eq!(field, "token_endpoint");
1268
1269 metadata.token_endpoint_auth_method =
1271 Some(OAuthClientAuthenticationMethod::ClientSecretJwt);
1272 metadata.jwks = None;
1273
1274 let field = assert_matches!(
1276 metadata.clone().validate(),
1277 Err(ClientMetadataVerificationError::MissingAuthSigningAlg(field)) => field
1278 );
1279 assert_eq!(field, "token_endpoint");
1280
1281 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::Rs256);
1283 metadata.validate().unwrap();
1284 }
1285
1286 #[test]
1287 fn validate_id_token_signed_response_alg() {
1288 let mut metadata = valid_client_metadata();
1289 metadata.id_token_signed_response_alg = Some(JsonWebSignatureAlg::None);
1290 metadata.grant_types = Some(vec![GrantType::AuthorizationCode, GrantType::Implicit]);
1291
1292 metadata.response_types = Some(vec![
1294 OAuthAuthorizationEndpointResponseType::CodeIdToken.into(),
1295 ]);
1296 assert_matches!(
1297 metadata.clone().validate(),
1298 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1299 );
1300
1301 metadata.response_types = Some(vec![
1303 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into(),
1304 ]);
1305 assert_matches!(
1306 metadata.clone().validate(),
1307 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1308 );
1309
1310 metadata.response_types =
1312 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1313 assert_matches!(
1314 metadata.clone().validate(),
1315 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1316 );
1317
1318 metadata.response_types = Some(vec![
1320 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1321 ]);
1322 assert_matches!(
1323 metadata.clone().validate(),
1324 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1325 );
1326
1327 metadata.response_types = Some(vec![
1329 OAuthAuthorizationEndpointResponseType::Code.into(),
1330 OAuthAuthorizationEndpointResponseType::CodeToken.into(),
1331 OAuthAuthorizationEndpointResponseType::Token.into(),
1332 OAuthAuthorizationEndpointResponseType::None.into(),
1333 ]);
1334 metadata.validate().unwrap();
1335 }
1336
1337 #[test]
1338 fn validate_id_token_encrypted_response() {
1339 let mut metadata = valid_client_metadata();
1340 metadata.id_token_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1341
1342 let field = assert_matches!(
1344 metadata.clone().validate(),
1345 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1346 );
1347 assert_eq!(field, "id_token");
1348
1349 metadata.id_token_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1351 metadata.validate().unwrap();
1352 }
1353
1354 #[test]
1355 fn validate_userinfo_encrypted_response() {
1356 let mut metadata = valid_client_metadata();
1357 metadata.userinfo_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1358
1359 let field = assert_matches!(
1361 metadata.clone().validate(),
1362 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1363 );
1364 assert_eq!(field, "userinfo");
1365
1366 metadata.userinfo_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1368 metadata.validate().unwrap();
1369 }
1370
1371 #[test]
1372 fn validate_request_object_encryption() {
1373 let mut metadata = valid_client_metadata();
1374 metadata.request_object_encryption_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1375
1376 let field = assert_matches!(
1378 metadata.clone().validate(),
1379 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1380 );
1381 assert_eq!(field, "request_object");
1382
1383 metadata.request_object_encryption_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1385 metadata.validate().unwrap();
1386 }
1387
1388 #[test]
1389 fn validate_initiate_login_uri() {
1390 let mut metadata = valid_client_metadata();
1391
1392 let initiate_uri = Url::parse("http://localhost/").unwrap();
1394 metadata.initiate_login_uri = Some(initiate_uri.clone());
1395 let (field, url) = assert_matches!(
1396 metadata.clone().validate(),
1397 Err(ClientMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1398 );
1399 assert_eq!(field, "initiate_login_uri");
1400 assert_eq!(url, initiate_uri);
1401
1402 metadata.initiate_login_uri = Some(Url::parse("https://localhost/").unwrap());
1404 metadata.validate().unwrap();
1405 }
1406
1407 #[test]
1408 fn validate_introspection_encrypted_response() {
1409 let mut metadata = valid_client_metadata();
1410 metadata.introspection_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1411
1412 let field = assert_matches!(
1414 metadata.clone().validate(),
1415 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1416 );
1417 assert_eq!(field, "introspection");
1418
1419 metadata.introspection_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1421 metadata.validate().unwrap();
1422 }
1423}