Separate out the log-out handling.

Repairing tests and regressions
Consistently use `Security::getCurrentUser()` and `Security::setCurrentUser()`
Fix for the logout handler to properly logout, some minor wording updates
Remove the login hashes for the member when logging out.
BasicAuth to use `HTTPRequest`
This commit is contained in:
Simon Erkelens 2017-05-20 16:32:25 +12:00
parent f9ea752bae
commit 2b26cafcff
42 changed files with 315 additions and 244 deletions

View File

@ -30,7 +30,7 @@ Example: Disallow creation of new players if the currently logged-in player is n
public function onBeforeWrite() {
// check on first write action, aka "database row creation" (ID-property is not set)
if(!$this->isInDb()) {
$currentPlayer = Member::currentUser();
$currentPlayer = Security::getCurrentUser();
if(!$currentPlayer->IsTeamManager()) {
user_error('Player-creation not allowed', E_USER_ERROR);

View File

@ -9,7 +9,7 @@ checks. Often it makes sense to centralize those checks on the model, regardless
The API provides four methods for this purpose: `canEdit()`, `canCreate()`, `canView()` and `canDelete()`.
Since they're PHP methods, they can contain arbitrary logic matching your own requirements. They can optionally receive
a `$member` argument, and default to the currently logged in member (through `Member::currentUser()`).
a `$member` argument, and default to the currently logged in member (through `Security::getCurrentUser()`).
<div class="notice" markdown="1">
By default, all `DataObject` subclasses can only be edited, created and viewed by users with the 'ADMIN' permission

View File

@ -40,7 +40,7 @@ includes [api:Controller], [api:FormField] and [api:DataObject] instances.
```php
$controller->renderWith(array('MyController', 'MyBaseController'));
Member::currentUser()->renderWith('Member_Profile');
Security::getCurrentUser()->renderWith('Member_Profile');
```
`renderWith` can be used to override the default template process. For instance, to provide an ajax version of a

View File

@ -109,7 +109,7 @@ we added a `SayHi` method which is unique to our extension.
**mysite/code/Page.php**
:::php
$member = Member::currentUser();
$member = Security::getCurrentUser();
echo $member->SayHi;
// "Hi Sam"
@ -220,7 +220,7 @@ To see what extensions are currently enabled on an object, use [api:Object::getE
:::php
$member = Member::currentUser();
$member = Security::getCurrentUser();
print_r($member->getExtensionInstances());

View File

@ -24,12 +24,12 @@ next method for testing if you just need to test.
}
**Member::currentUser()**
**Security::getCurrentUser()**
Returns the full *Member* Object for the current user, returns *null* if user is not logged in.
:::php
if( $member = Member::currentUser() ) {
if( $member = Security::getCurrentUser() ) {
// Work with $member
} else {
// Do non-member stuff

View File

@ -60,7 +60,7 @@ The PHP Logic..
$email = SilverStripe\Control\Email\Email::create()
->setHTMLTemplate('Email\\MyCustomEmail')
->setData(array(
'Member' => Member::currentUser(),
'Member' => Security::getCurrentUser(),
'Link'=> $link,
))
->setFrom($from)

View File

@ -9,6 +9,7 @@ use SilverStripe\ORM\DataModel;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Security\BasicAuth;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\View\SSViewer;
use SilverStripe\View\TemplateGlobalProvider;
@ -575,7 +576,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
public function can($perm, $member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
if (is_array($perm)) {
$perm = array_map(array($this, 'can'), $perm, array_fill(0, count($perm), $member));

View File

@ -5,6 +5,7 @@ namespace SilverStripe\Dev;
use SilverStripe\Control\Session;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Config\Config;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\BasicAuth;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
@ -415,11 +416,9 @@ class FunctionalTest extends SapphireTest
Security::setCurrentUser($member);
}
/**
* Log in as the given member
* Log out the member
*
* @param Member|int|string $member The ID, fixture codename, or Member object of the member that you want to log in
*/
public function logOut()
{

View File

@ -38,7 +38,7 @@ class TestSession
/**
* Necessary to use the mock session
* created in {@link session} in the normal controller stack,
* e.g. to overwrite Member::currentUser() with custom login data.
* e.g. to overwrite Security::getCurrentUser() with custom login data.
*
* @var Controller
*/

View File

@ -5,6 +5,7 @@ namespace SilverStripe\Forms;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\View\Requirements;
/**
@ -504,7 +505,7 @@ class ConfirmedPasswordField extends FormField
}
// Check this password is valid for the current user
$member = Member::currentUser();
$member = Security::getCurrentUser();
if (!$member) {
$validator->validationError(
$name,

View File

@ -10,6 +10,7 @@ use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\View\Requirements;
use SilverStripe\View\ArrayData;
@ -249,7 +250,7 @@ class GridFieldPrintButton implements GridField_HTMLProvider, GridField_ActionPr
"Header" => $header,
"ItemRows" => $itemRows,
"Datetime" => DBDatetime::now(),
"Member" => Member::currentUser(),
"Member" => Security::getCurrentUser(),
));
return $ret;

View File

@ -24,6 +24,7 @@ use SilverStripe\ORM\FieldType\DBComposite;
use SilverStripe\ORM\FieldType\DBClassName;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
use SilverStripe\Security\Security;
use SilverStripe\View\ViewableData;
use LogicException;
use InvalidArgumentException;
@ -76,11 +77,11 @@ use stdClass;
* static $api_access = true;
*
* function canView($member = false) {
* if(!$member) $member = Member::currentUser();
* if(!$member) $member = Security::getCurrentUser();
* return $member->inGroup('Subscribers');
* }
* function canEdit($member = false) {
* if(!$member) $member = Member::currentUser();
* if(!$member) $member = Security::getCurrentUser();
* return $member->inGroup('Editors');
* }
*
@ -2498,7 +2499,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
public function can($perm, $member = null, $context = array())
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
if ($member && Permission::checkMember($member, "ADMIN")) {

View File

@ -9,6 +9,7 @@ use SilverStripe\Forms\DateField;
use SilverStripe\i18n\i18n;
use SilverStripe\ORM\DB;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
/**
* Represents a date field.
@ -250,7 +251,7 @@ class DBDate extends DBField
public function FormatFromSettings($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
// Fall back to nice

View File

@ -7,6 +7,7 @@ use SilverStripe\Forms\DatetimeField;
use SilverStripe\i18n\i18n;
use SilverStripe\ORM\DB;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\View\TemplateGlobalProvider;
use Exception;
use InvalidArgumentException;
@ -97,7 +98,7 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
public function FormatFromSettings($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
// Fall back to nice

View File

@ -8,6 +8,7 @@ use SilverStripe\Forms\TimeField;
use SilverStripe\i18n\i18n;
use SilverStripe\ORM\DB;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
/**
* Represents a column in the database with the type 'Time'.
@ -153,7 +154,7 @@ class DBTime extends DBField
public function FormatFromSettings($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
// Fall back to nice

View File

@ -2,6 +2,8 @@
namespace SilverStripe\Security;
use Exception;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Control\RequestFilter;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
@ -15,13 +17,16 @@ class AuthenticationRequestFilter implements RequestFilter, IdentityStore
use Configurable;
/**
* @return array|IdentityStore[]
*/
protected function getHandlers()
{
return array_map(
function ($identifier) {
return Injector::inst()->get($identifier);
},
$this->config()->get('handlers')
static::config()->get('handlers')
);
}
@ -31,6 +36,7 @@ class AuthenticationRequestFilter implements RequestFilter, IdentityStore
public function preRequest(HTTPRequest $request, Session $session, DataModel $model)
{
try {
/** @var AuthenticationHandler $handler */
foreach ($this->getHandlers() as $handler) {
// @todo Update requestfilter logic to allow modification of initial response
// in order to add cookies, etc
@ -41,7 +47,7 @@ class AuthenticationRequestFilter implements RequestFilter, IdentityStore
break;
}
}
} catch (ValidationException $e) {
} catch (Exception $e) { // There's no valid exception currently. I would say AuthenticationException?
throw new HTTPResponse_Exception(
"Bad log-in details: " . $e->getMessage(),
400

View File

@ -39,16 +39,26 @@ interface Authenticator
/**
* Return RequestHandler to manage the log-in process.
*
* The default URL of the RequetHandler should return the initial log-in form, any other
* The default URL of the RequestHandler should return the initial log-in form, any other
* URL may be added for other steps & processing.
*
* URL-handling methods may return an array [ "Form" => (form-object) ] which can then
* be merged into a default controller.
*
* @param string $link The base link to use for this RequestHnadler
* @param string $link The base link to use for this RequestHandler
*/
public function getLoginHandler($link);
/**
* Return the RequestHandler to manage the log-out process.
*
* The default URL of the RequestHandler should log the user out immediately and destroy the session.
*
* @param string $link The base link to use for this RequestHandler
* @return mixed
*/
public function getLogOutHandler($link);
/**
* Return RequestHandler to manage the change-password process.
*
@ -62,6 +72,7 @@ interface Authenticator
*/
public function getChangePasswordHandler($link);
/**
* @todo
*/
@ -81,13 +92,4 @@ interface Authenticator
* @return array
*/
// public function getAuthenticateFields();
/**
* Log the member out of this Authentication method.
*
* @param Member $member by reference, to allow for multiple actions on the member with a single write
* @return boolean|Member if logout was unsuccessfull, return true, otherwise, the member is returned
*/
public function doLogOut(&$member);
}

View File

@ -2,11 +2,14 @@
namespace SilverStripe\Security;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Dev\Debug;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Core\Injector\Injector;
@ -51,15 +54,16 @@ class BasicAuth
*
* Used by {@link Controller::init()}.
*
* @throws HTTPResponse_Exception
*
* @param HTTPRequest $request
* @param string $realm
* @param string|array $permissionCode Optional
* @param boolean $tryUsingSessionLogin If true, then the method with authenticate against the
* session log-in if those credentials are disabled.
* @return Member|bool $member
* @return bool|Member
* @throws HTTPResponse_Exception
*/
public static function requireLogin($realm, $permissionCode = null, $tryUsingSessionLogin = true)
public static function requireLogin(HTTPRequest $request, $realm, $permissionCode = null, $tryUsingSessionLogin = true)
{
$isRunningTests = (class_exists('SilverStripe\\Dev\\SapphireTest', false) && SapphireTest::is_running_test());
if (!Security::database_is_ready() || (Director::is_cli() && !$isRunningTests)) {
@ -74,28 +78,32 @@ class BasicAuth
* The follow rewrite rule must be in the sites .htaccess file to enable this workaround
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
*/
$authHeader = (isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] :
(isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) ? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] : null));
$authHeader = $request->getHeader('Authorization');
$matches = array();
if ($authHeader && preg_match('/Basic\s+(.*)$/i', $authHeader, $matches)) {
list($name, $password) = explode(':', base64_decode($matches[1]));
$_SERVER['PHP_AUTH_USER'] = strip_tags($name);
$_SERVER['PHP_AUTH_PW'] = strip_tags($password);
$request->addHeader('PHP_AUTH_USER', strip_tags($name));
$request->addHeader('PHP_AUTH_PW', strip_tags($password));
}
$member = null;
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
if ($request->getHeader('PHP_AUTH_USER') && $request->getHeader('PHP_AUTH_PW')) {
/** @var Authenticator $authenticator */
$authenticator = Injector::inst()->get(Authenticator::class);
$member = $authenticator->authenticate([
'Email' => $_SERVER['PHP_AUTH_USER'],
'Password' => $_SERVER['PHP_AUTH_PW'],
'Email' => $request->getHeader('PHP_AUTH_USER'),
'Password' => $request->getHeader('PHP_AUTH_PW'),
], $dummy);
}
if($member) {
Security::setCurrentUser($member);
}
if (!$member && $tryUsingSessionLogin) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
// If we've failed the authentication mechanism, then show the login form
@ -103,7 +111,7 @@ class BasicAuth
$response = new HTTPResponse(null, 401);
$response->addHeader('WWW-Authenticate', "Basic realm=\"$realm\"");
if (isset($_SERVER['PHP_AUTH_USER'])) {
if ($request->getHeader('PHP_AUTH_USER')) {
$response->setBody(_t('SilverStripe\\Security\\BasicAuth.ERRORNOTREC', "That username / password isn't recognised"));
} else {
$response->setBody(_t('SilverStripe\\Security\\BasicAuth.ENTERINFO', "Please enter a username and password."));
@ -119,7 +127,7 @@ class BasicAuth
$response = new HTTPResponse(null, 401);
$response->addHeader('WWW-Authenticate', "Basic realm=\"$realm\"");
if (isset($_SERVER['PHP_AUTH_USER'])) {
if ($request->getHeader('PHP_AUTH_USER')) {
$response->setBody(_t('SilverStripe\\Security\\BasicAuth.ERRORNOTADMIN', "That user is not an administrator."));
}
@ -152,9 +160,9 @@ class BasicAuth
*/
public static function protect_entire_site($protect = true, $code = 'ADMIN', $message = null)
{
Config::inst()->update(self::class, 'entire_site_protected', $protect);
Config::inst()->update(self::class, 'entire_site_protected_code', $code);
Config::inst()->update(self::class, 'entire_site_protected_message', $message);
Config::modify()->set(self::class, 'entire_site_protected', $protect);
Config::modify()->set(self::class, 'entire_site_protected_code', $code);
Config::modify()->set(self::class, 'entire_site_protected_message', $message);
}
/**
@ -167,8 +175,14 @@ class BasicAuth
public static function protect_site_if_necessary()
{
$config = Config::forClass(BasicAuth::class);
if ($config->entire_site_protected) {
self::requireLogin($config->entire_site_protected_message, $config->entire_site_protected_code, false);
$request = Controller::curr()->getRequest();
if ($config->get('entire_site_protected')) {
/** @noinspection ExceptionsAnnotatingAndHandlingInspection */
static::requireLogin(
$request,
$config->get('entire_site_protected_message'),
$config->get('entire_site_protected_code'),
false);
}
}
}

View File

@ -476,7 +476,7 @@ class Group extends DataObject
public function canEdit($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
// extended access checks
@ -512,7 +512,7 @@ class Group extends DataObject
public function canView($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
// extended access checks
@ -534,7 +534,7 @@ class Group extends DataObject
public function canDelete($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
// extended access checks

View File

@ -15,18 +15,18 @@ interface IdentityStore
/**
* Log the given member into this identity store.
*
* @param $member The member to log in.
* @param $persistent boolean If set to true, the login may persist beyond the current session.
* @param $request The request of the visitor that is logging in, to get, for example, cookies.
* @param $response The response object to modify, if needed.
* @param Member $member The member to log in.
* @param Boolean $persistent boolean If set to true, the login may persist beyond the current session.
* @param HTTPRequest $request The request of the visitor that is logging in, to get, for example, cookies.
* @param HTTPResponse $response The response object to modify, if needed.
*/
public function logIn(Member $member, $persistent, HTTPRequest $request);
/**
* Log any logged-in member out of this identity store.
*
* @param $request The request of the visitor that is logging out, to get, for example, cookies.
* @param $response The response object to modify, if needed.
* @param HTTPRequest $request The request of the visitor that is logging out, to get, for example, cookies.
* @param HTTPResponse $response The response object to modify, if needed.
*/
public function logOut(HTTPRequest $request);
}

View File

@ -158,13 +158,13 @@ class InheritedPermissions implements PermissionChecker
{
switch ($permission) {
case self::EDIT:
$this->canEditMultiple($ids, Member::currentUser(), false);
$this->canEditMultiple($ids, Security::getCurrentUser(), false);
break;
case self::VIEW:
$this->canViewMultiple($ids, Member::currentUser(), false);
$this->canViewMultiple($ids, Security::getCurrentUser(), false);
break;
case self::DELETE:
$this->canDeleteMultiple($ids, Member::currentUser(), false);
$this->canDeleteMultiple($ids, Security::getCurrentUser(), false);
break;
default:
throw new InvalidArgumentException("Invalid permission type $permission");

View File

@ -57,7 +57,7 @@ use DateTime;
* @property string $DateFormat
* @property string $TimeFormat
*/
class Member extends DataObject implements TemplateGlobalProvider
class Member extends DataObject
{
private static $db = array(
@ -717,6 +717,8 @@ class Member extends DataObject implements TemplateGlobalProvider
/**
* Returns the current logged in user
*
* @deprecated use Security::getCurrentUser()
*
* @return Member
*/
public static function currentUser()
@ -759,6 +761,8 @@ class Member extends DataObject implements TemplateGlobalProvider
/**
* Get the ID of the current logged in user
*
* @deprecated use Security::getCurrentUser()
*
* @return int Returns the ID of the current logged in user or 0.
*/
public static function currentUserID()
@ -1077,7 +1081,7 @@ class Member extends DataObject implements TemplateGlobalProvider
foreach ($format['columns'] as $col) {
$values[] = $this->getField($col);
}
return join($format['sep'], $values);
return implode($format['sep'], $values);
}
if ($this->getField('ID') === 0) {
return $this->getField('Surname');
@ -1491,7 +1495,7 @@ class Member extends DataObject implements TemplateGlobalProvider
{
//get member
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
//check for extensions, we do this first as they can overrule everything
$extended = $this->extendedCan(__FUNCTION__, $member);
@ -1522,7 +1526,7 @@ class Member extends DataObject implements TemplateGlobalProvider
{
//get member
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
//check for extensions, we do this first as they can overrule everything
$extended = $this->extendedCan(__FUNCTION__, $member);
@ -1556,7 +1560,7 @@ class Member extends DataObject implements TemplateGlobalProvider
public function canDelete($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
//check for extensions, we do this first as they can overrule everything
$extended = $this->extendedCan(__FUNCTION__, $member);
@ -1686,12 +1690,4 @@ class Member extends DataObject implements TemplateGlobalProvider
// If can't find a suitable editor, just default to cms
return $currentName ? $currentName : 'cms';
}
public static function get_template_global_variables()
{
return array(
'CurrentMember' => 'currentUser',
'currentUser',
);
}
}

View File

@ -3,12 +3,10 @@
namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Cookie;
use SilverStripe\Control\Session;
use SilverStripe\ORM\ValidationResult;
use InvalidArgumentException;
use SilverStripe\Security\Authenticator as BaseAuthenticator;
use SilverStripe\Security\RememberLoginHash;
use SilverStripe\Security\Security;
use SilverStripe\Security\Member;
use SilverStripe\Security\LoginAttempt;
@ -186,38 +184,10 @@ class Authenticator implements BaseAuthenticator
}
/**
*
* @param Member $member
* @return bool|Member
* @inherit
*/
public function doLogOut(&$member)
public function getLogoutHandler($link)
{
if($member instanceof Member) {
Session::clear("loggedInAs");
if (Member::config()->login_marker_cookie) {
Cookie::set(Member::config()->login_marker_cookie, null, 0);
}
Session::destroy();
// Clears any potential previous hashes for this member
RememberLoginHash::clear($member, Cookie::get('alc_device'));
Cookie::set('alc_enc', null); // // Clear the Remember Me cookie
Cookie::force_expiry('alc_enc');
Cookie::set('alc_device', null);
Cookie::force_expiry('alc_device');
// Switch back to live in order to avoid infinite loops when
// redirecting to the login screen (if this login screen is versioned)
Session::clear('readingMode');
// Log out unsuccessful. Useful for 3rd-party logins that return failure. Shouldn't happen
// on the default authenticator though.
if(Member::currentUserID()) {
return Member::currentUser();
}
}
return true;
return LogoutHandler::create($link, $this);
}
}

View File

@ -37,5 +37,4 @@ class CMSAuthenticator extends Authenticator
{
return CMSLoginHandler::create($link, $this);
}
}
}

View File

@ -82,7 +82,7 @@ PHP
protected function redirectAfterSuccessfulLogin()
{
// Check password expiry
if (Member::currentUser()->isPasswordExpired()) {
if (Security::getCurrentUser()->isPasswordExpired()) {
// Redirect the user to the external password change form if necessary
return $this->redirectToChangePassword();
}

View File

@ -10,7 +10,7 @@ use SilverStripe\Forms\PasswordField;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\Form;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
/**
* Standard Change Password Form
@ -36,7 +36,7 @@ class ChangePasswordForm extends Form
// Security/changepassword?h=XXX redirects to Security/changepassword
// without GET parameter to avoid potential HTTP referer leakage.
// In this case, a user is not logged in, and no 'old password' should be necessary.
if (Member::currentUser()) {
if (Security::getCurrentUser()) {
$fields->push(new PasswordField("OldPassword", _t('SilverStripe\\Security\\Member.YOUROLDPASSWORD', "Your old password")));
}

View File

@ -21,7 +21,7 @@ class ChangePasswordHandler extends FormRequestHandler
*/
public function doChangePassword(array $data, $form)
{
$member = Member::currentUser();
$member = Security::getCurrentUser();
// The user was logged in, check the current password
if ($member && (
empty($data['OldPassword']) ||

View File

@ -2,10 +2,8 @@
namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Security\AuthenticationHandler as AuthenticationHandlerInterface;
use SilverStripe\Security\IdentityStore;
use SilverStripe\Security\RememberLoginHash;
@ -19,8 +17,19 @@ use SilverStripe\Control\Cookie;
class CookieAuthenticationHandler implements AuthenticationHandlerInterface, IdentityStore
{
/**
* @var string
*/
private $deviceCookieName;
/**
* @var string
*/
private $tokenCookieName;
/**
* @var IdentityStore
*/
private $cascadeLogInTo;
/**
@ -36,7 +45,7 @@ class CookieAuthenticationHandler implements AuthenticationHandlerInterface, Ide
/**
* Set the name of the cookie used to track this device
*
* @param string $cookieName
* @param $deviceCookieName
* @return null
*/
public function setDeviceCookieName($deviceCookieName)
@ -57,7 +66,7 @@ class CookieAuthenticationHandler implements AuthenticationHandlerInterface, Ide
/**
* Set the name of the cookie used to store an login token
*
* @param string $cookieName
* @param $tokenCookieName
* @return null
*/
public function setTokenCookieName($tokenCookieName)
@ -213,11 +222,17 @@ class CookieAuthenticationHandler implements AuthenticationHandlerInterface, Ide
*/
public function logOut(HTTPRequest $request)
{
$member = Security::getCurrentUser();
if ($member) {
RememberLoginHash::clear($member, Cookie::get('alc_device'));
}
// @todo couple the cookies to the response object
Cookie::set($this->getTokenCookieName(), null);
Cookie::set($this->getDeviceCookieName(), null);
Cookie::force_expiry($this->getTokenCookieName());
Cookie::force_expiry($this->getDeviceCookieName());
Security::setCurrentUser(null);
}
}

View File

@ -87,7 +87,9 @@ class LoginForm extends BaseLoginForm
$backURL = Session::get('BackURL');
}
if ($checkCurrentUser && Member::currentUser() && Member::logged_in_session_exists()) {
if ($checkCurrentUser && Security::getCurrentUser() && Member::logged_in_session_exists()) {
// @todo find a more elegant way to handle this
$logoutAction = Security::logout_url();
$fields = FieldList::create(
HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this)
);
@ -112,6 +114,9 @@ class LoginForm extends BaseLoginForm
parent::__construct($controller, $name, $fields, $actions);
if (isset($logoutAction)) {
$this->setFormAction($logoutAction);
}
$this->setValidator(RequiredFields::create(self::config()->get('required_fields')));
}
@ -182,7 +187,7 @@ class LoginForm extends BaseLoginForm
parent::restoreFormState();
$forceMessage = Session::get('MemberLoginForm.force_message');
if (($member = Member::currentUser()) && !$forceMessage) {
if (($member = Security::getCurrentUser()) && !$forceMessage) {
$message = _t(
'SilverStripe\\Security\\Member.LOGGEDINAS',
"You're logged in as {name}.",

View File

@ -3,6 +3,7 @@
namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\Session;
use SilverStripe\Control\RequestHandler;
@ -17,6 +18,9 @@ use SilverStripe\Security\IdentityStore;
*/
class LoginHandler extends RequestHandler
{
/**
* @var Authenticator
*/
protected $authenticator;
private static $url_handlers = [
@ -33,11 +37,10 @@ class LoginHandler extends RequestHandler
private static $allowed_actions = [
'login',
'LoginForm',
'dologin',
'logout',
];
private $link = null;
private $link;
/**
* @param string $link The URL to recreate this request handler
@ -53,15 +56,16 @@ class LoginHandler extends RequestHandler
/**
* Return a link to this request handler.
* The link returned is supplied in the constructor
* @param null $action
* @return string
*/
public function link($action = null)
{
if ($action) {
return Controller::join_links($this->link, $action);
} else {
return $this->link;
}
return $this->link;
}
/**
@ -89,7 +93,7 @@ class LoginHandler extends RequestHandler
/**
* Login form handler method
*
* This method is called when the user clicks on "Log in"
* This method is called when the user finishes the login flow
*
* @param array $data Submitted data
* @param LoginForm $form
@ -102,6 +106,7 @@ class LoginHandler extends RequestHandler
// Successful login
if ($member = $this->checkLogin($data, $failureMessage)) {
$this->performLogin($member, $data, $form->getRequestHandler()->getRequest());
return $this->redirectAfterSuccessfulLogin();
}
@ -119,7 +124,6 @@ class LoginHandler extends RequestHandler
return $form->getRequestHandler()->redirectBackToForm();
}
public function getReturnReferer()
{
return $this->link();
@ -137,7 +141,6 @@ class LoginHandler extends RequestHandler
* [Optional: 'Remember' => 1 ]
* )
*
* @param array $data
* @return HTTPResponse
*/
protected function redirectAfterSuccessfulLogin()
@ -145,7 +148,7 @@ class LoginHandler extends RequestHandler
Session::clear('SessionForms.MemberLoginForm.Email');
Session::clear('SessionForms.MemberLoginForm.Remember');
$member = Member::currentUser();
$member = Security::getCurrentUser();
if ($member->isPasswordExpired()) {
return $this->redirectToChangePassword();
}
@ -167,7 +170,7 @@ class LoginHandler extends RequestHandler
// Welcome message
$message = _t(
'SilverStripe\\Security\\Member.WELCOMEBACK',
"Welcome Back, {firstname}",
'Welcome Back, {firstname}',
['firstname' => $member->FirstName]
);
Security::setLoginMessage($message, ValidationResult::TYPE_GOOD);
@ -177,26 +180,11 @@ class LoginHandler extends RequestHandler
return $this->redirectBack();
}
/**
* Log out form handler method
*
* This method is called when the user clicks on "logout" on the form
* created when the parameter <i>$checkCurrentUser</i> of the
* {@link __construct constructor} was set to TRUE and the user was
* currently logged in.
*
* @return HTTPResponse
*/
public function logout()
{
Security::singleton()->logout();
return $this->redirectBack();
}
/**
* Try to authenticate the user
*
* @param array $data Submitted data
* @param string $message
* @return Member Returns the member object on successful authentication
* or NULL on failure.
*/
@ -206,19 +194,19 @@ class LoginHandler extends RequestHandler
$member = $this->authenticator->authenticate($data, $message);
if ($member) {
return $member;
} else {
// No member, can't login
$this->extend('authenticationFailed', $data);
return null;
}
// No member, can't login
$this->extend('authenticationFailed', $data);
return null;
}
/**
* Try to authenticate the user
*
* @param Member $member
* @param array $data Submitted data
* @param HTTPRequest $request
* @return Member Returns the member object on successful authentication
* or NULL on failure.
*/
@ -226,8 +214,10 @@ class LoginHandler extends RequestHandler
{
// @todo pass request/response
Injector::inst()->get(IdentityStore::class)->logIn($member, !empty($data['Remember']), $request);
return $member;
}
/**
* Invoked if password is expired and must be changed
*
@ -242,13 +232,15 @@ class LoginHandler extends RequestHandler
'good'
);
$changedPasswordLink = Security::singleton()->Link('changepassword');
return $this->redirect($this->addBackURLParam($changedPasswordLink));
}
/**
* @todo copypaste from FormRequestHandler - refactor
* @param string $link
* @return string
*/
protected function addBackURLParam($link)
{
@ -256,6 +248,7 @@ class LoginHandler extends RequestHandler
if ($backURL) {
return Controller::join_links($link, '?BackURL=' . urlencode($backURL));
}
return $link;
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\Control\Cookie;
use SilverStripe\Control\RequestHandler;
use SilverStripe\Control\Session;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Security\IdentityStore;
use SilverStripe\Security\Member;
use SilverStripe\Security\RememberLoginHash;
use SilverStripe\Security\Security;
/**
* Class LogoutHandler handles logging out Members from their session and/or cookie.
* The logout process destroys all traces of the member on the server (not the actual computer user
* at the other end of the line, don't worry)
*
* @package SilverStripe\Security\MemberAuthenticator
*/
class LogoutHandler extends RequestHandler
{
/**
* @var array
*/
private static $url_handlers = [
'' => 'logout'
];
/**
* @var array
*/
private static $allowed_actions = [
'logout'
];
/**
* Log out form handler method
*
* This method is called when the user clicks on "logout" on the form
* created when the parameter <i>$checkCurrentUser</i> of the
* {@link __construct constructor} was set to TRUE and the user was
* currently logged in.
*
* @return bool|Member
*/
public function logout()
{
$member = Security::getCurrentUser();
return $this->doLogOut($member);
}
/**
*
* @param Member $member
* @return bool|Member Return a member if something goes wrong
*/
public function doLogOut($member)
{
if ($member instanceof Member) {
Injector::inst()->get(IdentityStore::class)->logOut($this->getRequest());
}
return true;
}
}

View File

@ -2,6 +2,7 @@
namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\Control\Cookie;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\Control\HTTPRequest;
@ -52,7 +53,7 @@ class SessionAuthenticationHandler implements AuthenticationHandlerInterface, Id
if ($id = Session::get($this->getSessionVariable())) {
// If ID is a bad ID it will be treated as if the user is not logged in, rather than throwing a
// ValidationException
return DataObject::get_by_id(Member::class, $id);
return Member::get()->byID($id);
}
return null;
@ -66,13 +67,13 @@ class SessionAuthenticationHandler implements AuthenticationHandlerInterface, Id
// @todo couple the session to a request object
// $session = $request->getSession();
$this->regenerateSessionId();
static::regenerateSessionId();
Session::set($this->getSessionVariable(), $member->ID);
// This lets apache rules detect whether the user has logged in
// @todo make this a settign on the authentication handler
if (Member::config()->login_marker_cookie) {
Cookie::set(Member::config()->login_marker_cookie, 1, 0);
if (Member::config()->get('login_marker_cookie')) {
Cookie::set(Member::config()->get('login_marker_cookie'), 1, 0);
}
}

View File

@ -347,7 +347,7 @@ class Permission extends DataObject implements TemplateGlobalProvider, Resettabl
{
// Default to current member, with session-caching
if (!$memberID) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
if ($member && isset($_SESSION['Permission_groupList'][$member->ID])) {
return $_SESSION['Permission_groupList'][$member->ID];
}

View File

@ -22,11 +22,13 @@ use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\Connect\Database;
use SilverStripe\ORM\DataModel;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\ValidationResult;
use SilverStripe\Security\MemberAuthenticator\LogoutHandler;
use SilverStripe\View\ArrayData;
use SilverStripe\View\SSViewer;
use SilverStripe\View\TemplateGlobalProvider;
@ -230,6 +232,11 @@ class Security extends Controller implements TemplateGlobalProvider
*/
protected static $default_authenticator = MemberAuthenticator\Authenticator::class;
/**
* @var Member Currently logged in user (if available)
*/
private static $currentUser;
/**
* @inheritdoc
*/
@ -262,7 +269,7 @@ class Security extends Controller implements TemplateGlobalProvider
* Get the selected authenticator for this request
*
* @param $name string The identifier of the authenticator in your config
* @return string Class name of Authenticator
* @return Authenticator Class name of Authenticator
* @throws LogicException
*/
protected function getAuthenticator($name)
@ -287,15 +294,16 @@ class Security extends Controller implements TemplateGlobalProvider
{
$authenticators = self::config()->get('authenticators');
foreach($authenticators as $name => &$class) {
foreach ($authenticators as $name => &$class) {
/** @var Authenticator $authenticator */
$authenticator = Injector::inst()->get($class);
if($authenticator->supportedServices() & $service) {
if ($authenticator->supportedServices() & $service) {
$class = $authenticator;
} else {
unset($authenticators[$name]);
}
}
return $authenticators;
}
@ -348,7 +356,7 @@ class Security extends Controller implements TemplateGlobalProvider
if (Director::is_ajax()) {
$response = ($controller) ? $controller->getResponse() : new HTTPResponse();
$response->setStatusCode(403);
if (!Member::currentUser()) {
if (!static::getCurrentUser()) {
$response->setBody(_t('SilverStripe\\CMS\\Controllers\\ContentController.NOTLOGGEDIN', 'Not logged in'));
$response->setStatusDescription(_t('SilverStripe\\CMS\\Controllers\\ContentController.NOTLOGGEDIN', 'Not logged in'));
// Tell the CMS to allow re-aunthentication
@ -384,7 +392,7 @@ class Security extends Controller implements TemplateGlobalProvider
$messageSet = array('default' => $messageSet);
}
$member = Member::currentUser();
$member = static::getCurrentUser();
// Work out the right message to show
if ($member && $member->exists()) {
@ -428,8 +436,6 @@ class Security extends Controller implements TemplateGlobalProvider
));
}
private static $currentUser;
public static function setCurrentUser($currentUser)
{
self::$currentUser = $currentUser;
@ -498,36 +504,22 @@ class Security extends Controller implements TemplateGlobalProvider
public function logout($redirect = true)
{
$this->extend('beforeMemberLoggedOut');
$request = $this->getRequest();
$member = Member::currentUser();
// Reasoning for (now) to not go with a full LoginHandler call, is to not make it circular
// re-sending the request forward to the authenticator. In the case of logout, I think it would be
// overkill.
if (($name = $request->param('ID')) && self::hasAuthenticator($request->param('ID'))){
$member = static::getCurrentUser();
if ($member) { // If we don't have a member, there's not much to log out.
/** @var Authenticator $authenticator */
$authenticator = $this->getAuthenticator($request->param('ID'));
if($authenticator->doLogOut($member) !== true) {
$authenticator = $this->getAuthenticator('default'); // Always use the default authenticator to log out
$handler = $authenticator->getLogOutHandler(Controller::join_links($this->Link(), 'logout'));
$result = $this->delegateToHandler($handler, 'default', []);
if ($result !== true) {
$this->extend('failureMemberLoggedOut', $authenticator);
return $this->redirectBack();
}
$this->extend('successMemberLoggedOut', $authenticator);
} else {
$authenticators = static::getAuthenticators(Authenticator::LOGOUT);
/**
* @var string $name
* @var Authenticator $authenticator
*/
foreach ($authenticators as $name => $authenticator) {
if ($authenticator->logOut($member) !== true) {
$this->extend('failureMemberLoggedOut', $authenticator);
// Break on first log out failure(?)
return $this->redirectBack();
}
$this->extend('successMemberLoggedOut', $authenticator);
}
// Member is successfully logged out. Write possible changes to the database.
$member->write();
}
// Member is successfully logged out. Write possible changes to the database.
$member->write();
$this->extend('afterMemberLoggedOut');
if ($redirect && (!$this->getResponse()->isFinished())) {
@ -568,7 +560,7 @@ class Security extends Controller implements TemplateGlobalProvider
// where the user has permissions to continue but is not given the option.
if ($this->getRequest()->requestVar('BackURL')
&& !$this->getLoginMessage()
&& ($member = Member::currentUser())
&& ($member = static::getCurrentUser())
&& $member->exists()
) {
return $this->redirectBack();
@ -611,7 +603,7 @@ class Security extends Controller implements TemplateGlobalProvider
/**
* Combine the given forms into a formset with a tabbed interface
*
* @param array $authenticators List of Authenticator instances
* @param $forms
* @return string
*/
protected function generateLoginFormSet($forms)
@ -772,7 +764,6 @@ class Security extends Controller implements TemplateGlobalProvider
],
$templates
);
}
/**
@ -833,8 +824,8 @@ class Security extends Controller implements TemplateGlobalProvider
public function basicauthlogin()
{
$member = BasicAuth::requireLogin("SilverStripe login", 'ADMIN');
$member->logIn();
$member = BasicAuth::requireLogin($this->getRequest(), "SilverStripe login", 'ADMIN');
static::setCurrentUser($member);
}
/**
@ -888,8 +879,10 @@ class Security extends Controller implements TemplateGlobalProvider
// On first valid password reset request redirect to the same URL without hash to avoid referrer leakage.
// if there is a current member, they should be logged out
if ($curMember = Member::currentUser()) {
$curMember->logOut();
if ($curMember = static::getCurrentUser()) {
/** @var LogoutHandler $handler */
$handler = $this->getAuthenticator('default')->getLogoutHandler($this->Link('logout'));
$handler->doLogOut($curMember);
}
// Store the hash for the change password form. Will be unset after reload within the ChangePasswordForm.
@ -905,7 +898,7 @@ class Security extends Controller implements TemplateGlobalProvider
),
'Form' => $this->ChangePasswordForm(),
));
} elseif (Member::currentUser()) {
} elseif (static::getCurrentUser()) {
// Logged in user requested a password change form.
$customisedController = $controller->customise(array(
'Content' => DBField::create_field(
@ -1112,6 +1105,7 @@ class Security extends Controller implements TemplateGlobalProvider
/**
* Check that the default admin account has been set.
* @todo Check if we _actually_ only want this to work on dev
*/
public static function has_default_admin()
{
@ -1354,6 +1348,8 @@ class Security extends Controller implements TemplateGlobalProvider
"LoginURL" => "login_url",
"LogoutURL" => "logout_url",
"LostPasswordURL" => "lost_password_url",
"CurrentMember" => "getCurrentUser",
"currentUser" => "getCurrentUser"
);
}
}

View File

@ -23,6 +23,7 @@ use SilverStripe\Dev\Deprecation;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\ORM\DataModel;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\View\SSViewer;
class ControllerTest extends FunctionalTest
@ -203,7 +204,7 @@ class ControllerTest extends FunctionalTest
'if action is not a method but rather a template discovered by naming convention'
);
$this->session()->inst_set('loggedInAs', $adminUser->ID);
Security::setCurrentUser($adminUser);
$response = $this->get("AccessSecuredController/templateaction");
$this->assertEquals(
200,
@ -211,8 +212,8 @@ class ControllerTest extends FunctionalTest
'Access granted for logged in admin on action with $allowed_actions on defining controller, ' .
'if action is not a method but rather a template discovered by naming convention'
);
$this->session()->inst_set('loggedInAs', null);
Security::setCurrentUser(null);
$response = $this->get("AccessSecuredController/adminonly");
$this->assertEquals(
403,
@ -236,15 +237,15 @@ class ControllerTest extends FunctionalTest
"Access denied to protected method even if its listed in allowed_actions"
);
$this->session()->inst_set('loggedInAs', $adminUser->ID);
Security::setCurrentUser($adminUser);
$response = $this->get("AccessSecuredController/adminonly");
$this->assertEquals(
200,
$response->getStatusCode(),
"Permission codes are respected when set in \$allowed_actions"
);
$this->session()->inst_set('loggedInAs', null);
Security::setCurrentUser(null);
$response = $this->get('AccessBaseController/extensionmethod1');
$this->assertEquals(
200,
@ -285,7 +286,7 @@ class ControllerTest extends FunctionalTest
"and doesn't satisfy checks"
);
$this->session()->inst_set('loggedInAs', $adminUser->ID);
Security::setCurrentUser($adminUser);
$response = $this->get('IndexSecuredController/');
$this->assertEquals(
200,
@ -293,7 +294,7 @@ class ControllerTest extends FunctionalTest
"Access granted when index action is limited through allowed_actions, " .
"and does satisfy checks"
);
$this->session()->inst_set('loggedInAs', null);
Security::setCurrentUser(null);
}
public function testWildcardAllowedActions()

View File

@ -10,11 +10,10 @@ use SilverStripe\Forms\Tests\GridField\GridFieldTest\Team;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\ValidationException;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\Security\SecurityToken;
use SilverStripe\Dev\CSSContentParser;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\Session;
use SilverStripe\Forms\FieldList;
@ -67,8 +66,8 @@ class GridFieldDeleteActionTest extends SapphireTest
public function testDontShowDeleteButtons()
{
if (Member::currentUser()) {
Member::currentUser()->logOut();
if (Security::getCurrentUser()) {
Security::setCurrentUser(null);
}
$content = new CSSContentParser($this->gridField->FieldHolder());
// Check that there are content
@ -116,8 +115,8 @@ class GridFieldDeleteActionTest extends SapphireTest
public function testDeleteActionWithoutCorrectPermission()
{
if (Member::currentUser()) {
Member::currentUser()->logOut();
if (Security::getCurrentUser()) {
Security::setCurrentUser(null);
}
$this->setExpectedException(ValidationException::class);

View File

@ -17,6 +17,7 @@ use SilverStripe\Forms\Form;
use SilverStripe\Forms\GridField\GridFieldConfig;
use SilverStripe\Forms\GridField\GridFieldEditButton;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Security\Security;
class GridFieldEditButtonTest extends SapphireTest
{
@ -62,8 +63,8 @@ class GridFieldEditButtonTest extends SapphireTest
public function testShowEditLinks()
{
if (Member::currentUser()) {
Member::currentUser()->logOut();
if (Security::getCurrentUser()) {
Security::getCurrentUser()->logOut();
}
$content = new CSSContentParser($this->gridField->FieldHolder());

View File

@ -15,7 +15,7 @@ use SilverStripe\Security\Tests\BasicAuthTest\ControllerSecuredWithPermission;
class BasicAuthTest extends FunctionalTest
{
static $original_unique_identifier_field;
protected static $original_unique_identifier_field;
protected static $fixture_file = 'BasicAuthTest.yml';
@ -42,7 +42,7 @@ class BasicAuthTest extends FunctionalTest
unset($_SERVER['PHP_AUTH_USER']);
unset($_SERVER['PHP_AUTH_PW']);
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', null, $_SESSION, null, null, $_SERVER);
$this->assertEquals(401, $response->getStatusCode());
$_SERVER['PHP_AUTH_USER'] = $origUser;
@ -56,13 +56,13 @@ class BasicAuthTest extends FunctionalTest
unset($_SERVER['PHP_AUTH_USER']);
unset($_SERVER['PHP_AUTH_PW']);
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', null, $_SESSION, null, null, $_SERVER);
$this->assertFalse(BasicAuthTest\ControllerSecuredWithPermission::$index_called);
$this->assertFalse(BasicAuthTest\ControllerSecuredWithPermission::$post_init_called);
$_SERVER['PHP_AUTH_USER'] = 'user-in-mygroup@test.com';
$_SERVER['PHP_AUTH_PW'] = 'test';
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', null, $_SESSION, null, null, $_SERVER);
$this->assertTrue(BasicAuthTest\ControllerSecuredWithPermission::$index_called);
$this->assertTrue(BasicAuthTest\ControllerSecuredWithPermission::$post_init_called);
@ -77,17 +77,17 @@ class BasicAuthTest extends FunctionalTest
$_SERVER['PHP_AUTH_USER'] = 'user-in-mygroup@test.com';
$_SERVER['PHP_AUTH_PW'] = 'wrongpassword';
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', null, $_SESSION, null, null, $_SERVER);
$this->assertEquals(401, $response->getStatusCode(), 'Invalid users dont have access');
$_SERVER['PHP_AUTH_USER'] = 'user-without-groups@test.com';
$_SERVER['PHP_AUTH_PW'] = 'test';
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', null, $_SESSION, null, null, $_SERVER);
$this->assertEquals(401, $response->getStatusCode(), 'Valid user without required permission has no access');
$_SERVER['PHP_AUTH_USER'] = 'user-in-mygroup@test.com';
$_SERVER['PHP_AUTH_PW'] = 'test';
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', null, $_SESSION, null, null, $_SERVER);;
$this->assertEquals(200, $response->getStatusCode(), 'Valid user with required permission has access');
$_SERVER['PHP_AUTH_USER'] = $origUser;
@ -101,17 +101,17 @@ class BasicAuthTest extends FunctionalTest
$_SERVER['PHP_AUTH_USER'] = 'user-without-groups@test.com';
$_SERVER['PHP_AUTH_PW'] = 'wrongpassword';
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', null, $_SESSION, null, null, $_SERVER);
$this->assertEquals(401, $response->getStatusCode(), 'Invalid users dont have access');
$_SERVER['PHP_AUTH_USER'] = 'user-without-groups@test.com';
$_SERVER['PHP_AUTH_PW'] = 'test';
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', null, $_SESSION, null, null, $_SERVER);
$this->assertEquals(200, $response->getStatusCode(), 'All valid users have access');
$_SERVER['PHP_AUTH_USER'] = 'user-in-mygroup@test.com';
$_SERVER['PHP_AUTH_PW'] = 'test';
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', null, $_SESSION, null, null, $_SERVER);
$this->assertEquals(200, $response->getStatusCode(), 'All valid users have access');
$_SERVER['PHP_AUTH_USER'] = $origUser;
@ -127,19 +127,19 @@ class BasicAuthTest extends FunctionalTest
// First failed attempt
$_SERVER['PHP_AUTH_USER'] = 'failedlogin@test.com';
$_SERVER['PHP_AUTH_PW'] = 'test';
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', null, $_SESSION, null, null, $_SERVER);
$check = Member::get()->filter('Email', 'failedlogin@test.com')->first();
$this->assertEquals(1, $check->FailedLoginCount);
// Second failed attempt
$_SERVER['PHP_AUTH_PW'] = 'testwrong';
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', null, $_SESSION, null, null, $_SERVER);
$check = Member::get()->filter('Email', 'failedlogin@test.com')->first();
$this->assertEquals(2, $check->FailedLoginCount);
// successful basic auth should reset failed login count
$_SERVER['PHP_AUTH_PW'] = 'Password';
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
$response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', null, $_SESSION, null, null, $_SERVER);
$check = Member::get()->filter('Email', 'failedlogin@test.com')->first();
$this->assertEquals(0, $check->FailedLoginCount);
}

View File

@ -9,6 +9,7 @@ use SilverStripe\Security\InheritedPermissions;
use SilverStripe\Security\InheritedPermissionsExtension;
use SilverStripe\Security\Member;
use SilverStripe\Security\PermissionChecker;
use SilverStripe\Security\Security;
use SilverStripe\Versioned\Versioned;
/**
@ -45,7 +46,7 @@ class TestPermissionNode extends DataObject implements TestOnly
public function canEdit($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
return static::getInheritedPermissions()->canEdit($this->ID, $member);
}
@ -53,7 +54,7 @@ class TestPermissionNode extends DataObject implements TestOnly
public function canView($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
return static::getInheritedPermissions()->canView($this->ID, $member);
}
@ -61,7 +62,7 @@ class TestPermissionNode extends DataObject implements TestOnly
public function canDelete($member = null)
{
if (!$member) {
$member = Member::currentUser();
$member = Security::getCurrentUser();
}
return static::getInheritedPermissions()->canDelete($this->ID, $member);
}

View File

@ -3,6 +3,7 @@
namespace SilverStripe\Security\Tests;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\Control\Cookie;
use SilverStripe\i18n\i18n;
@ -553,7 +554,6 @@ class MemberTest extends FunctionalTest
$this->assertFalse($member->canDelete());
$this->assertFalse($member->canEdit());
$this->addExtensions($extensions);
$this->logOut();
}
@ -568,14 +568,11 @@ class MemberTest extends FunctionalTest
$this->assertTrue($member2->canDelete());
$this->assertTrue($member2->canEdit());
$this->addExtensions($extensions);
$this->logOut();
}
public function testExtendedCan()
{
$extensions = $this->removeExtensions(Object::get_extensions(Member::class));
$member = $this->objFromFixture(Member::class, 'test');
/* Normal behaviour is that you can't view a member unless canView() on an extension returns true */
@ -1369,12 +1366,12 @@ class MemberTest extends FunctionalTest
public function testCurrentUser()
{
$this->assertNull(Member::currentUser());
$this->assertNull(Security::getCurrentUser());
$adminMember = $this->objFromFixture(Member::class, 'admin');
$this->logInAs($adminMember);
$userFromSession = Member::currentUser();
$userFromSession = Security::getCurrentUser();
$this->assertEquals($adminMember->ID, $userFromSession->ID);
}
@ -1383,7 +1380,7 @@ class MemberTest extends FunctionalTest
*/
public function testActAsUserPermissions()
{
$this->assertNull(Member::currentUser());
$this->assertNull(Security::getCurrentUser());
/** @var Member $adminMember */
$adminMember = $this->objFromFixture(Member::class, 'admin');
@ -1422,7 +1419,7 @@ class MemberTest extends FunctionalTest
*/
public function testActAsUser()
{
$this->assertNull(Member::currentUser());
$this->assertNull(Security::getCurrentUser());
/** @var Member $adminMember */
$adminMember = $this->objFromFixture(Member::class, 'admin');

View File

@ -182,8 +182,8 @@ class SecurityTest extends FunctionalTest
public function testAutomaticRedirectionOnLogin()
{
// BackURL with permission error (not authenticated) should not redirect
if ($member = Member::currentUser()) {
$member->logOut();
if ($member = Security::getCurrentUser()) {
Security::setCurrentUser(null);
}
$response = $this->getRecursive('SecurityTest_SecuredController');
$this->assertContains(Convert::raw2xml("That page is secured."), $response->getBody());
@ -228,7 +228,7 @@ class SecurityTest extends FunctionalTest
$member = DataObject::get_one(Member::class);
/* Log in with any user that we can find */
$this->session()->inst_set('loggedInAs', $member->ID);
Security::setCurrentUser($member);
/* View the Security/login page */
$response = $this->get(Config::inst()->get(Security::class, 'login_url'));
@ -254,7 +254,7 @@ class SecurityTest extends FunctionalTest
$this->assertNotNull($response->getBody(), 'There is body content on the page');
/* Log the user out */
$this->session()->inst_set('loggedInAs', null);
Security::setCurrentUser(null);
}
public function testMemberIDInSessionDoesntExistInDatabaseHasToLogin()

View File

@ -16,6 +16,7 @@ use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\PaginatedList;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\Security\SecurityToken;
use SilverStripe\Security\Permission;
use SilverStripe\View\ArrayData;
@ -406,22 +407,22 @@ SS;
);
$this->assertEquals(
(string)Member::currentUser(),
(string)Security::getCurrentUser(),
$this->render('{$CurrentMember}'),
'Member template functions result correct result'
);
$this->assertEquals(
(string)Member::currentUser(),
(string)Security::getCurrentUser(),
$this->render('{$CurrentUser}'),
'Member template functions result correct result'
);
$this->assertEquals(
(string)Member::currentUser(),
(string)Security::getCurrentUser(),
$this->render('{$currentMember}'),
'Member template functions result correct result'
);
$this->assertEquals(
(string)Member::currentUser(),
(string)Security::getCurrentUser(),
$this->render('{$currentUser}'),
'Member template functions result correct result'
);