1use std::{fmt, ops::Deref};
12
13use language_tags::LanguageTag;
14use mas_iana::{
15 jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
16 oauth::{OAuthAccessTokenType, OAuthClientAuthenticationMethod, PkceCodeChallengeMethod},
17};
18use serde::{Deserialize, Serialize};
19use serde_with::{
20 DeserializeFromStr, SerializeDisplay, StringWithSeparator, formats::SpaceSeparator, serde_as,
21 skip_serializing_none,
22};
23use thiserror::Error;
24use url::Url;
25
26use crate::{
27 requests::{Display, GrantType, Prompt, ResponseMode},
28 response_type::ResponseType,
29};
30
31#[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug)]
34pub enum AuthenticationMethodOrAccessTokenType {
35 AuthenticationMethod(OAuthClientAuthenticationMethod),
37
38 AccessTokenType(OAuthAccessTokenType),
40
41 Unknown(String),
47}
48
49impl core::fmt::Display for AuthenticationMethodOrAccessTokenType {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match self {
52 Self::AuthenticationMethod(m) => m.fmt(f),
53 Self::AccessTokenType(t) => t.fmt(f),
54 Self::Unknown(s) => s.fmt(f),
55 }
56 }
57}
58
59impl core::str::FromStr for AuthenticationMethodOrAccessTokenType {
60 type Err = core::convert::Infallible;
61
62 fn from_str(s: &str) -> Result<Self, Self::Err> {
63 match OAuthClientAuthenticationMethod::from_str(s) {
64 Ok(OAuthClientAuthenticationMethod::Unknown(_)) | Err(_) => {}
65 Ok(m) => return Ok(m.into()),
66 }
67
68 match OAuthAccessTokenType::from_str(s) {
69 Ok(OAuthAccessTokenType::Unknown(_)) | Err(_) => {}
70 Ok(m) => return Ok(m.into()),
71 }
72
73 Ok(Self::Unknown(s.to_owned()))
74 }
75}
76
77impl AuthenticationMethodOrAccessTokenType {
78 #[must_use]
81 pub fn authentication_method(&self) -> Option<&OAuthClientAuthenticationMethod> {
82 match self {
83 Self::AuthenticationMethod(m) => Some(m),
84 _ => None,
85 }
86 }
87
88 #[must_use]
91 pub fn access_token_type(&self) -> Option<&OAuthAccessTokenType> {
92 match self {
93 Self::AccessTokenType(t) => Some(t),
94 _ => None,
95 }
96 }
97}
98
99impl From<OAuthClientAuthenticationMethod> for AuthenticationMethodOrAccessTokenType {
100 fn from(t: OAuthClientAuthenticationMethod) -> Self {
101 Self::AuthenticationMethod(t)
102 }
103}
104
105impl From<OAuthAccessTokenType> for AuthenticationMethodOrAccessTokenType {
106 fn from(t: OAuthAccessTokenType) -> Self {
107 Self::AccessTokenType(t)
108 }
109}
110
111#[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug)]
113pub enum ApplicationType {
114 Web,
116
117 Native,
119
120 Unknown(String),
122}
123
124impl core::fmt::Display for ApplicationType {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 Self::Web => f.write_str("web"),
128 Self::Native => f.write_str("native"),
129 Self::Unknown(s) => f.write_str(s),
130 }
131 }
132}
133
134impl core::str::FromStr for ApplicationType {
135 type Err = core::convert::Infallible;
136
137 fn from_str(s: &str) -> Result<Self, Self::Err> {
138 match s {
139 "web" => Ok(Self::Web),
140 "native" => Ok(Self::Native),
141 s => Ok(Self::Unknown(s.to_owned())),
142 }
143 }
144}
145
146#[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug)]
152pub enum SubjectType {
153 Public,
155
156 Pairwise,
160
161 Unknown(String),
163}
164
165impl core::fmt::Display for SubjectType {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 match self {
168 Self::Public => f.write_str("public"),
169 Self::Pairwise => f.write_str("pairwise"),
170 Self::Unknown(s) => f.write_str(s),
171 }
172 }
173}
174
175impl core::str::FromStr for SubjectType {
176 type Err = core::convert::Infallible;
177
178 fn from_str(s: &str) -> Result<Self, Self::Err> {
179 match s {
180 "public" => Ok(Self::Public),
181 "pairwise" => Ok(Self::Pairwise),
182 s => Ok(Self::Unknown(s.to_owned())),
183 }
184 }
185}
186
187#[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug)]
189pub enum ClaimType {
190 Normal,
192
193 Aggregated,
196
197 Distributed,
200
201 Unknown(String),
203}
204
205impl core::fmt::Display for ClaimType {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 match self {
208 Self::Normal => f.write_str("normal"),
209 Self::Aggregated => f.write_str("aggregated"),
210 Self::Distributed => f.write_str("distributed"),
211 Self::Unknown(s) => f.write_str(s),
212 }
213 }
214}
215
216impl core::str::FromStr for ClaimType {
217 type Err = core::convert::Infallible;
218
219 fn from_str(s: &str) -> Result<Self, Self::Err> {
220 match s {
221 "normal" => Ok(Self::Normal),
222 "aggregated" => Ok(Self::Aggregated),
223 "distributed" => Ok(Self::Distributed),
224 s => Ok(Self::Unknown(s.to_owned())),
225 }
226 }
227}
228
229#[derive(
233 SerializeDisplay, DeserializeFromStr, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
234)]
235#[non_exhaustive]
236pub enum AccountManagementAction {
237 Profile,
241
242 SessionsList,
246
247 SessionView,
251
252 SessionEnd,
256
257 AccountDeactivate,
261
262 CrossSigningReset,
266
267 Unknown(String),
269}
270
271impl core::fmt::Display for AccountManagementAction {
272 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
273 match self {
274 Self::Profile => write!(f, "org.matrix.profile"),
275 Self::SessionsList => write!(f, "org.matrix.sessions_list"),
276 Self::SessionView => write!(f, "org.matrix.session_view"),
277 Self::SessionEnd => write!(f, "org.matrix.session_end"),
278 Self::AccountDeactivate => write!(f, "org.matrix.account_deactivate"),
279 Self::CrossSigningReset => write!(f, "org.matrix.cross_signing_reset"),
280 Self::Unknown(value) => write!(f, "{value}"),
281 }
282 }
283}
284
285impl core::str::FromStr for AccountManagementAction {
286 type Err = core::convert::Infallible;
287
288 fn from_str(s: &str) -> Result<Self, Self::Err> {
289 match s {
290 "org.matrix.profile" => Ok(Self::Profile),
291 "org.matrix.sessions_list" => Ok(Self::SessionsList),
292 "org.matrix.session_view" => Ok(Self::SessionView),
293 "org.matrix.session_end" => Ok(Self::SessionEnd),
294 "org.matrix.account_deactivate" => Ok(Self::AccountDeactivate),
295 "org.matrix.cross_signing_reset" => Ok(Self::CrossSigningReset),
296 value => Ok(Self::Unknown(value.to_owned())),
297 }
298 }
299}
300
301pub static DEFAULT_RESPONSE_MODES_SUPPORTED: &[ResponseMode] =
303 &[ResponseMode::Query, ResponseMode::Fragment];
304
305pub static DEFAULT_GRANT_TYPES_SUPPORTED: &[GrantType] =
307 &[GrantType::AuthorizationCode, GrantType::Implicit];
308
309pub static DEFAULT_AUTH_METHODS_SUPPORTED: &[OAuthClientAuthenticationMethod] =
312 &[OAuthClientAuthenticationMethod::ClientSecretBasic];
313
314pub static DEFAULT_CLAIM_TYPES_SUPPORTED: &[ClaimType] = &[ClaimType::Normal];
316
317#[skip_serializing_none]
323#[derive(Debug, Serialize, Deserialize, Clone, Default)]
324pub struct ProviderMetadata {
325 pub issuer: Option<String>,
331
332 pub authorization_endpoint: Option<Url>,
339
340 pub token_endpoint: Option<Url>,
347
348 pub jwks_uri: Option<Url>,
354
355 pub registration_endpoint: Option<Url>,
362
363 pub scopes_supported: Option<Vec<String>>,
369
370 pub response_types_supported: Option<Vec<ResponseType>>,
377
378 pub response_modes_supported: Option<Vec<ResponseMode>>,
385
386 pub grant_types_supported: Option<Vec<GrantType>>,
393
394 pub token_endpoint_auth_methods_supported: Option<Vec<OAuthClientAuthenticationMethod>>,
399
400 pub token_endpoint_auth_signing_alg_values_supported: Option<Vec<JsonWebSignatureAlg>>,
410
411 pub service_documentation: Option<Url>,
414
415 pub ui_locales_supported: Option<Vec<LanguageTag>>,
420
421 pub op_policy_uri: Option<Url>,
425
426 pub op_tos_uri: Option<Url>,
429
430 pub revocation_endpoint: Option<Url>,
437
438 pub revocation_endpoint_auth_methods_supported: Option<Vec<OAuthClientAuthenticationMethod>>,
443
444 pub revocation_endpoint_auth_signing_alg_values_supported: Option<Vec<JsonWebSignatureAlg>>,
454
455 pub introspection_endpoint: Option<Url>,
461
462 pub introspection_endpoint_auth_methods_supported:
465 Option<Vec<AuthenticationMethodOrAccessTokenType>>,
466
467 pub introspection_endpoint_auth_signing_alg_values_supported: Option<Vec<JsonWebSignatureAlg>>,
477
478 pub code_challenge_methods_supported: Option<Vec<PkceCodeChallengeMethod>>,
483
484 pub userinfo_endpoint: Option<Url>,
488
489 pub acr_values_supported: Option<Vec<String>>,
492
493 pub subject_types_supported: Option<Vec<SubjectType>>,
498
499 pub id_token_signing_alg_values_supported: Option<Vec<JsonWebSignatureAlg>>,
504
505 pub id_token_encryption_alg_values_supported: Option<Vec<JsonWebEncryptionAlg>>,
508
509 pub id_token_encryption_enc_values_supported: Option<Vec<JsonWebEncryptionEnc>>,
512
513 pub userinfo_signing_alg_values_supported: Option<Vec<JsonWebSignatureAlg>>,
516
517 pub userinfo_encryption_alg_values_supported: Option<Vec<JsonWebEncryptionAlg>>,
520
521 pub userinfo_encryption_enc_values_supported: Option<Vec<JsonWebEncryptionEnc>>,
524
525 pub request_object_signing_alg_values_supported: Option<Vec<JsonWebSignatureAlg>>,
528
529 pub request_object_encryption_alg_values_supported: Option<Vec<JsonWebEncryptionAlg>>,
532
533 pub request_object_encryption_enc_values_supported: Option<Vec<JsonWebEncryptionEnc>>,
536
537 pub display_values_supported: Option<Vec<Display>>,
540
541 pub claim_types_supported: Option<Vec<ClaimType>>,
546
547 pub claims_supported: Option<Vec<String>>,
550
551 pub claims_locales_supported: Option<Vec<LanguageTag>>,
554
555 pub claims_parameter_supported: Option<bool>,
560
561 pub request_parameter_supported: Option<bool>,
566
567 pub request_uri_parameter_supported: Option<bool>,
572
573 pub require_request_uri_registration: Option<bool>,
578
579 pub require_signed_request_object: Option<bool>,
586
587 pub pushed_authorization_request_endpoint: Option<Url>,
592
593 pub require_pushed_authorization_requests: Option<bool>,
598
599 pub prompt_values_supported: Option<Vec<Prompt>>,
606
607 pub device_authorization_endpoint: Option<Url>,
611
612 pub end_session_endpoint: Option<Url>,
616
617 pub account_management_uri: Option<Url>,
622
623 pub account_management_actions_supported: Option<Vec<AccountManagementAction>>,
627}
628
629impl ProviderMetadata {
630 pub fn validate(
644 self,
645 issuer: &str,
646 ) -> Result<VerifiedProviderMetadata, ProviderMetadataVerificationError> {
647 let metadata = self.insecure_verify_metadata()?;
648
649 if metadata.issuer() != issuer {
650 return Err(ProviderMetadataVerificationError::IssuerUrlsDontMatch {
651 expected: issuer.to_owned(),
652 actual: metadata.issuer().to_owned(),
653 });
654 }
655
656 validate_url(
657 "issuer",
658 &metadata
659 .issuer()
660 .parse()
661 .map_err(|_| ProviderMetadataVerificationError::IssuerNotUrl)?,
662 ExtraUrlRestrictions::NoQueryOrFragment,
663 )?;
664
665 validate_url(
666 "authorization_endpoint",
667 metadata.authorization_endpoint(),
668 ExtraUrlRestrictions::NoFragment,
669 )?;
670
671 validate_url(
672 "token_endpoint",
673 metadata.token_endpoint(),
674 ExtraUrlRestrictions::NoFragment,
675 )?;
676
677 validate_url("jwks_uri", metadata.jwks_uri(), ExtraUrlRestrictions::None)?;
678
679 if let Some(url) = &metadata.registration_endpoint {
680 validate_url("registration_endpoint", url, ExtraUrlRestrictions::None)?;
681 }
682
683 if let Some(scopes) = &metadata.scopes_supported {
684 if !scopes.iter().any(|s| s == "openid") {
685 return Err(ProviderMetadataVerificationError::ScopesMissingOpenid);
686 }
687 }
688
689 validate_signing_alg_values_supported(
690 "token_endpoint",
691 metadata
692 .token_endpoint_auth_signing_alg_values_supported
693 .iter()
694 .flatten(),
695 metadata
696 .token_endpoint_auth_methods_supported
697 .iter()
698 .flatten(),
699 )?;
700
701 if let Some(url) = &metadata.revocation_endpoint {
702 validate_url("revocation_endpoint", url, ExtraUrlRestrictions::NoFragment)?;
703 }
704
705 validate_signing_alg_values_supported(
706 "revocation_endpoint",
707 metadata
708 .revocation_endpoint_auth_signing_alg_values_supported
709 .iter()
710 .flatten(),
711 metadata
712 .revocation_endpoint_auth_methods_supported
713 .iter()
714 .flatten(),
715 )?;
716
717 if let Some(url) = &metadata.introspection_endpoint {
718 validate_url("introspection_endpoint", url, ExtraUrlRestrictions::None)?;
719 }
720
721 let introspection_methods = metadata
724 .introspection_endpoint_auth_methods_supported
725 .as_ref()
726 .map(|v| {
727 v.iter()
728 .filter_map(AuthenticationMethodOrAccessTokenType::authentication_method)
729 .collect::<Vec<_>>()
730 });
731 validate_signing_alg_values_supported(
732 "introspection_endpoint",
733 metadata
734 .introspection_endpoint_auth_signing_alg_values_supported
735 .iter()
736 .flatten(),
737 introspection_methods.into_iter().flatten(),
738 )?;
739
740 if let Some(url) = &metadata.userinfo_endpoint {
741 validate_url("userinfo_endpoint", url, ExtraUrlRestrictions::None)?;
742 }
743
744 if let Some(url) = &metadata.pushed_authorization_request_endpoint {
745 validate_url(
746 "pushed_authorization_request_endpoint",
747 url,
748 ExtraUrlRestrictions::None,
749 )?;
750 }
751
752 if let Some(url) = &metadata.end_session_endpoint {
753 validate_url("end_session_endpoint", url, ExtraUrlRestrictions::None)?;
754 }
755
756 Ok(metadata)
757 }
758
759 pub fn insecure_verify_metadata(
781 self,
782 ) -> Result<VerifiedProviderMetadata, ProviderMetadataVerificationError> {
783 self.issuer
784 .as_ref()
785 .ok_or(ProviderMetadataVerificationError::MissingIssuer)?;
786
787 self.authorization_endpoint
788 .as_ref()
789 .ok_or(ProviderMetadataVerificationError::MissingAuthorizationEndpoint)?;
790
791 self.token_endpoint
792 .as_ref()
793 .ok_or(ProviderMetadataVerificationError::MissingTokenEndpoint)?;
794
795 self.jwks_uri
796 .as_ref()
797 .ok_or(ProviderMetadataVerificationError::MissingJwksUri)?;
798
799 self.response_types_supported
800 .as_ref()
801 .ok_or(ProviderMetadataVerificationError::MissingResponseTypesSupported)?;
802
803 self.subject_types_supported
804 .as_ref()
805 .ok_or(ProviderMetadataVerificationError::MissingSubjectTypesSupported)?;
806
807 self.id_token_signing_alg_values_supported
808 .as_ref()
809 .ok_or(ProviderMetadataVerificationError::MissingIdTokenSigningAlgValuesSupported)?;
810
811 Ok(VerifiedProviderMetadata { inner: self })
812 }
813
814 #[must_use]
819 pub fn response_modes_supported(&self) -> &[ResponseMode] {
820 self.response_modes_supported
821 .as_deref()
822 .unwrap_or(DEFAULT_RESPONSE_MODES_SUPPORTED)
823 }
824
825 #[must_use]
830 pub fn grant_types_supported(&self) -> &[GrantType] {
831 self.grant_types_supported
832 .as_deref()
833 .unwrap_or(DEFAULT_GRANT_TYPES_SUPPORTED)
834 }
835
836 #[must_use]
841 pub fn token_endpoint_auth_methods_supported(&self) -> &[OAuthClientAuthenticationMethod] {
842 self.token_endpoint_auth_methods_supported
843 .as_deref()
844 .unwrap_or(DEFAULT_AUTH_METHODS_SUPPORTED)
845 }
846
847 #[must_use]
852 pub fn revocation_endpoint_auth_methods_supported(&self) -> &[OAuthClientAuthenticationMethod] {
853 self.revocation_endpoint_auth_methods_supported
854 .as_deref()
855 .unwrap_or(DEFAULT_AUTH_METHODS_SUPPORTED)
856 }
857
858 #[must_use]
863 pub fn claim_types_supported(&self) -> &[ClaimType] {
864 self.claim_types_supported
865 .as_deref()
866 .unwrap_or(DEFAULT_CLAIM_TYPES_SUPPORTED)
867 }
868
869 #[must_use]
874 pub fn claims_parameter_supported(&self) -> bool {
875 self.claims_parameter_supported.unwrap_or(false)
876 }
877
878 #[must_use]
883 pub fn request_parameter_supported(&self) -> bool {
884 self.request_parameter_supported.unwrap_or(false)
885 }
886
887 #[must_use]
892 pub fn request_uri_parameter_supported(&self) -> bool {
893 self.request_uri_parameter_supported.unwrap_or(true)
894 }
895
896 #[must_use]
901 pub fn require_request_uri_registration(&self) -> bool {
902 self.require_request_uri_registration.unwrap_or(false)
903 }
904
905 #[must_use]
910 pub fn require_signed_request_object(&self) -> bool {
911 self.require_signed_request_object.unwrap_or(false)
912 }
913
914 #[must_use]
919 pub fn require_pushed_authorization_requests(&self) -> bool {
920 self.require_pushed_authorization_requests.unwrap_or(false)
921 }
922}
923
924#[derive(Debug, Clone)]
933pub struct VerifiedProviderMetadata {
934 inner: ProviderMetadata,
935}
936
937impl VerifiedProviderMetadata {
938 #[must_use]
940 pub fn issuer(&self) -> &str {
941 match &self.issuer {
942 Some(u) => u,
943 None => unreachable!(),
944 }
945 }
946
947 #[must_use]
949 pub fn authorization_endpoint(&self) -> &Url {
950 match &self.authorization_endpoint {
951 Some(u) => u,
952 None => unreachable!(),
953 }
954 }
955
956 #[must_use]
958 pub fn userinfo_endpoint(&self) -> &Url {
959 match &self.userinfo_endpoint {
960 Some(u) => u,
961 None => unreachable!(),
962 }
963 }
964
965 #[must_use]
967 pub fn token_endpoint(&self) -> &Url {
968 match &self.token_endpoint {
969 Some(u) => u,
970 None => unreachable!(),
971 }
972 }
973
974 #[must_use]
976 pub fn jwks_uri(&self) -> &Url {
977 match &self.jwks_uri {
978 Some(u) => u,
979 None => unreachable!(),
980 }
981 }
982
983 #[must_use]
986 pub fn response_types_supported(&self) -> &[ResponseType] {
987 match &self.response_types_supported {
988 Some(u) => u,
989 None => unreachable!(),
990 }
991 }
992
993 #[must_use]
996 pub fn subject_types_supported(&self) -> &[SubjectType] {
997 match &self.subject_types_supported {
998 Some(u) => u,
999 None => unreachable!(),
1000 }
1001 }
1002
1003 #[must_use]
1006 pub fn id_token_signing_alg_values_supported(&self) -> &[JsonWebSignatureAlg] {
1007 match &self.id_token_signing_alg_values_supported {
1008 Some(u) => u,
1009 None => unreachable!(),
1010 }
1011 }
1012}
1013
1014impl Deref for VerifiedProviderMetadata {
1015 type Target = ProviderMetadata;
1016
1017 fn deref(&self) -> &Self::Target {
1018 &self.inner
1019 }
1020}
1021
1022#[derive(Debug, Error)]
1024pub enum ProviderMetadataVerificationError {
1025 #[error("issuer is missing")]
1027 MissingIssuer,
1028
1029 #[error("issuer is not a valid URL")]
1031 IssuerNotUrl,
1032
1033 #[error("authorization endpoint is missing")]
1035 MissingAuthorizationEndpoint,
1036
1037 #[error("token endpoint is missing")]
1039 MissingTokenEndpoint,
1040
1041 #[error("JWK Set URI is missing")]
1043 MissingJwksUri,
1044
1045 #[error("supported response types are missing")]
1047 MissingResponseTypesSupported,
1048
1049 #[error("supported subject types are missing")]
1051 MissingSubjectTypesSupported,
1052
1053 #[error("supported ID token signing algorithm values are missing")]
1055 MissingIdTokenSigningAlgValuesSupported,
1056
1057 #[error("{0}'s URL doesn't use a https scheme: {1}")]
1059 UrlNonHttpsScheme(&'static str, Url),
1060
1061 #[error("{0}'s URL contains a query: {1}")]
1063 UrlWithQuery(&'static str, Url),
1064
1065 #[error("{0}'s URL contains a fragment: {1}")]
1067 UrlWithFragment(&'static str, Url),
1068
1069 #[error("issuer URLs don't match: expected {expected:?}, got {actual:?}")]
1071 IssuerUrlsDontMatch {
1072 expected: String,
1074 actual: String,
1076 },
1077
1078 #[error("missing openid scope")]
1080 ScopesMissingOpenid,
1081
1082 #[error("missing `code` response type")]
1084 ResponseTypesMissingCode,
1085
1086 #[error("missing `id_token` response type")]
1088 ResponseTypesMissingIdToken,
1089
1090 #[error("missing `id_token token` response type")]
1092 ResponseTypesMissingIdTokenToken,
1093
1094 #[error("missing `authorization_code` grant type")]
1096 GrantTypesMissingAuthorizationCode,
1097
1098 #[error("missing `implicit` grant type")]
1100 GrantTypesMissingImplicit,
1101
1102 #[error("{0} missing auth signing algorithm values")]
1106 MissingAuthSigningAlgValues(&'static str),
1107
1108 #[error("{0} signing algorithm values contain `none`")]
1111 SigningAlgValuesWithNone(&'static str),
1112}
1113
1114#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1116enum ExtraUrlRestrictions {
1117 None,
1119
1120 NoFragment,
1122
1123 NoQueryOrFragment,
1125}
1126
1127impl ExtraUrlRestrictions {
1128 fn can_have_fragment(self) -> bool {
1129 self == Self::None
1130 }
1131
1132 fn can_have_query(self) -> bool {
1133 self != Self::NoQueryOrFragment
1134 }
1135}
1136
1137fn validate_url(
1141 field: &'static str,
1142 url: &Url,
1143 restrictions: ExtraUrlRestrictions,
1144) -> Result<(), ProviderMetadataVerificationError> {
1145 if url.scheme() != "https" {
1146 return Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(
1147 field,
1148 url.clone(),
1149 ));
1150 }
1151
1152 if !restrictions.can_have_query() && url.query().is_some() {
1153 return Err(ProviderMetadataVerificationError::UrlWithQuery(
1154 field,
1155 url.clone(),
1156 ));
1157 }
1158
1159 if !restrictions.can_have_fragment() && url.fragment().is_some() {
1160 return Err(ProviderMetadataVerificationError::UrlWithFragment(
1161 field,
1162 url.clone(),
1163 ));
1164 }
1165
1166 Ok(())
1167}
1168
1169fn validate_signing_alg_values_supported<'a>(
1177 endpoint: &'static str,
1178 values: impl Iterator<Item = &'a JsonWebSignatureAlg>,
1179 mut methods: impl Iterator<Item = &'a OAuthClientAuthenticationMethod>,
1180) -> Result<(), ProviderMetadataVerificationError> {
1181 let mut no_values = true;
1182
1183 for value in values {
1184 if *value == JsonWebSignatureAlg::None {
1185 return Err(ProviderMetadataVerificationError::SigningAlgValuesWithNone(
1186 endpoint,
1187 ));
1188 }
1189
1190 no_values = false;
1191 }
1192
1193 if no_values
1194 && methods.any(|method| {
1195 matches!(
1196 method,
1197 OAuthClientAuthenticationMethod::ClientSecretJwt
1198 | OAuthClientAuthenticationMethod::PrivateKeyJwt
1199 )
1200 })
1201 {
1202 return Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint));
1203 }
1204
1205 Ok(())
1206}
1207
1208#[skip_serializing_none]
1212#[serde_as]
1213#[derive(Default, Serialize, Deserialize, Clone)]
1214pub struct RpInitiatedLogoutRequest {
1215 pub id_token_hint: Option<String>,
1220
1221 pub logout_hint: Option<String>,
1228
1229 pub client_id: Option<String>,
1238
1239 pub post_logout_redirect_uri: Option<Url>,
1245
1246 pub state: Option<String>,
1250
1251 #[serde_as(as = "Option<StringWithSeparator::<SpaceSeparator, LanguageTag>>")]
1254 #[serde(default)]
1255 pub ui_locales: Option<Vec<LanguageTag>>,
1256}
1257
1258impl fmt::Debug for RpInitiatedLogoutRequest {
1259 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1260 f.debug_struct("RpInitiatedLogoutRequest")
1261 .field("logout_hint", &self.logout_hint)
1262 .field("post_logout_redirect_uri", &self.post_logout_redirect_uri)
1263 .field("ui_locales", &self.ui_locales)
1264 .finish_non_exhaustive()
1265 }
1266}
1267
1268#[cfg(test)]
1269mod tests {
1270 use assert_matches::assert_matches;
1271 use mas_iana::{
1272 jose::JsonWebSignatureAlg,
1273 oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
1274 };
1275 use url::Url;
1276
1277 use super::*;
1278
1279 fn valid_provider_metadata() -> (ProviderMetadata, String) {
1280 let issuer = "https://localhost".to_owned();
1281 let metadata = ProviderMetadata {
1282 issuer: Some(issuer.clone()),
1283 authorization_endpoint: Some(Url::parse("https://localhost/auth").unwrap()),
1284 token_endpoint: Some(Url::parse("https://localhost/token").unwrap()),
1285 jwks_uri: Some(Url::parse("https://localhost/jwks").unwrap()),
1286 response_types_supported: Some(vec![
1287 OAuthAuthorizationEndpointResponseType::Code.into(),
1288 ]),
1289 subject_types_supported: Some(vec![SubjectType::Public]),
1290 id_token_signing_alg_values_supported: Some(vec![JsonWebSignatureAlg::Rs256]),
1291 ..Default::default()
1292 };
1293
1294 (metadata, issuer)
1295 }
1296
1297 #[test]
1298 fn validate_required_metadata() {
1299 let (metadata, issuer) = valid_provider_metadata();
1300 metadata.validate(&issuer).unwrap();
1301 }
1302
1303 #[test]
1304 fn validate_issuer() {
1305 let (mut metadata, issuer) = valid_provider_metadata();
1306
1307 metadata.issuer = None;
1309 assert_matches!(
1310 metadata.clone().validate(&issuer),
1311 Err(ProviderMetadataVerificationError::MissingIssuer)
1312 );
1313
1314 metadata.issuer = Some("not-an-url".to_owned());
1316 assert_matches!(
1317 metadata.clone().validate("not-an-url"),
1318 Err(ProviderMetadataVerificationError::IssuerNotUrl)
1319 );
1320
1321 metadata.issuer = Some("https://example.com/".to_owned());
1323 assert_matches!(
1324 metadata.clone().validate(&issuer),
1325 Err(ProviderMetadataVerificationError::IssuerUrlsDontMatch { .. })
1326 );
1327
1328 let issuer = "http://localhost/".to_owned();
1330 metadata.issuer = Some(issuer.clone());
1331 let (field, url) = assert_matches!(
1332 metadata.clone().validate(&issuer),
1333 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1334 );
1335 assert_eq!(field, "issuer");
1336 assert_eq!(url.as_str(), issuer);
1337
1338 let issuer = "https://localhost/?query".to_owned();
1340 metadata.issuer = Some(issuer.clone());
1341 let (field, url) = assert_matches!(
1342 metadata.clone().validate(&issuer),
1343 Err(ProviderMetadataVerificationError::UrlWithQuery(field, url)) => (field, url)
1344 );
1345 assert_eq!(field, "issuer");
1346 assert_eq!(url.as_str(), issuer);
1347
1348 let issuer = "https://localhost/#fragment".to_owned();
1350 metadata.issuer = Some(issuer.clone());
1351 let (field, url) = assert_matches!(
1352 metadata.clone().validate(&issuer),
1353 Err(ProviderMetadataVerificationError::UrlWithFragment(field, url)) => (field, url)
1354 );
1355 assert_eq!(field, "issuer");
1356 assert_eq!(url.as_str(), issuer);
1357
1358 let issuer = "https://localhost/issuer1".to_owned();
1360 metadata.issuer = Some(issuer.clone());
1361 metadata.validate(&issuer).unwrap();
1362 }
1363
1364 #[test]
1365 fn validate_authorization_endpoint() {
1366 let (mut metadata, issuer) = valid_provider_metadata();
1367
1368 metadata.authorization_endpoint = None;
1370 assert_matches!(
1371 metadata.clone().validate(&issuer),
1372 Err(ProviderMetadataVerificationError::MissingAuthorizationEndpoint)
1373 );
1374
1375 let endpoint = Url::parse("http://localhost/auth").unwrap();
1377 metadata.authorization_endpoint = Some(endpoint.clone());
1378 let (field, url) = assert_matches!(
1379 metadata.clone().validate(&issuer),
1380 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1381 );
1382 assert_eq!(field, "authorization_endpoint");
1383 assert_eq!(url, endpoint);
1384
1385 let endpoint = Url::parse("https://localhost/auth#fragment").unwrap();
1387 metadata.authorization_endpoint = Some(endpoint.clone());
1388 let (field, url) = assert_matches!(
1389 metadata.clone().validate(&issuer),
1390 Err(ProviderMetadataVerificationError::UrlWithFragment(field, url)) => (field, url)
1391 );
1392 assert_eq!(field, "authorization_endpoint");
1393 assert_eq!(url, endpoint);
1394
1395 metadata.authorization_endpoint = Some(Url::parse("https://localhost/auth?query").unwrap());
1397 metadata.validate(&issuer).unwrap();
1398 }
1399
1400 #[test]
1401 fn validate_token_endpoint() {
1402 let (mut metadata, issuer) = valid_provider_metadata();
1403
1404 metadata.token_endpoint = None;
1406 assert_matches!(
1407 metadata.clone().validate(&issuer),
1408 Err(ProviderMetadataVerificationError::MissingTokenEndpoint)
1409 );
1410
1411 let endpoint = Url::parse("http://localhost/token").unwrap();
1413 metadata.token_endpoint = Some(endpoint.clone());
1414 let (field, url) = assert_matches!(
1415 metadata.clone().validate(&issuer),
1416 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1417 );
1418 assert_eq!(field, "token_endpoint");
1419 assert_eq!(url, endpoint);
1420
1421 let endpoint = Url::parse("https://localhost/token#fragment").unwrap();
1423 metadata.token_endpoint = Some(endpoint.clone());
1424 let (field, url) = assert_matches!(
1425 metadata.clone().validate(&issuer),
1426 Err(ProviderMetadataVerificationError::UrlWithFragment(field, url)) => (field, url)
1427 );
1428 assert_eq!(field, "token_endpoint");
1429 assert_eq!(url, endpoint);
1430
1431 metadata.token_endpoint = Some(Url::parse("https://localhost/token?query").unwrap());
1433 metadata.validate(&issuer).unwrap();
1434 }
1435
1436 #[test]
1437 fn validate_jwks_uri() {
1438 let (mut metadata, issuer) = valid_provider_metadata();
1439
1440 metadata.jwks_uri = None;
1442 assert_matches!(
1443 metadata.clone().validate(&issuer),
1444 Err(ProviderMetadataVerificationError::MissingJwksUri)
1445 );
1446
1447 let endpoint = Url::parse("http://localhost/jwks").unwrap();
1449 metadata.jwks_uri = Some(endpoint.clone());
1450 let (field, url) = assert_matches!(
1451 metadata.clone().validate(&issuer),
1452 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1453 );
1454 assert_eq!(field, "jwks_uri");
1455 assert_eq!(url, endpoint);
1456
1457 metadata.jwks_uri = Some(Url::parse("https://localhost/token?query#fragment").unwrap());
1459 metadata.validate(&issuer).unwrap();
1460 }
1461
1462 #[test]
1463 fn validate_registration_endpoint() {
1464 let (mut metadata, issuer) = valid_provider_metadata();
1465
1466 let endpoint = Url::parse("http://localhost/registration").unwrap();
1468 metadata.registration_endpoint = Some(endpoint.clone());
1469 let (field, url) = assert_matches!(
1470 metadata.clone().validate(&issuer),
1471 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1472 );
1473 assert_eq!(field, "registration_endpoint");
1474 assert_eq!(url, endpoint);
1475
1476 metadata.registration_endpoint = None;
1478 metadata.clone().validate(&issuer).unwrap();
1479
1480 metadata.registration_endpoint =
1482 Some(Url::parse("https://localhost/registration?query#fragment").unwrap());
1483 metadata.validate(&issuer).unwrap();
1484 }
1485
1486 #[test]
1487 fn validate_scopes_supported() {
1488 let (mut metadata, issuer) = valid_provider_metadata();
1489
1490 metadata.scopes_supported = Some(vec!["custom".to_owned()]);
1492 assert_matches!(
1493 metadata.clone().validate(&issuer),
1494 Err(ProviderMetadataVerificationError::ScopesMissingOpenid)
1495 );
1496
1497 metadata.scopes_supported = None;
1499 metadata.clone().validate(&issuer).unwrap();
1500
1501 metadata.scopes_supported = Some(vec!["openid".to_owned(), "custom".to_owned()]);
1503 metadata.validate(&issuer).unwrap();
1504 }
1505
1506 #[test]
1507 fn validate_response_types_supported() {
1508 let (mut metadata, issuer) = valid_provider_metadata();
1509
1510 metadata.response_types_supported = None;
1512 assert_matches!(
1513 metadata.clone().validate(&issuer),
1514 Err(ProviderMetadataVerificationError::MissingResponseTypesSupported)
1515 );
1516
1517 metadata.response_types_supported =
1519 Some(vec![OAuthAuthorizationEndpointResponseType::Code.into()]);
1520 metadata.validate(&issuer).unwrap();
1521 }
1522
1523 #[test]
1524 fn validate_token_endpoint_signing_alg_values_supported() {
1525 let (mut metadata, issuer) = valid_provider_metadata();
1526
1527 metadata.token_endpoint_auth_signing_alg_values_supported = None;
1529 metadata.token_endpoint_auth_methods_supported = None;
1530 metadata.clone().validate(&issuer).unwrap();
1531
1532 metadata.token_endpoint_auth_signing_alg_values_supported =
1534 Some(vec![JsonWebSignatureAlg::None]);
1535 let endpoint = assert_matches!(
1536 metadata.clone().validate(&issuer),
1537 Err(ProviderMetadataVerificationError::SigningAlgValuesWithNone(endpoint)) => endpoint
1538 );
1539 assert_eq!(endpoint, "token_endpoint");
1540
1541 metadata.token_endpoint_auth_signing_alg_values_supported =
1543 Some(vec![JsonWebSignatureAlg::Rs256, JsonWebSignatureAlg::EdDsa]);
1544 metadata.clone().validate(&issuer).unwrap();
1545
1546 metadata.token_endpoint_auth_methods_supported =
1548 Some(vec![OAuthClientAuthenticationMethod::ClientSecretJwt]);
1549 metadata.token_endpoint_auth_signing_alg_values_supported = None;
1550 let endpoint = assert_matches!(
1551 metadata.clone().validate(&issuer),
1552 Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint)) => endpoint
1553 );
1554 assert_eq!(endpoint, "token_endpoint");
1555
1556 metadata.token_endpoint_auth_signing_alg_values_supported =
1558 Some(vec![JsonWebSignatureAlg::Rs256]);
1559 metadata.clone().validate(&issuer).unwrap();
1560
1561 metadata.token_endpoint_auth_methods_supported =
1563 Some(vec![OAuthClientAuthenticationMethod::PrivateKeyJwt]);
1564 metadata.token_endpoint_auth_signing_alg_values_supported = None;
1565 let endpoint = assert_matches!(
1566 metadata.clone().validate(&issuer),
1567 Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint)) => endpoint
1568 );
1569 assert_eq!(endpoint, "token_endpoint");
1570
1571 metadata.token_endpoint_auth_signing_alg_values_supported =
1573 Some(vec![JsonWebSignatureAlg::Rs256]);
1574 metadata.clone().validate(&issuer).unwrap();
1575
1576 metadata.token_endpoint_auth_methods_supported = Some(vec![
1578 OAuthClientAuthenticationMethod::ClientSecretBasic,
1579 OAuthClientAuthenticationMethod::ClientSecretPost,
1580 ]);
1581 metadata.token_endpoint_auth_signing_alg_values_supported = None;
1582 metadata.validate(&issuer).unwrap();
1583 }
1584
1585 #[test]
1586 fn validate_revocation_endpoint() {
1587 let (mut metadata, issuer) = valid_provider_metadata();
1588
1589 metadata.revocation_endpoint = None;
1591 metadata.clone().validate(&issuer).unwrap();
1592
1593 let endpoint = Url::parse("http://localhost/revocation").unwrap();
1595 metadata.revocation_endpoint = Some(endpoint.clone());
1596 let (field, url) = assert_matches!(
1597 metadata.clone().validate(&issuer),
1598 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1599 );
1600 assert_eq!(field, "revocation_endpoint");
1601 assert_eq!(url, endpoint);
1602
1603 let endpoint = Url::parse("https://localhost/revocation#fragment").unwrap();
1605 metadata.revocation_endpoint = Some(endpoint.clone());
1606 let (field, url) = assert_matches!(
1607 metadata.clone().validate(&issuer),
1608 Err(ProviderMetadataVerificationError::UrlWithFragment(field, url)) => (field, url)
1609 );
1610 assert_eq!(field, "revocation_endpoint");
1611 assert_eq!(url, endpoint);
1612
1613 metadata.revocation_endpoint =
1615 Some(Url::parse("https://localhost/revocation?query").unwrap());
1616 metadata.validate(&issuer).unwrap();
1617 }
1618
1619 #[test]
1620 fn validate_revocation_endpoint_signing_alg_values_supported() {
1621 let (mut metadata, issuer) = valid_provider_metadata();
1622
1623 metadata.revocation_endpoint_auth_signing_alg_values_supported = None;
1628 metadata.revocation_endpoint_auth_methods_supported = None;
1629 metadata.clone().validate(&issuer).unwrap();
1630
1631 metadata.revocation_endpoint_auth_signing_alg_values_supported =
1633 Some(vec![JsonWebSignatureAlg::None]);
1634 let endpoint = assert_matches!(
1635 metadata.validate(&issuer),
1636 Err(ProviderMetadataVerificationError::SigningAlgValuesWithNone(endpoint)) => endpoint
1637 );
1638 assert_eq!(endpoint, "revocation_endpoint");
1639 }
1640
1641 #[test]
1642 fn validate_introspection_endpoint() {
1643 let (mut metadata, issuer) = valid_provider_metadata();
1644
1645 metadata.introspection_endpoint = None;
1647 metadata.clone().validate(&issuer).unwrap();
1648
1649 let endpoint = Url::parse("http://localhost/introspection").unwrap();
1651 metadata.introspection_endpoint = Some(endpoint.clone());
1652 let (field, url) = assert_matches!(
1653 metadata.clone().validate(&issuer),
1654 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1655 );
1656 assert_eq!(field, "introspection_endpoint");
1657 assert_eq!(url, endpoint);
1658
1659 metadata.introspection_endpoint =
1661 Some(Url::parse("https://localhost/introspection?query#fragment").unwrap());
1662 metadata.validate(&issuer).unwrap();
1663 }
1664
1665 #[test]
1666 fn validate_introspection_endpoint_signing_alg_values_supported() {
1667 let (mut metadata, issuer) = valid_provider_metadata();
1668
1669 metadata.introspection_endpoint_auth_signing_alg_values_supported = None;
1674 metadata.introspection_endpoint_auth_methods_supported = None;
1675 metadata.clone().validate(&issuer).unwrap();
1676
1677 metadata.introspection_endpoint_auth_signing_alg_values_supported =
1679 Some(vec![JsonWebSignatureAlg::None]);
1680 let endpoint = assert_matches!(
1681 metadata.validate(&issuer),
1682 Err(ProviderMetadataVerificationError::SigningAlgValuesWithNone(endpoint)) => endpoint
1683 );
1684 assert_eq!(endpoint, "introspection_endpoint");
1685 }
1686
1687 #[test]
1688 fn validate_userinfo_endpoint() {
1689 let (mut metadata, issuer) = valid_provider_metadata();
1690
1691 metadata.userinfo_endpoint = None;
1693 metadata.clone().validate(&issuer).unwrap();
1694
1695 let endpoint = Url::parse("http://localhost/userinfo").unwrap();
1697 metadata.userinfo_endpoint = Some(endpoint.clone());
1698 let (field, url) = assert_matches!(
1699 metadata.clone().validate(&issuer),
1700 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1701 );
1702 assert_eq!(field, "userinfo_endpoint");
1703 assert_eq!(url, endpoint);
1704
1705 metadata.userinfo_endpoint =
1707 Some(Url::parse("https://localhost/userinfo?query#fragment").unwrap());
1708 metadata.validate(&issuer).unwrap();
1709 }
1710
1711 #[test]
1712 fn validate_subject_types_supported() {
1713 let (mut metadata, issuer) = valid_provider_metadata();
1714
1715 metadata.subject_types_supported = None;
1717 assert_matches!(
1718 metadata.clone().validate(&issuer),
1719 Err(ProviderMetadataVerificationError::MissingSubjectTypesSupported)
1720 );
1721
1722 metadata.subject_types_supported = Some(vec![SubjectType::Public, SubjectType::Pairwise]);
1724 metadata.validate(&issuer).unwrap();
1725 }
1726
1727 #[test]
1728 fn validate_id_token_signing_alg_values_supported() {
1729 let (mut metadata, issuer) = valid_provider_metadata();
1730
1731 metadata.id_token_signing_alg_values_supported = None;
1733 assert_matches!(
1734 metadata.clone().validate(&issuer),
1735 Err(ProviderMetadataVerificationError::MissingIdTokenSigningAlgValuesSupported)
1736 );
1737
1738 metadata.id_token_signing_alg_values_supported =
1740 Some(vec![JsonWebSignatureAlg::Rs256, JsonWebSignatureAlg::EdDsa]);
1741 metadata.validate(&issuer).unwrap();
1742 }
1743
1744 #[test]
1745 fn validate_pushed_authorization_request_endpoint() {
1746 let (mut metadata, issuer) = valid_provider_metadata();
1747
1748 metadata.pushed_authorization_request_endpoint = None;
1750 metadata.clone().validate(&issuer).unwrap();
1751
1752 let endpoint = Url::parse("http://localhost/par").unwrap();
1754 metadata.pushed_authorization_request_endpoint = Some(endpoint.clone());
1755 let (field, url) = assert_matches!(
1756 metadata.clone().validate(&issuer),
1757 Err(ProviderMetadataVerificationError::UrlNonHttpsScheme(field, url)) => (field, url)
1758 );
1759 assert_eq!(field, "pushed_authorization_request_endpoint");
1760 assert_eq!(url, endpoint);
1761
1762 metadata.pushed_authorization_request_endpoint =
1764 Some(Url::parse("https://localhost/par?query#fragment").unwrap());
1765 metadata.validate(&issuer).unwrap();
1766 }
1767
1768 #[test]
1769 fn serialize_application_type() {
1770 assert_eq!(
1771 serde_json::to_string(&ApplicationType::Web).unwrap(),
1772 "\"web\""
1773 );
1774 assert_eq!(
1775 serde_json::to_string(&ApplicationType::Native).unwrap(),
1776 "\"native\""
1777 );
1778 }
1779
1780 #[test]
1781 fn deserialize_application_type() {
1782 assert_eq!(
1783 serde_json::from_str::<ApplicationType>("\"web\"").unwrap(),
1784 ApplicationType::Web
1785 );
1786 assert_eq!(
1787 serde_json::from_str::<ApplicationType>("\"native\"").unwrap(),
1788 ApplicationType::Native
1789 );
1790 }
1791
1792 #[test]
1793 fn serialize_subject_type() {
1794 assert_eq!(
1795 serde_json::to_string(&SubjectType::Public).unwrap(),
1796 "\"public\""
1797 );
1798 assert_eq!(
1799 serde_json::to_string(&SubjectType::Pairwise).unwrap(),
1800 "\"pairwise\""
1801 );
1802 }
1803
1804 #[test]
1805 fn deserialize_subject_type() {
1806 assert_eq!(
1807 serde_json::from_str::<SubjectType>("\"public\"").unwrap(),
1808 SubjectType::Public
1809 );
1810 assert_eq!(
1811 serde_json::from_str::<SubjectType>("\"pairwise\"").unwrap(),
1812 SubjectType::Pairwise
1813 );
1814 }
1815
1816 #[test]
1817 fn serialize_claim_type() {
1818 assert_eq!(
1819 serde_json::to_string(&ClaimType::Normal).unwrap(),
1820 "\"normal\""
1821 );
1822 assert_eq!(
1823 serde_json::to_string(&ClaimType::Aggregated).unwrap(),
1824 "\"aggregated\""
1825 );
1826 assert_eq!(
1827 serde_json::to_string(&ClaimType::Distributed).unwrap(),
1828 "\"distributed\""
1829 );
1830 }
1831
1832 #[test]
1833 fn deserialize_claim_type() {
1834 assert_eq!(
1835 serde_json::from_str::<ClaimType>("\"normal\"").unwrap(),
1836 ClaimType::Normal
1837 );
1838 assert_eq!(
1839 serde_json::from_str::<ClaimType>("\"aggregated\"").unwrap(),
1840 ClaimType::Aggregated
1841 );
1842 assert_eq!(
1843 serde_json::from_str::<ClaimType>("\"distributed\"").unwrap(),
1844 ClaimType::Distributed
1845 );
1846 }
1847
1848 #[test]
1849 fn deserialize_auth_method_or_token_type_type() {
1850 assert_eq!(
1851 serde_json::from_str::<AuthenticationMethodOrAccessTokenType>("\"none\"").unwrap(),
1852 AuthenticationMethodOrAccessTokenType::AuthenticationMethod(
1853 OAuthClientAuthenticationMethod::None
1854 )
1855 );
1856 assert_eq!(
1857 serde_json::from_str::<AuthenticationMethodOrAccessTokenType>("\"Bearer\"").unwrap(),
1858 AuthenticationMethodOrAccessTokenType::AccessTokenType(OAuthAccessTokenType::Bearer)
1859 );
1860 assert_eq!(
1861 serde_json::from_str::<AuthenticationMethodOrAccessTokenType>("\"unknown_value\"")
1862 .unwrap(),
1863 AuthenticationMethodOrAccessTokenType::Unknown("unknown_value".to_owned())
1864 );
1865 }
1866}