fix: map_group_to_role should work even when custom_role is empty (#11408)

- Earlier when map_group_to_role env is enabled, the code flow was
ignoring the map_group_to_role flow when the custom_role was empty
(basically there is no custom role configured in the dex group claim).
This pr fixes this - so no matter whether the custom role is empty or
not, it will go to the map_group_to_role flow (this behaviour was there
earlier, but got broken when the sso claim parser was implemented)
- In the map_group_to_role flow, if the custom role array is empty it
was not adding the sso user to the DEX_DEFAULT_ORG at all even though
the ofga tuple mapping was being done. There is one issue in this pr
though that I just understood, it should add the user to dex_default_org
only when the organizations in the db user create payload is empty
(meaning, if the dex token contains nothing, the user should be added to
dex default org with default dex role). Will fix this shortly.
- When there is new custom org as per the token, it only adds the new
org, but does not remove existing org if there are not present in the
custom group claim returned by the sso claim parser.
This commit is contained in:
Subhra264
2026-04-23 10:40:32 +00:00
committed by GitHub
parent 6c31d98ec0
commit 232ccf5bf3
+49 -7
View File
@@ -21,7 +21,7 @@ use {
},
config::meta::user::{UserOrg, UserRole},
o2_dex::config::get_config as get_dex_config,
o2_openfga::authorizer::authz::get_add_user_to_org_tuples,
o2_openfga::authorizer::authz::{get_add_user_to_org_tuples, get_user_role_deletion_tuple},
o2_openfga::authorizer::roles::{
check_and_get_crole_tuple_for_new_user, get_roles_for_user, get_user_crole_removal_tuples,
},
@@ -77,7 +77,6 @@ pub async fn process_token(
#[cfg(not(feature = "cloud"))]
{
use config::get_config;
use o2_openfga::authorizer::authz::get_user_role_deletion_tuple;
use crate::common::meta::user::UserOrgRole;
@@ -158,7 +157,7 @@ pub async fn process_token(
source_orgs.len()
);
if openfga_cfg.map_group_to_role && !custom_roles.is_empty() {
if openfga_cfg.map_group_to_role {
log::info!("Calling map_group_to_custom_role");
map_group_to_custom_role(&user_email, &name, custom_roles, res.0.user_role).await;
return Ok(None);
@@ -527,12 +526,8 @@ async fn map_group_to_custom_role(
}
}
// Build organizations list for DB
// - If custom claim parsing enabled and custom orgs exist: add to those orgs
// - Otherwise: add to default org only
let mut organizations = Vec::new();
// Custom claim parsing: add user to custom orgs
for org_name in custom_orgs.keys() {
organizations.push(UserOrg {
role: role.clone(),
@@ -543,6 +538,17 @@ async fn map_group_to_custom_role(
});
}
// If the organizations is empty, add the user to the default org
if organizations.is_empty() {
organizations.push(UserOrg {
role: role.clone(),
name: dex_cfg.default_org.clone(),
org_name: dex_cfg.default_org.clone(),
token: Default::default(),
rum_token: Default::default(),
});
}
let (first_name, last_name) = split_name(name);
let updated_db_user = DBUser {
email: user_email.to_owned(),
@@ -635,6 +641,42 @@ async fn map_group_to_custom_role(
}
}
}
// Remove orgs no longer assigned via group membership (default org is never removed)
for existing_org in existing_user.organizations.iter() {
if existing_org.name != dex_cfg.default_org
&& !custom_orgs.contains_key(&existing_org.name)
{
match users::remove_user_from_org(
&existing_org.name,
user_email,
&config::get_config().auth.root_user_email,
)
.await
{
Ok(_) => {
log::info!(
"group_to_custom_role: User removed from org {} (group no longer assigned)",
existing_org.name
);
if openfga_cfg.enabled {
remove_tuples.push(get_user_role_deletion_tuple(
&existing_org.role.to_string(),
user_email,
&existing_org.name,
));
}
}
Err(e) => {
log::error!(
"group_to_custom_role: Error removing user from org {}: {e}",
existing_org.name
);
}
}
}
}
let existing_roles = get_roles_for_user(user_email).await;
// Find roles to delete: present in existing_role but not in custom_role