mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
feat: allow switch between spn and name for claims (#1043)
This commit is contained in:
parent
5c0a99ba34
commit
2b11ad0ad5
|
@ -1755,6 +1755,29 @@ impl KanidmClient {
|
|||
.await
|
||||
}
|
||||
|
||||
pub async fn idm_oauth2_rs_prefer_short_username(&self, id: &str) -> Result<(), ClientError> {
|
||||
let mut update_oauth2_rs = Entry {
|
||||
attrs: BTreeMap::new(),
|
||||
};
|
||||
update_oauth2_rs.attrs.insert(
|
||||
"oauth2_prefer_short_username".to_string(),
|
||||
vec!["true".to_string()],
|
||||
);
|
||||
self.perform_patch_request(format!("/v1/oauth2/{}", id).as_str(), update_oauth2_rs)
|
||||
.await
|
||||
}
|
||||
pub async fn idm_oauth2_rs_prefer_spn_username(&self, id: &str) -> Result<(), ClientError> {
|
||||
let mut update_oauth2_rs = Entry {
|
||||
attrs: BTreeMap::new(),
|
||||
};
|
||||
update_oauth2_rs.attrs.insert(
|
||||
"oauth2_prefer_short_username".to_string(),
|
||||
vec!["false".to_string()],
|
||||
);
|
||||
self.perform_patch_request(format!("/v1/oauth2/{}", id).as_str(), update_oauth2_rs)
|
||||
.await
|
||||
}
|
||||
|
||||
// ==== recycle bin
|
||||
pub async fn recycle_bin_list(&self) -> Result<Vec<Entry>, ClientError> {
|
||||
self.perform_get_request("/v1/recycle_bin").await
|
||||
|
|
|
@ -333,7 +333,7 @@ pub struct UserAuthToken {
|
|||
// may depend on the client application.
|
||||
pub expiry: time::OffsetDateTime,
|
||||
pub uuid: Uuid,
|
||||
// pub name: String,
|
||||
pub name: String,
|
||||
pub displayname: String,
|
||||
pub spn: String,
|
||||
pub mail_primary: Option<String>,
|
||||
|
|
|
@ -16,6 +16,8 @@ impl Oauth2Opt {
|
|||
Oauth2Opt::DisablePkce(nopt) => nopt.copt.debug,
|
||||
Oauth2Opt::EnableLegacyCrypto(nopt) => nopt.copt.debug,
|
||||
Oauth2Opt::DisableLegacyCrypto(nopt) => nopt.copt.debug,
|
||||
Oauth2Opt::PreferShortUsername(nopt) => nopt.copt.debug,
|
||||
Oauth2Opt::PreferSPNUsername(nopt) => nopt.copt.debug,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,6 +174,26 @@ impl Oauth2Opt {
|
|||
Err(e) => error!("Error -> {:?}", e),
|
||||
}
|
||||
}
|
||||
Oauth2Opt::PreferShortUsername(nopt) => {
|
||||
let client = nopt.copt.to_client().await;
|
||||
match client
|
||||
.idm_oauth2_rs_prefer_short_username(nopt.name.as_str())
|
||||
.await
|
||||
{
|
||||
Ok(_) => println!("Success"),
|
||||
Err(e) => error!("Error -> {:?}", e),
|
||||
}
|
||||
}
|
||||
Oauth2Opt::PreferSPNUsername(nopt) => {
|
||||
let client = nopt.copt.to_client().await;
|
||||
match client
|
||||
.idm_oauth2_rs_prefer_spn_username(nopt.name.as_str())
|
||||
.await
|
||||
{
|
||||
Ok(_) => println!("Success"),
|
||||
Err(e) => error!("Error -> {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -239,13 +239,17 @@ pub enum ServiceAccountPosix {
|
|||
pub struct PersonUpdateOpt {
|
||||
#[clap(flatten)]
|
||||
aopts: AccountCommonOpt,
|
||||
#[clap(long, short, help="Set the legal name for the person.")]
|
||||
#[clap(long, short, help = "Set the legal name for the person.")]
|
||||
legalname: Option<String>,
|
||||
#[clap(long, short, help="Set the account name for the person.")]
|
||||
#[clap(long, short, help = "Set the account name for the person.")]
|
||||
newname: Option<String>,
|
||||
#[clap(long, short='i', help="Set the display name for the person.")]
|
||||
#[clap(long, short = 'i', help = "Set the display name for the person.")]
|
||||
displayname: Option<String>,
|
||||
#[clap(long, short, help="Set the mail address, can be set multiple times for multiple addresses. The first listed mail address is the 'primary'")]
|
||||
#[clap(
|
||||
long,
|
||||
short,
|
||||
help = "Set the mail address, can be set multiple times for multiple addresses. The first listed mail address is the 'primary'"
|
||||
)]
|
||||
mail: Option<Vec<String>>,
|
||||
#[clap(flatten)]
|
||||
copt: CommonOpt,
|
||||
|
@ -339,11 +343,19 @@ pub enum ServiceAccountCredential {
|
|||
pub struct ServiceAccountUpdateOpt {
|
||||
#[clap(flatten)]
|
||||
aopts: AccountCommonOpt,
|
||||
#[clap(long, short, help="Set the account name for the service account.")]
|
||||
#[clap(long, short, help = "Set the account name for the service account.")]
|
||||
newname: Option<String>,
|
||||
#[clap(long, short='i', help="Set the display name for the service account.")]
|
||||
#[clap(
|
||||
long,
|
||||
short = 'i',
|
||||
help = "Set the display name for the service account."
|
||||
)]
|
||||
displayname: Option<String>,
|
||||
#[clap(long, short, help="Set the mail address, can be set multiple times for multiple addresses. The first listed mail address is the 'primary'")]
|
||||
#[clap(
|
||||
long,
|
||||
short,
|
||||
help = "Set the mail address, can be set multiple times for multiple addresses. The first listed mail address is the 'primary'"
|
||||
)]
|
||||
mail: Option<Vec<String>>,
|
||||
#[clap(flatten)]
|
||||
copt: CommonOpt,
|
||||
|
@ -575,10 +587,16 @@ pub enum Oauth2Opt {
|
|||
/// Disable legacy signing crypto on this oauth2 resource server. This is the default.
|
||||
#[clap(name = "disable_legacy_crypto")]
|
||||
DisableLegacyCrypto(Named),
|
||||
#[clap(name = "prefer_short_username")]
|
||||
/// Use the 'name' attribute instead of 'spn' for the preferred_username
|
||||
PreferShortUsername(Named),
|
||||
#[clap(name = "prefer_spn_username")]
|
||||
/// Use the 'spn' attribute instead of 'name' for the preferred_username
|
||||
PreferSPNUsername(Named),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct OptSetDomainDisplayName{
|
||||
pub struct OptSetDomainDisplayName {
|
||||
#[clap(flatten)]
|
||||
copt: CommonOpt,
|
||||
#[clap(name = "new_display_Name")]
|
||||
|
@ -636,7 +654,7 @@ pub enum KanidmClientOpt {
|
|||
/// Actions to manage and view person (user) accounts
|
||||
Person {
|
||||
#[clap(subcommand)]
|
||||
commands: PersonOpt
|
||||
commands: PersonOpt,
|
||||
},
|
||||
/// Actions to manage groups
|
||||
Group {
|
||||
|
@ -666,9 +684,7 @@ pub enum KanidmClientOpt {
|
|||
commands: RawOpt,
|
||||
},
|
||||
/// Print the program version and exit
|
||||
Version {
|
||||
|
||||
}
|
||||
Version {},
|
||||
}
|
||||
|
||||
#[derive(Debug, clap::Parser)]
|
||||
|
|
|
@ -1183,7 +1183,8 @@ pub const JSON_IDM_HP_ACP_OAUTH2_MANAGE_PRIV_V1: &str = r#"{
|
|||
"es256_private_key_der",
|
||||
"oauth2_allow_insecure_client_disable_pkce",
|
||||
"rs256_private_key_der",
|
||||
"oauth2_jwt_legacy_crypto_enable"
|
||||
"oauth2_jwt_legacy_crypto_enable",
|
||||
"oauth2_prefer_short_username"
|
||||
],
|
||||
"acp_modify_removedattr": [
|
||||
"description",
|
||||
|
@ -1197,7 +1198,8 @@ pub const JSON_IDM_HP_ACP_OAUTH2_MANAGE_PRIV_V1: &str = r#"{
|
|||
"es256_private_key_der",
|
||||
"oauth2_allow_insecure_client_disable_pkce",
|
||||
"rs256_private_key_der",
|
||||
"oauth2_jwt_legacy_crypto_enable"
|
||||
"oauth2_jwt_legacy_crypto_enable",
|
||||
"oauth2_prefer_short_username"
|
||||
],
|
||||
"acp_modify_presentattr": [
|
||||
"description",
|
||||
|
@ -1207,7 +1209,8 @@ pub const JSON_IDM_HP_ACP_OAUTH2_MANAGE_PRIV_V1: &str = r#"{
|
|||
"oauth2_rs_scope_map",
|
||||
"oauth2_rs_implicit_scopes",
|
||||
"oauth2_allow_insecure_client_disable_pkce",
|
||||
"oauth2_jwt_legacy_crypto_enable"
|
||||
"oauth2_jwt_legacy_crypto_enable",
|
||||
"oauth2_prefer_short_username"
|
||||
],
|
||||
"acp_modify_class": [],
|
||||
"acp_create_attr": [
|
||||
|
@ -1219,7 +1222,8 @@ pub const JSON_IDM_HP_ACP_OAUTH2_MANAGE_PRIV_V1: &str = r#"{
|
|||
"oauth2_rs_scope_map",
|
||||
"oauth2_rs_implicit_scopes",
|
||||
"oauth2_allow_insecure_client_disable_pkce",
|
||||
"oauth2_jwt_legacy_crypto_enable"
|
||||
"oauth2_jwt_legacy_crypto_enable",
|
||||
"oauth2_prefer_short_username"
|
||||
],
|
||||
"acp_create_class": ["oauth2_resource_server", "oauth2_resource_server_basic", "object"]
|
||||
}
|
||||
|
|
|
@ -1018,6 +1018,35 @@ pub const JSON_SCHEMA_ATTR_DYNGROUP_FILTER: &str = r#"{
|
|||
}
|
||||
}"#;
|
||||
|
||||
pub const JSON_SCHEMA_ATTR_OAUTH2_PREFER_SHORT_USERNAME: &str = r#"{
|
||||
"attrs": {
|
||||
"class": [
|
||||
"object",
|
||||
"system",
|
||||
"attributetype"
|
||||
],
|
||||
"description": [
|
||||
"Use 'name' instead of 'spn' in the preferred_username claim"
|
||||
],
|
||||
"index": [],
|
||||
"unique": [
|
||||
"false"
|
||||
],
|
||||
"multivalue": [
|
||||
"false"
|
||||
],
|
||||
"attributename": [
|
||||
"oauth2_prefer_short_username"
|
||||
],
|
||||
"syntax": [
|
||||
"BOOLEAN"
|
||||
],
|
||||
"uuid": [
|
||||
"00000000-0000-0000-0000-ffff00000109"
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
// === classes ===
|
||||
|
||||
pub const JSON_SCHEMA_CLASS_PERSON: &str = r#"
|
||||
|
@ -1344,7 +1373,8 @@ pub const JSON_SCHEMA_CLASS_OAUTH2_RS: &str = r#"
|
|||
"oauth2_rs_implicit_scopes",
|
||||
"oauth2_allow_insecure_client_disable_pkce",
|
||||
"rs256_private_key_der",
|
||||
"oauth2_jwt_legacy_crypto_enable"
|
||||
"oauth2_jwt_legacy_crypto_enable",
|
||||
"oauth2_prefer_short_username"
|
||||
],
|
||||
"systemmust": [
|
||||
"oauth2_rs_name",
|
||||
|
|
|
@ -184,6 +184,8 @@ pub const UUID_SCHEMA_ATTR_SCOPE: Uuid = uuid!("00000000-0000-0000-0000-ffff0000
|
|||
pub const UUID_SCHEMA_CLASS_SERVICE_ACCOUNT: Uuid = uuid!("00000000-0000-0000-0000-ffff00000106");
|
||||
pub const _UUID_SCHEMA_CLASS_DYNGROUP: Uuid = uuid!("00000000-0000-0000-0000-ffff00000107");
|
||||
pub const _UUID_SCHEMA_ATTR_DYNGROUP_FILTER: Uuid = uuid!("00000000-0000-0000-0000-ffff00000108");
|
||||
pub const _UUID_SCHEMA_ATTR_OAUTH2_PREFERR_SHORT_USERNAME: Uuid =
|
||||
uuid!("00000000-0000-0000-0000-ffff00000109");
|
||||
|
||||
// System and domain infos
|
||||
// I'd like to strongly criticise william of the past for making poor choices about these allocations.
|
||||
|
|
|
@ -202,7 +202,7 @@ impl Account {
|
|||
auth_type,
|
||||
expiry,
|
||||
uuid: self.uuid,
|
||||
// name: self.name.clone(),
|
||||
name: self.name.clone(),
|
||||
displayname: self.displayname.clone(),
|
||||
spn: self.spn.clone(),
|
||||
mail_primary: self.mail_primary.clone(),
|
||||
|
|
|
@ -205,6 +205,7 @@ pub struct Oauth2RS {
|
|||
userinfo_endpoint: Url,
|
||||
jwks_uri: Url,
|
||||
scopes_supported: Vec<String>,
|
||||
prefer_short_username: bool,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Oauth2RS {
|
||||
|
@ -367,6 +368,10 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
|
|||
.map(|e| !e)
|
||||
.unwrap_or(true);
|
||||
|
||||
let prefer_short_username = ent
|
||||
.get_ava_single_bool("oauth2_prefer_short_username")
|
||||
.unwrap_or(false);
|
||||
|
||||
let mut authorization_endpoint = self.inner.origin.clone();
|
||||
authorization_endpoint.set_path("/ui/oauth2");
|
||||
|
||||
|
@ -408,6 +413,7 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
|
|||
userinfo_endpoint,
|
||||
jwks_uri,
|
||||
scopes_supported,
|
||||
prefer_short_username,
|
||||
};
|
||||
|
||||
Ok((client_id, rscfg))
|
||||
|
@ -935,6 +941,13 @@ impl Oauth2ResourceServersReadTransaction {
|
|||
(None, None)
|
||||
};
|
||||
|
||||
admin_warn!("prefer_short_username: {:?}", o2rs.prefer_short_username);
|
||||
let preferred_username = if o2rs.prefer_short_username {
|
||||
Some(code_xchg.uat.name.clone())
|
||||
} else {
|
||||
Some(code_xchg.uat.spn.clone())
|
||||
};
|
||||
|
||||
// TODO: If max_age was requested in the request, we MUST provide auth_time.
|
||||
|
||||
// amr == auth method
|
||||
|
@ -963,10 +976,10 @@ impl Oauth2ResourceServersReadTransaction {
|
|||
// Map from displayname
|
||||
name: Some(code_xchg.uat.displayname.clone()),
|
||||
// Map from spn
|
||||
preferred_username: Some(code_xchg.uat.spn.clone()),
|
||||
scopes: code_xchg.scopes.clone(),
|
||||
email,
|
||||
email_verified,
|
||||
preferred_username,
|
||||
..Default::default()
|
||||
},
|
||||
claims: Default::default(),
|
||||
|
|
|
@ -2646,6 +2646,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
JSON_SCHEMA_CLASS_OAUTH2_RS,
|
||||
JSON_SCHEMA_CLASS_OAUTH2_RS_BASIC,
|
||||
JSON_SCHEMA_ATTR_NSUNIQUEID,
|
||||
JSON_SCHEMA_ATTR_OAUTH2_PREFER_SHORT_USERNAME,
|
||||
];
|
||||
|
||||
let r = idm_schema
|
||||
|
|
Loading…
Reference in a new issue