1use std::{collections::HashMap, ops::Deref};
12
13use chrono::{DateTime, Duration, Utc};
14use language_tags::LanguageTag;
15use mas_iana::{
16 jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
17 oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
18};
19use mas_jose::jwk::PublicJsonWebKeySet;
20use serde::{Deserialize, Serialize};
21use serde_with::{TimestampSeconds, serde_as, skip_serializing_none};
22use thiserror::Error;
23use url::Url;
24
25use crate::{
26 oidc::{ApplicationType, SubjectType},
27 requests::GrantType,
28 response_type::ResponseType,
29};
30
31mod client_metadata_serde;
32use client_metadata_serde::ClientMetadataSerdeHelper;
33
34pub const DEFAULT_RESPONSE_TYPES: [OAuthAuthorizationEndpointResponseType; 1] =
36 [OAuthAuthorizationEndpointResponseType::Code];
37
38pub const DEFAULT_GRANT_TYPES: &[GrantType] = &[GrantType::AuthorizationCode];
40
41pub const DEFAULT_APPLICATION_TYPE: ApplicationType = ApplicationType::Web;
43
44pub const DEFAULT_TOKEN_AUTH_METHOD: &OAuthClientAuthenticationMethod =
46 &OAuthClientAuthenticationMethod::ClientSecretBasic;
47
48pub const DEFAULT_SIGNING_ALGORITHM: &JsonWebSignatureAlg = &JsonWebSignatureAlg::Rs256;
50
51pub const DEFAULT_ENCRYPTION_ENC_ALGORITHM: &JsonWebEncryptionEnc =
53 &JsonWebEncryptionEnc::A128CbcHs256;
54
55#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct Localized<T> {
60 non_localized: T,
61 localized: HashMap<LanguageTag, T>,
62}
63
64impl<T> Localized<T> {
65 pub fn new(non_localized: T, localized: impl IntoIterator<Item = (LanguageTag, T)>) -> Self {
68 Self {
69 non_localized,
70 localized: localized.into_iter().collect(),
71 }
72 }
73
74 #[allow(clippy::len_without_is_empty)]
76 pub fn len(&self) -> usize {
77 self.localized.len() + 1
78 }
79
80 pub fn non_localized(&self) -> &T {
82 &self.non_localized
83 }
84
85 pub fn to_non_localized(self) -> T {
87 self.non_localized
88 }
89
90 pub fn get(&self, language: Option<&LanguageTag>) -> Option<&T> {
92 match language {
93 Some(lang) => self.localized.get(lang),
94 None => Some(&self.non_localized),
95 }
96 }
97
98 pub fn iter(&self) -> impl Iterator<Item = (Option<&LanguageTag>, &T)> {
100 Some(&self.non_localized)
101 .into_iter()
102 .map(|val| (None, val))
103 .chain(self.localized.iter().map(|(lang, val)| (Some(lang), val)))
104 }
105}
106
107impl<T> From<(T, HashMap<LanguageTag, T>)> for Localized<T> {
108 fn from(t: (T, HashMap<LanguageTag, T>)) -> Self {
109 Localized {
110 non_localized: t.0,
111 localized: t.1,
112 }
113 }
114}
115
116#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Default)]
122#[serde(from = "ClientMetadataSerdeHelper")]
123pub struct ClientMetadata {
124 pub redirect_uris: Option<Vec<Url>>,
134
135 pub response_types: Option<Vec<ResponseType>>,
146
147 pub grant_types: Option<Vec<GrantType>>,
162
163 pub application_type: Option<ApplicationType>,
167
168 pub contacts: Option<Vec<String>>,
170
171 pub client_name: Option<Localized<String>>,
173
174 pub logo_uri: Option<Localized<Url>>,
176
177 pub client_uri: Option<Localized<Url>>,
179
180 pub policy_uri: Option<Localized<Url>>,
183
184 pub tos_uri: Option<Localized<Url>>,
187
188 pub jwks_uri: Option<Url>,
199
200 pub jwks: Option<PublicJsonWebKeySet>,
209
210 pub software_id: Option<String>,
217
218 pub software_version: Option<String>,
221
222 pub sector_identifier_uri: Option<Url>,
229
230 pub subject_type: Option<SubjectType>,
234
235 pub token_endpoint_auth_method: Option<OAuthClientAuthenticationMethod>,
244
245 pub token_endpoint_auth_signing_alg: Option<JsonWebSignatureAlg>,
257
258 pub id_token_signed_response_alg: Option<JsonWebSignatureAlg>,
269
270 pub id_token_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
277
278 pub id_token_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
286
287 pub userinfo_signed_response_alg: Option<JsonWebSignatureAlg>,
291
292 pub userinfo_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
301
302 pub userinfo_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
312
313 pub request_object_signing_alg: Option<JsonWebSignatureAlg>,
320
321 pub request_object_encryption_alg: Option<JsonWebEncryptionAlg>,
328
329 pub request_object_encryption_enc: Option<JsonWebEncryptionEnc>,
337
338 pub default_max_age: Option<Duration>,
346
347 pub require_auth_time: Option<bool>,
351
352 pub default_acr_values: Option<Vec<String>>,
354
355 pub initiate_login_uri: Option<Url>,
361
362 pub request_uris: Option<Vec<Url>>,
376
377 pub require_signed_request_object: Option<bool>,
384
385 pub require_pushed_authorization_requests: Option<bool>,
392
393 pub introspection_signed_response_alg: Option<JsonWebSignatureAlg>,
399
400 pub introspection_encrypted_response_alg: Option<JsonWebEncryptionAlg>,
412
413 pub introspection_encrypted_response_enc: Option<JsonWebEncryptionEnc>,
425
426 pub post_logout_redirect_uris: Option<Vec<Url>>,
431}
432
433impl ClientMetadata {
434 #[allow(clippy::too_many_lines)]
443 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]
577 pub fn response_types(&self) -> Vec<ResponseType> {
578 self.response_types.clone().unwrap_or_else(|| {
579 DEFAULT_RESPONSE_TYPES
580 .into_iter()
581 .map(ResponseType::from)
582 .collect()
583 })
584 }
585
586 #[must_use]
599 pub fn grant_types(&self) -> &[GrantType] {
600 self.grant_types.as_deref().unwrap_or(DEFAULT_GRANT_TYPES)
601 }
602
603 #[must_use]
607 pub fn application_type(&self) -> ApplicationType {
608 self.application_type
609 .clone()
610 .unwrap_or(DEFAULT_APPLICATION_TYPE)
611 }
612
613 #[must_use]
619 pub fn token_endpoint_auth_method(&self) -> &OAuthClientAuthenticationMethod {
620 self.token_endpoint_auth_method
621 .as_ref()
622 .unwrap_or(DEFAULT_TOKEN_AUTH_METHOD)
623 }
624
625 #[must_use]
636 pub fn id_token_signed_response_alg(&self) -> &JsonWebSignatureAlg {
637 self.id_token_signed_response_alg
638 .as_ref()
639 .unwrap_or(DEFAULT_SIGNING_ALGORITHM)
640 }
641
642 #[must_use]
651 pub fn id_token_encrypted_response(
652 &self,
653 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
654 self.id_token_encrypted_response_alg.as_ref().map(|alg| {
655 (
656 alg,
657 self.id_token_encrypted_response_enc
658 .as_ref()
659 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
660 )
661 })
662 }
663
664 #[must_use]
673 pub fn userinfo_encrypted_response(
674 &self,
675 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
676 self.userinfo_encrypted_response_alg.as_ref().map(|alg| {
677 (
678 alg,
679 self.userinfo_encrypted_response_enc
680 .as_ref()
681 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
682 )
683 })
684 }
685
686 #[must_use]
695 pub fn request_object_encryption(
696 &self,
697 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
698 self.request_object_encryption_alg.as_ref().map(|alg| {
699 (
700 alg,
701 self.request_object_encryption_enc
702 .as_ref()
703 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
704 )
705 })
706 }
707
708 #[must_use]
712 pub fn require_auth_time(&self) -> bool {
713 self.require_auth_time.unwrap_or_default()
714 }
715
716 #[must_use]
723 pub fn require_signed_request_object(&self) -> bool {
724 self.require_signed_request_object.unwrap_or_default()
725 }
726
727 #[must_use]
734 pub fn require_pushed_authorization_requests(&self) -> bool {
735 self.require_pushed_authorization_requests
736 .unwrap_or_default()
737 }
738
739 #[must_use]
749 pub fn introspection_encrypted_response(
750 &self,
751 ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
752 self.introspection_encrypted_response_alg
753 .as_ref()
754 .map(|alg| {
755 (
756 alg,
757 self.introspection_encrypted_response_enc
758 .as_ref()
759 .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
760 )
761 })
762 }
763}
764
765#[derive(Serialize, Debug, PartialEq, Eq, Clone)]
774#[serde(into = "ClientMetadataSerdeHelper")]
775pub struct VerifiedClientMetadata {
776 inner: ClientMetadata,
777}
778
779impl VerifiedClientMetadata {
780 #[must_use]
788 pub fn redirect_uris(&self) -> &[Url] {
789 match &self.redirect_uris {
790 Some(v) => v,
791 None => &[],
792 }
793 }
794}
795
796impl Deref for VerifiedClientMetadata {
797 type Target = ClientMetadata;
798
799 fn deref(&self) -> &Self::Target {
800 &self.inner
801 }
802}
803
804#[derive(Debug, Error)]
806pub enum ClientMetadataVerificationError {
807 #[error("redirect URIs are missing")]
809 MissingRedirectUris,
810
811 #[error("redirect URI with fragment: {0}")]
813 RedirectUriWithFragment(Url),
814
815 #[error("'{0}' response type not compatible with grant types")]
817 IncoherentResponseType(ResponseType),
818
819 #[error("jwks_uri and jwks are mutually exclusive")]
822 JwksUriAndJwksMutuallyExclusive,
823
824 #[error("{0}'s URL doesn't use a https scheme: {1}")]
826 UrlNonHttpsScheme(&'static str, Url),
827
828 #[error("missing JWK Set for token auth method")]
830 MissingJwksForTokenMethod,
831
832 #[error("none signing alg unauthorized for {0}")]
834 UnauthorizedSigningAlgNone(&'static str),
835
836 #[error("{0} missing auth signing algorithm")]
840 MissingAuthSigningAlg(&'static str),
841
842 #[error("ID Token signing alg is none")]
845 IdTokenSigningAlgNone,
846
847 #[error("{0} missing encryption alg value")]
849 MissingEncryptionAlg(&'static str),
850}
851
852#[serde_as]
854#[skip_serializing_none]
855#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
856pub struct ClientRegistrationResponse {
857 pub client_id: String,
859
860 #[serde(default)]
862 pub client_secret: Option<String>,
863
864 #[serde(default)]
866 #[serde_as(as = "Option<TimestampSeconds<i64>>")]
867 pub client_id_issued_at: Option<DateTime<Utc>>,
868
869 #[serde(default)]
873 #[serde_as(as = "Option<TimestampSeconds<i64>>")]
874 pub client_secret_expires_at: Option<DateTime<Utc>>,
875}
876
877#[cfg(test)]
878mod tests {
879 use assert_matches::assert_matches;
880 use mas_iana::{
881 jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
882 oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
883 };
884 use mas_jose::jwk::PublicJsonWebKeySet;
885 use url::Url;
886
887 use super::{ClientMetadata, ClientMetadataVerificationError};
888 use crate::{requests::GrantType, response_type::ResponseType};
889
890 fn valid_client_metadata() -> ClientMetadata {
891 ClientMetadata {
892 redirect_uris: Some(vec![Url::parse("http://localhost/oidc").unwrap()]),
893 ..Default::default()
894 }
895 }
896
897 fn jwks() -> PublicJsonWebKeySet {
898 serde_json::from_value(serde_json::json!({
899 "keys": [
900 {
901 "alg": "RS256",
902 "kty": "RSA",
903 "n": "tCwhHOxX_ylh5kVwfVqW7QIBTIsPjkjCjVCppDrynuF_3msEdtEaG64eJUz84ODFNMCC0BQ57G7wrKQVWkdSDxWUEqGk2BixBiHJRWZdofz1WOBTdPVicvHW5Zl_aIt7uXWMdOp_SODw-O2y2f05EqbFWFnR2-1y9K8KbiOp82CD72ny1Jbb_3PxTs2Z0F4ECAtTzpDteaJtjeeueRjr7040JAjQ-5fpL5D1g8x14LJyVIo-FL_y94NPFbMp7UCi69CIfVHXFO8WYFz949og-47mWRrID5lS4zpx-QLuvNhUb_lSqmylUdQB3HpRdOcYdj3xwy4MHJuu7tTaf0AmCQ",
904 "use": "sig",
905 "kid": "d98f49bc6ca4581eae8dfadd494fce10ea23aab0",
906 "e": "AQAB"
907 }
908 ]
909 })).unwrap()
910 }
911
912 #[test]
913 fn validate_required_metadata() {
914 let metadata = valid_client_metadata();
915 metadata.validate().unwrap();
916 }
917
918 #[test]
919 fn validate_redirect_uris() {
920 let mut metadata = ClientMetadata::default();
921
922 assert_matches!(
924 metadata.clone().validate(),
925 Err(ClientMetadataVerificationError::MissingRedirectUris)
926 );
927
928 let wrong_uri = Url::parse("http://localhost/#fragment").unwrap();
930 metadata.redirect_uris = Some(vec![
931 Url::parse("http://localhost/").unwrap(),
932 wrong_uri.clone(),
933 ]);
934 let uri = assert_matches!(
935 metadata.clone().validate(),
936 Err(ClientMetadataVerificationError::RedirectUriWithFragment(uri)) => uri
937 );
938 assert_eq!(uri, wrong_uri);
939
940 metadata.redirect_uris = Some(vec![
942 Url::parse("http://localhost/").unwrap(),
943 Url::parse("http://localhost/oidc").unwrap(),
944 Url::parse("http://localhost/?oidc").unwrap(),
945 Url::parse("http://localhost/my-client?oidc").unwrap(),
946 ]);
947 metadata.validate().unwrap();
948 }
949
950 #[test]
951 #[allow(clippy::too_many_lines)]
952 fn validate_response_types() {
953 let mut metadata = valid_client_metadata();
954
955 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
958 metadata.clone().validate().unwrap();
959
960 let response_type: ResponseType =
962 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
963 metadata.response_types = Some(vec![response_type.clone()]);
964 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
965 assert_eq!(res, response_type);
966
967 let response_type: ResponseType =
969 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
970 metadata.response_types = Some(vec![response_type.clone()]);
971 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
972 assert_eq!(res, response_type);
973
974 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
976 metadata.response_types = Some(vec![response_type.clone()]);
977 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
978 assert_eq!(res, response_type);
979
980 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::IdToken.into();
982 metadata.response_types = Some(vec![response_type.clone()]);
983 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
984 assert_eq!(res, response_type);
985
986 let response_type: ResponseType =
988 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
989 metadata.response_types = Some(vec![response_type.clone()]);
990 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
991 assert_eq!(res, response_type);
992
993 let response_type: ResponseType =
995 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
996 metadata.response_types = Some(vec![response_type.clone()]);
997 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
998 assert_eq!(res, response_type);
999
1000 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1002 metadata.clone().validate().unwrap();
1003
1004 metadata.grant_types = Some(vec![GrantType::Implicit]);
1006 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Code.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::CodeIdToken.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 =
1021 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1022 metadata.response_types = Some(vec![response_type.clone()]);
1023 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1024 assert_eq!(res, response_type);
1025
1026 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1028 metadata.response_types = Some(vec![response_type.clone()]);
1029 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1030 assert_eq!(res, response_type);
1031
1032 metadata.response_types =
1034 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1035 metadata.clone().validate().unwrap();
1036
1037 metadata.response_types = Some(vec![
1039 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1040 ]);
1041 metadata.clone().validate().unwrap();
1042
1043 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Token.into()]);
1045 metadata.clone().validate().unwrap();
1046
1047 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1049 metadata.clone().validate().unwrap();
1050
1051 metadata.grant_types = Some(vec![GrantType::AuthorizationCode, GrantType::Implicit]);
1053 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
1055 metadata.clone().validate().unwrap();
1056
1057 metadata.response_types = Some(vec![
1059 OAuthAuthorizationEndpointResponseType::CodeIdToken.into(),
1060 ]);
1061 metadata.clone().validate().unwrap();
1062
1063 metadata.response_types = Some(vec![
1065 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into(),
1066 ]);
1067 metadata.clone().validate().unwrap();
1068
1069 metadata.response_types = Some(vec![
1071 OAuthAuthorizationEndpointResponseType::CodeToken.into(),
1072 ]);
1073 metadata.clone().validate().unwrap();
1074
1075 metadata.response_types =
1077 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1078 metadata.clone().validate().unwrap();
1079
1080 metadata.response_types = Some(vec![
1082 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1083 ]);
1084 metadata.clone().validate().unwrap();
1085
1086 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::Token.into()]);
1088 metadata.clone().validate().unwrap();
1089
1090 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1092 metadata.clone().validate().unwrap();
1093
1094 metadata.grant_types = Some(vec![GrantType::RefreshToken, GrantType::ClientCredentials]);
1096 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Code.into();
1098 metadata.response_types = Some(vec![response_type.clone()]);
1099 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1100 assert_eq!(res, response_type);
1101
1102 let response_type: ResponseType =
1104 OAuthAuthorizationEndpointResponseType::CodeIdToken.into();
1105 metadata.response_types = Some(vec![response_type.clone()]);
1106 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1107 assert_eq!(res, response_type);
1108
1109 let response_type: ResponseType =
1111 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into();
1112 metadata.response_types = Some(vec![response_type.clone()]);
1113 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1114 assert_eq!(res, response_type);
1115
1116 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::CodeToken.into();
1118 metadata.response_types = Some(vec![response_type.clone()]);
1119 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1120 assert_eq!(res, response_type);
1121
1122 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::IdToken.into();
1124 metadata.response_types = Some(vec![response_type.clone()]);
1125 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1126 assert_eq!(res, response_type);
1127
1128 let response_type: ResponseType =
1130 OAuthAuthorizationEndpointResponseType::IdTokenToken.into();
1131 metadata.response_types = Some(vec![response_type.clone()]);
1132 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1133 assert_eq!(res, response_type);
1134
1135 let response_type: ResponseType = OAuthAuthorizationEndpointResponseType::Token.into();
1137 metadata.response_types = Some(vec![response_type.clone()]);
1138 let res = assert_matches!(metadata.clone().validate(), Err(ClientMetadataVerificationError::IncoherentResponseType(res)) => res);
1139 assert_eq!(res, response_type);
1140
1141 metadata.response_types = Some(vec![OAuthAuthorizationEndpointResponseType::None.into()]);
1143 metadata.validate().unwrap();
1144 }
1145
1146 #[test]
1147 fn validate_jwks() {
1148 let mut metadata = valid_client_metadata();
1149
1150 metadata.jwks_uri = Some(Url::parse("http://localhost/jwks").unwrap());
1152 metadata.clone().validate().unwrap();
1153
1154 metadata.jwks = Some(jwks());
1156 assert_matches!(
1157 metadata.clone().validate(),
1158 Err(ClientMetadataVerificationError::JwksUriAndJwksMutuallyExclusive)
1159 );
1160
1161 metadata.jwks_uri = None;
1163 metadata.validate().unwrap();
1164 }
1165
1166 #[test]
1167 fn validate_sector_identifier_uri() {
1168 let mut metadata = valid_client_metadata();
1169
1170 let identifier_uri = Url::parse("http://localhost/").unwrap();
1172 metadata.sector_identifier_uri = Some(identifier_uri.clone());
1173 let (field, url) = assert_matches!(
1174 metadata.clone().validate(),
1175 Err(ClientMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1176 );
1177 assert_eq!(field, "sector_identifier_uri");
1178 assert_eq!(url, identifier_uri);
1179
1180 metadata.sector_identifier_uri = Some(Url::parse("https://localhost/").unwrap());
1182 metadata.validate().unwrap();
1183 }
1184
1185 #[test]
1186 fn validate_token_endpoint_auth_method() {
1187 let mut metadata = valid_client_metadata();
1188
1189 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::None);
1191 let field = assert_matches!(
1192 metadata.clone().validate(),
1193 Err(ClientMetadataVerificationError::UnauthorizedSigningAlgNone(field)) => field
1194 );
1195 assert_eq!(field, "token_endpoint");
1196
1197 metadata.token_endpoint_auth_method = Some(OAuthClientAuthenticationMethod::PrivateKeyJwt);
1199 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::Rs256);
1200
1201 assert_matches!(
1203 metadata.clone().validate(),
1204 Err(ClientMetadataVerificationError::MissingJwksForTokenMethod)
1205 );
1206
1207 metadata.jwks_uri = Some(Url::parse("https://localhost/jwks").unwrap());
1209 metadata.clone().validate().unwrap();
1210
1211 metadata.jwks_uri = None;
1213 metadata.jwks = Some(jwks());
1214 metadata.clone().validate().unwrap();
1215
1216 metadata.token_endpoint_auth_signing_alg = None;
1218 let field = assert_matches!(
1219 metadata.clone().validate(),
1220 Err(ClientMetadataVerificationError::MissingAuthSigningAlg(field)) => field
1221 );
1222 assert_eq!(field, "token_endpoint");
1223
1224 metadata.token_endpoint_auth_method =
1226 Some(OAuthClientAuthenticationMethod::ClientSecretJwt);
1227 metadata.jwks = None;
1228
1229 let field = assert_matches!(
1231 metadata.clone().validate(),
1232 Err(ClientMetadataVerificationError::MissingAuthSigningAlg(field)) => field
1233 );
1234 assert_eq!(field, "token_endpoint");
1235
1236 metadata.token_endpoint_auth_signing_alg = Some(JsonWebSignatureAlg::Rs256);
1238 metadata.validate().unwrap();
1239 }
1240
1241 #[test]
1242 fn validate_id_token_signed_response_alg() {
1243 let mut metadata = valid_client_metadata();
1244 metadata.id_token_signed_response_alg = Some(JsonWebSignatureAlg::None);
1245 metadata.grant_types = Some(vec![GrantType::AuthorizationCode, GrantType::Implicit]);
1246
1247 metadata.response_types = Some(vec![
1249 OAuthAuthorizationEndpointResponseType::CodeIdToken.into(),
1250 ]);
1251 assert_matches!(
1252 metadata.clone().validate(),
1253 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1254 );
1255
1256 metadata.response_types = Some(vec![
1258 OAuthAuthorizationEndpointResponseType::CodeIdTokenToken.into(),
1259 ]);
1260 assert_matches!(
1261 metadata.clone().validate(),
1262 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1263 );
1264
1265 metadata.response_types =
1267 Some(vec![OAuthAuthorizationEndpointResponseType::IdToken.into()]);
1268 assert_matches!(
1269 metadata.clone().validate(),
1270 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1271 );
1272
1273 metadata.response_types = Some(vec![
1275 OAuthAuthorizationEndpointResponseType::IdTokenToken.into(),
1276 ]);
1277 assert_matches!(
1278 metadata.clone().validate(),
1279 Err(ClientMetadataVerificationError::IdTokenSigningAlgNone)
1280 );
1281
1282 metadata.response_types = Some(vec![
1284 OAuthAuthorizationEndpointResponseType::Code.into(),
1285 OAuthAuthorizationEndpointResponseType::CodeToken.into(),
1286 OAuthAuthorizationEndpointResponseType::Token.into(),
1287 OAuthAuthorizationEndpointResponseType::None.into(),
1288 ]);
1289 metadata.validate().unwrap();
1290 }
1291
1292 #[test]
1293 fn validate_id_token_encrypted_response() {
1294 let mut metadata = valid_client_metadata();
1295 metadata.id_token_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1296
1297 let field = assert_matches!(
1299 metadata.clone().validate(),
1300 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1301 );
1302 assert_eq!(field, "id_token");
1303
1304 metadata.id_token_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1306 metadata.validate().unwrap();
1307 }
1308
1309 #[test]
1310 fn validate_userinfo_encrypted_response() {
1311 let mut metadata = valid_client_metadata();
1312 metadata.userinfo_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1313
1314 let field = assert_matches!(
1316 metadata.clone().validate(),
1317 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1318 );
1319 assert_eq!(field, "userinfo");
1320
1321 metadata.userinfo_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1323 metadata.validate().unwrap();
1324 }
1325
1326 #[test]
1327 fn validate_request_object_encryption() {
1328 let mut metadata = valid_client_metadata();
1329 metadata.request_object_encryption_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1330
1331 let field = assert_matches!(
1333 metadata.clone().validate(),
1334 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1335 );
1336 assert_eq!(field, "request_object");
1337
1338 metadata.request_object_encryption_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1340 metadata.validate().unwrap();
1341 }
1342
1343 #[test]
1344 fn validate_initiate_login_uri() {
1345 let mut metadata = valid_client_metadata();
1346
1347 let initiate_uri = Url::parse("http://localhost/").unwrap();
1349 metadata.initiate_login_uri = Some(initiate_uri.clone());
1350 let (field, url) = assert_matches!(
1351 metadata.clone().validate(),
1352 Err(ClientMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1353 );
1354 assert_eq!(field, "initiate_login_uri");
1355 assert_eq!(url, initiate_uri);
1356
1357 metadata.initiate_login_uri = Some(Url::parse("https://localhost/").unwrap());
1359 metadata.validate().unwrap();
1360 }
1361
1362 #[test]
1363 fn validate_introspection_encrypted_response() {
1364 let mut metadata = valid_client_metadata();
1365 metadata.introspection_encrypted_response_enc = Some(JsonWebEncryptionEnc::A128CbcHs256);
1366
1367 let field = assert_matches!(
1369 metadata.clone().validate(),
1370 Err(ClientMetadataVerificationError::MissingEncryptionAlg(field)) => field
1371 );
1372 assert_eq!(field, "introspection");
1373
1374 metadata.introspection_encrypted_response_alg = Some(JsonWebEncryptionAlg::RsaOaep);
1376 metadata.validate().unwrap();
1377 }
1378}