mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Add rfc8414 metadata (#2434)
This commit is contained in:
parent
8e4980b2c1
commit
b1e7cb13a5
|
@ -60,6 +60,12 @@ Kanidm will expose its OAuth2 APIs at the following URLs:
|
||||||
- rfc7662 token introspection url: `https://idm.example.com/oauth2/token/introspect`
|
- rfc7662 token introspection url: `https://idm.example.com/oauth2/token/introspect`
|
||||||
- rfc7009 token revoke url: `https://idm.example.com/oauth2/token/revoke`
|
- rfc7009 token revoke url: `https://idm.example.com/oauth2/token/revoke`
|
||||||
|
|
||||||
|
Oauth2 Server Metadata - you need to substitute your OAuth2 `:client_id:` in the following urls:
|
||||||
|
|
||||||
|
- Oauth2 issuer uri: `https://idm.example.com/oauth2/openid/:client_id:/`
|
||||||
|
- Oauth2 rfc8414 discovery:
|
||||||
|
`https://idm.example.com/oauth2/openid/:client_id:/.well-known/oauth-authorization-server`
|
||||||
|
|
||||||
OpenID Connect discovery - you need to substitute your OAuth2 `:client_id:` in the following urls:
|
OpenID Connect discovery - you need to substitute your OAuth2 `:client_id:` in the following urls:
|
||||||
|
|
||||||
- OpenID connect issuer uri: `https://idm.example.com/oauth2/openid/:client_id:/`
|
- OpenID connect issuer uri: `https://idm.example.com/oauth2/openid/:client_id:/`
|
||||||
|
|
|
@ -224,6 +224,11 @@ pub enum SubjectType {
|
||||||
Public,
|
Public,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
pub enum PkceAlg {
|
||||||
|
S256,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "UPPERCASE")]
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
// WE REFUSE TO SUPPORT NONE. DONT EVEN ASK. IT WON'T HAPPEN.
|
// WE REFUSE TO SUPPORT NONE. DONT EVEN ASK. IT WON'T HAPPEN.
|
||||||
|
@ -343,6 +348,52 @@ pub struct OidcDiscoveryResponse {
|
||||||
pub require_request_uri_registration: bool,
|
pub require_request_uri_registration: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
||||||
|
pub struct Oauth2Rfc8414MetadataResponse {
|
||||||
|
pub issuer: Url,
|
||||||
|
pub authorization_endpoint: Url,
|
||||||
|
pub token_endpoint: Url,
|
||||||
|
|
||||||
|
pub jwks_uri: Option<Url>,
|
||||||
|
|
||||||
|
// rfc7591 reg endpoint.
|
||||||
|
pub registration_endpoint: Option<Url>,
|
||||||
|
|
||||||
|
pub scopes_supported: Option<Vec<String>>,
|
||||||
|
|
||||||
|
// For Oauth2 should be Code, Token.
|
||||||
|
pub response_types_supported: Vec<ResponseType>,
|
||||||
|
#[serde(default = "response_modes_supported_default")]
|
||||||
|
pub response_modes_supported: Vec<ResponseMode>,
|
||||||
|
#[serde(default = "grant_types_supported_default")]
|
||||||
|
pub grant_types_supported: Vec<GrantType>,
|
||||||
|
|
||||||
|
#[serde(default = "token_endpoint_auth_methods_supported_default")]
|
||||||
|
pub token_endpoint_auth_methods_supported: Vec<TokenEndpointAuthMethod>,
|
||||||
|
|
||||||
|
pub token_endpoint_auth_signing_alg_values_supported: Option<Vec<IdTokenSignAlg>>,
|
||||||
|
|
||||||
|
pub service_documentation: Option<Url>,
|
||||||
|
pub ui_locales_supported: Option<Vec<String>>,
|
||||||
|
|
||||||
|
pub op_policy_uri: Option<Url>,
|
||||||
|
pub op_tos_uri: Option<Url>,
|
||||||
|
|
||||||
|
// rfc7009
|
||||||
|
pub revocation_endpoint: Option<Url>,
|
||||||
|
pub revocation_endpoint_auth_methods_supported: Vec<TokenEndpointAuthMethod>,
|
||||||
|
|
||||||
|
// rfc7662
|
||||||
|
pub introspection_endpoint: Option<Url>,
|
||||||
|
pub introspection_endpoint_auth_methods_supported: Vec<TokenEndpointAuthMethod>,
|
||||||
|
pub introspection_endpoint_auth_signing_alg_values_supported: Option<Vec<IdTokenSignAlg>>,
|
||||||
|
|
||||||
|
// RFC7636
|
||||||
|
pub code_challenge_methods_supported: Vec<PkceAlg>,
|
||||||
|
}
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
pub struct ErrorResponse {
|
pub struct ErrorResponse {
|
||||||
|
|
|
@ -32,7 +32,8 @@ use kanidmd_lib::{
|
||||||
idm::ldap::{LdapBoundToken, LdapResponseState, LdapServer},
|
idm::ldap::{LdapBoundToken, LdapResponseState, LdapServer},
|
||||||
idm::oauth2::{
|
idm::oauth2::{
|
||||||
AccessTokenIntrospectRequest, AccessTokenIntrospectResponse, AuthorisationRequest,
|
AccessTokenIntrospectRequest, AccessTokenIntrospectResponse, AuthorisationRequest,
|
||||||
AuthoriseResponse, JwkKeySet, Oauth2Error, OidcDiscoveryResponse, OidcToken,
|
AuthoriseResponse, JwkKeySet, Oauth2Error, Oauth2Rfc8414MetadataResponse,
|
||||||
|
OidcDiscoveryResponse, OidcToken,
|
||||||
},
|
},
|
||||||
idm::server::{IdmServer, IdmServerTransaction},
|
idm::server::{IdmServer, IdmServerTransaction},
|
||||||
idm::serviceaccount::ListApiTokenEvent,
|
idm::serviceaccount::ListApiTokenEvent,
|
||||||
|
@ -1432,6 +1433,20 @@ impl QueryServerReadV1 {
|
||||||
idms_prox_read.oauth2_openid_discovery(&client_id)
|
idms_prox_read.oauth2_openid_discovery(&client_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(
|
||||||
|
level = "info",
|
||||||
|
skip_all,
|
||||||
|
fields(uuid = ?eventid)
|
||||||
|
)]
|
||||||
|
pub async fn handle_oauth2_rfc8414_metadata(
|
||||||
|
&self,
|
||||||
|
client_id: String,
|
||||||
|
eventid: Uuid,
|
||||||
|
) -> Result<Oauth2Rfc8414MetadataResponse, OperationError> {
|
||||||
|
let idms_prox_read = self.idms.proxy_read().await;
|
||||||
|
idms_prox_read.oauth2_rfc8414_metadata(&client_id)
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(
|
#[instrument(
|
||||||
level = "info",
|
level = "info",
|
||||||
skip_all,
|
skip_all,
|
||||||
|
|
|
@ -519,8 +519,6 @@ pub async fn oauth2_openid_discovery_get(
|
||||||
Path(client_id): Path<String>,
|
Path(client_id): Path<String>,
|
||||||
Extension(kopid): Extension<KOpId>,
|
Extension(kopid): Extension<KOpId>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
// let client_id = req.get_url_param("client_id")?;
|
|
||||||
|
|
||||||
let res = state
|
let res = state
|
||||||
.qe_r_ref
|
.qe_r_ref
|
||||||
.handle_oauth2_openid_discovery(client_id, kopid.eventid)
|
.handle_oauth2_openid_discovery(client_id, kopid.eventid)
|
||||||
|
@ -540,6 +538,30 @@ pub async fn oauth2_openid_discovery_get(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn oauth2_rfc8414_metadata_get(
|
||||||
|
State(state): State<ServerState>,
|
||||||
|
Path(client_id): Path<String>,
|
||||||
|
Extension(kopid): Extension<KOpId>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let res = state
|
||||||
|
.qe_r_ref
|
||||||
|
.handle_oauth2_rfc8414_metadata(client_id, kopid.eventid)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(dsc) => (
|
||||||
|
StatusCode::OK,
|
||||||
|
[(ACCESS_CONTROL_ALLOW_ORIGIN, "*")],
|
||||||
|
Json(dsc),
|
||||||
|
)
|
||||||
|
.into_response(),
|
||||||
|
Err(e) => {
|
||||||
|
error!(err = ?e, "Unable to access discovery info");
|
||||||
|
WebError::from(e).response_with_access_control_origin_header()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn oauth2_openid_userinfo_get(
|
pub async fn oauth2_openid_userinfo_get(
|
||||||
State(state): State<ServerState>,
|
State(state): State<ServerState>,
|
||||||
|
@ -758,6 +780,12 @@ pub fn route_setup(state: ServerState) -> Router<ServerState> {
|
||||||
"/oauth2/openid/:client_id/public_key.jwk",
|
"/oauth2/openid/:client_id/public_key.jwk",
|
||||||
get(oauth2_openid_publickey_get),
|
get(oauth2_openid_publickey_get),
|
||||||
)
|
)
|
||||||
|
// // ⚠️ ⚠️ WARNING ⚠️ ⚠️
|
||||||
|
// // IF YOU CHANGE THESE VALUES YOU MUST UPDATE OAUTH2 DISCOVERY URLS
|
||||||
|
.route(
|
||||||
|
"/oauth2/openid/:client_id/.well-known/oauth-authorization-server",
|
||||||
|
get(oauth2_rfc8414_metadata_get).options(oauth2_preflight_options),
|
||||||
|
)
|
||||||
.with_state(state.clone());
|
.with_state(state.clone());
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
|
|
|
@ -24,7 +24,7 @@ use kanidm_proto::constants::*;
|
||||||
pub use kanidm_proto::oauth2::{
|
pub use kanidm_proto::oauth2::{
|
||||||
AccessTokenIntrospectRequest, AccessTokenIntrospectResponse, AccessTokenRequest,
|
AccessTokenIntrospectRequest, AccessTokenIntrospectResponse, AccessTokenRequest,
|
||||||
AccessTokenResponse, AuthorisationRequest, CodeChallengeMethod, ErrorResponse, GrantTypeReq,
|
AccessTokenResponse, AuthorisationRequest, CodeChallengeMethod, ErrorResponse, GrantTypeReq,
|
||||||
OidcDiscoveryResponse, TokenRevokeRequest,
|
Oauth2Rfc8414MetadataResponse, OidcDiscoveryResponse, PkceAlg, TokenRevokeRequest,
|
||||||
};
|
};
|
||||||
use kanidm_proto::oauth2::{
|
use kanidm_proto::oauth2::{
|
||||||
ClaimType, DisplayValue, GrantType, IdTokenSignAlg, ResponseMode, ResponseType, SubjectType,
|
ClaimType, DisplayValue, GrantType, IdTokenSignAlg, ResponseMode, ResponseType, SubjectType,
|
||||||
|
@ -283,6 +283,8 @@ pub struct Oauth2RS {
|
||||||
// For discovery we need to build and keep a number of values.
|
// For discovery we need to build and keep a number of values.
|
||||||
authorization_endpoint: Url,
|
authorization_endpoint: Url,
|
||||||
token_endpoint: Url,
|
token_endpoint: Url,
|
||||||
|
revocation_endpoint: Url,
|
||||||
|
introspection_endpoint: Url,
|
||||||
userinfo_endpoint: Url,
|
userinfo_endpoint: Url,
|
||||||
jwks_uri: Url,
|
jwks_uri: Url,
|
||||||
scopes_supported: BTreeSet<String>,
|
scopes_supported: BTreeSet<String>,
|
||||||
|
@ -533,6 +535,12 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
|
||||||
let mut token_endpoint = self.inner.origin.clone();
|
let mut token_endpoint = self.inner.origin.clone();
|
||||||
token_endpoint.set_path("/oauth2/token");
|
token_endpoint.set_path("/oauth2/token");
|
||||||
|
|
||||||
|
let mut revocation_endpoint = self.inner.origin.clone();
|
||||||
|
revocation_endpoint.set_path("/oauth2/token/revoke");
|
||||||
|
|
||||||
|
let mut introspection_endpoint = self.inner.origin.clone();
|
||||||
|
introspection_endpoint.set_path("/oauth2/token/introspect");
|
||||||
|
|
||||||
let mut userinfo_endpoint = self.inner.origin.clone();
|
let mut userinfo_endpoint = self.inner.origin.clone();
|
||||||
userinfo_endpoint.set_path(&format!("/oauth2/openid/{name}/userinfo"));
|
userinfo_endpoint.set_path(&format!("/oauth2/openid/{name}/userinfo"));
|
||||||
|
|
||||||
|
@ -571,6 +579,8 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
|
||||||
iss,
|
iss,
|
||||||
authorization_endpoint,
|
authorization_endpoint,
|
||||||
token_endpoint,
|
token_endpoint,
|
||||||
|
revocation_endpoint,
|
||||||
|
introspection_endpoint,
|
||||||
userinfo_endpoint,
|
userinfo_endpoint,
|
||||||
jwks_uri,
|
jwks_uri,
|
||||||
scopes_supported,
|
scopes_supported,
|
||||||
|
@ -1936,6 +1946,82 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip_all)]
|
||||||
|
pub fn oauth2_rfc8414_metadata(
|
||||||
|
&self,
|
||||||
|
client_id: &str,
|
||||||
|
) -> Result<Oauth2Rfc8414MetadataResponse, OperationError> {
|
||||||
|
let o2rs = self.oauth2rs.inner.rs_set.get(client_id).ok_or_else(|| {
|
||||||
|
admin_warn!(
|
||||||
|
"Invalid OAuth2 client_id (have you configured the OAuth2 resource server?)"
|
||||||
|
);
|
||||||
|
OperationError::NoMatchingEntries
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let issuer = o2rs.iss.clone();
|
||||||
|
let authorization_endpoint = o2rs.authorization_endpoint.clone();
|
||||||
|
let token_endpoint = o2rs.token_endpoint.clone();
|
||||||
|
let revocation_endpoint = Some(o2rs.revocation_endpoint.clone());
|
||||||
|
let introspection_endpoint = Some(o2rs.introspection_endpoint.clone());
|
||||||
|
let jwks_uri = Some(o2rs.jwks_uri.clone());
|
||||||
|
let scopes_supported = Some(o2rs.scopes_supported.iter().cloned().collect());
|
||||||
|
let response_types_supported = vec![ResponseType::Code];
|
||||||
|
let response_modes_supported = vec![ResponseMode::Query];
|
||||||
|
let grant_types_supported = vec![GrantType::AuthorisationCode];
|
||||||
|
|
||||||
|
let token_endpoint_auth_methods_supported = vec![
|
||||||
|
TokenEndpointAuthMethod::ClientSecretBasic,
|
||||||
|
TokenEndpointAuthMethod::ClientSecretPost,
|
||||||
|
];
|
||||||
|
|
||||||
|
let revocation_endpoint_auth_methods_supported = vec![
|
||||||
|
TokenEndpointAuthMethod::ClientSecretBasic,
|
||||||
|
TokenEndpointAuthMethod::ClientSecretPost,
|
||||||
|
];
|
||||||
|
|
||||||
|
let introspection_endpoint_auth_methods_supported = vec![
|
||||||
|
TokenEndpointAuthMethod::ClientSecretBasic,
|
||||||
|
TokenEndpointAuthMethod::ClientSecretPost,
|
||||||
|
];
|
||||||
|
|
||||||
|
let service_documentation = Some(URL_SERVICE_DOCUMENTATION.clone());
|
||||||
|
|
||||||
|
let require_pkce = match &o2rs.type_ {
|
||||||
|
OauthRSType::Basic { enable_pkce, .. } => *enable_pkce,
|
||||||
|
OauthRSType::Public { .. } => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let code_challenge_methods_supported = if require_pkce {
|
||||||
|
vec![PkceAlg::S256]
|
||||||
|
} else {
|
||||||
|
Vec::with_capacity(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Oauth2Rfc8414MetadataResponse {
|
||||||
|
issuer,
|
||||||
|
authorization_endpoint,
|
||||||
|
token_endpoint,
|
||||||
|
jwks_uri,
|
||||||
|
registration_endpoint: None,
|
||||||
|
scopes_supported,
|
||||||
|
response_types_supported,
|
||||||
|
response_modes_supported,
|
||||||
|
grant_types_supported,
|
||||||
|
token_endpoint_auth_methods_supported,
|
||||||
|
token_endpoint_auth_signing_alg_values_supported: None,
|
||||||
|
service_documentation,
|
||||||
|
ui_locales_supported: None,
|
||||||
|
op_policy_uri: None,
|
||||||
|
op_tos_uri: None,
|
||||||
|
revocation_endpoint,
|
||||||
|
revocation_endpoint_auth_methods_supported,
|
||||||
|
introspection_endpoint,
|
||||||
|
introspection_endpoint_auth_methods_supported,
|
||||||
|
introspection_endpoint_auth_signing_alg_values_supported: None,
|
||||||
|
code_challenge_methods_supported,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip_all)]
|
#[instrument(level = "debug", skip_all)]
|
||||||
pub fn oauth2_openid_discovery(
|
pub fn oauth2_openid_discovery(
|
||||||
&self,
|
&self,
|
||||||
|
@ -3527,6 +3613,114 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[idm_test]
|
||||||
|
async fn test_idm_oauth2_rfc8414_metadata(
|
||||||
|
idms: &IdmServer,
|
||||||
|
_idms_delayed: &mut IdmServerDelayed,
|
||||||
|
) {
|
||||||
|
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||||
|
let (_secret, _uat, _ident, _) =
|
||||||
|
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||||
|
|
||||||
|
let idms_prox_read = idms.proxy_read().await;
|
||||||
|
|
||||||
|
// check the discovery end point works as we expect
|
||||||
|
assert!(
|
||||||
|
idms_prox_read
|
||||||
|
.oauth2_rfc8414_metadata("nosuchclient")
|
||||||
|
.unwrap_err()
|
||||||
|
== OperationError::NoMatchingEntries
|
||||||
|
);
|
||||||
|
|
||||||
|
let discovery = idms_prox_read
|
||||||
|
.oauth2_rfc8414_metadata("test_resource_server")
|
||||||
|
.expect("Failed to get discovery");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
discovery.issuer
|
||||||
|
== Url::parse("https://idm.example.com/oauth2/openid/test_resource_server")
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
discovery.authorization_endpoint
|
||||||
|
== Url::parse("https://idm.example.com/ui/oauth2").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
discovery.token_endpoint == Url::parse("https://idm.example.com/oauth2/token").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
discovery.jwks_uri
|
||||||
|
== Some(
|
||||||
|
Url::parse(
|
||||||
|
"https://idm.example.com/oauth2/openid/test_resource_server/public_key.jwk"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(discovery.registration_endpoint.is_none());
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
discovery.scopes_supported
|
||||||
|
== Some(vec![
|
||||||
|
"groups".to_string(),
|
||||||
|
OAUTH2_SCOPE_OPENID.to_string(),
|
||||||
|
"supplement".to_string(),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(discovery.response_types_supported == vec![ResponseType::Code]);
|
||||||
|
assert!(discovery.response_modes_supported == vec![ResponseMode::Query]);
|
||||||
|
assert!(discovery.grant_types_supported == vec![GrantType::AuthorisationCode]);
|
||||||
|
assert!(
|
||||||
|
discovery.token_endpoint_auth_methods_supported
|
||||||
|
== vec![
|
||||||
|
TokenEndpointAuthMethod::ClientSecretBasic,
|
||||||
|
TokenEndpointAuthMethod::ClientSecretPost
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert!(discovery.service_documentation.is_some());
|
||||||
|
|
||||||
|
assert!(discovery.ui_locales_supported.is_none());
|
||||||
|
assert!(discovery.op_policy_uri.is_none());
|
||||||
|
assert!(discovery.op_tos_uri.is_none());
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
discovery.revocation_endpoint
|
||||||
|
== Some(Url::parse("https://idm.example.com/oauth2/token/revoke").unwrap())
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
discovery.revocation_endpoint_auth_methods_supported
|
||||||
|
== vec![
|
||||||
|
TokenEndpointAuthMethod::ClientSecretBasic,
|
||||||
|
TokenEndpointAuthMethod::ClientSecretPost
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
discovery.introspection_endpoint
|
||||||
|
== Some(Url::parse("https://idm.example.com/oauth2/token/introspect").unwrap())
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
discovery.introspection_endpoint_auth_methods_supported
|
||||||
|
== vec![
|
||||||
|
TokenEndpointAuthMethod::ClientSecretBasic,
|
||||||
|
TokenEndpointAuthMethod::ClientSecretPost
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert!(discovery
|
||||||
|
.introspection_endpoint_auth_signing_alg_values_supported
|
||||||
|
.is_none());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
discovery.code_challenge_methods_supported,
|
||||||
|
vec![PkceAlg::S256]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[idm_test]
|
#[idm_test]
|
||||||
async fn test_idm_oauth2_openid_discovery(
|
async fn test_idm_oauth2_openid_discovery(
|
||||||
idms: &IdmServer,
|
idms: &IdmServer,
|
||||||
|
@ -3611,7 +3805,6 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
eprintln!("{:?}", discovery.scopes_supported);
|
|
||||||
assert!(
|
assert!(
|
||||||
discovery.scopes_supported
|
discovery.scopes_supported
|
||||||
== Some(vec![
|
== Some(vec![
|
||||||
|
|
Loading…
Reference in a new issue