mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-07 01:54:27 +00:00
PHRAS-4108 openid : add claims mapping and groups filtering (#4563)
* openid add group mapping * add migration patch for configuration injection
This commit is contained in:
@@ -229,6 +229,14 @@ authentication:
|
||||
debug: false
|
||||
auto-logout: false
|
||||
auto-connect-idp-name: null
|
||||
groupmask: "/phraseanet_([^,]+)/i"
|
||||
fieldmap:
|
||||
id: sub
|
||||
login: email
|
||||
firstname: given_name
|
||||
lastname: family_name
|
||||
email: email
|
||||
groups: group
|
||||
registration-fields:
|
||||
-
|
||||
name: company
|
||||
|
@@ -32,6 +32,14 @@ authentication:
|
||||
# logout with phraseanet and also logout with keycloak
|
||||
auto-logout: true
|
||||
auto-connect-idp-name: null
|
||||
groupmask: "/cn=phraseanet_([^,]+),cn=users,ou=alchemy$/i"
|
||||
fieldmap:
|
||||
id: sub
|
||||
login: email
|
||||
firstname: given_name
|
||||
lastname: family_name
|
||||
email: email
|
||||
groups: group
|
||||
|
||||
```
|
||||
|
||||
@@ -47,16 +55,19 @@ authentication:
|
||||
|
||||
set the 'Valid post logout redirect URIs' field with `https://{phraseanet-host}/login/logout/` eg: https://phraseanet.phrasea.local/login/logout/
|
||||
|
||||
- Choose a client > client scopes > '.... dedicated'
|
||||
|
||||
add a 'groups' mapper if not exist, > Add mapper > by configuration
|
||||
|
||||
- if not exist create a client scope with mapper type Group Membership
|
||||
`Mapper type` => Group Membership
|
||||
`Name` => groups
|
||||
`Token Claim Name` => groups
|
||||
`Name` => group
|
||||
`Token Claim Name` => group
|
||||
`Full group path` => off
|
||||
`Add to userinfo` => on
|
||||
|
||||
- Add the created client scope to the client
|
||||
|
||||
Choose a client > client scopes > Add client scope > choose the scope
|
||||
|
||||
|
||||
|
||||
#### token expiration
|
||||
- we can define token expiration in keycloak
|
||||
|
||||
|
@@ -343,20 +343,26 @@ class Openid extends AbstractProvider
|
||||
|
||||
$this->debug();
|
||||
|
||||
$userName = $data['preferred_username'];
|
||||
$usegroups = isset($this->config['usegroups']) ? $this->config['usegroups'] : false;
|
||||
$idKey = isset($this->config['fieldmap']['id']) ? $this->config['fieldmap']['id'] : 'sub';
|
||||
$loginKey = isset($this->config['fieldmap']['login']) ? $this->config['fieldmap']['login'] : 'email';
|
||||
$firstnameKey = isset($this->config['fieldmap']['firstname']) ? $this->config['fieldmap']['firstname'] : 'given_name';
|
||||
$lastnameKey = isset($this->config['fieldmap']['lastname']) ? $this->config['fieldmap']['lastname'] : 'family_name';
|
||||
$emailKey = isset($this->config['fieldmap']['email']) ? $this->config['fieldmap']['email'] : 'email';
|
||||
$groupsKey = isset($this->config['fieldmap']['groups']) ? $this->config['fieldmap']['groups'] : 'groups';
|
||||
$distantUserId = $data['sub'];
|
||||
|
||||
if (!\Swift_Validate::email($userName) && isset($data['email'])) {
|
||||
$userName = $data['email'];// login to be an email
|
||||
if (!\Swift_Validate::email($data[$loginKey]) && isset($data['email'])) {
|
||||
$loginKey = 'email';// login to be an email
|
||||
}
|
||||
|
||||
$usegroups = isset($this->config['usegroups']) ? $this->config['usegroups'] : false;
|
||||
$userUA = $this->CreateUser([
|
||||
'id' => $distantUserId = $data['sub'],
|
||||
'login' => $userName,
|
||||
'firstname' => isset($data['given_name']) ? $data['given_name'] : '',
|
||||
'lastname' => isset($data['family_name']) ? $data['family_name'] : '' ,
|
||||
'email' => isset($data['email']) ? $data['email'] : '',
|
||||
'_groups' => isset($data['groups']) && $usegroups ? $data['groups'] : ''
|
||||
'id' => $data[$idKey],
|
||||
'login' => $userName = $data[$loginKey],
|
||||
'firstname' => isset($data[$firstnameKey]) ? $data[$firstnameKey] : '',
|
||||
'lastname' => isset($data[$lastnameKey]) ? $data[$lastnameKey] : '' ,
|
||||
'email' => isset($data[$emailKey]) ? $data[$emailKey] : '',
|
||||
'_groups' => isset($data[$groupsKey]) && $usegroups ? $this->filterGroups($data[$groupsKey]) : ''
|
||||
]);
|
||||
|
||||
$userAuthProviderRepository = $this->getUsrAuthProviderRepository();
|
||||
@@ -715,6 +721,36 @@ class Openid extends AbstractProvider
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function filterGroups($groups)
|
||||
{
|
||||
$this->debug(sprintf("filtering openid groups :\n%s", print_r($groups, true)));
|
||||
|
||||
$ret = [];
|
||||
if ($this->config['groupmask']) {
|
||||
$this->debug(sprintf("filtering groups with regexp : \"%s\"", $this->config['groupmask']));
|
||||
foreach ($groups as $grp) {
|
||||
$matches = [];
|
||||
$retpreg = preg_match_all($this->config['groupmask'], $grp, $matches, PREG_SET_ORDER);
|
||||
|
||||
$this->debug(sprintf("preg_match('%s', '%s', ...)\n - returned %s \n - matches = %s "
|
||||
, $this->config['groupmask'], $grp
|
||||
, print_r($retpreg, true), print_r($matches, true)));
|
||||
|
||||
foreach ($matches as $match) {
|
||||
if (count($match)>0 && isset($match[1]) && !array_key_exists($match[1], $ret)) {
|
||||
$ret[] = $match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->debug(sprintf("no groupmask defined, openid groups ignored"));
|
||||
}
|
||||
|
||||
$this->debug(sprintf("filtered groups :\n%s", print_r($ret, true)));
|
||||
|
||||
return empty($ret) ? '' : $ret ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -50,13 +50,36 @@ class patch_4111PHRAS4106 implements patchInterface
|
||||
$conf = $app['conf'];
|
||||
foreach ($app['conf']->get(['authentication', 'providers'], []) as $providerId => $data) {
|
||||
if ($data['type'] === "openid") {
|
||||
if(!isset($data['options']['usegroups'])) {
|
||||
if (!isset($data['options']['usegroups'])) {
|
||||
$data['options']['usegroups'] = false;
|
||||
|
||||
$providerConfig[$providerId] = $data;
|
||||
|
||||
$conf->merge(['authentication', 'providers'], $providerConfig);
|
||||
}
|
||||
|
||||
if (!isset($data['options']['fieldmap'])) {
|
||||
$data['options']['fieldmap'] = [
|
||||
'id' => 'sub',
|
||||
'login' => 'email',
|
||||
'firstname' => 'given_name',
|
||||
'lastname' => 'family_name',
|
||||
'email' => 'email',
|
||||
'groups' => 'group',
|
||||
];
|
||||
|
||||
$providerConfig[$providerId] = $data;
|
||||
|
||||
$conf->merge(['authentication', 'providers'], $providerConfig);
|
||||
}
|
||||
|
||||
if (!isset($data['options']['groupmask'])) {
|
||||
$data['options']['groupmask'] = "/phraseanet_([^,]+)/i";
|
||||
|
||||
$providerConfig[$providerId] = $data;
|
||||
|
||||
$conf->merge(['authentication', 'providers'], $providerConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -246,6 +246,14 @@ authentication:
|
||||
debug: false
|
||||
auto-logout: false
|
||||
auto-connect-idp-name: null
|
||||
groupmask: "/phraseanet_([^,]+)/i"
|
||||
fieldmap:
|
||||
id: sub
|
||||
login: email
|
||||
firstname: given_name
|
||||
lastname: family_name
|
||||
email: email
|
||||
groups: group
|
||||
registration-fields:
|
||||
-
|
||||
name: company
|
||||
|
Reference in New Issue
Block a user