feat: allow switch between spn and name for claims (#1043)

This commit is contained in:
Dominik Süß 2022-09-15 03:42:08 +02:00 committed by GitHub
parent 5c0a99ba34
commit 2b11ad0ad5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 131 additions and 20 deletions

View file

@ -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

View file

@ -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>,

View file

@ -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),
}
}
}
}
}

View file

@ -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)]

View file

@ -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"]
}

View file

@ -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",

View file

@ -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.

View file

@ -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(),

View file

@ -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(),

View file

@ -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