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");
 }