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));
     }
 }
 /**
  * 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 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;
 }
 /**
  * Attempt to find and authenticate member if possible from the given data
  *
  * @param array $data
  * @param Form $form
  * @param bool &$success Success flag
  * @return Member Found member, regardless of successful login
  */
 protected static function authenticate_member($data, $form, &$success)
 {
     // Default success to false
     $success = false;
     // Attempt to identify by temporary ID
     $member = null;
     $email = null;
     if (!empty($data['tempid'])) {
         // Find user by tempid, in case they are re-validating an existing session
         $member = Member::member_from_tempid($data['tempid']);
         if ($member) {
             $email = $member->Email;
         }
     }
     // Otherwise, get email from posted value instead
     /** @skipUpgrade */
     if (!$member && !empty($data['Email'])) {
         $email = $data['Email'];
     }
     // Check default login (see Security::setDefaultAdmin())
     $asDefaultAdmin = $email === Security::default_admin_username();
     if ($asDefaultAdmin) {
         // If logging is as default admin, ensure record is setup correctly
         $member = Member::default_admin();
         $success = !$member->isLockedOut() && Security::check_default_admin($email, $data['Password']);
         //protect against failed login
         if ($success) {
             return $member;
         }
     }
     // Attempt to identify user by email
     if (!$member && $email) {
         // Find user by email
         $member = Member::get()->filter(Member::config()->unique_identifier_field, $email)->first();
     }
     // Validate against member if possible
     if ($member && !$asDefaultAdmin) {
         $result = $member->checkPassword($data['Password']);
         $success = $result->valid();
     } else {
         $result = new ValidationResult(false, _t('Member.ERRORWRONGCRED'));
     }
     // Emit failure to member and form (if available)
     if (!$success) {
         if ($member) {
             $member->registerFailedLogin();
         }
         if ($form) {
             $form->sessionMessage($result->message(), 'bad');
         }
     } else {
         if ($member) {
             $member->registerSuccessfulLogin();
         }
     }
     return $member;
 }
 public function testCMSAccess()
 {
     $members = Member::get()->byIDs($this->allFixtureIDs('SilverStripe\\Security\\Member'));
     foreach ($members as $member) {
         $this->assertTrue(Permission::checkMember($member, 'CMS_ACCESS'));
         $this->assertTrue(Permission::checkMember($member, array('CMS_ACCESS', 'CMS_ACCESS_Security')));
         $this->assertTrue(Permission::checkMember($member, array('CMS_ACCESS_Security', 'CMS_ACCESS')));
     }
     $member = new Member();
     $member->update(array('FirstName' => 'No CMS', 'Surname' => 'Access', 'Email' => '*****@*****.**'));
     $member->write();
     $this->assertFalse(Permission::checkMember($member, 'CMS_ACCESS'));
     $this->assertFalse(Permission::checkMember($member, array('CMS_ACCESS', 'CMS_ACCESS_Security')));
     $this->assertFalse(Permission::checkMember($member, array('CMS_ACCESS_Security', 'CMS_ACCESS')));
 }
 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 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;
 }
 /**
  * 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'));
 }
 /**
  * Check if the submitted member data is valid (server-side)
  *
  * Check if a member with that email doesn't already exist, or if it does
  * that it is this member.
  *
  * @param array $data Submitted data
  * @return bool Returns TRUE if the submitted data is valid, otherwise
  *              FALSE.
  */
 public function php($data)
 {
     $valid = parent::php($data);
     $identifierField = (string) Member::config()->unique_identifier_field;
     // Only validate identifier field if it's actually set. This could be the case if
     // somebody removes `Email` from the list of required fields.
     if (isset($data[$identifierField])) {
         $id = isset($data['ID']) ? (int) $data['ID'] : 0;
         if (!$id && ($ctrl = $this->form->getController())) {
             // get the record when within GridField (Member editing page in CMS)
             if ($ctrl instanceof GridFieldDetailForm_ItemRequest && ($record = $ctrl->getRecord())) {
                 $id = $record->ID;
             }
         }
         // If there's no ID passed via controller or form-data, use the assigned member (if available)
         if (!$id && ($member = $this->getForMember())) {
             $id = $member->exists() ? $member->ID : 0;
         }
         // set the found ID to the data array, so that extensions can also use it
         $data['ID'] = $id;
         $members = Member::get()->filter($identifierField, $data[$identifierField]);
         if ($id) {
             $members = $members->exclude('ID', $id);
         }
         if ($members->count() > 0) {
             $this->validationError($identifierField, _t('Member.VALIDATIONMEMBEREXISTS', 'A member already exists with the same {identifier}', array('identifier' => Member::singleton()->fieldLabel($identifierField))), 'required');
             $valid = false;
         }
     }
     // Execute the validators on the extensions
     $results = $this->extend('updatePHP', $data, $this->form);
     $results[] = $valid;
     return min($results);
 }
 /**
  * @covers GridField::getColumnCount
  */
 public function testGetColumnCount()
 {
     $obj = new GridField('testfield', 'testfield', Member::get());
     $this->assertEquals(3, $obj->getColumnCount());
 }
 /**
  * Forgot password form handler method.
  * Called when the user clicks on "I've lost my password".
  * Extensions can use the 'forgotPassword' method to veto executing
  * the logic, by returning FALSE. In this case, the user will be redirected back
  * to the form without further action. It is recommended to set a message
  * in the form detailing why the action was denied.
  *
  * @param array $data Submitted data
  * @return SS_HTTPResponse
  */
 public function forgotPassword($data)
 {
     // Ensure password is given
     if (empty($data['Email'])) {
         $this->sessionMessage(_t('Member.ENTEREMAIL', 'Please enter an email address to get a password reset link.'), 'bad');
         $this->controller->redirect('Security/lostpassword');
         return;
     }
     // Find existing member
     $member = Member::get()->filter("Email", $data['Email'])->first();
     // Allow vetoing forgot password requests
     $results = $this->extend('forgotPassword', $member);
     if ($results && is_array($results) && in_array(false, $results, true)) {
         return $this->controller->redirect('Security/lostpassword');
     }
     if ($member) {
         $token = $member->generateAutologinTokenAndStoreHash();
         /** @var Email $e */
         $e = Email::create();
         $e->setSubject(_t('Member.SUBJECTPASSWORDRESET', "Your password reset link", 'Email subject'));
         $e->setTemplate('ForgotPasswordEmail');
         $e->populateTemplate($member);
         $e->populateTemplate(array('PasswordResetLink' => Security::getPasswordResetLink($member, $token)));
         $e->setTo($member->Email);
         $e->send();
         $this->controller->redirect('Security/passwordsent/' . urlencode($data['Email']));
     } elseif ($data['Email']) {
         // Avoid information disclosure by displaying the same status,
         // regardless wether the email address actually exists
         $this->controller->redirect('Security/passwordsent/' . rawurlencode($data['Email']));
     } else {
         $this->sessionMessage(_t('Member.ENTEREMAIL', 'Please enter an email address to get a password reset link.'), 'bad');
         $this->controller->redirect('Security/lostpassword');
     }
 }
 /**
  * Get a map of all members in the groups given that have CMS permissions
  *
  * If no groups are passed, all groups with CMS permissions will be used.
  *
  * @param array $groups Groups to consider or NULL to use all groups with
  *                      CMS permissions.
  * @return Map Returns a map of all members in the groups given that
  *                have CMS permissions.
  */
 public static function mapInCMSGroups($groups = null)
 {
     if (!$groups || $groups->Count() == 0) {
         $perms = array('ADMIN', 'CMS_ACCESS_AssetAdmin');
         if (class_exists('SilverStripe\\CMS\\Controllers\\CMSMain')) {
             $cmsPerms = CMSMain::singleton()->providePermissions();
         } else {
             $cmsPerms = LeftAndMain::singleton()->providePermissions();
         }
         if (!empty($cmsPerms)) {
             $perms = array_unique(array_merge($perms, array_keys($cmsPerms)));
         }
         $permsClause = DB::placeholders($perms);
         /** @skipUpgrade */
         $groups = Group::get()->innerJoin("Permission", '"Permission"."GroupID" = "Group"."ID"')->where(array("\"Permission\".\"Code\" IN ({$permsClause})" => $perms));
     }
     $groupIDList = array();
     if ($groups instanceof SS_List) {
         foreach ($groups as $group) {
             $groupIDList[] = $group->ID;
         }
     } elseif (is_array($groups)) {
         $groupIDList = $groups;
     }
     /** @skipUpgrade */
     $members = Member::get()->innerJoin("Group_Members", '"Group_Members"."MemberID" = "Member"."ID"')->innerJoin("Group", '"Group"."ID" = "Group_Members"."GroupID"');
     if ($groupIDList) {
         $groupClause = DB::placeholders($groupIDList);
         $members = $members->where(array("\"Group\".\"ID\" IN ({$groupClause})" => $groupIDList));
     }
     return $members->sort('"Member"."Surname", "Member"."FirstName"')->map();
 }
 public function testBasicAuthFailureIncreasesFailedLoginCount()
 {
     // Prior to login
     $check = Member::get()->filter('Email', '*****@*****.**')->first();
     $this->assertEquals(0, $check->FailedLoginCount);
     // First failed attempt
     $_SERVER['PHP_AUTH_USER'] = '******';
     $_SERVER['PHP_AUTH_PW'] = 'test';
     $response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
     $check = Member::get()->filter('Email', '*****@*****.**')->first();
     $this->assertEquals(1, $check->FailedLoginCount);
     // Second failed attempt
     $_SERVER['PHP_AUTH_PW'] = 'testwrong';
     $response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
     $check = Member::get()->filter('Email', '*****@*****.**')->first();
     $this->assertEquals(2, $check->FailedLoginCount);
     // successful basic auth should reset failed login count
     $_SERVER['PHP_AUTH_PW'] = 'Password';
     $response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission');
     $check = Member::get()->filter('Email', '*****@*****.**')->first();
     $this->assertEquals(0, $check->FailedLoginCount);
 }
 /**
  * @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());
 }