From 2857c2d7ff34c2b0ca9fdd43ed657799d2224631 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Wed, 27 Sep 2017 16:06:52 +1300 Subject: [PATCH] API Remove SAML module code and update namespaces for SilverStripe\LDAP --- .travis.yml | 4 +- .upgrade.yml | 23 -- CHANGELOG.md | 64 ------ README.md | 11 +- _config/ldap.yml | 22 +- _config/legacy.yml | 6 - _config/saml.yml | 32 --- composer.json | 15 +- license.md | 2 +- phpunit.xml.dist | 6 +- src/Authenticators/LDAPAuthenticator.php | 10 +- .../LDAPChangePasswordHandler.php | 6 +- src/Authenticators/LDAPLoginHandler.php | 4 +- .../LDAPLostPasswordHandler.php | 14 +- src/Authenticators/LDAPMemberLoginHandler.php | 6 +- src/Authenticators/SAMLAuthenticator.php | 92 -------- src/Authenticators/SAMLLoginForm.php | 105 --------- src/Authenticators/SAMLLoginHandler.php | 17 -- src/Authenticators/SAMLSecurityExtension.php | 64 ------ src/Control/LDAPDebugController.php | 10 +- src/Control/SAMLController.php | 200 ------------------ src/Extensions/LDAPGroupExtension.php | 13 +- src/Extensions/LDAPMemberExtension.php | 6 +- src/Extensions/SAMLMemberExtension.php | 50 ----- src/Forms/LDAPChangePasswordForm.php | 12 +- src/Forms/LDAPLoginForm.php | 6 +- src/Helpers/SAMLHelper.php | 39 ---- src/Jobs/LDAPAllSyncJob.php | 6 +- src/Jobs/LDAPMemberSyncJob.php | 6 +- src/Model/LDAPGateway.php | 4 +- src/Model/LDAPGroupMapping.php | 8 +- src/Model/LDAPUtil.php | 4 +- src/Services/LDAPService.php | 12 +- src/Services/SAMLConfiguration.php | 150 ------------- src/Tasks/LDAPGroupSyncTask.php | 5 +- src/Tasks/LDAPMemberSyncTask.php | 7 +- src/Tasks/LDAPMigrateExistingMembersTask.php | 11 +- tests/php/FakeGatewayTest.php | 8 +- tests/php/LDAPAuthenticatorTest.php | 6 +- tests/php/LDAPServiceTest.php | 16 +- tests/php/Model/LDAPFakeGateway.php | 9 +- 41 files changed, 108 insertions(+), 983 deletions(-) delete mode 100644 .upgrade.yml delete mode 100644 CHANGELOG.md delete mode 100644 _config/legacy.yml delete mode 100644 _config/saml.yml delete mode 100644 src/Authenticators/SAMLAuthenticator.php delete mode 100644 src/Authenticators/SAMLLoginForm.php delete mode 100644 src/Authenticators/SAMLLoginHandler.php delete mode 100644 src/Authenticators/SAMLSecurityExtension.php delete mode 100644 src/Control/SAMLController.php delete mode 100644 src/Extensions/SAMLMemberExtension.php delete mode 100644 src/Helpers/SAMLHelper.php delete mode 100644 src/Services/SAMLConfiguration.php diff --git a/.travis.yml b/.travis.yml index 3ffecec..cd59baa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: php env: global: - - COMPOSER_ROOT_VERSION="4.0.x-dev" + - COMPOSER_ROOT_VERSION="1.0.x-dev" matrix: include: @@ -26,7 +26,7 @@ before_script: - composer update script: - - if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit tests/; fi + - if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit; fi - if [[ $PHPUNIT_COVERAGE_TEST ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-clover=coverage.xml; fi - if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs --standard=framework/phpcs.xml.dist src/ tests/ ; fi diff --git a/.upgrade.yml b/.upgrade.yml deleted file mode 100644 index 3524e56..0000000 --- a/.upgrade.yml +++ /dev/null @@ -1,23 +0,0 @@ -mappings: - LDAPAuthenticator: SilverStripe\ActiveDirectory\Authenticators\LDAPAuthenticator - LDAPLoginForm: SilverStripe\ActiveDirectory\Forms\LDAPLoginForm - SAMLAuthenticator: SilverStripe\ActiveDirectory\Authenticators\SAMLAuthenticator - SAMLLoginForm: SilverStripe\ActiveDirectory\Authenticators\SAMLLoginForm - SAMLSecurityExtension: SilverStripe\ActiveDirectory\Authenticators\SAMLSecurityExtension - LDAPDebugController: SilverStripe\ActiveDirectory\Control\LDAPDebugController - SAMLController: SilverStripe\ActiveDirectory\Control\SAMLController - LDAPGroupExtension: SilverStripe\ActiveDirectory\Extensions\LDAPGroupExtension - LDAPMemberExtension: SilverStripe\ActiveDirectory\Extensions\LDAPMemberExtension - SAMLMemberExtension: SilverStripe\ActiveDirectory\Extensions\SAMLMemberExtension - LDAPChangePasswordForm: SilverStripe\ActiveDirectory\Forms\LDAPChangePasswordForm - SAMLHelper: SilverStripe\ActiveDirectory\Helpers\SAMLHelper - LDAPAllSyncJob: SilverStripe\ActiveDirectory\Jobs\LDAPAllSyncJob - LDAPMemberSyncJob: SilverStripe\ActiveDirectory\Jobs\LDAPMemberSyncJob - LDAPGateway: SilverStripe\ActiveDirectory\Model\LDAPGateway - LDAPGroupMapping: SilverStripe\ActiveDirectory\Model\LDAPGroupMapping - LDAPUtil: SilverStripe\ActiveDirectory\Model\LDAPUtil - LDAPService: SilverStripe\ActiveDirectory\Services\LDAPService - SAMLConfiguration: SilverStripe\ActiveDirectory\Services\SAMLConfiguration - LDAPGroupSyncTask: SilverStripe\ActiveDirectory\Tasks\LDAPGroupSyncTask - LDAPMemberSyncTask: SilverStripe\ActiveDirectory\Tasks\LDAPMemberSyncTask - LDAPMigrateExistingMembersTask: SilverStripe\ActiveDirectory\Tasks\LDAPMigrateExistingMembersTask diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 27b1f20..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,64 +0,0 @@ -# Changelog - -## 4.0.0 (Unreleased) - -New module requirements: - - - Minimum SilverStripe framework version: 4.0 or above - - Minimum PHP version: 5.5 or above - - Support for PHP 7 - -## 3.0.0 (Unreleased) - -Adding features to allow writing Member data back to LDAP. -See [Writing LDAP data from SilverStripe](docs/en/developer.md#writing-ldap-data-from-silverstripe). - - - IsImportedFromLDAP field removed from Group and Member. To determine if - either of these are imported from LDAP, check if the GUID field is not NULL. - -## 2.0.0 - -LDAP functionality that modifies user data (i.e. password reset) will require -binding credentials with LDAP write access. - - - SAML defaults to the SHA-256 hash signature hash - - An issue was fixed where absolute paths couldn't be used for certificates and - keys in YAML configuration. - - Better LDAP group syncing that isn't as likely to crash and leave the database - in an unknown state. - - Removes LDAP group mappings when a security group is deleted - - Minor UI changes for the login form - - Moved the AD fields in the CMS to a separate tab and made them read-only. - - Member "last synced" time is now showing the correct date and time. - - Adding a script to rotate LDAP binding credentials for system administrators - - Samba has been confirmed to work - - Automatic syncing of LDAP groups and users via the `LDAPAllSyncJob` build task - - Users can now reset their AD password via the "I've lost my password" on the - login form. - - Updated documentation - -The source code is now following the SilverStripe supported modules standard. - -## 1.0.0 - -Initial release. - -# Migration - -## 2.0.0 - -This module is now using SHA-256 hashing algorithm for the SAML integration. -SHA-1 is no longer recommended. - -If you are upgrading from an earlier version you will need to change the "secure -hash algorithm" setting in ADFS from `SHA-1` to `SHA-256`, see -[Set the secure hash algorithm](docs/en/adfs.md#set-the-secure-hash-algorithm). - -If you can't change the ADFS setting, you will need to downgrade to SHA-1 -in YAML, i.e `mysite/_config/saml.yml`: - -``` -SAMLConfiguration: - Security: - signatureAlgorithm: "http://www.w3.org/2000/09/xmldsig#rsa-sha1" -``` diff --git a/README.md b/README.md index 1ba9541..29f256c 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ -# SilverStripe Active Directory module +# SilverStripe LDAP module -[![Build Status](https://secure.travis-ci.org/silverstripe/silverstripe-activedirectory.svg)](https://travis-ci.org/silverstripe/silverstripe-activedirectory) +[![Build Status](https://secure.travis-ci.org/silverstripe/silverstripe-ldap.svg)](https://travis-ci.org/silverstripe/silverstripe-ldap) ## Introduction -This SilverStripe module provides Active Directory integration. It comes with three major components: +This SilverStripe module provides LDAP integration. It comes with two major components: -* Single sign-on authentication with SAML * Synchronisation of Active Directory users and group memberships via LDAP * Active Directory authentication via LDAP binding @@ -14,7 +13,7 @@ These components may be used in any combination, also alongside the default Silv ## Requirements - * PHP 5.5+ with extensions: ldap, openssl, dom, and mcrypt + * PHP 5.6+ with extensions: ldap, openssl, dom, and mcrypt * SilverStripe 4.0+ * Active Directory on Windows Server 2008 R2 or greater (AD) * Active Directory Federation Services 2.0 or greater (ADFS) @@ -65,4 +64,4 @@ AD user synchronisation and authentication is hidden behind the backend (server ## Changelog -The changelog can be found at [CHANGELOG.MD](CHANGELOG.MD). +Please see the GitHub releases for changes. diff --git a/_config/ldap.yml b/_config/ldap.yml index 52eadc9..185d924 100644 --- a/_config/ldap.yml +++ b/_config/ldap.yml @@ -3,19 +3,19 @@ Name: ldapconfig --- SilverStripe\Control\Director: rules: - 'LDAPDebug': SilverStripe\ActiveDirectory\Control\LDAPDebugController + 'LDAPDebug': SilverStripe\LDAP\Control\LDAPDebugController SilverStripe\Security\Group: extensions: - - SilverStripe\ActiveDirectory\Extensions\LDAPGroupExtension + - SilverStripe\LDAP\Extensions\LDAPGroupExtension SilverStripe\Security\Member: extensions: - - SilverStripe\ActiveDirectory\Extensions\LDAPMemberExtension + - SilverStripe\LDAP\Extensions\LDAPMemberExtension -SilverStripe\ActiveDirectory\Authenticators\LDAPAuthenticator: +SilverStripe\LDAP\Authenticators\LDAPAuthenticator: name: "LDAP" -SilverStripe\ActiveDirectory\Services\LDAPService: +SilverStripe\LDAP\Services\LDAPService: allow_password_change: false SilverStripe\Core\Injector\Injector: @@ -28,20 +28,20 @@ SilverStripe\Core\Injector\Injector: SilverStripe\Dev\Backtrace: ignore_function_args: - - - 'SilverStripe\\ActiveDirectory\\Model\\LDAPGateway' + - 'SilverStripe\\LDAP\\Model\\LDAPGateway' - 'authenticate' - - - 'SilverStripe\\ActiveDirectory\\Model\\LDAPGateway' + - 'SilverStripe\\LDAP\\Model\\LDAPGateway' - 'changePassword' - - - 'SilverStripe\\ActiveDirectory\\Model\\LDAPGateway' + - 'SilverStripe\\LDAP\\Model\\LDAPGateway' - 'resetPassword' - - - 'SilverStripe\\ActiveDirectory\\Services\\LDAPService' + - 'SilverStripe\\LDAP\\Services\\LDAPService' - 'authenticate' - - - 'SilverStripe\\ActiveDirectory\\Services\\LDAPService' + - 'SilverStripe\\LDAP\\Services\\LDAPService' - 'setPassword' - - - 'SilverStripe\\ActiveDirectory\\Services\\LDAPService' + - 'SilverStripe\\LDAP\\Services\\LDAPService' - 'passwordHistoryWorkaround' diff --git a/_config/legacy.yml b/_config/legacy.yml deleted file mode 100644 index ba6080b..0000000 --- a/_config/legacy.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -Name: activedirectorylegacy ---- -SilverStripe\ORM\DatabaseAdmin: - classname_value_remapping: - LDAPGroupMapping: SilverStripe\ActiveDirectory\Model\LDAPGroupMapping diff --git a/_config/saml.yml b/_config/saml.yml deleted file mode 100644 index feb04f8..0000000 --- a/_config/saml.yml +++ /dev/null @@ -1,32 +0,0 @@ ---- -Name: samlsettings -After: '#rootroutes' ---- -SilverStripe\Control\Director: - rules: - 'saml': SilverStripe\ActiveDirectory\Control\SAMLController - -SilverStripe\Security\Member: - extensions: - - SilverStripe\ActiveDirectory\Extensions\SAMLMemberExtension - -SilverStripe\Security\Security: - extensions: - - SilverStripe\ActiveDirectory\Authenticators\SAMLSecurityExtension - -SilverStripe\Core\Injector\Injector: - SAMLConfService: SilverStripe\ActiveDirectory\Services\SAMLConfiguration - -SilverStripe\ActiveDirectory\Authenticators\SAMLAuthenticator: - name: "SAML" - -SilverStripe\ActiveDirectory\Services\SAMLConfiguration: - strict: true - debug: false - Security: - # Algorithm that the toolkit will use on signing process. Options: - # - 'http://www.w3.org/2000/09/xmldsig#rsa-sha1' - # - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' - # - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384' - # - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512' - signatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" diff --git a/composer.json b/composer.json index b6d025e..8438486 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { - "name": "silverstripe/activedirectory", - "description": "Adds Active Directory support to SilverStripe including user synchronisation and SSO/LDAP authentication", + "name": "silverstripe/ldap", + "description": "Adds LDAP support to SilverStripe including user synchronisation and authentication", "type": "silverstripe-module", - "keywords": ["silverstripe", "ad", "active", "directory", "ldap", "sso", "saml"], + "keywords": ["silverstripe", "ad", "active", "directory", "ldap"], "license": "BSD-3-Clause", "authors": [ { @@ -21,8 +21,7 @@ "symbiote/silverstripe-queuedjobs": "^4@dev", "zendframework/zend-ldap": "^2.5.1", "zendframework/zend-authentication": "^2.5.1", - "zendframework/zend-session": "^2.5.1", - "onelogin/php-saml": "^2.10.7" + "zendframework/zend-session": "^2.5.1" }, "require-dev": { "phpunit/phpunit": "^5.7", @@ -30,13 +29,13 @@ }, "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "SilverStripe\\ActiveDirectory\\": "src/", - "SilverStripe\\ActiveDirectory\\Tests\\": "tests/" + "SilverStripe\\LDAP\\": "src/", + "SilverStripe\\LDAP\\Tests\\": "tests/" } }, "minimum-stability": "dev", diff --git a/license.md b/license.md index 9445c8e..8794670 100644 --- a/license.md +++ b/license.md @@ -1,4 +1,4 @@ -Copyright (c) 2016, SilverStripe Limited +Copyright (c) 2017, SilverStripe Limited All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5dd6854..94af341 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,14 @@ - - tests + tests/ - src/. + src/ tests/ - diff --git a/src/Authenticators/LDAPAuthenticator.php b/src/Authenticators/LDAPAuthenticator.php index d6ff298..198aeb7 100644 --- a/src/Authenticators/LDAPAuthenticator.php +++ b/src/Authenticators/LDAPAuthenticator.php @@ -1,14 +1,14 @@ get(LDAPAuthenticator::class, 'allow_email_login') != 'yes') { $form->sessionMessage( _t( - 'SilverStripe\\ActiveDirectory\\Forms\\LDAPLoginForm.USERNAMEINSTEADOFEMAIL', + 'SilverStripe\\LDAP\\Forms\\LDAPLoginForm.USERNAMEINSTEADOFEMAIL', 'Please enter your username instead of your email to get a password reset link.' ), 'bad' @@ -133,7 +133,7 @@ public function forgotPassword($data, $form) if (Config::inst()->get(LDAPAuthenticator::class, 'allow_email_login') === 'yes') { $form->sessionMessage( _t( - 'SilverStripe\\ActiveDirectory\\Forms\\LDAPLoginForm.ENTERUSERNAMEOREMAIL', + 'SilverStripe\\LDAP\\Forms\\LDAPLoginForm.ENTERUSERNAMEOREMAIL', 'Please enter your username or your email address to get a password reset link.' ), 'bad' @@ -141,7 +141,7 @@ public function forgotPassword($data, $form) } else { $form->sessionMessage( _t( - 'SilverStripe\\ActiveDirectory\\Forms\\LDAPLoginForm.ENTERUSERNAME', + 'SilverStripe\\LDAP\\Forms\\LDAPLoginForm.ENTERUSERNAME', 'Please enter your username to get a password reset link.' ), 'bad' @@ -159,8 +159,8 @@ public function forgotPassword($data, $form) public function lostPasswordForm() { $loginFieldLabel = (Config::inst()->get(LDAPAuthenticator::class, 'allow_email_login') === 'yes') ? - _t('SilverStripe\\ActiveDirectory\\Forms\\LDAPLoginForm.USERNAMEOREMAIL', 'Username or email') : - _t('SilverStripe\\ActiveDirectory\\Forms\\LDAPLoginForm.USERNAME', 'Username'); + _t('SilverStripe\\LDAP\\Forms\\LDAPLoginForm.USERNAMEOREMAIL', 'Username or email') : + _t('SilverStripe\\LDAP\\Forms\\LDAPLoginForm.USERNAME', 'Username'); $loginField = TextField::create('Login', $loginFieldLabel); $action = FormAction::create( diff --git a/src/Authenticators/LDAPMemberLoginHandler.php b/src/Authenticators/LDAPMemberLoginHandler.php index 3fc3a5a..59d22fe 100644 --- a/src/Authenticators/LDAPMemberLoginHandler.php +++ b/src/Authenticators/LDAPMemberLoginHandler.php @@ -1,11 +1,7 @@ get(self::class, 'name'); - } - - /** - * @param Controller $controller - * @return SAMLLoginForm - */ - public static function get_login_form(Controller $controller) - { - return new SAMLLoginForm($controller, 'LoginForm'); - } - - /** - * Sends the authentication process down the SAML rabbit hole. It will trigger - * the IdP redirection via the 3rd party implementation, and if successful, the user - * will be delivered to the SAMLController::acs. - * - * @param array $data - * @param HTTPRequest $request - * @param ValidationResult|null $result - * @return bool|Member|void - */ - public function authenticate(array $data, HTTPRequest $request, ValidationResult &$result = null) - { - // $data is not used - the form is just one button, with no fields. - $auth = Injector::inst()->get(SAMLHelper::class)->getSAMLAuth(); - $request->getSession()->set('BackURL', isset($data['BackURL']) ? $data['BackURL'] : null); - $request->getSession()->save($request); - $auth->login(Director::absoluteBaseURL().'saml/'); - } - - /** - * @inheritdoc - */ - public function getLoginHandler($link) - { - return SAMLLoginHandler::create($link, $this); - } - - /** - * @inheritdoc - */ - public function supportedServices() - { - return Authenticator::LOGIN | Authenticator::LOGOUT; - } -} diff --git a/src/Authenticators/SAMLLoginForm.php b/src/Authenticators/SAMLLoginForm.php deleted file mode 100644 index 2382dce..0000000 --- a/src/Authenticators/SAMLLoginForm.php +++ /dev/null @@ -1,105 +0,0 @@ -getSession()->get('BackURL'); - - if (!empty($this->getRequest()->requestVar('BackURL'))) { - $backURL = $this->getRequest()->requestVar('BackURL'); - } - if ($this->shouldShowLogoutFields()) { - $fields = FieldList::create([ - HiddenField::create('AuthenticationMethod', null, $this->authenticator_class, $this) - ]); - $actions = FieldList::create([ - FormAction::create( - 'logout', - _t('SilverStripe\\Security\\Member.BUTTONLOGINOTHER', 'Log in as someone else') - ) - ]); - } else { - $fields = $this->getFormFields(); - $actions = $this->getFormActions(); - } - - if ($backURL) { - $fields->push(HiddenField::create('BackURL', 'BackURL', $backURL)); - } - - $this->setFormMethod('POST', true); - - parent::__construct($controller, $name, $fields, $actions); - } - - protected function getFormFields() - { - return FieldList::create([ - HiddenField::create('AuthenticationMethod', null, $this->authenticator_class, $this) - ]); - } - - protected function getFormActions() - { - return FieldList::create([ - FormAction::create('dologin', _t('SilverStripe\\Security\\Member.BUTTONLOGIN', 'Log in')) - ]); - } - - /** - * @return bool - */ - protected function shouldShowLogoutFields() - { - if (!Security::getCurrentUser()) { - return false; - } - return true; - } -} diff --git a/src/Authenticators/SAMLLoginHandler.php b/src/Authenticators/SAMLLoginHandler.php deleted file mode 100644 index fc8d436..0000000 --- a/src/Authenticators/SAMLLoginHandler.php +++ /dev/null @@ -1,17 +0,0 @@ -authenticator), - 'LoginForm' - ); - } -} diff --git a/src/Authenticators/SAMLSecurityExtension.php b/src/Authenticators/SAMLSecurityExtension.php deleted file mode 100644 index d0e74c6..0000000 --- a/src/Authenticators/SAMLSecurityExtension.php +++ /dev/null @@ -1,64 +0,0 @@ -owner->request->getVar('showloginform') == 1) { - return; - } - - // if member is already logged in, don't auto-sign-on, this is most likely because - // of insufficient permissions. - $member = Security::getCurrentUser(); - if ($member && $member->exists()) { - return; - } - $session = $this->owner->getRequest()->getSession(); - // if there are form messages, don't auto-sign-on, this is most likely because of - // login errors / failures or other notices. - if ($session->get('FormInfo')) { - // since FormInfo can be a "nulled" array, we have to check - foreach ($session->get('FormInfo') as $form => $info) { - foreach ($info as $name => $value) { - if ($value !== null) { - return; - } - } - } - } - - $backURL = $session->get('BackURL'); - if ($this->owner->request->getVar('BackURL')) { - $backURL = $this->owner->request->getVar('BackURL'); - } - - $this->owner->getRequest()->getSession()->set('BackURL', $backURL); - } -} diff --git a/src/Control/LDAPDebugController.php b/src/Control/LDAPDebugController.php index 58d2363..5dc19a4 100644 --- a/src/Control/LDAPDebugController.php +++ b/src/Control/LDAPDebugController.php @@ -1,13 +1,13 @@ get(SAMLHelper::class)->getSAMLAuth(); - $auth->processResponse(); - - $error = $auth->getLastErrorReason(); - if (!empty($error)) { - $this->getLogger()->error($error); - - $this->getForm()->sessionMessage("Authentication error: '{$error}'", 'bad'); - $this->getRequest()->getSession()->save($this->getRequest()); - return $this->getRedirect(); - } - - if (!$auth->isAuthenticated()) { - $this->getForm()->sessionMessage(_t('SilverStripe\\Security\\Member.ERRORWRONGCRED'), 'bad'); - $this->getRequest()->getSession()->save($this->getRequest()); - return $this->getRedirect(); - } - - $decodedNameId = base64_decode($auth->getNameId()); - // check that the NameID is a binary string (which signals that it is a guid - if (ctype_print($decodedNameId)) { - $this->getForm()->sessionMessage('Name ID provided by IdP is not a binary GUID.', 'bad'); - $this->getRequest()->getSession()->save($this->getRequest()); - return $this->getRedirect(); - } - - // transform the NameId to guid - $guid = LDAPUtil::bin_to_str_guid($decodedNameId); - if (!LDAPUtil::validGuid($guid)) { - $errorMessage = "Not a valid GUID '{$guid}' recieved from server."; - $this->getLogger()->error($errorMessage); - $this->getForm()->sessionMessage($errorMessage, 'bad'); - $this->getRequest()->getSession()->save($this->getRequest()); - return $this->getRedirect(); - } - - // Write a rudimentary member with basic fields on every login, so that we at least have something - // if LDAP synchronisation fails. - $member = Member::get()->filter('GUID', $guid)->limit(1)->first(); - if (!($member && $member->exists())) { - $member = new Member(); - $member->GUID = $guid; - } - - $attributes = $auth->getAttributes(); - - foreach ($member->config()->claims_field_mappings as $claim => $field) { - if (!isset($attributes[$claim][0])) { - $this->getLogger()->warning( - sprintf( - 'Claim rule \'%s\' configured in LDAPMember.claims_field_mappings, ' . - 'but wasn\'t passed through. Please check IdP claim rules.', - $claim - ) - ); - - continue; - } - - $member->$field = $attributes[$claim][0]; - } - - $member->SAMLSessionIndex = $auth->getSessionIndex(); - - // This will trigger LDAP update through LDAPMemberExtension::memberLoggedIn. - // The LDAP update will also write the Member record. We shouldn't write before - // calling this, as any onAfterWrite hooks that attempt to update LDAP won't - // have the Username field available yet for new Member records, and fail. - // Both SAML and LDAP identify Members by the GUID field. - Security::setCurrentUser($member); - - return $this->getRedirect(); - } - - /** - * Generate this SP's metadata. This is needed for intialising the SP-IdP relationship. - * IdP is instructed to call us back here to establish the relationship. IdP may also be configured - * to hit this endpoint periodically during normal operation, to check the SP availability. - */ - public function metadata() - { - try { - $auth = Injector::inst()->get('SilverStripe\\ActiveDirectory\\Helpers\\SAMLHelper')->getSAMLAuth(); - $settings = $auth->getSettings(); - $metadata = $settings->getSPMetadata(); - $errors = $settings->validateMetadata($metadata); - if (empty($errors)) { - header('Content-Type: text/xml'); - echo $metadata; - } else { - throw new \OneLogin_Saml2_Error( - 'Invalid SP metadata: ' . implode(', ', $errors), - \OneLogin_Saml2_Error::METADATA_SP_INVALID - ); - } - } catch (Exception $e) { - $this->getLogger()->error($e->getMessage()); - echo $e->getMessage(); - } - } - - /** - * @return HTTPResponse - */ - protected function getRedirect() - { - // Absolute redirection URLs may cause spoofing - if ($this->getRequest()->getSession()->get('BackURL') - && Director::is_site_url($this->getRequest()->getSession()->get('BackURL'))) { - return $this->redirect($this->getRequest()->getSession()->get('BackURL')); - } - - // Spoofing attack, redirect to homepage instead of spoofing url - if ($this->getRequest()->getSession()->get('BackURL') - && !Director::is_site_url($this->getRequest()->getSession()->get('BackURL'))) { - return $this->redirect(Director::absoluteBaseURL()); - } - - // If a default login dest has been set, redirect to that. - if (Security::config()->default_login_dest) { - return $this->redirect(Director::absoluteBaseURL() . Security::config()->default_login_dest); - } - - // fallback to redirect back to home page - return $this->redirect(Director::absoluteBaseURL()); - } - - /** - * Get a logger - * - * @return LoggerInterface - */ - public function getLogger() - { - return Injector::inst()->get(LoggerInterface::class); - } - - /** - * Gets the login form - * - * @return SAMLLoginForm - */ - public function getForm() - { - return Injector::inst()->get(SAMLLoginForm::class); - } -} diff --git a/src/Extensions/LDAPGroupExtension.php b/src/Extensions/LDAPGroupExtension.php index 932938c..96204ec 100644 --- a/src/Extensions/LDAPGroupExtension.php +++ b/src/Extensions/LDAPGroupExtension.php @@ -1,20 +1,19 @@ 'SilverStripe\\ActiveDirectory\\Model\\LDAPGroupMapping' + 'LDAPGroupMappings' => LDAPGroupMapping::class, ]; /** diff --git a/src/Extensions/LDAPMemberExtension.php b/src/Extensions/LDAPMemberExtension.php index d4caf91..92e24b7 100644 --- a/src/Extensions/LDAPMemberExtension.php +++ b/src/Extensions/LDAPMemberExtension.php @@ -1,9 +1,9 @@ 'Varchar(50)', 'Username' => 'Varchar(64)', 'IsExpired' => 'Boolean', diff --git a/src/Extensions/SAMLMemberExtension.php b/src/Extensions/SAMLMemberExtension.php deleted file mode 100644 index 4522684..0000000 --- a/src/Extensions/SAMLMemberExtension.php +++ /dev/null @@ -1,50 +0,0 @@ - 'Varchar(255)', - // Unique user identifier, same field is used by LDAPMemberExtension - 'GUID' => 'Varchar(50)', - ]; - - /** - * These are used by {@link SAMLController} to map specific IdP claim rules - * to {@link Member} fields. Availability of these claim rules are defined - * on the IdP. - * - * @var array - * @config - */ - private static $claims_field_mappings = [ - 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname' => 'FirstName', - 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname' => 'Surname', - 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress' => 'Email' - ]; - - /** - * @param FieldList $fields - */ - public function updateCMSFields(FieldList $fields) - { - $fields->replaceField('GUID', ReadonlyField::create('GUID')); - $fields->removeFieldFromTab('Root', 'SAMLSessionIndex'); - } -} diff --git a/src/Forms/LDAPChangePasswordForm.php b/src/Forms/LDAPChangePasswordForm.php index 9b1ec6b..29166bb 100644 --- a/src/Forms/LDAPChangePasswordForm.php +++ b/src/Forms/LDAPChangePasswordForm.php @@ -1,13 +1,14 @@ '%$SilverStripe\\ActiveDirectory\\Services\\SAMLConfiguration', - ]; - - /** - * @var SAMLConfiguration - */ - public $SAMLConfService; - - /** - * @return OneLogin_Saml2_Auth - */ - public function getSAMLauth() - { - $samlConfig = $this->SAMLConfService->asArray(); - return new OneLogin_Saml2_Auth($samlConfig); - } -} diff --git a/src/Jobs/LDAPAllSyncJob.php b/src/Jobs/LDAPAllSyncJob.php index 7633384..1a6e271 100644 --- a/src/Jobs/LDAPAllSyncJob.php +++ b/src/Jobs/LDAPAllSyncJob.php @@ -1,9 +1,9 @@ 'SilverStripe\\Security\\Group' + 'Group' => Group::class ]; /** @@ -45,7 +47,7 @@ class LDAPGroupMapping extends DataObject * @var array */ private static $dependencies = [ - 'ldapService' => '%$SilverStripe\\ActiveDirectory\\Services\\LDAPService' + 'ldapService' => '%$' . LDAPService::class, ]; /** diff --git a/src/Model/LDAPUtil.php b/src/Model/LDAPUtil.php index 26db0e7..cefcea6 100644 --- a/src/Model/LDAPUtil.php +++ b/src/Model/LDAPUtil.php @@ -1,13 +1,11 @@ getLogger()->warning(sprintf('Cannot update Member ID %s, GUID not set', $member->ID)); $validationResult->addError( _t( - 'SilverStripe\\ActiveDirectory\\Authenticators\\LDAPAuthenticator.NOUSER', + 'SilverStripe\\LDAP\\Authenticators\\LDAPAuthenticator.NOUSER', 'Your account hasn\'t been setup properly, please contact an administrator.' ) ); @@ -1053,7 +1051,7 @@ public function setPassword(Member $member, $password, $oldPassword = null) if (empty($userData['distinguishedname'])) { $validationResult->addError( _t( - 'SilverStripe\\ActiveDirectory\\Authenticators\\LDAPAuthenticator.NOUSER', + 'SilverStripe\\LDAP\\Authenticators\\LDAPAuthenticator.NOUSER', 'Your account hasn\'t been setup properly, please contact an administrator.' ) ); diff --git a/src/Services/SAMLConfiguration.php b/src/Services/SAMLConfiguration.php deleted file mode 100644 index 8c1b65d..0000000 --- a/src/Services/SAMLConfiguration.php +++ /dev/null @@ -1,150 +0,0 @@ -config()->get('strict'); - $conf['debug'] = $this->config()->get('debug'); - - // SERVICE PROVIDER SECTION - $sp = $this->config()->get('SP'); - $spCertPath = Director::is_absolute($sp['x509cert']) - ? $sp['x509cert'] - : sprintf('%s/%s', BASE_PATH, $sp['x509cert']); - $spKeyPath = Director::is_absolute($sp['privateKey']) - ? $sp['privateKey'] - : sprintf('%s/%s', BASE_PATH, $sp['privateKey']); - - // set baseurl for SAML messages coming back to the SP - $conf['baseurl'] = $sp['entityId']; - - $conf['sp']['entityId'] = $sp['entityId']; - $conf['sp']['assertionConsumerService'] = [ - 'url' => $sp['entityId'] . '/saml/acs', - 'binding' => OneLogin_Saml2_Constants::BINDING_HTTP_POST - ]; - $conf['sp']['NameIDFormat'] = isset($sp['nameIdFormat']) ? - $sp['nameIdFormat'] : OneLogin_Saml2_Constants::NAMEID_TRANSIENT; - $conf['sp']['x509cert'] = file_get_contents($spCertPath); - $conf['sp']['privateKey'] = file_get_contents($spKeyPath); - - // IDENTITY PROVIDER SECTION - $idp = $this->config()->get('IdP'); - $conf['idp']['entityId'] = $idp['entityId']; - $conf['idp']['singleSignOnService'] = [ - 'url' => $idp['singleSignOnService'], - 'binding' => OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT, - ]; - if (isset($idp['singleLogoutService'])) { - $conf['idp']['singleLogoutService'] = [ - 'url' => $idp['singleLogoutService'], - 'binding' => OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT, - ]; - } - - $idpCertPath = Director::is_absolute($idp['x509cert']) - ? $idp['x509cert'] - : sprintf('%s/%s', BASE_PATH, $idp['x509cert']); - $conf['idp']['x509cert'] = file_get_contents($idpCertPath); - - // SECURITY SECTION - $security = $this->config()->get('Security'); - $signatureAlgorithm = $security['signatureAlgorithm']; - - $conf['security'] = [ - /** signatures and encryptions offered */ - // Indicates that the nameID of the sent by this SP will be encrypted. - 'nameIdEncrypted' => true, - // Indicates whether the messages sent by this SP will be signed. [Metadata of the - // SP will offer this info] - 'authnRequestsSigned' => true, - // Indicates whether the messages sent by this SP will be signed. - 'logoutRequestSigned' => true, - // Indicates whether the messages sent by this SP will be signed. - 'logoutResponseSigned' => true, - 'signMetadata' => false, - /** signatures and encryptions required **/ - // Indicates a requirement for the , - // and elements received by this SP to be signed. - 'wantMessagesSigned' => false, - // Indicates a requirement for the elements received by - // this SP to be signed. [Metadata of the SP will offer this info] - 'wantAssertionsSigned' => true, - // Indicates a requirement for the NameID received by - // this SP to be encrypted. - 'wantNameIdEncrypted' => false, - - // Algorithm that the toolkit will use on signing process. Options: - // - 'http://www.w3.org/2000/09/xmldsig#rsa-sha1' - // - 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' - // - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' - // - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384' - // - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512' - 'signatureAlgorithm' => $signatureAlgorithm, - - // Authentication context. - // Set to false and no AuthContext will be sent in the AuthNRequest, - // Set true or don't present thi parameter and you will get an AuthContext - // 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport' - // Set an array with the possible auth context values: - // array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'), - 'requestedAuthnContext' => [ - 'urn:federation:authentication:windows', - 'urn:oasis:names:tc:SAML:2.0:ac:classes:Password', - 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509', - ], - // Indicates if the SP will validate all received xmls. - // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true). - 'wantXMLValidation' => true, - ]; - - return $conf; - } -} diff --git a/src/Tasks/LDAPGroupSyncTask.php b/src/Tasks/LDAPGroupSyncTask.php index 7143aee..d88cbf4 100644 --- a/src/Tasks/LDAPGroupSyncTask.php +++ b/src/Tasks/LDAPGroupSyncTask.php @@ -1,10 +1,11 @@ '%$SilverStripe\\ActiveDirectory\\Services\\LDAPService' + 'ldapService' => '%$' . LDAPService::class, ]; /** diff --git a/src/Tasks/LDAPMemberSyncTask.php b/src/Tasks/LDAPMemberSyncTask.php index 97cc8db..4039686 100644 --- a/src/Tasks/LDAPMemberSyncTask.php +++ b/src/Tasks/LDAPMemberSyncTask.php @@ -1,12 +1,13 @@ '%$SilverStripe\\ActiveDirectory\\Services\\LDAPService' + 'ldapService' => '%$' . LDAPService::class, ]; /** diff --git a/src/Tasks/LDAPMigrateExistingMembersTask.php b/src/Tasks/LDAPMigrateExistingMembersTask.php index 26eb636..e62f2ee 100644 --- a/src/Tasks/LDAPMigrateExistingMembersTask.php +++ b/src/Tasks/LDAPMigrateExistingMembersTask.php @@ -1,11 +1,12 @@ '%$SilverStripe\\ActiveDirectory\\Services\\LDAPService' + 'ldapService' => '%$' . LDAPService::class, ]; /** diff --git a/tests/php/FakeGatewayTest.php b/tests/php/FakeGatewayTest.php index 2c9294a..3004f86 100644 --- a/tests/php/FakeGatewayTest.php +++ b/tests/php/FakeGatewayTest.php @@ -1,12 +1,12 @@