public function testMemberGroupRelationForm() { Session::set('loggedInAs', $this->idFromFixture('GroupTest_Member', 'admin')); $adminGroup = $this->objFromFixture('SilverStripe\\Security\\Group', 'admingroup'); $parentGroup = $this->objFromFixture('SilverStripe\\Security\\Group', 'parentgroup'); $childGroup = $this->objFromFixture('SilverStripe\\Security\\Group', 'childgroup'); // Test single group relation through checkboxsetfield /** @skipUpgrade */ $form = new GroupTest_MemberForm($this, 'Form'); $member = $this->objFromFixture('GroupTest_Member', 'admin'); $form->loadDataFrom($member); $checkboxSetField = $form->Fields()->fieldByName('Groups'); $checkboxSetField->setValue(array($adminGroup->ID => $adminGroup->ID, $parentGroup->ID => $parentGroup->ID)); $form->saveInto($member); $updatedGroups = $member->Groups(); $this->assertEquals(2, count($updatedGroups->column()), "Adding a toplevel group works"); $this->assertContains($adminGroup->ID, $updatedGroups->column('ID')); $this->assertContains($parentGroup->ID, $updatedGroups->column('ID')); // Test unsetting relationship $form->loadDataFrom($member); $checkboxSetField = $form->Fields()->fieldByName('Groups'); $checkboxSetField->setValue(array($adminGroup->ID => $adminGroup->ID)); $form->saveInto($member); $member->flushCache(); $updatedGroups = $member->Groups(); $this->assertEquals(1, count($updatedGroups->column()), "Removing a previously added toplevel group works"); $this->assertContains($adminGroup->ID, $updatedGroups->column('ID')); // Test adding child group }
public function testGetAllElements() { Session::clear_all(); // Remove all session that might've been set by the test harness Session::set('Test', 'Test'); Session::set('Test-2', 'Test-2'); $session = Session::get_all(); unset($session['HTTP_USER_AGENT']); $this->assertEquals($session, array('Test' => 'Test', 'Test-2' => 'Test-2')); }
/** * @return array */ public function getAttributes() { // Store state in session, and pass ID to client side. $state = array('grid' => $this->getNameFromParent(), 'actionName' => $this->actionName, 'args' => $this->args); // Ensure $id doesn't contain only numeric characters $id = 'gf_' . substr(md5(serialize($state)), 0, 8); Session::set($id, $state); $actionData['StateID'] = $id; return array_merge(parent::getAttributes(), array('name' => 'action_gridFieldAlterAction' . '?' . http_build_query($actionData), 'data-url' => $this->gridField->Link())); }
public function revoke($filename, $hash) { $fileID = $this->getFileID($filename, $hash); $granted = Session::get(self::GRANTS_SESSION) ?: array(); unset($granted[$fileID]); if ($granted) { Session::set(self::GRANTS_SESSION, $granted); } else { Session::clear(self::GRANTS_SESSION); } }
/** * Processing that occurs before a form is executed. * * This includes form validation, if it fails, we redirect back * to the form with appropriate error messages. * Always return true if the current form action is exempt from validation * * Triggered through {@link httpSubmission()}. * * Note that CSRF protection takes place in {@link httpSubmission()}, * if it fails the form data will never reach this method. * * @return boolean */ public function validate() { $action = $this->buttonClicked(); if ($action && $this->actionIsValidationExempt($action)) { return true; } if ($this->validator) { $errors = $this->validator->validate(); if ($errors) { // Load errors into session and post back $data = $this->getData(); // Encode validation messages as XML before saving into session state // As per Form::addErrorMessage() $errors = array_map(function ($error) { // Encode message as XML by default if ($error['message'] instanceof DBField) { $error['message'] = $error['message']->forTemplate(); } else { $error['message'] = Convert::raw2xml($error['message']); } return $error; }, $errors); Session::set("FormInfo.{$this->FormName()}.errors", $errors); Session::set("FormInfo.{$this->FormName()}.data", $data); return false; } } return true; }
/** * Forces the current page to be set in session, * which can be retrieved later through {@link currentPageID()}. * Keep in mind that setting an ID through GET/POST or * as a URL parameter will overrule this value. * * @param int $id */ public function setCurrentPageID($id) { $id = (int) $id; Session::set($this->sessionNamespace() . ".currentPage", $id); }
/** * Show the "change password" page. * This page can either be called directly by logged-in users * (in which case they need to provide their old password), * or through a link emailed through {@link lostpassword()}. * In this case no old password is required, authentication is ensured * through the Member.AutoLoginHash property. * * @see ChangePasswordForm * * @return string|HTTPRequest Returns the "change password" page as HTML code, or a redirect response */ public function changepassword() { $controller = $this->getResponseController(_t('Security.CHANGEPASSWORDHEADER', 'Change your password')); // if the controller calls Director::redirect(), this will break early if (($response = $controller->getResponse()) && $response->isFinished()) { return $response; } // Extract the member from the URL. /** @var Member $member */ $member = null; if (isset($_REQUEST['m'])) { $member = Member::get()->filter('ID', (int) $_REQUEST['m'])->first(); } // Check whether we are merely changin password, or resetting. if (isset($_REQUEST['t']) && $member && $member->validateAutoLoginToken($_REQUEST['t'])) { // 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(); } // Store the hash for the change password form. Will be unset after reload within the ChangePasswordForm. Session::set('AutoLoginHash', $member->encryptWithUserSettings($_REQUEST['t'])); return $this->redirect($this->Link('changepassword')); } elseif (Session::get('AutoLoginHash')) { // Subsequent request after the "first load with hash" (see previous if clause). $customisedController = $controller->customise(array('Content' => '<p>' . _t('Security.ENTERNEWPASSWORD', 'Please enter a new password.') . '</p>', 'Form' => $this->ChangePasswordForm())); } elseif (Member::currentUser()) { // Logged in user requested a password change form. $customisedController = $controller->customise(array('Content' => '<p>' . _t('Security.CHANGEPASSWORDBELOW', 'You can change your password below.') . '</p>', 'Form' => $this->ChangePasswordForm())); } else { // Show friendly message if it seems like the user arrived here via password reset feature. if (isset($_REQUEST['m']) || isset($_REQUEST['t'])) { $customisedController = $controller->customise(array('Content' => _t('Security.NOTERESETLINKINVALID', '<p>The password reset link is invalid or expired.</p>' . '<p>You can request a new one <a href="{link1}">here</a> or change your password after' . ' you <a href="{link2}">logged in</a>.</p>', array('link1' => $this->Link('lostpassword'), 'link2' => $this->Link('login'))))); } else { return self::permissionFailure($this, _t('Security.ERRORPASSWORDPERMISSION', 'You must be logged in in order to change your password!')); } } return $customisedController->renderWith($this->getTemplatesFor('changepassword')); }
/** * Log the user in if the "remember login" cookie is set * * The <i>remember login token</i> will be changed on every successful * auto-login. */ public static function autoLogin() { // Don't bother trying this multiple times if (!class_exists('SilverStripe\\Dev\\SapphireTest', false) || !SapphireTest::is_running_test()) { self::$_already_tried_to_auto_log_in = true; } if (!Security::config()->autologin_enabled || strpos(Cookie::get('alc_enc'), ':') === false || Session::get("loggedInAs") || !Security::database_is_ready()) { return; } if (strpos(Cookie::get('alc_enc'), ':') && Cookie::get('alc_device') && !Session::get("loggedInAs")) { list($uid, $token) = explode(':', Cookie::get('alc_enc'), 2); if (!$uid || !$token) { return; } $deviceID = Cookie::get('alc_device'); /** @var Member $member */ $member = Member::get()->byID($uid); /** @var RememberLoginHash $rememberLoginHash */ $rememberLoginHash = null; // check if autologin token matches if ($member) { $hash = $member->encryptWithUserSettings($token); $rememberLoginHash = RememberLoginHash::get()->filter(array('MemberID' => $member->ID, 'DeviceID' => $deviceID, 'Hash' => $hash))->first(); if (!$rememberLoginHash) { $member = null; } else { // Check for expired token $expiryDate = new DateTime($rememberLoginHash->ExpiryDate); $now = DBDatetime::now(); $now = new DateTime($now->Rfc2822()); if ($now > $expiryDate) { $member = null; } } } if ($member) { self::session_regenerate_id(); Session::set("loggedInAs", $member->ID); // This lets apache rules detect whether the user has logged in if (Member::config()->login_marker_cookie) { Cookie::set(Member::config()->login_marker_cookie, 1, 0, null, null, false, true); } if ($rememberLoginHash) { $rememberLoginHash->renew(); $tokenExpiryDays = RememberLoginHash::config()->get('token_expiry_days'); Cookie::set('alc_enc', $member->ID . ':' . $rememberLoginHash->getToken(), $tokenExpiryDays, null, null, false, true); } $member->write(); // Audit logging hook $member->extend('memberAutoLoggedIn'); } } }
/** * Redirect the user to the change password form. * * @return HTTPResponse */ protected function redirectToChangePassword() { // Since this form is loaded via an iframe, this redirect must be performed via javascript $changePasswordForm = new ChangePasswordForm($this->controller, 'SilverStripe\\Security\\ChangePasswordForm'); $changePasswordForm->sessionMessage(_t('Member.PASSWORDEXPIRED', 'Your password has expired. Please choose a new one.'), 'good'); // Get redirect url $changePasswordURL = $this->getExternalLink('changepassword'); if ($backURL = $this->controller->getRequest()->requestVar('BackURL')) { Session::set('BackURL', $backURL); $changePasswordURL = Controller::join_links($changePasswordURL, '?BackURL=' . urlencode($backURL)); } $changePasswordURLATT = Convert::raw2att($changePasswordURL); $changePasswordURLJS = Convert::raw2js($changePasswordURL); $message = _t('CMSMemberLoginForm.PASSWORDEXPIRED', '<p>Your password has expired. <a target="_top" href="{link}">Please choose a new one.</a></p>', 'Message displayed to user if their session cannot be restored', array('link' => $changePasswordURLATT)); // Redirect to change password page $this->controller->getResponse()->setStatusCode(200); $this->controller->getResponse()->setBody(<<<PHP <!DOCTYPE html> <html><body> {$message} <script type="application/javascript"> setTimeout(function(){top.location.href = "{$changePasswordURLJS}";}, 0); </script> </body></html> PHP ); return $this->controller->getResponse(); }
/** * @param String $val */ public function setValue($val) { Session::set($this->getName(), $val); }
/** * Login in the user and figure out where to redirect the browser. * * The $data has this format * array( * 'AuthenticationMethod' => 'MemberAuthenticator', * 'Email' => '*****@*****.**', * 'Password' => '1nitialPassword', * 'BackURL' => 'test/link', * [Optional: 'Remember' => 1 ] * ) * * @param array $data * @return HTTPResponse */ protected function logInUserAndRedirect($data) { Session::clear('SessionForms.MemberLoginForm.Email'); Session::clear('SessionForms.MemberLoginForm.Remember'); if (Member::currentUser()->isPasswordExpired()) { if (isset($_REQUEST['BackURL']) && ($backURL = $_REQUEST['BackURL'])) { Session::set('BackURL', $backURL); } /** @skipUpgrade */ $cp = ChangePasswordForm::create($this->controller, 'ChangePasswordForm'); $cp->sessionMessage(_t('Member.PASSWORDEXPIRED', 'Your password has expired. Please choose a new one.'), 'good'); return $this->controller->redirect('Security/changepassword'); } // Absolute redirection URLs may cause spoofing if (!empty($_REQUEST['BackURL'])) { $url = $_REQUEST['BackURL']; if (Director::is_site_url($url)) { $url = Director::absoluteURL($url); } else { // Spoofing attack, redirect to homepage instead of spoofing url $url = Director::absoluteBaseURL(); } return $this->controller->redirect($url); } // If a default login dest has been set, redirect to that. if ($url = Security::config()->default_login_dest) { $url = Controller::join_links(Director::absoluteBaseURL(), $url); return $this->controller->redirect($url); } // Redirect the user to the page where they came from $member = Member::currentUser(); if ($member) { $firstname = Convert::raw2xml($member->FirstName); if (!empty($data['Remember'])) { Session::set('SessionForms.MemberLoginForm.Remember', '1'); $member->logIn(true); } else { $member->logIn(); } Session::set('Security.Message.message', _t('Member.WELCOMEBACK', "Welcome Back, {firstname}", array('firstname' => $firstname))); Session::set("Security.Message.type", "good"); } return Controller::curr()->redirectBack(); }
public function testDeleteActionRemoveRelation() { $this->logInWithPermission('ADMIN'); $config = GridFieldConfig::create()->addComponent(new GridFieldDeleteAction(true)); $gridField = new GridField('testfield', 'testfield', $this->list, $config); $form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList()); $stateID = 'testGridStateActionField'; Session::set($stateID, array('grid' => '', 'actionName' => 'deleterecord', 'args' => array('RecordID' => $this->idFromFixture('GridFieldAction_Delete_Team', 'team1')))); $token = SecurityToken::inst(); $request = new HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID=' . $stateID => true, $token->getName() => $token->getValue())); $this->gridField->gridFieldAlterAction(array('StateID' => $stateID), $this->form, $request); $this->assertEquals(2, $this->list->count(), 'User should be able to delete records with ADMIN permission.'); }
/** * Sets the appropriate form message in session, with type. This will be shown once, * for the form specified. * * @param string $formname the form name you wish to use ( usually $form->FormName() ) * @param string $message the message you wish to add to it * @param string $type the type of message */ public static function setFormMessage($formname, $message, $type) { Session::set("FormInfo.{$formname}.formError.message", $message); Session::set("FormInfo.{$formname}.formError.type", $type); }
/** * Choose the stage the site is currently on. * * If $_GET['stage'] is set, then it will use that stage, and store it in * the session. * * if $_GET['archiveDate'] is set, it will use that date, and store it in * the session. * * If neither of these are set, it checks the session, otherwise the stage * is set to 'Live'. */ public static function choose_site_stage() { // Check any pre-existing session mode $preexistingMode = Session::get('readingMode'); // Determine the reading mode if (isset($_GET['stage'])) { $stage = ucfirst(strtolower($_GET['stage'])); if (!in_array($stage, array(static::DRAFT, static::LIVE))) { $stage = static::LIVE; } $mode = 'Stage.' . $stage; } elseif (isset($_GET['archiveDate']) && strtotime($_GET['archiveDate'])) { $mode = 'Archive.' . $_GET['archiveDate']; } elseif ($preexistingMode) { $mode = $preexistingMode; } else { $mode = static::DEFAULT_MODE; } // Save reading mode Versioned::set_reading_mode($mode); // Try not to store the mode in the session if not needed if ($preexistingMode && $preexistingMode !== $mode || !$preexistingMode && $mode !== static::DEFAULT_MODE) { Session::set('readingMode', $mode); } if (!headers_sent() && !Director::is_cli()) { if (Versioned::get_stage() == 'Live') { // clear the cookie if it's set if (Cookie::get('bypassStaticCache')) { Cookie::force_expiry('bypassStaticCache', null, null, false, true); } } else { // set the cookie if it's cleared if (!Cookie::get('bypassStaticCache')) { Cookie::set('bypassStaticCache', '1', 0, null, null, false, true); } } } }
/** * Tests that reading mode persists between requests */ public function testReadingPersistent() { $session = Injector::inst()->create('SilverStripe\\Control\\Session', array()); $adminID = $this->logInWithPermission('ADMIN'); $session->inst_set('loggedInAs', $adminID); // Set to stage Director::test('/?stage=Stage', null, $session); $this->assertEquals('Stage.Stage', $session->inst_get('readingMode'), 'Check querystring changes reading mode to Stage'); Director::test('/', null, $session); $this->assertEquals('Stage.Stage', $session->inst_get('readingMode'), 'Check that subsequent requests in the same session remain in Stage mode'); // Test live persists Director::test('/?stage=Live', null, $session); $this->assertEquals('Stage.Live', $session->inst_get('readingMode'), 'Check querystring changes reading mode to Live'); Director::test('/', null, $session); $this->assertEquals('Stage.Live', $session->inst_get('readingMode'), 'Check that subsequent requests in the same session remain in Live mode'); // Test that session doesn't redundantly store the default stage if it doesn't need to $session2 = Injector::inst()->create('SilverStripe\\Control\\Session', array()); $session2->inst_set('loggedInAs', $adminID); Director::test('/', null, $session2); $this->assertArrayNotHasKey('readingMode', $session2->inst_changedData()); Director::test('/?stage=Live', null, $session2); $this->assertArrayNotHasKey('readingMode', $session2->inst_changedData()); // Test choose_site_stage unset($_GET['stage']); unset($_GET['archiveDate']); Session::set('readingMode', 'Stage.Stage'); Versioned::choose_site_stage(); $this->assertEquals('Stage.Stage', Versioned::get_reading_mode()); Session::set('readingMode', 'Archive.2014-01-01'); Versioned::choose_site_stage(); $this->assertEquals('Archive.2014-01-01', Versioned::get_reading_mode()); Session::clear('readingMode'); Versioned::choose_site_stage(); $this->assertEquals('Stage.Live', Versioned::get_reading_mode()); }
public function testCanEdit() { $file = $this->objFromFixture('SilverStripe\\Assets\\Image', 'gif'); // Test anonymous permissions Session::set('loggedInAs', null); $this->assertFalse($file->canEdit(), "Anonymous users can't edit files"); // Test permissionless user $this->objFromFixture('SilverStripe\\Security\\Member', 'frontend')->logIn(); $this->assertFalse($file->canEdit(), "Permissionless users can't edit files"); // Test global CMS section users $this->objFromFixture('SilverStripe\\Security\\Member', 'cms')->logIn(); $this->assertTrue($file->canEdit(), "Users with all CMS section access can edit files"); // Test cms access users without file access $this->objFromFixture('SilverStripe\\Security\\Member', 'security')->logIn(); $this->assertFalse($file->canEdit(), "Security CMS users can't edit files"); // Test asset-admin user $this->objFromFixture('SilverStripe\\Security\\Member', 'assetadmin')->logIn(); $this->assertTrue($file->canEdit(), "Asset admin users can edit files"); // Test admin $this->objFromFixture('SilverStripe\\Security\\Member', 'admin')->logIn(); $this->assertTrue($file->canEdit(), "Admins can edit files"); }