public function testRun() { $m = new Member(); $m->Password = '******'; $m->PasswordEncryption = 'none'; $m->write(); $t = new EncryptAllPasswordsTask(); $t->run(null); $m = DataObject::get_by_id('SilverStripe\\Security\\Member', $m->ID); $this->assertEquals($m->PasswordEncryption, 'blowfish'); $this->assertNotEquals($m->Password, 'plain'); $result = $m->checkPassword('plain'); $this->assertTrue($result->valid()); }
public function testOverwriteExistingImport() { $author1 = new Member(); $author1->FirstName = 'author1_first_old'; $author1->Email = '*****@*****.**'; $author1->write(); $loader = new MemberCsvBulkLoader(); $results = $loader->load($this->getCurrentRelativePath() . '/MemberCsvBulkLoaderTest.csv'); $created = $results->Created()->toArray(); $this->assertEquals(count($created), 1); $updated = $results->Updated()->toArray(); $this->assertEquals(count($updated), 1); $this->assertEquals($created[0]->Email, '*****@*****.**'); $this->assertEquals($updated[0]->Email, '*****@*****.**'); $this->assertEquals($updated[0]->FirstName, 'author1_first'); }
/** * Member object of the person who last published this record * * @return Member */ public function Publisher() { if (!$this->record['WasPublished']) { return null; } return Member::get()->byID($this->record['PublisherID']); }
public function testHashHidden() { $field = new ConfirmedPasswordField('Password', 'Password', 'valueA'); $field->setCanBeEmpty(true); $this->assertEquals('valueA', $field->Value()); $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_Password]')->Value()); $this->assertEquals('valueA', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value()); $member = new Member(); $member->Password = "******"; $member->write(); $form = new Form($this, 'Form', new FieldList($field), new FieldList()); $form->loadDataFrom($member); $this->assertEquals('', $field->Value()); $this->assertEquals('', $field->children->fieldByName($field->getName() . '[_Password]')->Value()); $this->assertEquals('', $field->children->fieldByName($field->getName() . '[_ConfirmPassword]')->Value()); }
/** * 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(); }
public function getEditForm($id = null, $fields = null) { // TODO Duplicate record fetching (see parent implementation) if (!$id) { $id = $this->currentPageID(); } $form = parent::getEditForm($id); // TODO Duplicate record fetching (see parent implementation) $record = $this->getRecord($id); if ($record && !$record->canView()) { return Security::permissionFailure($this); } $memberList = GridField::create('Members', false, Member::get(), $memberListConfig = GridFieldConfig_RecordEditor::create()->addComponent(new GridFieldButtonRow('after'))->addComponent(new GridFieldExportButton('buttons-after-left')))->addExtraClass("members_grid"); if ($record && method_exists($record, 'getValidator')) { $validator = $record->getValidator(); } else { $validator = Member::singleton()->getValidator(); } $memberListConfig->getComponentByType('GridFieldDetailForm')->setValidator($validator); $groupList = GridField::create('Groups', false, Group::get(), GridFieldConfig_RecordEditor::create()); $columns = $groupList->getConfig()->getComponentByType('GridFieldDataColumns'); $columns->setDisplayFields(array('Breadcrumbs' => singleton('SilverStripe\\Security\\Group')->fieldLabel('Title'))); $columns->setFieldFormatting(array('Breadcrumbs' => function ($val, $item) { return Convert::raw2xml($item->getBreadcrumbs(' > ')); })); $fields = new FieldList($root = new TabSet('Root', $usersTab = new Tab('Users', _t('SecurityAdmin.Users', 'Users'), new LiteralField('MembersCautionText', sprintf('<div class="alert alert-warning" role="alert">%s</div>', _t('SecurityAdmin.MemberListCaution', 'Caution: Removing members from this list will remove them from all groups and the database'))), $memberList), $groupsTab = new Tab('Groups', singleton('SilverStripe\\Security\\Group')->i18n_plural_name(), $groupList)), new HiddenField('ID', false, 0)); // Add import capabilities. Limit to admin since the import logic can affect assigned permissions if (Permission::check('ADMIN')) { $fields->addFieldsToTab('Root.Users', array(new HeaderField(_t('SecurityAdmin.IMPORTUSERS', 'Import users'), 3), new LiteralField('MemberImportFormIframe', sprintf('<iframe src="%s" id="MemberImportFormIframe" width="100%%" height="250px" frameBorder="0">' . '</iframe>', $this->Link('memberimport'))))); $fields->addFieldsToTab('Root.Groups', array(new HeaderField(_t('SecurityAdmin.IMPORTGROUPS', 'Import groups'), 3), new LiteralField('GroupImportFormIframe', sprintf('<iframe src="%s" id="GroupImportFormIframe" width="100%%" height="250px" frameBorder="0">' . '</iframe>', $this->Link('groupimport'))))); } // Tab nav in CMS is rendered through separate template $root->setTemplate('CMSTabSet'); // Add roles editing interface if (Permission::check('APPLY_ROLES')) { $rolesField = GridField::create('Roles', false, PermissionRole::get(), GridFieldConfig_RecordEditor::create()); $rolesTab = $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.TABROLES', 'Roles')); $rolesTab->push($rolesField); } $actionParam = $this->getRequest()->param('Action'); if ($actionParam == 'groups') { $groupsTab->addExtraClass('ui-state-active'); } elseif ($actionParam == 'users') { $usersTab->addExtraClass('ui-state-active'); } elseif ($actionParam == 'roles') { $rolesTab->addExtraClass('ui-state-active'); } $actions = new FieldList(); $form = Form::create($this, 'EditForm', $fields, $actions)->setHTMLID('Form_EditForm'); $form->addExtraClass('cms-edit-form'); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); // Tab nav in CMS is rendered through separate template if ($form->Fields()->hasTabset()) { $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet'); } $form->addExtraClass('center ss-tabset cms-tabset ' . $this->BaseCSSClasses()); $form->setAttribute('data-pjax-fragment', 'CurrentForm'); $this->extend('updateEditForm', $form); return $form; }
public function run($request) { $algo = Security::config()->password_encryption_algorithm; if ($algo == 'none') { $this->debugMessage('Password encryption disabled'); return; } // Are there members with a clear text password? $members = Member::get()->where(array('"Member"."PasswordEncryption"' => 'none', '"Member"."Password" IS NOT NULL')); if (!$members) { $this->debugMessage('No passwords to encrypt'); return; } // Encrypt the passwords... $this->debugMessage('Encrypting all passwords'); $this->debugMessage(sprintf('The passwords will be encrypted using the %s algorithm', $algo)); foreach ($members as $member) { // Force the update of the member record, as new passwords get // automatically encrypted according to the settings, this will do all // the work for us $member->PasswordEncryption = $algo; $member->forceChange(); $member->write(); $this->debugMessage(sprintf('Encrypted credentials for member #%d;', $member->ID)); } }
/** * 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')); } } }
public function testDefaultAdmin() { $adminMembers = Permission::get_members_by_permission('ADMIN'); $this->assertEquals(0, $adminMembers->count()); $admin = Member::default_admin(); $this->assertInstanceOf('SilverStripe\\Security\\Member', $admin); $this->assertTrue(Permission::checkMember($admin, 'ADMIN')); $this->assertEquals($admin->Email, Security::default_admin_username()); $this->assertNull($admin->Password); }
/** * 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 testExtendedPermissionsStopEditingOwnProfile() { $existingExtensions = Member::config()->get('extensions'); Member::config()->update('extensions', array('CMSProfileControllerTestExtension')); $member = $this->objFromFixture('SilverStripe\\Security\\Member', 'user1'); $this->session()->inst_set('loggedInAs', $member->ID); $response = $this->post('admin/myprofile/EditForm', array('action_save' => 1, 'ID' => $member->ID, 'FirstName' => 'JoeEdited', 'Surname' => 'BloggsEdited', 'Email' => $member->Email, 'Locale' => $member->Locale, 'Password[_Password]' => 'password', 'Password[_ConfirmPassword]' => 'password')); $member = $this->objFromFixture('SilverStripe\\Security\\Member', 'user1'); $this->assertNotEquals($member->FirstName, 'JoeEdited', 'FirstName field was NOT changed because we modified canEdit'); Member::config()->remove('extensions')->update('extensions', $existingExtensions); }
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 save($data, $form) { $member = Member::get()->byID($data['ID']); if (!$member) { return $this->httpError(404); } $origLocale = $member->Locale; if (!$member->canEdit()) { $form->sessionMessage(_t('Member.CANTEDIT', 'You don\'t have permission to do that'), 'bad'); return $this->redirectBack(); } $response = parent::save($data, $form); if ($origLocale != $data['Locale']) { $response->addHeader('X-Reload', true); $response->addHeader('X-ControllerURL', $this->Link()); } return $response; }
/** * 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); } }
/** * 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; }
/** * 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); }
/** * 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; }
/** * Create a member and group with the given permission code, and log in with it. * Returns the member ID. * * @param string|array $permCode Either a permission, or list of permissions * @return int Member ID */ public function logInWithPermission($permCode = "ADMIN") { if (is_array($permCode)) { $permArray = $permCode; $permCode = implode('.', $permCode); } else { $permArray = array($permCode); } // Check cached member if (isset($this->cache_generatedMembers[$permCode])) { $member = $this->cache_generatedMembers[$permCode]; } else { // Generate group with these permissions $group = Group::create(); $group->Title = "{$permCode} group"; $group->write(); // Create each individual permission foreach ($permArray as $permArrayItem) { $permission = Permission::create(); $permission->Code = $permArrayItem; $permission->write(); $group->Permissions()->add($permission); } $member = DataObject::get_one('SilverStripe\\Security\\Member', array('"Member"."Email"' => "{$permCode}@example.org")); if (!$member) { $member = Member::create(); } $member->FirstName = $permCode; $member->Surname = "User"; $member->Email = "{$permCode}@example.org"; $member->write(); $group->Members()->add($member); $this->cache_generatedMembers[$permCode] = $member; } $member->logIn(); return $member->ID; }
/** * 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; }
/** * Return an existing member with administrator privileges, or create one of necessary. * * Will create a default 'Administrators' group if no group is found * with an ADMIN permission. Will create a new 'Admin' member with administrative permissions * if no existing Member with these permissions is found. * * Important: Any newly created administrator accounts will NOT have valid * login credentials (Email/Password properties), which means they can't be used for login * purposes outside of any default credentials set through {@link Security::setDefaultAdmin()}. * * @return Member */ public static function findAnAdministrator() { // coupling to subsites module $origSubsite = null; if (is_callable('Subsite::changeSubsite')) { $origSubsite = \Subsite::currentSubsiteID(); \Subsite::changeSubsite(0); } $member = null; // find a group with ADMIN permission $adminGroup = Permission::get_groups_by_permission('ADMIN')->first(); if (is_callable('Subsite::changeSubsite')) { \Subsite::changeSubsite($origSubsite); } if ($adminGroup) { $member = $adminGroup->Members()->First(); } if (!$adminGroup) { Group::singleton()->requireDefaultRecords(); $adminGroup = Permission::get_groups_by_permission('ADMIN')->first(); } if (!$member) { Member::singleton()->requireDefaultRecords(); $member = Permission::get_members_by_permission('ADMIN')->first(); } if (!$member) { $member = Member::default_admin(); } if (!$member) { // Failover to a blank admin $member = Member::create(); $member->FirstName = _t('Member.DefaultAdminFirstname', 'Default Admin'); $member->write(); // Add member to group instead of adding group to member // This bypasses the privilege escallation code in Member_GroupSet $adminGroup->DirectMembers()->add($member); } return $member; }
/** * 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); }
/** * Returns all members for a specific permission. * * @param $code String|array Either a single permission code, or a list of permission codes * @return SS_List Returns a set of member that have the specified * permission. */ public static function get_members_by_permission($code) { $toplevelGroups = self::get_groups_by_permission($code); if (!$toplevelGroups) { return new ArrayList(); } $groupIDs = array(); foreach ($toplevelGroups as $group) { $familyIDs = $group->collateFamilyIDs(); if (is_array($familyIDs)) { $groupIDs = array_merge($groupIDs, array_values($familyIDs)); } } if (empty($groupIDs)) { return new ArrayList(); } $groupClause = DB::placeholders($groupIDs); /** @skipUpgrade */ $members = Member::get()->where(array("\"Group\".\"ID\" IN ({$groupClause})" => $groupIDs))->leftJoin("Group_Members", '"Member"."ID" = "Group_Members"."MemberID"')->leftJoin("Group", '"Group_Members"."GroupID" = "Group"."ID"'); return $members; }
/** * 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; } }
public function testEmptyMemberFails() { $member = new Member(); $this->assertFalse($member->exists()); $this->logInWithPermission('ADMIN'); $this->assertFalse(Permission::checkMember($member, 'ADMIN')); $this->assertFalse(Permission::checkMember($member, 'CMS_ACCESS_LeftAndMain')); }
/** * Make sure the file has a name */ protected function onBeforeWrite() { // Set default owner if (!$this->isInDB() && !$this->OwnerID) { $this->OwnerID = Member::currentUserID(); } // Set default name if (!$this->getField('Name')) { $this->Name = "new-" . strtolower($this->class); } // Propegate changes to the AssetStore and update the DBFile field $this->updateFilesystem(); parent::onBeforeWrite(); }
/** * Check default state of this record * * @param DataObject $record * @return string One of AssetManipulationList::STATE_* constants */ protected function getRecordState($record) { if ($this->isVersioned()) { // Check stage this record belongs to $stage = $record->getSourceQueryParam('Versioned.stage') ?: Versioned::get_stage(); // Non-live stages are automatically non-public if ($stage !== Versioned::LIVE) { return AssetManipulationList::STATE_PROTECTED; } } // Check if canView permits anonymous viewers return $record->canView(Member::create()) ? AssetManipulationList::STATE_PUBLIC : AssetManipulationList::STATE_PROTECTED; }
/** * Log login attempt * TODO We could handle this with an extension * * @param array $data * @param Member $member * @param bool $success */ protected static function record_login_attempt($data, $member, $success) { if (!Security::config()->login_recording) { return; } // Check email is valid $email = isset($data['Email']) ? $data['Email'] : null; if (is_array($email)) { throw new InvalidArgumentException("Bad email passed to MemberAuthenticator::authenticate(): {$email}"); } $attempt = new LoginAttempt(); if ($success) { // successful login (member is existing with matching password) $attempt->MemberID = $member->ID; $attempt->Status = 'Success'; // Audit logging hook $member->extend('authenticated'); } else { // Failed login - we're trying to see if a user exists with this email (disregarding wrong passwords) $attempt->Status = 'Failure'; if ($member) { // Audit logging hook $attempt->MemberID = $member->ID; $member->extend('authenticationFailed'); } else { // Audit logging hook Member::singleton()->extend('authenticationFailedUnknownUser', $data); } } $attempt->Email = $email; $attempt->IP = Controller::curr()->getRequest()->getIP(); $attempt->write(); }
/** * Deletes existing tokens for this member * if logout_across_devices is true, all tokens are deleted, otherwise * only the token for the provided device ID will be removed * * @param Member $member * @param string $alcDevice */ public static function clear(Member $member, $alcDevice = null) { if (!$member->exists()) { return; } $filter = array('MemberID' => $member->ID); if (!static::config()->logout_across_devices && $alcDevice) { $filter['DeviceID'] = $alcDevice; } RememberLoginHash::get()->filter($filter)->removeAll(); }
/** * @covers GridFieldDataColumns::setDisplayFields * @covers GridFieldDataColumns::getDisplayFields */ public function testGridFieldDisplayFieldsWithBadArguments() { $this->setExpectedException('InvalidArgumentException'); $obj = new GridField('testfield', 'testfield', Member::get()); $columns = $obj->getConfig()->getComponentByType('GridFieldDataColumns'); $columns->setDisplayFields(new stdClass()); }