mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Use Config
for authenticator settings
This commit is contained in:
parent
c21f71405f
commit
ff3ad6eb6b
@ -1015,6 +1015,23 @@ to update those with the appropriate function or config call. See
|
|||||||
[CMS architecture](/developer_guides/customising_the_admin_interface/cms-architecture#the-admin-url) for language
|
[CMS architecture](/developer_guides/customising_the_admin_interface/cms-architecture#the-admin-url) for language
|
||||||
specific functions.
|
specific functions.
|
||||||
|
|
||||||
|
#### Upgrading custom Authenticators
|
||||||
|
|
||||||
|
The methods `register` and `unregister` on `Authenticator` are deprecated in favor of the `Config` system. This means that any custom Authenticator needs to be registered through the yml config:
|
||||||
|
```yaml
|
||||||
|
SilverStripe\Security\Authenticator;
|
||||||
|
authenticators:
|
||||||
|
- MyVendor\MyModule\MyAuthenticator
|
||||||
|
```
|
||||||
|
If there is no authenticator registered, `Authenticator` will try to fall back on the `default_authenticator`, which can be changed using the following config, replacing the MemberAuthenticator with your authenticator:
|
||||||
|
```yaml
|
||||||
|
SilverStripe\Security\Authenticator:
|
||||||
|
default_authenticator: SilverStripe\Security\MemberAuthenticator
|
||||||
|
```
|
||||||
|
|
||||||
|
As soon as a custom authenticator is registered, the default authenticator will not be available anymore, unless enabled specifically in the config.
|
||||||
|
|
||||||
|
By default, the `SilverStripe\Security\MemberAuthenticator` is seen as the default authenticator until it's explicitly set in the config.
|
||||||
|
|
||||||
#### Upgrading Config API usages
|
#### Upgrading Config API usages
|
||||||
|
|
||||||
@ -1784,3 +1801,4 @@ New `TimeField` methods replace `getConfig()` / `setConfig()`
|
|||||||
you will need to define this method and return a short name describing the login method.
|
you will need to define this method and return a short name describing the login method.
|
||||||
* `MemberLoginForm` has a new constructor argument for the authenticator class, athough tis is usually
|
* `MemberLoginForm` has a new constructor argument for the authenticator class, athough tis is usually
|
||||||
constructed by `MemberAuthenticator` and won't affect normal use.
|
constructed by `MemberAuthenticator` and won't affect normal use.
|
||||||
|
* `Authenticator` methods `register` and `unregister` are deprecated in favor of using `Config`
|
@ -4,6 +4,7 @@ namespace SilverStripe\Security;
|
|||||||
|
|
||||||
use SilverStripe\Core\Object;
|
use SilverStripe\Core\Object;
|
||||||
use SilverStripe\Control\Controller;
|
use SilverStripe\Control\Controller;
|
||||||
|
use SilverStripe\Dev\Deprecation;
|
||||||
use SilverStripe\Forms\Form;
|
use SilverStripe\Forms\Form;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,7 +23,7 @@ abstract class Authenticator extends Object
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private static $authenticators = array(MemberAuthenticator::class);
|
private static $authenticators = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to influence the order of authenticators on the login-screen
|
* Used to influence the order of authenticators on the login-screen
|
||||||
@ -78,68 +79,6 @@ abstract class Authenticator extends Object
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function register($authenticator)
|
|
||||||
{
|
|
||||||
self::register_authenticator($authenticator);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a new authenticator
|
|
||||||
*
|
|
||||||
* The new authenticator has to exist and to be derived from the
|
|
||||||
* {@link Authenticator}.
|
|
||||||
* Every authenticator can be registered only once.
|
|
||||||
*
|
|
||||||
* @param string $authenticator Name of the authenticator class to
|
|
||||||
* register
|
|
||||||
* @return bool Returns TRUE on success, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
public static function register_authenticator($authenticator)
|
|
||||||
{
|
|
||||||
$authenticator = trim($authenticator);
|
|
||||||
|
|
||||||
if (class_exists($authenticator) == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_subclass_of($authenticator, self::class) == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array($authenticator, self::$authenticators) == false) {
|
|
||||||
if (call_user_func(array($authenticator, 'on_register')) === true) {
|
|
||||||
array_push(self::$authenticators, $authenticator);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function unregister($authenticator)
|
|
||||||
{
|
|
||||||
self::unregister_authenticator($authenticator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a previously registered authenticator
|
|
||||||
*
|
|
||||||
* @param string $authenticator Name of the authenticator class to register
|
|
||||||
* @return bool Returns TRUE on success, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
public static function unregister_authenticator($authenticator)
|
|
||||||
{
|
|
||||||
if (call_user_func(array($authenticator, 'on_unregister')) === true) {
|
|
||||||
if (in_array($authenticator, self::$authenticators)) {
|
|
||||||
unset(self::$authenticators[array_search($authenticator, self::$authenticators)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a given authenticator is registered
|
* Check if a given authenticator is registered
|
||||||
*
|
*
|
||||||
@ -149,7 +88,12 @@ abstract class Authenticator extends Object
|
|||||||
*/
|
*/
|
||||||
public static function is_registered($authenticator)
|
public static function is_registered($authenticator)
|
||||||
{
|
{
|
||||||
return in_array($authenticator, self::$authenticators);
|
$authenticators = self::config()->get('authenticators');
|
||||||
|
if (count($authenticators) === 0) {
|
||||||
|
$authenticators = [self::config()->get('default_authenticator')];
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array($authenticator, $authenticators, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -161,23 +105,20 @@ abstract class Authenticator extends Object
|
|||||||
*/
|
*/
|
||||||
public static function get_authenticators()
|
public static function get_authenticators()
|
||||||
{
|
{
|
||||||
|
$authenticators = self::config()->get('authenticators');
|
||||||
|
$default = self::config()->get('default_authenticator');
|
||||||
|
|
||||||
|
if (count($authenticators) === 0) {
|
||||||
|
$authenticators = [$default];
|
||||||
|
}
|
||||||
// put default authenticator first (mainly for tab-order on loginform)
|
// put default authenticator first (mainly for tab-order on loginform)
|
||||||
if ($key = array_search(self::$default_authenticator, self::$authenticators)) {
|
// But only if there's no other authenticator
|
||||||
unset(self::$authenticators[$key]);
|
if (($key = array_search($default, $authenticators, true)) && count($authenticators) > 1) {
|
||||||
array_unshift(self::$authenticators, self::$default_authenticator);
|
unset($authenticators[$key]);
|
||||||
|
array_unshift($authenticators, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$authenticators;
|
return $authenticators;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a default authenticator (shows first in tabs)
|
|
||||||
*
|
|
||||||
* @param string
|
|
||||||
*/
|
|
||||||
public static function set_default_authenticator($authenticator)
|
|
||||||
{
|
|
||||||
self::$default_authenticator = $authenticator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,33 +126,6 @@ abstract class Authenticator extends Object
|
|||||||
*/
|
*/
|
||||||
public static function get_default_authenticator()
|
public static function get_default_authenticator()
|
||||||
{
|
{
|
||||||
return self::$default_authenticator;
|
return self::config()->get('default_authenticator');
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback function that is called when the authenticator is registered
|
|
||||||
*
|
|
||||||
* Use this method for initialization of a newly registered authenticator.
|
|
||||||
* Just overload this method and it will be called when the authenticator
|
|
||||||
* is registered.
|
|
||||||
* <b>If the method returns FALSE, the authenticator won't be
|
|
||||||
* registered!</b>
|
|
||||||
*
|
|
||||||
* @return bool Returns TRUE on success, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
protected static function on_register()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback function that is called when an authenticator is removed.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected static function on_unregister()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,13 @@
|
|||||||
|
|
||||||
namespace SilverStripe\Security;
|
namespace SilverStripe\Security;
|
||||||
|
|
||||||
use SilverStripe\Control\HTTPResponse;
|
|
||||||
use SilverStripe\Core\Convert;
|
|
||||||
use SilverStripe\Control\Controller;
|
use SilverStripe\Control\Controller;
|
||||||
use SilverStripe\Control\Session;
|
|
||||||
use SilverStripe\Forms\HiddenField;
|
|
||||||
use SilverStripe\Forms\PasswordField;
|
|
||||||
use SilverStripe\Forms\LiteralField;
|
|
||||||
use SilverStripe\Forms\FieldList;
|
|
||||||
use SilverStripe\Forms\CheckboxField;
|
use SilverStripe\Forms\CheckboxField;
|
||||||
|
use SilverStripe\Forms\FieldList;
|
||||||
use SilverStripe\Forms\FormAction;
|
use SilverStripe\Forms\FormAction;
|
||||||
|
use SilverStripe\Forms\HiddenField;
|
||||||
|
use SilverStripe\Forms\LiteralField;
|
||||||
|
use SilverStripe\Forms\PasswordField;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the in-cms session re-authentication form for the "member" authenticator
|
* Provides the in-cms session re-authentication form for the "member" authenticator
|
||||||
@ -29,12 +26,34 @@ class CMSMemberLoginForm extends LoginForm
|
|||||||
return Security::singleton()->Link($action);
|
return Security::singleton()->Link($action);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct(Controller $controller, $name)
|
/**
|
||||||
|
* CMSMemberLoginForm constructor.
|
||||||
|
* @param Controller $controller
|
||||||
|
* @param string $authenticatorClass
|
||||||
|
* @param FieldList $name
|
||||||
|
*/
|
||||||
|
public function __construct(Controller $controller, $authenticatorClass, $name)
|
||||||
|
{
|
||||||
|
$this->controller = $controller;
|
||||||
|
|
||||||
|
$this->authenticator_class = $authenticatorClass;
|
||||||
|
|
||||||
|
$fields = $this->getFormFields();
|
||||||
|
|
||||||
|
$actions = $this->getFormActions();
|
||||||
|
|
||||||
|
parent::__construct($controller, $name, $fields, $actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getFormFields()
|
||||||
{
|
{
|
||||||
// Set default fields
|
// Set default fields
|
||||||
$fields = new FieldList(
|
$fields = new FieldList(
|
||||||
HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this),
|
HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this),
|
||||||
HiddenField::create('tempid', null, $controller->getRequest()->requestVar('tempid')),
|
HiddenField::create('tempid', null, $this->controller->getRequest()->requestVar('tempid')),
|
||||||
PasswordField::create("Password", _t('Member.PASSWORD', 'Password')),
|
PasswordField::create("Password", _t('Member.PASSWORD', 'Password')),
|
||||||
LiteralField::create(
|
LiteralField::create(
|
||||||
'forgotPassword',
|
'forgotPassword',
|
||||||
@ -53,9 +72,18 @@ class CMSMemberLoginForm extends LoginForm
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getFormActions()
|
||||||
|
{
|
||||||
|
|
||||||
// Determine returnurl to redirect to parent page
|
// Determine returnurl to redirect to parent page
|
||||||
$logoutLink = $this->getExternalLink('logout');
|
$logoutLink = $this->getExternalLink('logout');
|
||||||
if ($returnURL = $controller->getRequest()->requestVar('BackURL')) {
|
if ($returnURL = $this->controller->getRequest()->requestVar('BackURL')) {
|
||||||
$logoutLink = Controller::join_links($logoutLink, '?BackURL=' . urlencode($returnURL));
|
$logoutLink = Controller::join_links($logoutLink, '?BackURL=' . urlencode($returnURL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +100,7 @@ class CMSMemberLoginForm extends LoginForm
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
parent::__construct($controller, $name, $fields, $actions);
|
return $actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildRequestHandler()
|
protected function buildRequestHandler()
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace SilverStripe\Security;
|
namespace SilverStripe\Security;
|
||||||
|
|
||||||
use SilverStripe\Core\Injector\Injector;
|
use SilverStripe\Core\Injector\Injector;
|
||||||
|
use SilverStripe\Forms\FieldList;
|
||||||
use SilverStripe\Forms\Form;
|
use SilverStripe\Forms\Form;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,4 +33,18 @@ abstract class LoginForm extends Form
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract public function getAuthenticatorName();
|
abstract public function getAuthenticatorName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required FieldList creation on a LoginForm
|
||||||
|
*
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
abstract protected function getFormFields();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required FieldList creation for the login actions on this LoginForm
|
||||||
|
*
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
abstract protected function getFormActions();
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ class MemberAuthenticator extends Authenticator
|
|||||||
public static function get_cms_login_form(Controller $controller)
|
public static function get_cms_login_form(Controller $controller)
|
||||||
{
|
{
|
||||||
/** @skipUpgrade */
|
/** @skipUpgrade */
|
||||||
return CMSMemberLoginForm::create($controller, "LoginForm");
|
return CMSMemberLoginForm::create($controller, self::class, "LoginForm");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function supports_cms()
|
public static function supports_cms()
|
||||||
|
@ -369,7 +369,7 @@ class Security extends Controller implements TemplateGlobalProvider
|
|||||||
$authenticator = $this->getRequest()->requestVar('AuthenticationMethod');
|
$authenticator = $this->getRequest()->requestVar('AuthenticationMethod');
|
||||||
if ($authenticator && Authenticator::is_registered($authenticator)) {
|
if ($authenticator && Authenticator::is_registered($authenticator)) {
|
||||||
return $authenticator;
|
return $authenticator;
|
||||||
} elseif ($authenticator !== "" && Authenticator::is_registered(Authenticator::get_default_authenticator())) {
|
} elseif ($authenticator !== '' && Authenticator::is_registered(Authenticator::get_default_authenticator())) {
|
||||||
return Authenticator::get_default_authenticator();
|
return Authenticator::get_default_authenticator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace SilverStripe\Security\Tests;
|
namespace SilverStripe\Security\Tests;
|
||||||
|
|
||||||
|
use PhpConsole\Auth;
|
||||||
use SilverStripe\ORM\DataObject;
|
use SilverStripe\ORM\DataObject;
|
||||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||||
use SilverStripe\ORM\FieldType\DBClassName;
|
use SilverStripe\ORM\FieldType\DBClassName;
|
||||||
@ -50,12 +51,10 @@ class SecurityTest extends FunctionalTest
|
|||||||
// This test assumes that MemberAuthenticator is present and the default
|
// This test assumes that MemberAuthenticator is present and the default
|
||||||
$this->priorAuthenticators = Authenticator::get_authenticators();
|
$this->priorAuthenticators = Authenticator::get_authenticators();
|
||||||
$this->priorDefaultAuthenticator = Authenticator::get_default_authenticator();
|
$this->priorDefaultAuthenticator = Authenticator::get_default_authenticator();
|
||||||
foreach ($this->priorAuthenticators as $authenticator) {
|
|
||||||
Authenticator::unregister($authenticator);
|
|
||||||
}
|
|
||||||
|
|
||||||
Authenticator::register(MemberAuthenticator::class);
|
// Set to an empty array of authenticators to enable the default
|
||||||
Authenticator::set_default_authenticator(MemberAuthenticator::class);
|
Config::modify()->set(Authenticator::class, 'authenticators', []);
|
||||||
|
Config::modify()->set(Authenticator::class, 'default_authenticator', MemberAuthenticator::class);
|
||||||
|
|
||||||
// And that the unique identified field is 'Email'
|
// And that the unique identified field is 'Email'
|
||||||
$this->priorUniqueIdentifierField = Member::config()->unique_identifier_field;
|
$this->priorUniqueIdentifierField = Member::config()->unique_identifier_field;
|
||||||
@ -67,7 +66,7 @@ class SecurityTest extends FunctionalTest
|
|||||||
|
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', '/');
|
Config::modify()->merge('SilverStripe\\Control\\Director', 'alternate_base_url', '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function tearDown()
|
protected function tearDown()
|
||||||
@ -75,13 +74,8 @@ class SecurityTest extends FunctionalTest
|
|||||||
// Restore selected authenticator
|
// Restore selected authenticator
|
||||||
|
|
||||||
// MemberAuthenticator might not actually be present
|
// MemberAuthenticator might not actually be present
|
||||||
if (!in_array(MemberAuthenticator::class, $this->priorAuthenticators)) {
|
Config::modify()->set(Authenticator::class, 'authenticators', $this->priorAuthenticators);
|
||||||
Authenticator::unregister(MemberAuthenticator::class);
|
Config::modify()->set(Authenticator::class, 'default_authenticator', $this->priorDefaultAuthenticator);
|
||||||
}
|
|
||||||
foreach ($this->priorAuthenticators as $authenticator) {
|
|
||||||
Authenticator::register($authenticator);
|
|
||||||
}
|
|
||||||
Authenticator::set_default_authenticator($this->priorDefaultAuthenticator);
|
|
||||||
|
|
||||||
// Restore unique identifier field
|
// Restore unique identifier field
|
||||||
Member::config()->unique_identifier_field = $this->priorUniqueIdentifierField;
|
Member::config()->unique_identifier_field = $this->priorUniqueIdentifierField;
|
||||||
@ -129,8 +123,8 @@ class SecurityTest extends FunctionalTest
|
|||||||
'Default permission failure message value was not present'
|
'Default permission failure message value was not present'
|
||||||
);
|
);
|
||||||
|
|
||||||
Config::inst()->remove(Security::class, 'default_message_set');
|
Config::modify()->remove(Security::class, 'default_message_set');
|
||||||
Config::inst()->update(Security::class, 'default_message_set', array('default' => 'arrayvalue'));
|
Config::modify()->merge(Security::class, 'default_message_set', array('default' => 'arrayvalue'));
|
||||||
Security::permissionFailure($controller);
|
Security::permissionFailure($controller);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'arrayvalue',
|
'arrayvalue',
|
||||||
|
Loading…
Reference in New Issue
Block a user