/**
  * Get the locale of the Member, or if we're not logged in or don't have a locale, use the default one
  * @return string
  */
 protected function locale()
 {
     if (($member = Member::currentUser()) && $member->Locale) {
         return $member->Locale;
     }
     return i18n::get_locale();
 }
 /**
  * Change the password
  *
  * @param array $data The user submitted data
  * @return SS_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()) {
                 $member->logIn();
                 // TODO Add confirmation message to login redirect
                 Session::clear('AutoLoginHash');
                 // Clear locked out status
                 $member->LockedOutUntil = null;
                 $member->FailedLoginCount = null;
                 $member->write();
                 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'));
         }
     }
 }
 /**
  * Require basic authentication.  Will request a username and password if none is given.
  *
  * Used by {@link Controller::init()}.
  *
  * @throws HTTPResponse_Exception
  *
  * @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
  */
 public static function requireLogin($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) {
         return true;
     }
     /*
      * Enable HTTP Basic authentication workaround for PHP running in CGI mode with Apache
      * Depending on server configuration the auth header may be in HTTP_AUTHORIZATION or
      * REDIRECT_HTTP_AUTHORIZATION
      *
      * 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);
     $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);
     }
     $member = null;
     if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
         $member = MemberAuthenticator::authenticate(array('Email' => $_SERVER['PHP_AUTH_USER'], 'Password' => $_SERVER['PHP_AUTH_PW']), null);
     }
     if (!$member && $tryUsingSessionLogin) {
         $member = Member::currentUser();
     }
     // If we've failed the authentication mechanism, then show the login form
     if (!$member) {
         $response = new HTTPResponse(null, 401);
         $response->addHeader('WWW-Authenticate', "Basic realm=\"{$realm}\"");
         if (isset($_SERVER['PHP_AUTH_USER'])) {
             $response->setBody(_t('BasicAuth.ERRORNOTREC', "That username / password isn't recognised"));
         } else {
             $response->setBody(_t('BasicAuth.ENTERINFO', "Please enter a username and password."));
         }
         // Exception is caught by RequestHandler->handleRequest() and will halt further execution
         $e = new HTTPResponse_Exception(null, 401);
         $e->setResponse($response);
         throw $e;
     }
     if ($permissionCode && !Permission::checkMember($member->ID, $permissionCode)) {
         $response = new HTTPResponse(null, 401);
         $response->addHeader('WWW-Authenticate', "Basic realm=\"{$realm}\"");
         if (isset($_SERVER['PHP_AUTH_USER'])) {
             $response->setBody(_t('BasicAuth.ERRORNOTADMIN', "That user is not an administrator."));
         }
         // Exception is caught by RequestHandler->handleRequest() and will halt further execution
         $e = new HTTPResponse_Exception(null, 401);
         $e->setResponse($response);
         throw $e;
     }
     return $member;
 }
 public function testShowEditLinks()
 {
     if (Member::currentUser()) {
         Member::currentUser()->logOut();
     }
     $content = new CSSContentParser($this->gridField->FieldHolder());
     // Check that there are content
     $this->assertEquals(3, count($content->getBySelector('.ss-gridfield-item')));
     // Make sure that there are edit links, even though the user doesn't have "edit" permissions
     // (they can still view the records)
     $this->assertEquals(2, count($content->getBySelector('.edit-link')), 'Edit links should show when not logged in.');
 }
 public function testDeleteActionWithoutCorrectPermission()
 {
     if (Member::currentUser()) {
         Member::currentUser()->logOut();
     }
     $this->setExpectedException('SilverStripe\\ORM\\ValidationException');
     $stateID = 'testGridStateActionField';
     Session::set($stateID, array('grid' => '', 'actionName' => 'deleterecord', 'args' => array('RecordID' => $this->idFromFixture('GridFieldAction_Delete_Team', 'team1'))));
     $token = SecurityToken::inst();
     $request = new SS_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(3, $this->list->count(), 'User should\'t be able to delete records without correct permissions.');
 }
 public function canView($member = null)
 {
     if (!$member && $member !== false) {
         $member = Member::currentUser();
     }
     // cms menus only for logged-in members
     if (!$member) {
         return false;
     }
     // Check they can access the CMS and that they are trying to edit themselves
     if (Permission::checkMember($member, "CMS_ACCESS") && $member->ID === Member::currentUserID()) {
         return true;
     }
     return false;
 }
 /**
  * Returns the main menu of the CMS.  This is also used by init()
  * to work out which sections the user has access to.
  *
  * @param bool $cached
  * @return SS_List
  */
 public function MainMenu($cached = true)
 {
     if (!isset($this->_cache_MainMenu) || !$cached) {
         // Don't accidentally return a menu if you're not logged in - it's used to determine access.
         if (!Member::currentUser()) {
             return new ArrayList();
         }
         // Encode into DO set
         $menu = new ArrayList();
         $menuItems = CMSMenu::get_viewable_menu_items();
         // extra styling for custom menu-icons
         $menuIconStyling = '';
         if ($menuItems) {
             /** @var CMSMenuItem $menuItem */
             foreach ($menuItems as $code => $menuItem) {
                 // alternate permission checks (in addition to LeftAndMain->canView())
                 if (isset($menuItem->controller) && $this->hasMethod('alternateMenuDisplayCheck') && !$this->alternateMenuDisplayCheck($menuItem->controller)) {
                     continue;
                 }
                 $linkingmode = "link";
                 if ($menuItem->controller && get_class($this) == $menuItem->controller) {
                     $linkingmode = "current";
                 } else {
                     if (strpos($this->Link(), $menuItem->url) !== false) {
                         if ($this->Link() == $menuItem->url) {
                             $linkingmode = "current";
                             // default menu is the one with a blank {@link url_segment}
                         } else {
                             if (singleton($menuItem->controller)->stat('url_segment') == '') {
                                 if ($this->Link() == AdminRootController::admin_url()) {
                                     $linkingmode = "current";
                                 }
                             } else {
                                 $linkingmode = "current";
                             }
                         }
                     }
                 }
                 // already set in CMSMenu::populate_menu(), but from a static pre-controller
                 // context, so doesn't respect the current user locale in _t() calls - as a workaround,
                 // we simply call LeftAndMain::menu_title() again
                 // if we're dealing with a controller
                 if ($menuItem->controller) {
                     $title = LeftAndMain::menu_title($menuItem->controller);
                 } else {
                     $title = $menuItem->title;
                 }
                 // Provide styling for custom $menu-icon. Done here instead of in
                 // CMSMenu::populate_menu(), because the icon is part of
                 // the CMS right pane for the specified class as well...
                 if ($menuItem->controller) {
                     $menuIcon = LeftAndMain::menu_icon_for_class($menuItem->controller);
                     if (!empty($menuIcon)) {
                         $menuIconStyling .= $menuIcon;
                     }
                 }
                 $menu->push(new ArrayData(array("MenuItem" => $menuItem, "AttributesHTML" => $menuItem->getAttributesHTML(), "Title" => Convert::raw2xml($title), "Code" => $code, "Icon" => strtolower($code), "Link" => $menuItem->url, "LinkingMode" => $linkingmode)));
             }
         }
         if ($menuIconStyling) {
             Requirements::customCSS($menuIconStyling);
         }
         $this->_cache_MainMenu = $menu;
     }
     return $this->_cache_MainMenu;
 }
Exemplo n.º 8
0
 /**
  * Return a date formatted as per a CMS user's settings.
  *
  * @param Member $member
  * @return boolean | string A date formatted as per user-defined settings.
  */
 public function FormatFromSettings($member = null)
 {
     require_once 'Zend/Date.php';
     if (!$member) {
         if (!Member::currentUserID()) {
             return false;
         }
         $member = Member::currentUser();
     }
     $formatD = $member->getDateFormat();
     $zendDate = new Zend_Date($this->getValue(), 'y-MM-dd');
     return $zendDate->toString($formatD);
 }
 /**
  * Send user to the right location after login
  *
  * @param array $data
  * @return HTTPResponse
  */
 protected function logInUserAndRedirect($data)
 {
     // Check password expiry
     if (Member::currentUser()->isPasswordExpired()) {
         // Redirect the user to the external password change form if necessary
         return $this->redirectToChangePassword();
     } else {
         // Link to success template
         $url = $this->controller->Link('success');
         return $this->controller->redirect($url);
     }
 }
Exemplo n.º 10
0
 /**
  * Generate a CSV import form for a single {@link DataObject} subclass.
  *
  * @return Form
  */
 public function ImportForm()
 {
     $modelSNG = singleton($this->modelClass);
     $modelName = $modelSNG->i18n_singular_name();
     // check if a import form should be generated
     if (!$this->showImportForm || is_array($this->showImportForm) && !in_array($this->modelClass, $this->showImportForm)) {
         return false;
     }
     $importers = $this->getModelImporters();
     if (!$importers || !isset($importers[$this->modelClass])) {
         return false;
     }
     if (!$modelSNG->canCreate(Member::currentUser())) {
         return false;
     }
     $fields = new FieldList(new HiddenField('ClassName', _t('ModelAdmin.CLASSTYPE'), $this->modelClass), new FileField('_CsvFile', false));
     // get HTML specification for each import (column names etc.)
     $importerClass = $importers[$this->modelClass];
     $importer = new $importerClass($this->modelClass);
     $spec = $importer->getImportSpec();
     $specFields = new ArrayList();
     foreach ($spec['fields'] as $name => $desc) {
         $specFields->push(new ArrayData(array('Name' => $name, 'Description' => $desc)));
     }
     $specRelations = new ArrayList();
     foreach ($spec['relations'] as $name => $desc) {
         $specRelations->push(new ArrayData(array('Name' => $name, 'Description' => $desc)));
     }
     $specHTML = $this->customise(array('ClassName' => $this->sanitiseClassName($this->modelClass), 'ModelName' => Convert::raw2att($modelName), 'Fields' => $specFields, 'Relations' => $specRelations))->renderWith('Includes/ModelAdmin_ImportSpec');
     $fields->push(new LiteralField("SpecFor{$modelName}", $specHTML));
     $fields->push(new CheckboxField('EmptyBeforeImport', _t('ModelAdmin.EMPTYBEFOREIMPORT', 'Replace data'), false));
     $actions = new FieldList(new FormAction('import', _t('ModelAdmin.IMPORT', 'Import from CSV')));
     $form = new Form($this, "ImportForm", $fields, $actions);
     $form->setFormAction(Controller::join_links($this->Link($this->sanitiseClassName($this->modelClass)), 'ImportForm'));
     $this->extend('updateImportForm', $form);
     return $form;
 }
 /**
  * Returns true if the member is allowed to do the given action. Defaults to the currently logged
  * in user.
  *
  * @param string $perm
  * @param null|member $member
  *
  * @return bool
  */
 public function can($perm, $member = null)
 {
     if (!$member) {
         $member = Member::currentUser();
     }
     if (is_array($perm)) {
         $perm = array_map(array($this, 'can'), $perm, array_fill(0, count($perm), $member));
         return min($perm);
     }
     if ($this->hasMethod($methodName = 'can' . $perm)) {
         return $this->{$methodName}($member);
     } else {
         return true;
     }
 }
 /**
  * Validate this field
  *
  * @param Validator $validator
  * @return bool
  */
 public function validate($validator)
 {
     $name = $this->name;
     // if field isn't visible, don't validate
     if (!$this->isSaveable()) {
         return true;
     }
     $this->passwordField->setValue($this->value);
     $this->confirmPasswordfield->setValue($this->confirmValue);
     $value = $this->passwordField->Value();
     // both password-fields should be the same
     if ($value != $this->confirmPasswordfield->Value()) {
         $validator->validationError($name, _t('Form.VALIDATIONPASSWORDSDONTMATCH', "Passwords don't match"), "validation");
         return false;
     }
     if (!$this->canBeEmpty) {
         // both password-fields shouldn't be empty
         if (!$value || !$this->confirmPasswordfield->Value()) {
             $validator->validationError($name, _t('Form.VALIDATIONPASSWORDSNOTEMPTY', "Passwords can't be empty"), "validation");
             return false;
         }
     }
     // lengths
     if ($this->minLength || $this->maxLength) {
         $errorMsg = null;
         $limit = null;
         if ($this->minLength && $this->maxLength) {
             $limit = "{{$this->minLength},{$this->maxLength}}";
             $errorMsg = _t('ConfirmedPasswordField.BETWEEN', 'Passwords must be {min} to {max} characters long.', array('min' => $this->minLength, 'max' => $this->maxLength));
         } elseif ($this->minLength) {
             $limit = "{{$this->minLength}}.*";
             $errorMsg = _t('ConfirmedPasswordField.ATLEAST', 'Passwords must be at least {min} characters long.', array('min' => $this->minLength));
         } elseif ($this->maxLength) {
             $limit = "{0,{$this->maxLength}}";
             $errorMsg = _t('ConfirmedPasswordField.MAXIMUM', 'Passwords must be at most {max} characters long.', array('max' => $this->maxLength));
         }
         $limitRegex = '/^.' . $limit . '$/';
         if (!empty($value) && !preg_match($limitRegex, $value)) {
             $validator->validationError($name, $errorMsg, "validation");
         }
     }
     if ($this->requireStrongPassword) {
         if (!preg_match('/^(([a-zA-Z]+\\d+)|(\\d+[a-zA-Z]+))[a-zA-Z0-9]*$/', $value)) {
             $validator->validationError($name, _t('Form.VALIDATIONSTRONGPASSWORD', "Passwords must have at least one digit and one alphanumeric character"), "validation");
             return false;
         }
     }
     // Check if current password is valid
     if (!empty($value) && $this->getRequireExistingPassword()) {
         if (!$this->currentPasswordValue) {
             $validator->validationError($name, _t('ConfirmedPasswordField.CURRENT_PASSWORD_MISSING', "You must enter your current password."), "validation");
             return false;
         }
         // Check this password is valid for the current user
         $member = Member::currentUser();
         if (!$member) {
             $validator->validationError($name, _t('ConfirmedPasswordField.LOGGED_IN_ERROR', "You must be logged in to change your password."), "validation");
             return false;
         }
         // With a valid user and password, check the password is correct
         $checkResult = $member->checkPassword($this->currentPasswordValue);
         if (!$checkResult->valid()) {
             $validator->validationError($name, _t('ConfirmedPasswordField.CURRENT_PASSWORD_ERROR', "The current password you have entered is not correct."), "validation");
             return false;
         }
     }
     return true;
 }
 /**
  * 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 SS_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);
         }
         $cp = ChangePasswordForm::create($this->controller, 'SilverStripe\\Security\\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");
     }
     Controller::curr()->redirectBack();
 }
Exemplo n.º 14
0
 public function canDelete($member = null)
 {
     if (!$member || !is_a($member, 'SilverStripe\\Security\\Member') || is_numeric($member)) {
         $member = Member::currentUser();
     }
     // extended access checks
     $results = $this->extend('canDelete', $member);
     if ($results && is_array($results)) {
         if (!min($results)) {
             return false;
         }
     }
     return $this->canEdit($member);
 }
Exemplo n.º 15
0
 /**
  * Check if this file can be deleted
  *
  * @param Member $member
  * @return boolean
  */
 public function canDelete($member = null)
 {
     if (!$member) {
         $member = Member::currentUser();
     }
     $result = $this->extendedCan('canDelete', $member);
     if ($result !== null) {
         return $result;
     }
     return $this->canEdit($member);
 }
 /**
  * @param Member $member
  * @return bool
  */
 public function canView($member = null)
 {
     if (!$member) {
         $member = Member::currentUser();
     }
     // Expectation that versioned::canView will hide this object in draft
     $result = $this->extendedCan('canView', $member);
     if ($result !== null) {
         return $result;
     }
     // Open to public
     return true;
 }
 /**
  * Export core.
  *
  * @param GridField $gridField
  * @return ArrayData
  */
 public function generatePrintData(GridField $gridField)
 {
     $printColumns = $this->getPrintColumnsForGridField($gridField);
     $header = null;
     if ($this->printHasHeader) {
         $header = new ArrayList();
         foreach ($printColumns as $field => $label) {
             $header->push(new ArrayData(array("CellString" => $label)));
         }
     }
     $items = $gridField->getManipulatedList();
     $itemRows = new ArrayList();
     /** @var DataObject $item */
     foreach ($items->limit(null) as $item) {
         $itemRow = new ArrayList();
         foreach ($printColumns as $field => $label) {
             $value = $gridField->getDataFieldValue($item, $field);
             if ($item->escapeTypeForField($field) != 'xml') {
                 $value = Convert::raw2xml($value);
             }
             $itemRow->push(new ArrayData(array("CellString" => $value)));
         }
         $itemRows->push(new ArrayData(array("ItemRow" => $itemRow)));
         if ($item->hasMethod('destroy')) {
             $item->destroy();
         }
     }
     $ret = new ArrayData(array("Title" => $this->getTitle($gridField), "Header" => $header, "ItemRows" => $itemRows, "Datetime" => DBDatetime::now(), "Member" => Member::currentUser()));
     return $ret;
 }
 public function testAutomaticRedirectionOnLogin()
 {
     // BackURL with permission error (not authenticated) should not redirect
     if ($member = Member::currentUser()) {
         $member->logOut();
     }
     $response = $this->getRecursive('SecurityTest_SecuredController');
     $this->assertContains(Convert::raw2xml("That page is secured."), $response->getBody());
     $this->assertContains('<input type="submit" name="action_dologin"', $response->getBody());
     // Non-logged in user should not be redirected, but instead shown the login form
     // No message/context is available as the user has not attempted to view the secured controller
     $response = $this->getRecursive('Security/login?BackURL=SecurityTest_SecuredController/');
     $this->assertNotContains(Convert::raw2xml("That page is secured."), $response->getBody());
     $this->assertNotContains(Convert::raw2xml("You don't have access to this page"), $response->getBody());
     $this->assertContains('<input type="submit" name="action_dologin"', $response->getBody());
     // BackURL with permission error (wrong permissions) should not redirect
     $this->logInAs('grouplessmember');
     $response = $this->getRecursive('SecurityTest_SecuredController');
     $this->assertContains(Convert::raw2xml("You don't have access to this page"), $response->getBody());
     $this->assertContains('<input type="submit" name="action_logout" value="Log in as someone else"', $response->getBody());
     // Directly accessing this page should attempt to follow the BackURL, but stop when it encounters the error
     $response = $this->getRecursive('Security/login?BackURL=SecurityTest_SecuredController/');
     $this->assertContains(Convert::raw2xml("You don't have access to this page"), $response->getBody());
     $this->assertContains('<input type="submit" name="action_logout" value="Log in as someone else"', $response->getBody());
     // Check correctly logged in admin doesn't generate the same errors
     $this->logInAs('admin');
     $response = $this->getRecursive('SecurityTest_SecuredController');
     $this->assertContains(Convert::raw2xml("Success"), $response->getBody());
     // Directly accessing this page should attempt to follow the BackURL and succeed
     $response = $this->getRecursive('Security/login?BackURL=SecurityTest_SecuredController/');
     $this->assertContains(Convert::raw2xml("Success"), $response->getBody());
 }
Exemplo n.º 19
0
 /**
  * Users can edit their own record.
  * Otherwise they'll need ADMIN or CMS_ACCESS_SecurityAdmin permissions
  *
  * @param Member $member
  * @return bool
  */
 public function canDelete($member = null)
 {
     if (!$member instanceof Member) {
         $member = Member::currentUser();
     }
     //check for extensions, we do this first as they can overrule everything
     $extended = $this->extendedCan(__FUNCTION__, $member);
     if ($extended !== null) {
         return $extended;
     }
     //need to be logged in and/or most checks below rely on $member being a Member
     if (!$member) {
         return false;
     }
     // Members are not allowed to remove themselves,
     // since it would create inconsistencies in the admin UIs.
     if ($this->ID && $member->ID == $this->ID) {
         return false;
     }
     // HACK: if you want to delete a member, you have to be a member yourself.
     // this is a hack because what this should do is to stop a user
     // deleting a member who has more privileges (e.g. a non-Admin deleting an Admin)
     if (Permission::checkMember($this, 'ADMIN')) {
         if (!Permission::checkMember($member, 'ADMIN')) {
             return false;
         }
     }
     //standard check
     return Permission::checkMember($member, 'CMS_ACCESS_SecurityAdmin');
 }
Exemplo n.º 20
0
 /**
  * Get all menu items that the passed member can view.
  * Defaults to {@link Member::currentUser()}.
  *
  * @param Member $member
  * @return array
  */
 public static function get_viewable_menu_items($member = null)
 {
     if (!$member && $member !== FALSE) {
         $member = Member::currentUser();
     }
     $viewableMenuItems = array();
     $allMenuItems = self::get_menu_items();
     if ($allMenuItems) {
         foreach ($allMenuItems as $code => $menuItem) {
             // exclude all items which have a controller to perform permission
             // checks on
             if ($menuItem->controller) {
                 $controllerObj = singleton($menuItem->controller);
                 if (Controller::has_curr()) {
                     // Necessary for canView() to have request data available,
                     // e.g. to check permissions against LeftAndMain->currentPage()
                     $controllerObj->setRequest(Controller::curr()->getRequest());
                     if (!$controllerObj->canView($member)) {
                         continue;
                     }
                 }
             }
             $viewableMenuItems[$code] = $menuItem;
         }
     }
     return $viewableMenuItems;
 }
Exemplo n.º 21
0
 /**
  * Determine if the current user is able to set the given site stage / archive
  *
  * @param SS_HTTPRequest $request
  * @return bool
  */
 public static function can_choose_site_stage($request)
 {
     // Request is allowed if stage isn't being modified
     if ((!$request->getVar('stage') || $request->getVar('stage') === static::LIVE) && !$request->getVar('archiveDate')) {
         return true;
     }
     // Check permissions with member ID in session.
     $member = Member::currentUser();
     $permissions = Config::inst()->get(get_called_class(), 'non_live_permissions');
     return $member && Permission::checkMember($member, $permissions);
 }
Exemplo n.º 22
0
 /**
  * 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 Returns the "change password" page as HTML code.
  */
 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.
     $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 {
             self::permissionFailure($this, _t('Security.ERRORPASSWORDPERMISSION', 'You must be logged in in order to change your password!'));
             return;
         }
     }
     return $customisedController->renderWith($this->getTemplatesFor('changepassword'));
 }
 /**
  * Default permissions for this ChangeSetItem
  *
  * @param string $perm
  * @param Member $member
  * @param array $context
  * @return bool
  */
 public function can($perm, $member = null, $context = array())
 {
     if (!$member) {
         $member = Member::currentUser();
     }
     // Allow extensions to bypass default permissions, but only if
     // each change can be individually published.
     $extended = $this->extendedCan($perm, $member, $context);
     if ($extended !== null) {
         return $extended;
     }
     // Default permissions
     return (bool) Permission::checkMember($member, ChangeSet::config()->required_permission);
 }
Exemplo n.º 24
0
 /**
  * Get the list of groups that the given member belongs to.
  *
  * Call without an argument to get the groups that the current member
  * belongs to. In this case, the results will be session-cached.
  *
  * @param int $memberID The ID of the member. Leave blank for the current
  *                      member.
  * @return array Returns a list of group IDs to which the member belongs
  *               to or NULL.
  */
 public static function groupList($memberID = null)
 {
     // Default to current member, with session-caching
     if (!$memberID) {
         $member = Member::currentUser();
         if ($member && isset($_SESSION['Permission_groupList'][$member->ID])) {
             return $_SESSION['Permission_groupList'][$member->ID];
         }
     } else {
         $member = DataObject::get_by_id("SilverStripe\\Security\\Member", $memberID);
     }
     if ($member) {
         // Build a list of the IDs of the groups.  Most of the heavy lifting
         // is done by Member::Groups
         // NOTE: This isn't effecient; but it's called once per session so
         // it's a low priority to fix.
         $groups = $member->Groups();
         $groupList = array();
         if ($groups) {
             foreach ($groups as $group) {
                 $groupList[] = $group->ID;
             }
         }
         // Session caching
         if (!$memberID) {
             $_SESSION['Permission_groupList'][$member->ID] = $groupList;
         }
         return isset($groupList) ? $groupList : null;
     }
 }
 /**
  * Returns true if the member is allowed to do the given action.
  * See {@link extendedCan()} for a more versatile tri-state permission control.
  *
  * @param string $perm The permission to be checked, such as 'View'.
  * @param Member $member The member whose permissions need checking.  Defaults to the currently logged
  * in user.
  * @param array $context Additional $context to pass to extendedCan()
  *
  * @return boolean True if the the member is allowed to do the given action
  */
 public function can($perm, $member = null, $context = array())
 {
     if (!isset($member)) {
         $member = Member::currentUser();
     }
     if (Permission::checkMember($member, "ADMIN")) {
         return true;
     }
     if ($this->getSchema()->manyManyComponent(static::class, 'Can' . $perm)) {
         if ($this->ParentID && $this->SecurityType == 'Inherit') {
             if (!($p = $this->Parent)) {
                 return false;
             }
             return $this->Parent->can($perm, $member);
         } else {
             $permissionCache = $this->uninherited('permissionCache');
             $memberID = $member ? $member->ID : 'none';
             if (!isset($permissionCache[$memberID][$perm])) {
                 if ($member->ID) {
                     $groups = $member->Groups();
                 }
                 $groupList = implode(', ', $groups->column("ID"));
                 // TODO Fix relation table hardcoding
                 $query = new SQLSelect("\"Page_Can{$perm}\".PageID", array("\"Page_Can{$perm}\""), "GroupID IN ({$groupList})");
                 $permissionCache[$memberID][$perm] = $query->execute()->column();
                 if ($perm == "View") {
                     // TODO Fix relation table hardcoding
                     $query = new SQLSelect("\"SiteTree\".\"ID\"", array("\"SiteTree\"", "LEFT JOIN \"Page_CanView\" ON \"Page_CanView\".\"PageID\" = \"SiteTree\".\"ID\""), "\"Page_CanView\".\"PageID\" IS NULL");
                     $unsecuredPages = $query->execute()->column();
                     if ($permissionCache[$memberID][$perm]) {
                         $permissionCache[$memberID][$perm] = array_merge($permissionCache[$memberID][$perm], $unsecuredPages);
                     } else {
                         $permissionCache[$memberID][$perm] = $unsecuredPages;
                     }
                 }
                 Config::inst()->update($this->class, 'permissionCache', $permissionCache);
             }
             if ($permissionCache[$memberID][$perm]) {
                 return in_array($this->ID, $permissionCache[$memberID][$perm]);
             }
         }
     } else {
         return parent::can($perm, $member);
     }
 }
 public function testCoreGlobalVariableCalls()
 {
     $this->assertEquals(Director::absoluteBaseURL(), $this->render('{$absoluteBaseURL}'), 'Director::absoluteBaseURL can be called from within template');
     $this->assertEquals(Director::absoluteBaseURL(), $this->render('{$AbsoluteBaseURL}'), 'Upper-case %AbsoluteBaseURL can be called from within template');
     $this->assertEquals(Director::is_ajax(), $this->render('{$isAjax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$IsAjax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$is_ajax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$Is_ajax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(i18n::get_locale(), $this->render('{$i18nLocale}'), 'i18n template functions result correct result');
     $this->assertEquals(i18n::get_locale(), $this->render('{$get_locale}'), 'i18n template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$CurrentMember}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$CurrentUser}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$currentMember}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$currentUser}'), 'Member template functions result correct result');
     $this->assertEquals(SecurityToken::getSecurityID(), $this->render('{$getSecurityID}'), 'SecurityToken template functions result correct result');
     $this->assertEquals(SecurityToken::getSecurityID(), $this->render('{$SecurityID}'), 'SecurityToken template functions result correct result');
     $this->assertEquals(Permission::check("ADMIN"), (bool) $this->render('{$HasPerm(\'ADMIN\')}'), 'Permissions template functions result correct result');
     $this->assertEquals(Permission::check("ADMIN"), (bool) $this->render('{$hasPerm(\'ADMIN\')}'), 'Permissions template functions result correct result');
 }