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
 }
 /**
  * @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()));
 }
 /**
  * Gets the current state of this form as a nested array.
  *
  * @param Form $form
  * @return array
  */
 public function getState(Form $form)
 {
     // Ensure that session errors are populated within form field messages
     $form->setupFormErrors();
     // @todo - Replace with ValidationResult handling
     // Currently tri-state; null (unsubmitted), true (submitted-valid), false (submitted-invalid)
     $errors = Session::get("FormInfo.{$form->FormName()}.errors");
     $valid = isset($errors) ? empty($errors) : null;
     $state = ['id' => $form->FormName(), 'fields' => [], 'valid' => $valid, 'messages' => []];
     // flattened nested fields are returned, rather than only top level fields.
     $state['fields'] = array_merge($this->getFieldStates($form->Fields()), $this->getFieldStates($form->Actions()));
     if ($message = $form->Message()) {
         $state['messages'][] = ['value' => ['html' => $message], 'type' => $form->MessageType()];
     }
     return $state;
 }
 /**
  * Get the ID of the current logged in user
  *
  * @return int Returns the ID of the current logged in user or 0.
  */
 public static function currentUserID()
 {
     $id = Session::get("loggedInAs");
     if (!$id && !self::$_already_tried_to_auto_log_in) {
         self::autoLogin();
         $id = Session::get("loggedInAs");
     }
     return is_numeric($id) ? $id : 0;
 }
 /**
  * Determine if a grant exists for the given FileID
  *
  * @param string $fileID
  * @return bool
  */
 protected function isGranted($fileID)
 {
     // Since permissions are applied to the non-variant only,
     // map back to the original file before checking
     $originalID = $this->removeVariant($fileID);
     $granted = Session::get(self::GRANTS_SESSION) ?: array();
     return !empty($granted[$originalID]);
 }
 /**
  * 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'));
 }
 /**
  * Process the given URL, creating the appropriate controller and executing it.
  *
  * Request processing is handled as follows:
  * - Director::direct() creates a new HTTPResponse object and passes this to
  *   Director::handleRequest().
  * - Director::handleRequest($request) checks each of the Director rules and identifies a controller
  *   to handle this request.
  * - Controller::handleRequest($request) is then called.  This will find a rule to handle the URL,
  *   and call the rule handling method.
  * - RequestHandler::handleRequest($request) is recursively called whenever a rule handling method
  *   returns a RequestHandler object.
  *
  * In addition to request processing, Director will manage the session, and perform the output of
  * the actual response to the browser.
  *
  * @uses handleRequest() rule-lookup logic is handled by this.
  * @uses Controller::handleRequest() This handles the page logic for a Director::direct() call.
  * @param string $url
  * @param DataModel $model
  * @throws HTTPResponse_Exception
  */
 public static function direct($url, DataModel $model)
 {
     // Validate $_FILES array before merging it with $_POST
     foreach ($_FILES as $k => $v) {
         if (is_array($v['tmp_name'])) {
             $v = ArrayLib::array_values_recursive($v['tmp_name']);
             foreach ($v as $tmpFile) {
                 if ($tmpFile && !is_uploaded_file($tmpFile)) {
                     user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR);
                 }
             }
         } else {
             if ($v['tmp_name'] && !is_uploaded_file($v['tmp_name'])) {
                 user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR);
             }
         }
     }
     $req = new HTTPRequest(isset($_SERVER['X-HTTP-Method-Override']) ? $_SERVER['X-HTTP-Method-Override'] : $_SERVER['REQUEST_METHOD'], $url, $_GET, ArrayLib::array_merge_recursive((array) $_POST, (array) $_FILES), @file_get_contents('php://input'));
     $headers = self::extract_request_headers($_SERVER);
     foreach ($headers as $header => $value) {
         $req->addHeader($header, $value);
     }
     // Initiate an empty session - doesn't initialize an actual PHP session until saved (see below)
     $session = Session::create(isset($_SESSION) ? $_SESSION : array());
     // Only resume a session if its not started already, and a session identifier exists
     if (!isset($_SESSION) && Session::request_contains_session_id()) {
         $session->inst_start();
     }
     $output = RequestProcessor::singleton()->preRequest($req, $session, $model);
     if ($output === false) {
         // @TODO Need to NOT proceed with the request in an elegant manner
         throw new HTTPResponse_Exception(_t('Director.INVALID_REQUEST', 'Invalid request'), 400);
     }
     $result = Director::handleRequest($req, $session, $model);
     // Save session data. Note that inst_save() will start/resume the session if required.
     $session->inst_save();
     // Return code for a redirection request
     if (is_string($result) && substr($result, 0, 9) == 'redirect:') {
         $url = substr($result, 9);
         if (Director::is_cli()) {
             // on cli, follow SilverStripe redirects automatically
             Director::direct(str_replace(Director::absoluteBaseURL(), '', $url), DataModel::inst());
             return;
         } else {
             $response = new HTTPResponse();
             $response->redirect($url);
             $res = RequestProcessor::singleton()->postRequest($req, $response, $model);
             if ($res !== false) {
                 $response->output();
             }
         }
         // Handle a controller
     } elseif ($result) {
         if ($result instanceof HTTPResponse) {
             $response = $result;
         } else {
             $response = new HTTPResponse();
             $response->setBody($result);
         }
         $res = RequestProcessor::singleton()->postRequest($req, $response, $model);
         if ($res !== false) {
             $response->output();
         } else {
             // @TODO Proper response here.
             throw new HTTPResponse_Exception("Invalid response");
         }
         //$controllerObj->getSession()->inst_save();
     }
 }
 /**
  * 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);
             }
         }
     }
 }
 public function testNonStandardPath()
 {
     Config::inst()->update('SilverStripe\\Control\\Session', 'store_path', realpath(dirname($_SERVER['DOCUMENT_ROOT']) . '/../session'));
     Session::start();
     $this->assertEquals(Config::inst()->get('SilverStripe\\Control\\Session', 'store_path'), '');
 }
 public function testCanViewStage()
 {
     $public = $this->objFromFixture('VersionedTest_PublicStage', 'public1');
     $private = $this->objFromFixture('VersionedTest_DataObject', 'page1');
     Session::clear("loggedInAs");
     Versioned::set_stage(Versioned::DRAFT);
     // Test that all (and only) public pages are viewable in stage mode
     // Unpublished records are not viewable in live regardless of permissions
     $this->assertTrue($public->canViewStage('Stage'));
     $this->assertFalse($private->canViewStage('Stage'));
     $this->assertFalse($public->canViewStage('Live'));
     $this->assertFalse($private->canViewStage('Live'));
     // Writing records to live should make both stage and live modes viewable
     $private->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
     $public->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
     $this->assertTrue($public->canViewStage('Stage'));
     $this->assertTrue($private->canViewStage('Stage'));
     $this->assertTrue($public->canViewStage('Live'));
     $this->assertTrue($private->canViewStage('Live'));
     // If the draft mode changes, the live mode remains public, although the updated
     // draft mode is secured for non-public records.
     $private->Title = 'Secret Title';
     $private->write();
     $public->Title = 'Public Title';
     $public->write();
     $this->assertTrue($public->canViewStage('Stage'));
     $this->assertFalse($private->canViewStage('Stage'));
     $this->assertTrue($public->canViewStage('Live'));
     $this->assertTrue($private->canViewStage('Live'));
 }
 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");
 }
 /**
  * Method to authenticate an user
  *
  * @param array $data Raw data to authenticate the user
  * @param Form $form Optional: If passed, better error messages can be
  *                             produced by using
  *                             {@link Form::sessionMessage()}
  * @return bool|Member Returns FALSE if authentication fails, otherwise
  *                     the member object
  * @see Security::setDefaultAdmin()
  */
 public static function authenticate($data, Form $form = null)
 {
     // Find authenticated member
     $member = static::authenticate_member($data, $form, $success);
     // Optionally record every login attempt as a {@link LoginAttempt} object
     static::record_login_attempt($data, $member, $success);
     // Legacy migration to precision-safe password hashes.
     // A login-event with cleartext passwords is the only time
     // when we can rehash passwords to a different hashing algorithm,
     // bulk-migration doesn't work due to the nature of hashing.
     // See PasswordEncryptor_LegacyPHPHash class.
     if ($success && $member && isset(self::$migrate_legacy_hashes[$member->PasswordEncryption])) {
         $member->Password = $data['Password'];
         $member->PasswordEncryption = self::$migrate_legacy_hashes[$member->PasswordEncryption];
         $member->write();
     }
     if ($success) {
         Session::clear('BackURL');
     }
     return $success ? $member : null;
 }
        $chain->setSuppression(false);
    }
    // Load in core
    require_once 'Core/Core.php';
    // Connect to database
    global $databaseConfig;
    if ($databaseConfig) {
        DB::connect($databaseConfig);
    }
    // Check if a token is requesting a redirect
    if (!$reloadToken) {
        return;
    }
    // Otherwise, we start up the session if needed
    if (!isset($_SESSION) && Session::request_contains_session_id()) {
        Session::start();
    }
    // Next, check if we're in dev mode, or the database doesn't have any security data, or we are admin
    if (Director::isDev() || !Security::database_is_ready() || Permission::check('ADMIN')) {
        return $reloadToken->reloadWithToken();
    }
    // Fail and redirect the user to the login page
    $loginPage = Director::absoluteURL(Security::config()->login_url);
    $loginPage .= "?BackURL=" . urlencode($_SERVER['REQUEST_URI']);
    header('location: ' . $loginPage, true, 302);
    die;
})->thenIfErrored(function () use($reloadToken) {
    if ($reloadToken) {
        $reloadToken->reloadWithToken();
    }
})->execute();
 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.');
 }
 public function testPermissionFailureSetsCorrectFormMessages()
 {
     Config::nest();
     // Controller that doesn't attempt redirections
     $controller = new SecurityTest_NullController();
     $controller->setResponse(new HTTPResponse());
     Security::permissionFailure($controller, array('default' => 'Oops, not allowed'));
     $this->assertEquals('Oops, not allowed', Session::get('Security.Message.message'));
     // Test that config values are used correctly
     Config::inst()->update('SilverStripe\\Security\\Security', 'default_message_set', 'stringvalue');
     Security::permissionFailure($controller);
     $this->assertEquals('stringvalue', Session::get('Security.Message.message'), 'Default permission failure message value was not present');
     Config::inst()->remove('SilverStripe\\Security\\Security', 'default_message_set');
     Config::inst()->update('SilverStripe\\Security\\Security', 'default_message_set', array('default' => 'arrayvalue'));
     Security::permissionFailure($controller);
     $this->assertEquals('arrayvalue', Session::get('Security.Message.message'), 'Default permission failure message value was not present');
     // Test that non-default messages work.
     // NOTE: we inspect the response body here as the session message has already
     // been fetched and output as part of it, so has been removed from the session
     $this->logInWithPermission('EDITOR');
     Config::inst()->update('SilverStripe\\Security\\Security', 'default_message_set', array('default' => 'default', 'alreadyLoggedIn' => 'You are already logged in!'));
     Security::permissionFailure($controller);
     $this->assertContains('You are already logged in!', $controller->getResponse()->getBody(), 'Custom permission failure message was ignored');
     Security::permissionFailure($controller, array('default' => 'default', 'alreadyLoggedIn' => 'One-off failure message'));
     $this->assertContains('One-off failure message', $controller->getResponse()->getBody(), "Message set passed to Security::permissionFailure() didn't override Config values");
     Config::unnest();
 }
 /**
  * This is the action that gets executed when a GridField_AlterAction gets clicked.
  *
  * @param array $data
  * @param Form $form
  * @param HTTPRequest $request
  *
  * @return string
  */
 public function gridFieldAlterAction($data, $form, HTTPRequest $request)
 {
     $data = $request->requestVars();
     // Protection against CSRF attacks
     $token = $this->getForm()->getSecurityToken();
     if (!$token->checkRequest($request)) {
         $this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE", "There seems to have been a technical problem. Please click the back button, " . "refresh your browser, and try again."));
     }
     $name = $this->getName();
     $fieldData = null;
     if (isset($data[$name])) {
         $fieldData = $data[$name];
     }
     $state = $this->getState(false);
     /** @skipUpgrade */
     if (isset($fieldData['GridState'])) {
         $state->setValue($fieldData['GridState']);
     }
     foreach ($data as $dataKey => $dataValue) {
         if (preg_match('/^action_gridFieldAlterAction\\?StateID=(.*)/', $dataKey, $matches)) {
             $stateChange = Session::get($matches[1]);
             $actionName = $stateChange['actionName'];
             $arguments = array();
             if (isset($stateChange['args'])) {
                 $arguments = $stateChange['args'];
             }
             $html = $this->handleAlterAction($actionName, $arguments, $data);
             if ($html) {
                 return $html;
             }
         }
     }
     if ($request->getHeader('X-Pjax') === 'CurrentField') {
         return $this->FieldHolder();
     }
     return $form->forTemplate();
 }
 public function setUp()
 {
     //nest config and injector for each test so they are effectively sandboxed per test
     Config::nest();
     Injector::nest();
     $this->originalReadingMode = Versioned::get_reading_mode();
     // We cannot run the tests on this abstract class.
     if (get_class($this) == __CLASS__) {
         $this->markTestSkipped(sprintf('Skipping %s ', get_class($this)));
         return;
     }
     // Mark test as being run
     $this->originalIsRunningTest = self::$is_running_test;
     self::$is_running_test = true;
     // i18n needs to be set to the defaults or tests fail
     i18n::set_locale(i18n::config()->get('default_locale'));
     i18n::config()->date_format = null;
     i18n::config()->time_format = null;
     // Set default timezone consistently to avoid NZ-specific dependencies
     date_default_timezone_set('UTC');
     // Remove password validation
     $this->originalMemberPasswordValidator = Member::password_validator();
     $this->originalRequirements = Requirements::backend();
     Member::set_password_validator(null);
     Cookie::config()->update('report_errors', false);
     if (class_exists('SilverStripe\\CMS\\Controllers\\RootURLController')) {
         RootURLController::reset();
     }
     if (class_exists('Translatable')) {
         Translatable::reset();
     }
     Versioned::reset();
     DataObject::reset();
     if (class_exists('SilverStripe\\CMS\\Model\\SiteTree')) {
         SiteTree::reset();
     }
     Hierarchy::reset();
     if (Controller::has_curr()) {
         Controller::curr()->setSession(Session::create(array()));
     }
     Security::$database_is_ready = null;
     // Add controller-name auto-routing
     // @todo Fix to work with namespaced controllers
     Director::config()->update('rules', array('$Controller//$Action/$ID/$OtherID' => '*'));
     $fixtureFiles = $this->getFixturePaths();
     // Todo: this could be a special test model
     $this->model = DataModel::inst();
     // Set up fixture
     if ($fixtureFiles || $this->usesDatabase) {
         if (!self::using_temp_db()) {
             self::create_temp_db();
         }
         DataObject::singleton()->flushCache();
         self::empty_temp_db();
         foreach ($this->requireDefaultRecordsFrom as $className) {
             $instance = singleton($className);
             if (method_exists($instance, 'requireDefaultRecords')) {
                 $instance->requireDefaultRecords();
             }
             if (method_exists($instance, 'augmentDefaultRecords')) {
                 $instance->augmentDefaultRecords();
             }
         }
         foreach ($fixtureFiles as $fixtureFilePath) {
             $fixture = YamlFixture::create($fixtureFilePath);
             $fixture->writeInto($this->getFixtureFactory());
         }
         $this->logInWithPermission("ADMIN");
     }
     // Preserve memory settings
     $this->originalMemoryLimit = ini_get('memory_limit');
     // turn off template debugging
     SSViewer::config()->update('source_file_comments', false);
     // Clear requirements
     Requirements::clear();
     // Set up email
     $this->mailer = new TestMailer();
     Injector::inst()->registerService($this->mailer, 'SilverStripe\\Control\\Email\\Mailer');
     Email::config()->remove('send_all_emails_to');
 }
 /**
  * Given a successful login, tell the parent frame to close the dialog
  *
  * @return HTTPResponse|DBField
  */
 public function success()
 {
     // Ensure member is properly logged in
     if (!Member::currentUserID()) {
         return $this->redirectToExternalLogin();
     }
     // Get redirect url
     $controller = $this->getResponseController(_t('CMSSecurity.SUCCESS', 'Success'));
     $backURLs = array($this->getRequest()->requestVar('BackURL'), Session::get('BackURL'), Director::absoluteURL(AdminRootController::config()->url_base, true));
     $backURL = null;
     foreach ($backURLs as $backURL) {
         if ($backURL && Director::is_site_url($backURL)) {
             break;
         }
     }
     // Show login
     $controller = $controller->customise(array('Content' => _t('CMSSecurity.SUCCESSCONTENT', '<p>Login success. If you are not automatically redirected ' . '<a target="_top" href="{link}">click here</a></p>', 'Login message displayed in the cms popup once a user has re-authenticated themselves', array('link' => $backURL))));
     return $controller->renderWith($this->getTemplatesFor('success'));
 }
 /**
  * Change the password
  *
  * @param array $data The user submitted data
  * @return HTTPResponse
  */
 public function doChangePassword(array $data)
 {
     if ($member = Member::currentUser()) {
         // The user was logged in, check the current password
         if (empty($data['OldPassword']) || !$member->checkPassword($data['OldPassword'])->valid()) {
             $this->clearMessage();
             $this->sessionMessage(_t('Member.ERRORPASSWORDNOTMATCH', "Your current password does not match, please try again"), "bad");
             // redirect back to the form, instead of using redirectBack() which could send the user elsewhere.
             return $this->controller->redirect($this->controller->Link('changepassword'));
         }
     }
     if (!$member) {
         if (Session::get('AutoLoginHash')) {
             $member = Member::member_from_autologinhash(Session::get('AutoLoginHash'));
         }
         // The user is not logged in and no valid auto login hash is available
         if (!$member) {
             Session::clear('AutoLoginHash');
             return $this->controller->redirect($this->controller->Link('login'));
         }
     }
     // Check the new password
     if (empty($data['NewPassword1'])) {
         $this->clearMessage();
         $this->sessionMessage(_t('Member.EMPTYNEWPASSWORD', "The new password can't be empty, please try again"), "bad");
         // redirect back to the form, instead of using redirectBack() which could send the user elsewhere.
         return $this->controller->redirect($this->controller->Link('changepassword'));
     } else {
         if ($data['NewPassword1'] == $data['NewPassword2']) {
             $isValid = $member->changePassword($data['NewPassword1']);
             if ($isValid->valid()) {
                 // Clear locked out status
                 $member->LockedOutUntil = null;
                 $member->FailedLoginCount = null;
                 $member->write();
                 if ($member->canLogIn()->valid()) {
                     $member->logIn();
                 }
                 // TODO Add confirmation message to login redirect
                 Session::clear('AutoLoginHash');
                 if (!empty($_REQUEST['BackURL']) && Director::is_site_url($_REQUEST['BackURL'])) {
                     $url = Director::absoluteURL($_REQUEST['BackURL']);
                     return $this->controller->redirect($url);
                 } else {
                     // Redirect to default location - the login form saying "You are logged in as..."
                     $redirectURL = HTTP::setGetVar('BackURL', Director::absoluteBaseURL(), $this->controller->Link('login'));
                     return $this->controller->redirect($redirectURL);
                 }
             } else {
                 $this->clearMessage();
                 $this->sessionMessage(_t('Member.INVALIDNEWPASSWORD', "We couldn't accept that password: {password}", array('password' => nl2br("\n" . Convert::raw2xml($isValid->starredList())))), "bad", false);
                 // redirect back to the form, instead of using redirectBack() which could send the user elsewhere.
                 return $this->controller->redirect($this->controller->Link('changepassword'));
             }
         } else {
             $this->clearMessage();
             $this->sessionMessage(_t('Member.ERRORNEWPASSWORD', "You have entered your new password differently, try again"), "bad");
             // redirect back to the form, instead of using redirectBack() which could send the user elsewhere.
             return $this->controller->redirect($this->controller->Link('changepassword'));
         }
     }
 }
 /**
  * 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 testCanView()
 {
     // Create changeset containing all items (unpublished)
     $this->logInWithPermission('ADMIN');
     $changeSet = new ChangeSet();
     $changeSet->write();
     $base = $this->objFromFixture(ChangeSetTest_Base::class, 'base');
     $changeSet->addObject($base);
     $changeSet->sync();
     $this->assertEquals(5, $changeSet->Changes()->count());
     // Check canView
     Session::clear("loggedInAs");
     $this->assertFalse($changeSet->canView());
     $this->logInWithPermission('SomeWrongPermission');
     $this->assertFalse($changeSet->canView());
     $this->logInWithPermission('CMS_ACCESS_CampaignAdmin');
     $this->assertTrue($changeSet->canView());
 }
 /**
  * @param String $val
  */
 public function setValue($val)
 {
     Session::set($this->getName(), $val);
 }
 public function testCanUploadWithPermissionCode()
 {
     $field = UploadField::create('MyField');
     Session::clear("loggedInAs");
     $field->setCanUpload(true);
     $this->assertTrue($field->canUpload());
     $field->setCanUpload(false);
     $this->assertFalse($field->canUpload());
     $this->loginWithPermission('ADMIN');
     $field->setCanUpload(false);
     $this->assertFalse($field->canUpload());
     $field->setCanUpload('ADMIN');
     $this->assertTrue($field->canUpload());
 }
    /**
     * 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();
    }