mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-24 13:07:00 +01:00
Correct issuer to match url of connected client (#635)
This commit is contained in:
parent
79e958ad37
commit
a0ef768fc8
|
@ -243,5 +243,32 @@ You can choose to disable other login methods with:
|
||||||
You can login directly by appending `?direct=1` to your login page still. You can re-enable
|
You can login directly by appending `?direct=1` to your login page still. You can re-enable
|
||||||
other backends by setting the value to `1`
|
other backends by setting the value to `1`
|
||||||
|
|
||||||
|
### Velociraptor
|
||||||
|
|
||||||
|
Velociraptor supports OIDC. To configure it select "Authenticate with SSO" then "OIDC" during
|
||||||
|
the interactive configuration generator. Alternately, you can set the following keys in server.config.yaml:
|
||||||
|
|
||||||
|
GUI:
|
||||||
|
authenticator:
|
||||||
|
type: OIDC
|
||||||
|
oidc_issuer: https://idm.example.com/oauth2/openid/:client\_id:/
|
||||||
|
oauth_client_id: <resource server name/>
|
||||||
|
oauth_client_secret: <resource server secret>
|
||||||
|
|
||||||
|
Velociraptor does not support PKCE. You will need to run the following:
|
||||||
|
|
||||||
|
kanidm system oauth2 warning_insecure_client_disable_pkce <resource server name>
|
||||||
|
|
||||||
|
Initial users are mapped via their email in the Velociraptor server.config.yaml config:
|
||||||
|
|
||||||
|
GUI:
|
||||||
|
initial_users:
|
||||||
|
- name: <email address>
|
||||||
|
|
||||||
|
Accounts require the `openid` and `email` scopes to be authenticated. It is recommended you limit
|
||||||
|
these to a group with a scope map due to Velociraptors high impact.
|
||||||
|
|
||||||
|
# kanidm group create velociraptor_users
|
||||||
|
# kanidm group add_members velociraptor_users ...
|
||||||
|
kanidm system oauth2 create_scope_map <resource server name> velociraptor_users openid email
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,11 @@ fn test_oauth2_openid_basic_flow() {
|
||||||
|
|
||||||
// Most values are checked in idm/oauth2.rs, but we want to sanity check
|
// Most values are checked in idm/oauth2.rs, but we want to sanity check
|
||||||
// the urls here as an extended function smoke test.
|
// the urls here as an extended function smoke test.
|
||||||
assert!(discovery.issuer == Url::parse("https://idm.example.com/").unwrap());
|
assert!(
|
||||||
|
discovery.issuer
|
||||||
|
== Url::parse("https://idm.example.com/oauth2/openid/test_integration")
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
discovery.authorization_endpoint
|
discovery.authorization_endpoint
|
||||||
|
@ -328,7 +332,11 @@ fn test_oauth2_openid_basic_flow() {
|
||||||
|
|
||||||
// This is mostly checked inside of idm/oauth2.rs. This is more to check the oidc
|
// This is mostly checked inside of idm/oauth2.rs. This is more to check the oidc
|
||||||
// token and the userinfo endpoints.
|
// token and the userinfo endpoints.
|
||||||
assert!(oidc.iss == Url::parse("https://idm.example.com/").unwrap());
|
assert!(
|
||||||
|
oidc.iss
|
||||||
|
== Url::parse("https://idm.example.com/oauth2/openid/test_integration")
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
assert!(oidc.s_claims.email.as_deref() == Some("admin@example.com"));
|
assert!(oidc.s_claims.email.as_deref() == Some("admin@example.com"));
|
||||||
assert!(oidc.s_claims.email_verified == Some(true));
|
assert!(oidc.s_claims.email_verified == Some(true));
|
||||||
|
|
||||||
|
|
|
@ -349,13 +349,19 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
|
||||||
|
|
||||||
let mut authorization_endpoint = self.inner.origin.clone();
|
let mut authorization_endpoint = self.inner.origin.clone();
|
||||||
authorization_endpoint.set_path("/ui/oauth2");
|
authorization_endpoint.set_path("/ui/oauth2");
|
||||||
|
|
||||||
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 userinfo_endpoint = self.inner.origin.clone();
|
let mut userinfo_endpoint = self.inner.origin.clone();
|
||||||
userinfo_endpoint.set_path(&format!("/oauth2/openid/{}/userinfo", name));
|
userinfo_endpoint.set_path(&format!("/oauth2/openid/{}/userinfo", name));
|
||||||
|
|
||||||
let mut jwks_uri = self.inner.origin.clone();
|
let mut jwks_uri = self.inner.origin.clone();
|
||||||
jwks_uri.set_path(&format!("/oauth2/openid/{}/public_key.jwk", name));
|
jwks_uri.set_path(&format!("/oauth2/openid/{}/public_key.jwk", name));
|
||||||
|
|
||||||
|
let mut iss = self.inner.origin.clone();
|
||||||
|
iss.set_path(&format!("/oauth2/openid/{}", name));
|
||||||
|
|
||||||
let scopes_supported: BTreeSet<String> = implicit_scopes
|
let scopes_supported: BTreeSet<String> = implicit_scopes
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -376,7 +382,7 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
|
||||||
jws_signer,
|
jws_signer,
|
||||||
// jws_validator,
|
// jws_validator,
|
||||||
enable_pkce,
|
enable_pkce,
|
||||||
iss: self.inner.origin.clone(),
|
iss,
|
||||||
authorization_endpoint,
|
authorization_endpoint,
|
||||||
token_endpoint,
|
token_endpoint,
|
||||||
userinfo_endpoint,
|
userinfo_endpoint,
|
||||||
|
@ -837,8 +843,10 @@ impl Oauth2ResourceServersReadTransaction {
|
||||||
// TODO: Make configurable from auth policy!
|
// TODO: Make configurable from auth policy!
|
||||||
let exp = iat + (expires_in as i64);
|
let exp = iat + (expires_in as i64);
|
||||||
|
|
||||||
|
let iss = o2rs.iss.clone();
|
||||||
|
|
||||||
let oidc = OidcToken {
|
let oidc = OidcToken {
|
||||||
iss: self.inner.origin.clone(),
|
iss,
|
||||||
sub: OidcSubject::U(code_xchg.uat.uuid),
|
sub: OidcSubject::U(code_xchg.uat.uuid),
|
||||||
aud: client_id.clone(),
|
aud: client_id.clone(),
|
||||||
iat,
|
iat,
|
||||||
|
@ -1059,10 +1067,12 @@ impl Oauth2ResourceServersReadTransaction {
|
||||||
|
|
||||||
let amr = Some(vec![at.auth_type.to_string()]);
|
let amr = Some(vec![at.auth_type.to_string()]);
|
||||||
|
|
||||||
|
let iss = o2rs.iss.clone();
|
||||||
|
|
||||||
// ==== good to generate response ====
|
// ==== good to generate response ====
|
||||||
|
|
||||||
Ok(OidcToken {
|
Ok(OidcToken {
|
||||||
iss: self.inner.origin.clone(),
|
iss,
|
||||||
sub: OidcSubject::U(at.uuid),
|
sub: OidcSubject::U(at.uuid),
|
||||||
aud: client_id.to_string(),
|
aud: client_id.to_string(),
|
||||||
iat: at.iat,
|
iat: at.iat,
|
||||||
|
@ -2038,7 +2048,11 @@ mod tests {
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(discovery.issuer == Url::parse("https://idm.example.com/").unwrap());
|
assert!(
|
||||||
|
discovery.issuer
|
||||||
|
== Url::parse("https://idm.example.com/oauth2/openid/test_resource_server")
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
discovery.authorization_endpoint
|
discovery.authorization_endpoint
|
||||||
|
@ -2180,7 +2194,11 @@ mod tests {
|
||||||
.expect("Failed to verify oidc");
|
.expect("Failed to verify oidc");
|
||||||
|
|
||||||
// Are the id_token values what we expect?
|
// Are the id_token values what we expect?
|
||||||
assert!(oidc.iss == Url::parse("https://idm.example.com/").unwrap());
|
assert!(
|
||||||
|
oidc.iss
|
||||||
|
== Url::parse("https://idm.example.com/oauth2/openid/test_resource_server")
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
assert!(oidc.sub == OidcSubject::U(*UUID_ADMIN));
|
assert!(oidc.sub == OidcSubject::U(*UUID_ADMIN));
|
||||||
assert!(oidc.aud == "test_resource_server");
|
assert!(oidc.aud == "test_resource_server");
|
||||||
assert!(oidc.iat == iat);
|
assert!(oidc.iat == iat);
|
||||||
|
|
Loading…
Reference in a new issue