Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
lib
unicaen
auth
Commits
dd5c8b60
Commit
dd5c8b60
authored
Jun 03, 2021
by
Bertrand Gauthier
Browse files
Merge branch 'release-3.2.0'
parents
ff93d62a
06ac47cc
Pipeline
#9952
passed with stage
in 14 seconds
Changes
9
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
CHANGELOG.md
View file @
dd5c8b60
...
...
@@ -45,3 +45,6 @@ Première version officielle sous ZF3.
-
Possibilité de connaître la source de l'authentification (db, ldap, cas, shib).
-
Possibilité de stopper l'usurpation en cours pour revenir à l'identité d'origine.
-
[FIX] Usurpation d'un compte local en BDD.
-
[FIX] Lorsque l'usurpateur stoppait l'usurpation, il ne récupérait pas son dernier endossé
-
[FIX] En cas d'usurpation puis de déconnexion puis de reconnexion, on revenait dans la peau de l'usurpé sans pouvoir
stopper l'usurpation
\ No newline at end of file
config/module.config.php
View file @
dd5c8b60
...
...
@@ -194,22 +194,33 @@ $settings = [
* Ex: identifiant de l'usager au sein du référentiel établissement, transmis par l'IDP via le supannRefId.
*/
'shib_user_id_extractor'
=>
[
/*
// domaine (ex: 'unicaen.fr') de l'EPPN (ex: hochonp@unicaen.fr')
'unicaen.fr' => [
[
// nom du 1er attribut recherché
'name'
=>
'supannRefId'
,
// ex: '{
REFERENTIEL
}1234;{ISO15693}044D1AZE7A5P80'
'name' => 'supannRefId', // ex: '{
OCTOPUS:ID
}1234;{ISO15693}044D1AZE7A5P80'
// pattern éventuel pour extraire la partie intéressante
'preg_match_pattern'
=>
'|\{
REFERENTIEL
\}(\d+)|'
,
// ex: permet d'extraire '1234'
'preg_match_pattern' => '|\{
OCTOPUS:ID
\}(\d+)|', // ex: permet d'extraire '1234'
],
[
// nom du 2e attribut recherché
// nom du 2e attribut recherché
, si le 1er est introuvable
'name' => 'supannEmpId',
// pas de pattern donc valeur
directement
utilis
abl
e
// pas de pattern donc valeur
brute
utilis
é
e
'preg_match_pattern' => null,
],
[
// nom du 3e attribut recherché
// nom du 3e attribut recherché, si le 2e est introuvable
'name' => 'supannEtuId',
],
],
*/
// config de repli pour tous les autres domaines
'default'
=>
[
[
'name'
=>
'supannEmpId'
,
],
[
'name'
=>
'supannEtuId'
,
],
],
...
...
config/unicaen-auth.local.php.dist
View file @
dd5c8b60
...
...
@@ -123,21 +123,30 @@ return [
*/
'shib_user_id_extractor'
=>
[
// domaine (ex: 'unicaen.fr') de l'EPPN (ex: hochonp@unicaen.fr')
'unicaen.fr'
=>
[
[
// nom du 1er attribut recherché
'name'
=>
'supannRefId'
,
// ex: '{REFERENTIEL}1234;{ISO15693}044D1AZE7A5P80'
// pattern éventuel pour extraire la partie intéressante
'preg_match_pattern'
=>
'|\{REFERENTIEL\}(\d+)|'
,
// ex: permet d'extraire '1234'
],
// 'unicaen.fr' => [
// [
// // nom du 1er attribut recherché
// 'name' => 'supannRefId', // ex: '{OCTOPUS:ID}1234;{ISO15693}044D1AZE7A5P80'
// // pattern éventuel pour extraire la partie intéressante
// 'preg_match_pattern' => '|\{OCTOPUS:ID\}(\d+)|', // ex: permet d'extraire '1234'
// ],
// [
// // nom du 2e attribut recherché
// 'name' => 'supannEmpId',
// // pas de pattern donc valeur brute utilisée
// 'preg_match_pattern' => null,
// ],
// [
// // nom du 3e attribut recherché
// 'name' => 'supannEtuId',
// ],
// ],
// config de repli pour tous les autres domaines
'default'
=>
[
[
// nom du 2e attribut recherché
'name'
=>
'supannEmpId'
,
// pas de pattern donc valeur directement utilisable
'preg_match_pattern'
=>
null
,
],
[
// nom du 3e attribut recherché
'name'
=>
'supannEtuId'
,
],
],
...
...
src/UnicaenAuth/Authentication/Adapter/LocalAdapterFactory.php
View file @
dd5c8b60
...
...
@@ -28,11 +28,11 @@ class LocalAdapterFactory
// db adapter
if
(
array_key_exists
(
'db'
,
$localConfig
))
{
$this
->
attachSubAdapter
(
$localAdapter
,
$container
,
$localConfig
[
'db'
]
);
$this
->
attachSubAdapter
(
$localAdapter
,
$container
,
$localConfig
[
'db'
]
,
20
);
// en 1er
}
// ldap adapter
if
(
array_key_exists
(
'ldap'
,
$localConfig
))
{
$this
->
attachSubAdapter
(
$localAdapter
,
$container
,
$localConfig
[
'ldap'
]
);
$this
->
attachSubAdapter
(
$localAdapter
,
$container
,
$localConfig
[
'ldap'
]
,
10
);
// en 2e
}
return
$localAdapter
;
...
...
@@ -42,8 +42,9 @@ class LocalAdapterFactory
* @param LocalAdapter $localAdapter
* @param ContainerInterface $container
* @param array $config
* @param int $priority
*/
private
function
attachSubAdapter
(
LocalAdapter
$localAdapter
,
ContainerInterface
$container
,
array
$config
)
private
function
attachSubAdapter
(
LocalAdapter
$localAdapter
,
ContainerInterface
$container
,
array
$config
,
int
$priority
)
{
$enabled
=
isset
(
$config
[
'enabled'
])
&&
$config
[
'enabled'
]
===
true
;
if
(
!
$enabled
)
{
...
...
@@ -52,7 +53,7 @@ class LocalAdapterFactory
/** @var AbstractAdapter $subAdapter */
$subAdapter
=
$container
->
get
(
$config
[
'adapter'
]);
$subAdapter
->
attach
(
$localAdapter
->
getEventManager
());
$subAdapter
->
attach
(
$localAdapter
->
getEventManager
()
,
$priority
);
}
}
\ No newline at end of file
src/UnicaenAuth/Authentication/Storage/Shib.php
View file @
dd5c8b60
...
...
@@ -54,4 +54,14 @@ class Shib extends AbstractStorage
return
$this
->
shibService
->
getAuthenticatedUser
();
}
/**
* @inheritDoc
*/
public
function
clear
(
ChainEvent
$e
)
{
parent
::
clear
(
$e
);
$this
->
shibService
->
deactivateUsurpation
();
}
}
src/UnicaenAuth/Entity/Db/AbstractUser.php
View file @
dd5c8b60
...
...
@@ -6,6 +6,7 @@ use BjyAuthorize\Provider\Role\ProviderInterface;
use
Doctrine\Common\Collections\ArrayCollection
;
use
Doctrine\Common\Collections\Collection
;
use
Doctrine\ORM\Mapping
as
ORM
;
use
UnicaenAuth\Entity\Db\Role
;
/**
* User entity abstract mother class.
...
...
@@ -71,6 +72,13 @@ abstract class AbstractUser implements UserInterface, ProviderInterface
*/
protected
$roles
;
/**
* @var AbstractRole
* @ORM\ManyToOne(targetEntity="UnicaenAuth\Entity\Db\Role")
* @ORM\JoinColumn(name="last_role_id", referencedColumnName="id")
*/
protected
$lastRole
;
/**
* Initialies the roles variable.
*/
...
...
@@ -259,6 +267,25 @@ abstract class AbstractUser implements UserInterface, ProviderInterface
return
$this
;
}
/**
* @return AbstractRole|null
*/
public
function
getLastRole
()
{
return
$this
->
lastRole
;
}
/**
* @param AbstractRole|null $lastRole
* @return self
*/
public
function
setLastRole
(
AbstractRole
$lastRole
=
null
)
{
$this
->
lastRole
=
$lastRole
;
return
$this
;
}
/**
* Retourne true si cet utilisateur est local.
*
...
...
src/UnicaenAuth/Event/Listener/AuthenticatedUserSavedAbstractListener.php
View file @
dd5c8b60
...
...
@@ -2,11 +2,14 @@
namespace
UnicaenAuth\Event\Listener
;
use
Zend\EventManager\EventManagerInterface
;
use
Zend\EventManager\ListenerAggregateInterface
;
use
UnicaenApp\Service\EntityManagerAwareInterface
;
use
UnicaenApp\Service\EntityManagerAwareTrait
;
use
UnicaenAuth\Entity\Db\AbstractUser
;
use
UnicaenAuth\Event\UserAuthenticatedEvent
;
use
UnicaenAuth\Service\Traits\UserContextServiceAwareTrait
;
use
Zend\EventManager\EventManagerInterface
;
use
Zend\EventManager\ListenerAggregateInterface
;
use
Zend\EventManager\ListenerAggregateTrait
;
/**
* Classe abstraites pour les classes désirant scruter un événement déclenché lors de l'authentification
...
...
@@ -14,16 +17,19 @@ use UnicaenAuth\Event\UserAuthenticatedEvent;
*
* Événements disponibles :
* - juste avant que l'entité utilisateur ne soit persistée.
* - juste après que l'entité utilisateur ait été persistée.
*
* @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr>
* @see UserAuthenticatedEvent
*/
abstract
class
AuthenticatedUserSavedAbstractListener
implements
ListenerAggregateInterface
,
EntityManagerAwareInterface
{
use
ListenerAggregateTrait
;
use
EntityManagerAwareTrait
;
use
UserContextServiceAwareTrait
;
/**
* @var
\Zend\Stdlib\CallbackHand
le
r
[]
* @var
callab
le[]
*/
protected
$listeners
=
[];
...
...
@@ -31,20 +37,33 @@ abstract class AuthenticatedUserSavedAbstractListener implements ListenerAggrega
* Méthode appelée juste avant que l'entité utilisateur soit persistée.
*
* @param UserAuthenticatedEvent $e
* @return void
*/
public
function
onUserAuthenticatedPrePersist
(
UserAuthenticatedEvent
$e
)
{
/** @var AbstractUser $user */
$user
=
$e
->
getDbUser
();
// Sélection du dernier rôle endossé.
$this
->
selectLastUserRole
(
$user
);
}
/**
* Méthode appelée juste après que l'entité utilisateur soit persistée.
*
* @param UserAuthenticatedEvent $e
* @return void
*/
public
function
onUserAuthenticatedPostPersist
(
UserAuthenticatedEvent
$e
)
{
// nop
}
protected
function
selectLastUserRole
(
AbstractUser
$user
)
{
if
(
$role
=
$user
->
getLastRole
())
{
$this
->
serviceUserContext
->
setNextSelectedIdentityRole
(
$role
);
}
}
/**
...
...
@@ -66,18 +85,4 @@ abstract class AuthenticatedUserSavedAbstractListener implements ListenerAggrega
[
$this
,
'onUserAuthenticatedPostPersist'
],
100
);
}
/**
* Detach all previously attached listeners
*
* @param EventManagerInterface $events
*/
public
function
detach
(
EventManagerInterface
$events
)
{
foreach
(
$this
->
listeners
as
$index
=>
$listener
)
{
if
(
$events
->
detach
(
$listener
))
{
unset
(
$this
->
listeners
[
$index
]);
}
}
}
}
\ No newline at end of file
src/UnicaenAuth/Service/ShibService.php
View file @
dd5c8b60
...
...
@@ -21,6 +21,8 @@ class ShibService
{
const
SHIB_USER_ID_EXTRACTOR
=
'shib_user_id_extractor'
;
const
DOMAIN_DEFAULT
=
'default'
;
const
KEY_fromShibUser
=
'fromShibUser'
;
const
KEY_toShibUser
=
'toShibUser'
;
...
...
@@ -197,13 +199,21 @@ EOS;
return
(
array
)
$this
->
shibbolethConfig
[
'required_attributes'
];
}
/**
* @return array
*/
private
function
getShibUserIdExtractorDefaultConfig
():
array
{
return
$this
->
getShibUserIdExtractorConfigForDomain
(
self
::
DOMAIN_DEFAULT
);
}
/**
* Retourne la config permettant d'extraire l'id à partir des attributs.
*
* @param string $domain
* @return array
*/
private
function
getShibUserIdExtractorForDomain
(
string
$domain
):
array
private
function
getShibUserIdExtractor
Config
ForDomain
(
string
$domain
):
array
{
$key
=
self
::
SHIB_USER_ID_EXTRACTOR
;
if
(
!
array_key_exists
(
$key
,
$this
->
shibbolethConfig
))
{
...
...
@@ -213,7 +223,7 @@ EOS;
$config
=
$this
->
shibbolethConfig
[
$key
];
if
(
!
array_key_exists
(
$domain
,
$config
))
{
throw
new
RuntimeException
(
"Aucune config '
$key
' trouvée pour le domaine '
$domain
'."
)
;
return
[]
;
}
return
$config
[
$domain
];
...
...
@@ -481,14 +491,23 @@ EOS;
*/
private
function
extractShibUserIdValueForDomainFromShibData
(
string
$domain
,
array
$data
):
?string
{
$config
=
$this
->
getShibUserIdExtractorForDomain
(
$domain
);
$config
=
$this
->
getShibUserIdExtractorConfigForDomain
(
$domain
);
if
(
empty
(
$config
))
{
$config
=
$this
->
getShibUserIdExtractorDefaultConfig
();
if
(
empty
(
$config
))
{
throw
new
RuntimeException
(
"Aucune config trouvée ni pour le domaine '
$domain
' ni par défaut."
);
}
}
foreach
(
$config
as
$array
)
{
$name
=
$array
[
'name'
];
$value
=
$this
->
getValueFromShibData
(
$name
,
$data
);
if
(
$value
!==
null
)
{
$pregMatchPattern
=
$array
[
'preg_match_pattern'
]
??
null
;
if
(
$pregMatchPattern
!==
null
&&
preg_match
(
$pregMatchPattern
,
$value
,
$matches
))
{
if
(
$pregMatchPattern
!==
null
)
{
if
(
preg_match
(
$pregMatchPattern
,
$value
,
$matches
)
===
0
)
{
throw
new
RuntimeException
(
"Le pattern '
$pregMatchPattern
' n'a pas permis d'extraire une valeur de '
$name
'."
);
}
$value
=
$matches
[
1
];
}
...
...
src/UnicaenAuth/Service/UserContext.php
View file @
dd5c8b60
...
...
@@ -2,7 +2,7 @@
namespace
UnicaenAuth\Service
;
use
BjyAutho
ri
z
e\
Acl\Role
;
use
Doct
ri
n
e\
ORM\ORMException
;
use
UnicaenApp\Exception\RuntimeException
;
use
UnicaenApp\Traits\SessionContainerTrait
;
use
UnicaenAuth\Acl\NamedRole
;
...
...
@@ -10,6 +10,8 @@ use UnicaenAuth\Authentication\SessionIdentity;
use
UnicaenAuth\Authentication\Storage\Auth
;
use
UnicaenAuth\Authentication\Storage\Usurpation
;
use
UnicaenAuth\Entity\Db\AbstractUser
;
use
UnicaenAuth\Entity\Db\AbstractRole
;
use
UnicaenAuth\Entity\Db\Role
;
use
UnicaenAuth\Entity\Ldap\People
;
use
UnicaenAuth\Entity\Shibboleth\ShibUser
;
use
UnicaenAuth\Event\UserRoleSelectedEvent
;
...
...
@@ -19,8 +21,6 @@ use UnicaenAuth\Provider\Identity\Chain;
use
Zend\Authentication\AuthenticationService
;
use
Zend\EventManager\EventManagerAwareInterface
;
use
Zend\EventManager\EventManagerAwareTrait
;
use
Zend\Http\Request
;
use
Zend\Http\Response
;
use
Zend\Permissions\Acl\Role\RoleInterface
;
use
ZfcUser\Entity\UserInterface
;
...
...
@@ -335,11 +335,35 @@ class UserContext extends AbstractService implements EventManagerAwareInterface
unset
(
$this
->
getSessionContainer
()
->
selectedIdentityRole
);
}
$role
=
$this
->
getSelectableIdentityRoles
()[
$role
];
if
(
$role
instanceof
AbstractRole
)
{
$this
->
saveUserLastRole
(
$role
);
}
$this
->
triggerUserRoleSelectedEvent
(
UserRoleSelectedEvent
::
POST_SELECTION
,
$role
);
return
$this
;
}
/**
* @param AbstractRole $role
*/
private
function
saveUserLastRole
(
AbstractRole
$role
)
{
/** @var AbstractUser $user */
$user
=
$this
->
getDbUser
();
if
(
!
$user
)
{
return
;
}
$user
->
setLastRole
(
$role
);
try
{
$this
->
getEntityManager
()
->
flush
(
$user
);
}
catch
(
ORMException
$e
)
{
throw
new
RuntimeException
(
"Erreur rencontrée lors de l'enregistrement en bdd"
,
null
,
$e
);
}
}
/**
* Retourne l'éventuel rôle spécifié en session devant être le prochain rôle sélectionné.
*
...
...
@@ -372,6 +396,11 @@ class UserContext extends AbstractService implements EventManagerAwareInterface
unset
(
$this
->
getSessionContainer
()
->
nextSelectedIdentityRole
);
}
$role
=
$this
->
getSelectableIdentityRoles
()[
$role
];
if
(
$role
instanceof
AbstractRole
)
{
$this
->
saveUserLastRole
(
$role
);
}
$this
->
triggerUserRoleSelectedEvent
(
UserRoleSelectedEvent
::
POST_SELECTION
,
$role
);
return
$this
;
...
...
@@ -499,5 +528,10 @@ class UserContext extends AbstractService implements EventManagerAwareInterface
$sessionIdentity
=
SessionIdentity
::
newInstance
(
$usurpateur
->
getUsername
(),
$this
->
getAuthenticationType
());
$this
->
authenticationService
->
getStorage
()
->
write
(
$sessionIdentity
);
// Sélection du dernier rôle endossé.
if
(
$role
=
$usurpateur
->
getLastRole
())
{
$this
->
setNextSelectedIdentityRole
(
$role
);
}
}
}
\ No newline at end of file
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment