mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-20 17:15:51 +02:00
Allow to select the priority of SAML role mapping based on the order in the configuration option
This commit is contained in:
parent
bbe4de996a
commit
8fad743e85
4 changed files with 22 additions and 10 deletions
3
.env
3
.env
|
@ -80,10 +80,11 @@ ERROR_PAGE_SHOW_HELP=1
|
|||
SAML_ENABLED=0
|
||||
|
||||
# A JSON encoded array of role mappings in the form { "saml_role": PARTDB_GROUP_ID, "*": PARTDB_GROUP_ID }
|
||||
# The first match is used, so the order is important! Put the group mapping with the most privileges first.
|
||||
# Please not to only use single quotes to enclose the JSON string
|
||||
SAML_ROLE_MAPPING='{}'
|
||||
# A mapping could look like the following
|
||||
#SAML_ROLE_MAPPING='{ "*": 2, "editor": 3, "admin": 1 }'
|
||||
#SAML_ROLE_MAPPING='{ "*": 2, "admin": 1, "editor": 3}'
|
||||
|
||||
# When this is set to 1, the group of SAML users will be updated everytime they login based on their SAML roles
|
||||
SAML_UPDATE_GROUP_ON_LOGIN=1
|
||||
|
|
|
@ -107,11 +107,15 @@ For example if you want to assign the group with ID 1 (by default admin) to ever
|
|||
SAML_ROLE_MAPPING='{"admin": 1, "editor": 3, "*": 2}'
|
||||
```
|
||||
|
||||
Please not that the order of the mapping is important. The first matching role will be assigned to the user. So if you have a user with the roles `admin` and `editor`, he will be assigned to the group with ID 1 (admin) and not to the group with ID 3 (editor), as the `admin` role comes first in the JSON map.
|
||||
This mean that you should always put the most specific roles (e.g. admins) first of the map and the most general roles (e.g. normal users) later.
|
||||
|
||||
If you want to assign users with a certain role to a empty group, provide the group ID -1 as the value. This is not a valid group ID, so the user will not be assigned to any group.
|
||||
|
||||
The SAML roles (or groups depending on your configuration), have to be supplied via a SAML attribute `group`. You have to configure your SAML identity provider to provide this attribute. For example in Keycloak you can configure this attribute in the `Client scopes` page. Select the `sp-dedicatd` client scope (or create a new one) and click on `Add mappers`. Select `Role mapping` or `Group membership`, change the field name and click `Add`. Now Part-DB will be provided with the groups of the user based on the Keycloak user database.
|
||||
|
||||
By default the group is assigned to the user on the first login and updated on every login based on the SAML attributes. This allows you to configure the groups in the SAML identity provider and the users will automatically stay up to date with their permissions. However if you want to disable this behavior (and let the Part-DB admins configure the groups manually, after the first login), you can set the `SAML_UPDATE_GROUP_ON_LOGIN` environment variable to `false`. If you want to disable the automatic group assignment completly (so not even on the first login of a user), set the `SAML_ROLE_MAPPING` to `{}` (empty JSON object).
|
||||
By default, the group is assigned to the user on the first login and updated on every login based on the SAML attributes. This allows you to configure the groups in the SAML identity provider and the users will automatically stay up to date with their permissions. However if you want to disable this behavior (and let the Part-DB admins configure the groups manually, after the first login), you can set the `SAML_UPDATE_GROUP_ON_LOGIN` environment variable to `false`. If you want to disable the automatic group assignment completly (so not even on the first login of a user), set the `SAML_ROLE_MAPPING` to `{}` (empty JSON object).
|
||||
|
||||
|
||||
### Use SAML Login for existing users
|
||||
Part-DB distinguishes between local users and SAML users. Local users are users, which can login via Part-DB login form and which use the password (hash) saved in the Part-DB database. SAML users are stored in the database too (they are created on the first login of the user via SAML), but they use the SAML identity provider to authenticate the user and have no password stored in the database. When you try you will get an error message.
|
||||
|
|
|
@ -120,6 +120,7 @@ class SamlUserFactory implements SamlUserFactoryInterface, EventSubscriberInterf
|
|||
|
||||
/**
|
||||
* Maps a list of SAML roles to a local group ID.
|
||||
* The first available mapping will be used (so the order of the $map is important, first match wins).
|
||||
* @param array $roles The list of SAML roles
|
||||
* @param array $map|null The mapping from SAML roles. If null, the global mapping will be used.
|
||||
* @return int|null The ID of the local group or null if no mapping was found.
|
||||
|
@ -128,14 +129,18 @@ class SamlUserFactory implements SamlUserFactoryInterface, EventSubscriberInterf
|
|||
{
|
||||
$map = $map ?? $this->saml_role_mapping;
|
||||
|
||||
//Iterate over all roles and check if we have a mapping for it.
|
||||
foreach ($roles as $role) {
|
||||
if (array_key_exists($role, $map)) {
|
||||
//We use the first available mapping
|
||||
return (int) $map[$role];
|
||||
//Iterate over the mapping (from first to last) and check if we have a match
|
||||
foreach ($map as $saml_role => $group_id) {
|
||||
//Skip wildcard
|
||||
if ($saml_role === '*') {
|
||||
continue;
|
||||
}
|
||||
if (in_array($saml_role, $roles, true)) {
|
||||
return (int) $group_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//If no applicable mapping was found, check if we have a default mapping
|
||||
if (array_key_exists('*', $map)) {
|
||||
return (int) $map['*'];
|
||||
|
|
|
@ -66,18 +66,20 @@ class SamlUserFactoryTest extends WebTestCase
|
|||
public function testMapSAMLRolesToLocalGroupID()
|
||||
{
|
||||
$mapping = [
|
||||
'admin' => 2, //This comes first, as this should have higher priority
|
||||
'employee' => 1,
|
||||
'admin' => 2,
|
||||
'manager' => 3,
|
||||
'administrator' => 2,
|
||||
'*' => 4,
|
||||
];
|
||||
|
||||
//Test if mapping works
|
||||
$this->assertEquals(1, $this->service->mapSAMLRolesToLocalGroupID(['employee'], $mapping));
|
||||
$this->assertSame(1, $this->service->mapSAMLRolesToLocalGroupID(['employee'], $mapping));
|
||||
//Only the first valid mapping should be used
|
||||
$this->assertEquals(1, $this->service->mapSAMLRolesToLocalGroupID(['employee', 'admin'], $mapping));
|
||||
$this->assertSame(2, $this->service->mapSAMLRolesToLocalGroupID(['employee', 'admin'], $mapping));
|
||||
$this->assertSame(2, $this->service->mapSAMLRolesToLocalGroupID(['does_not_matter', 'admin', 'employee'], $mapping));
|
||||
$this->assertSame(1, $this->service->mapSAMLRolesToLocalGroupID(['employee', 'does_not_matter', 'manager'], $mapping));
|
||||
$this->assertSame(3, $this->service->mapSAMLRolesToLocalGroupID(['administrator', 'does_not_matter', 'manager'], $mapping));
|
||||
//Test if mapping is case sensitive
|
||||
$this->assertEquals(4, $this->service->mapSAMLRolesToLocalGroupID(['ADMIN'], $mapping));
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue