From 78ec0f1ea3046d324ed1e4b5ec708c62bfb6db45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Mon, 20 Feb 2023 23:04:20 +0100 Subject: [PATCH] Create a new DB user when somebody logs in using SAML --- config/packages/hslavich_onelogin_saml.yaml | 2 +- config/packages/security.yaml | 19 +++------ config/services.yaml | 3 ++ src/Entity/UserSystem/User.php | 23 ++++++++++- .../UserSystem/LoginSuccessSubscriber.php | 5 ++- src/Security/SamlUserFactory.php | 41 +++++++++++++++++++ 6 files changed, 75 insertions(+), 18 deletions(-) create mode 100644 src/Security/SamlUserFactory.php diff --git a/config/packages/hslavich_onelogin_saml.yaml b/config/packages/hslavich_onelogin_saml.yaml index de3882ab..d33376d3 100644 --- a/config/packages/hslavich_onelogin_saml.yaml +++ b/config/packages/hslavich_onelogin_saml.yaml @@ -28,7 +28,7 @@ hslavich_onelogin_saml: # nameIdEncrypted: false authnRequestsSigned: true logoutRequestSigned: true - # logoutResponseSigned: false + logoutResponseSigned: true # wantMessagesSigned: false # wantAssertionsSigned: true # wantNameIdEncrypted: false diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 0e3b5c88..6758cf80 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -4,23 +4,13 @@ security: password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' - # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers providers: - local_users: + # used to reload user from session & other features (e.g. switch_user) + app_user_provider: entity: class: App\Entity\UserSystem\User property: name - saml_users: - saml: - user_class: App\Entity\UserSystem\User - default_roles: [ 'ROLE_USER' ] - - # used to reload user from session & other features (e.g. switch_user) - app_user_provider: - chain: - providers: ['local_users', 'saml_users'] - firewalls: dev: @@ -41,8 +31,9 @@ security: max_attempts: 5 # per minute saml: - #username_attribute: username - #use_attribute_friendly_name: false + use_referer: true + user_factory: saml_user_factory + persist_user: true check_path: saml_acs login_path: saml_login failure_path: saml_login diff --git a/config/services.yaml b/config/services.yaml index f2200115..5b5f1f35 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -127,6 +127,9 @@ services: # Security #################################################################################################################### + saml_user_factory: + class: App\Security\SamlUserFactory + #################################################################################################################### # Cache #################################################################################################################### diff --git a/src/Entity/UserSystem/User.php b/src/Entity/UserSystem/User.php index 56034dfd..e29880db 100644 --- a/src/Entity/UserSystem/User.php +++ b/src/Entity/UserSystem/User.php @@ -30,6 +30,7 @@ use App\Security\Interfaces\HasPermissionsInterface; use App\Validator\Constraints\Selectable; use App\Validator\Constraints\ValidPermission; use App\Validator\Constraints\ValidTheme; +use Hslavich\OneloginSamlBundle\Security\User\SamlUserInterface; use Jbtronics\TFAWebauthn\Model\LegacyU2FKeyInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Webauthn\PublicKeyCredentialUserEntity; @@ -60,7 +61,8 @@ use Jbtronics\TFAWebauthn\Model\TwoFactorInterface as WebauthnTwoFactorInterface * @ORM\EntityListeners({"App\EntityListeners\TreeCacheInvalidationListener"}) * @UniqueEntity("name", message="validator.user.username_already_used") */ -class User extends AttachmentContainingDBElement implements UserInterface, HasPermissionsInterface, TwoFactorInterface, BackupCodeInterface, TrustedDeviceInterface, WebauthnTwoFactorInterface, PreferredProviderInterface, PasswordAuthenticatedUserInterface +class User extends AttachmentContainingDBElement implements UserInterface, HasPermissionsInterface, TwoFactorInterface, + BackupCodeInterface, TrustedDeviceInterface, WebauthnTwoFactorInterface, PreferredProviderInterface, PasswordAuthenticatedUserInterface, SamlUserInterface { //use MasterAttachmentTrait; @@ -860,4 +862,23 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe { $this->webauthn_keys->add($webauthnKey); } + + public function setSamlAttributes(array $attributes) + { + //When mail attribute exists, set it + if (isset($attributes['email'])) { + $this->setEmail($attributes['email'][0]); + } + //When first name attribute exists, set it + if (isset($attributes['firstName'])) { + $this->setFirstName($attributes['firstName'][0]); + } + //When last name attribute exists, set it + if (isset($attributes['lastName'])) { + $this->setLastName($attributes['lastName'][0]); + } + if (isset($attributes['department'])) { + $this->setDepartment($attributes['department'][0]); + } + } } diff --git a/src/EventSubscriber/UserSystem/LoginSuccessSubscriber.php b/src/EventSubscriber/UserSystem/LoginSuccessSubscriber.php index 00b99fca..5e18826b 100644 --- a/src/EventSubscriber/UserSystem/LoginSuccessSubscriber.php +++ b/src/EventSubscriber/UserSystem/LoginSuccessSubscriber.php @@ -57,10 +57,11 @@ final class LoginSuccessSubscriber implements EventSubscriberInterface $ip = $event->getRequest()->getClientIp(); $log = new UserLoginLogEntry($ip, $this->gpdr_compliance); $user = $event->getAuthenticationToken()->getUser(); - if ($user instanceof User) { + if ($user instanceof User && $user->getID()) { $log->setTargetElement($user); + $this->eventLogger->logAndFlush($log); } - $this->eventLogger->logAndFlush($log); + $this->flashBag->add('notice', $this->translator->trans('flash.login_successful')); } diff --git a/src/Security/SamlUserFactory.php b/src/Security/SamlUserFactory.php new file mode 100644 index 00000000..b5659da6 --- /dev/null +++ b/src/Security/SamlUserFactory.php @@ -0,0 +1,41 @@ +. + */ + +namespace App\Security; + +use App\Entity\UserSystem\User; +use Hslavich\OneloginSamlBundle\Security\User\SamlUserFactoryInterface; +use Symfony\Component\Security\Core\User\UserInterface; + +class SamlUserFactory implements SamlUserFactoryInterface +{ + public function createUser($username, array $attributes = []): UserInterface + { + $user = new User(); + $user->setName($username); + $user->setNeedPwChange(false); + $user->setPassword('$$SAML$$'); + + $user->setSamlAttributes($attributes); + + + return $user; + } +} \ No newline at end of file