/** * EmailVerificationLoginForm is the same as MemberLoginForm with the following changes: * - The code has been cleaned up. * - A form action for users who have lost their verification email has been added. * * We add fields in the constructor so the form is generated when instantiated. * * @param Controller $controller The parent controller, necessary to create the appropriate form action tag. * @param string $name The method on the controller that will return this form object. * @param FieldList|FormField $fields All of the fields in the form - a {@link FieldList} of {@link FormField} objects. * @param FieldList|FormAction $actions All of the action buttons in the form - a {@link FieldList} of {@link FormAction} objects * @param bool $checkCurrentUser If set to TRUE, it will be checked if a the user is currently logged in, and if so, only a logout button will be rendered */ function __construct($controller, $name, $fields = null, $actions = null, $checkCurrentUser = true) { $email_field_label = singleton('Member')->fieldLabel(Member::config()->unique_identifier_field); $email_field = TextField::create('Email', $email_field_label, null, null, $this)->setAttribute('autofocus', 'autofocus'); $password_field = PasswordField::create('Password', _t('Member.PASSWORD', 'Password')); $authentication_method_field = HiddenField::create('AuthenticationMethod', null, $this->authenticator_class, $this); $remember_me_field = CheckboxField::create('Remember', 'Remember me next time?', true); if ($checkCurrentUser && Member::currentUser() && Member::logged_in_session_exists()) { $fields = FieldList::create($authentication_method_field); $actions = FieldList::create(FormAction::create('logout', _t('Member.BUTTONLOGINOTHER', "Log in as someone else"))); } else { if (!$fields) { $fields = FieldList::create($authentication_method_field, $email_field, $password_field); if (Security::config()->remember_username) { $email_field->setValue(Session::get('SessionForms.MemberLoginForm.Email')); } else { // Some browsers won't respect this attribute unless it's added to the form $this->setAttribute('autocomplete', 'off'); $email_field->setAttribute('autocomplete', 'off'); } } if (!$actions) { $actions = FieldList::create(FormAction::create('doLogin', _t('Member.BUTTONLOGIN', "Log in")), new LiteralField('forgotPassword', '<p id="ForgotPassword"><a href="Security/lostpassword">' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>'), new LiteralField('resendEmail', '<p id="ResendEmail"><a href="Security/verify-email">' . _t('MemberEmailVerification.BUTTONLOSTVERIFICATIONEMAIL', "I've lost my verification email") . '</a></p>')); } } if (isset($_REQUEST['BackURL'])) { $fields->push(HiddenField::create('BackURL', 'BackURL', $_REQUEST['BackURL'])); } // Reduce attack surface by enforcing POST requests $this->setFormMethod('POST', true); parent::__construct($controller, $name, $fields, $actions); $this->setValidator(RequiredFields::create('Email', 'Password')); }
/** * Constructor. * * @param Controller $controller * @param string $name method on the $controller * @param FieldList $fields * @param FieldList $actions * @param bool $checkCurrentUser - show logout button if logged in */ public function __construct($controller, $name, $fields = null, $actions = null, $checkCurrentUser = true) { parent::__construct($controller, $name, $fields, $actions, $checkCurrentUser); // will be used to get correct Link() $this->ldapSecController = Injector::inst()->create('LDAPSecurityController'); $usernameField = new TextField('Username', _t('Member.USERNAME', 'Username'), null, null, $this); $this->Fields()->replaceField('Email', $usernameField); $this->setValidator(new RequiredFields('Username', 'Password')); if (Security::config()->remember_username) { $usernameField->setValue(Session::get('SessionForms.MemberLoginForm.Email')); } else { // Some browsers won't respect this attribute unless it's added to the form $this->setAttribute('autocomplete', 'off'); $usernameField->setAttribute('autocomplete', 'off'); } // Users can't change passwords unless appropriate a LDAP user with write permissions is // configured the LDAP connection binding $this->Actions()->remove($this->Actions()->fieldByName('forgotPassword')); $allowPasswordChange = Config::inst()->get('LDAPService', 'allow_password_change'); if ($allowPasswordChange && $name != 'LostPasswordForm' && !Member::currentUser()) { $forgotPasswordLink = sprintf('<p id="ForgotPassword"><a href="%s">%s</a></p>', $this->ldapSecController->Link('lostpassword'), _t('Member.BUTTONLOSTPASSWORD', "I've lost my password")); $forgotPassword = new LiteralField('forgotPassword', $forgotPasswordLink); $this->Actions()->add($forgotPassword); } // Focus on the Username field when the page is loaded Requirements::block('MemberLoginFormFieldFocus'); $js = <<<JS \t\t\t(function() { \t\t\t\tvar el = document.getElementById("Username"); \t\t\t\tif(el && el.focus && (typeof jQuery == 'undefined' || jQuery(el).is(':visible'))) el.focus(); \t\t\t})(); JS; Requirements::customScript($js, 'LDAPLoginFormFieldFocus'); }
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 = DataObject::get("Member")->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)); } }
public function testCleartextPasswordsAreHashedWithDefaultAlgo() { $loader = new MemberCsvBulkLoader(); $results = $loader->load($this->getCurrentRelativePath() . '/MemberCsvBulkLoaderTest_cleartextpws.csv'); $member = $results->Created()->First(); $memberID = $member->ID; DataObject::flush_and_destroy_cache(); $member = DataObject::get_by_id('Member', $memberID); // TODO Direct getter doesn't work, wtf! $this->assertEquals(Security::config()->password_encryption_algorithm, $member->getField('PasswordEncryption')); $result = $member->checkPassword('mypassword'); $this->assertTrue($result->valid()); }
public function __construct($controller, $name, $fields = null, $actions = null, $checkCurrentUser = true) { // This is now set on the class directly to make it easier to create subclasses // $this->authenticator_class = $authenticatorClassName; $customCSS = project() . '/css/member_login.css'; if (Director::fileExists($customCSS)) { Requirements::css($customCSS); } if (isset($_REQUEST['BackURL'])) { $backURL = $_REQUEST['BackURL']; } else { $backURL = Session::get('BackURL'); } if ($checkCurrentUser && Member::currentUser() && Member::logged_in_session_exists()) { $fields = new FieldList(new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this)); $actions = new FieldList(new FormAction("logout", _t('Member.BUTTONLOGINOTHER', "Log in as someone else"))); } else { if (!$fields) { $label = singleton('Member')->fieldLabel(Member::config()->unique_identifier_field); $fields = new FieldList(new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this), $emailField = new TextField("Email", $label, null, null, $this), new PasswordField("Password", _t('Member.PASSWORD', 'Password'))); if (Security::config()->remember_username) { $emailField->setValue(Session::get('SessionForms.MemberLoginForm.Email')); } else { // Some browsers won't respect this attribute unless it's added to the form $this->setAttribute('autocomplete', 'off'); $emailField->setAttribute('autocomplete', 'off'); } if (Security::config()->autologin_enabled) { $fields->push(new CheckboxField("Remember", _t('Member.REMEMBERME', "Remember me next time?"))); } } if (!$actions) { $actions = new FieldList(new FormAction('dologin', _t('Member.BUTTONLOGIN', "Log in")), new LiteralField('forgotPassword', '<p id="ForgotPassword"><a href="Security/lostpassword">' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>')); } } if (isset($backURL)) { $fields->push(new HiddenField('BackURL', 'BackURL', $backURL)); } // Reduce attack surface by enforcing POST requests $this->setFormMethod('POST', true); parent::__construct($controller, $name, $fields, $actions); $this->setValidator(new RequiredFields()); // Focus on the email input when the page is loaded $js = <<<JS \t\t\t(function() { \t\t\t\tvar el = document.getElementById("MemberLoginForm_LoginForm_Email"); \t\t\t\tif(el && el.focus && (typeof jQuery == 'undefined' || jQuery(el).is(':visible'))) el.focus(); \t\t\t})(); JS; Requirements::customScript($js, 'MemberLoginFormFieldFocus'); }
public function __construct(Controller $controller, $name) { // Set default fields $fields = new FieldList(HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this), HiddenField::create('tempid', null, $controller->getRequest()->requestVar('tempid')), PasswordField::create("Password", _t('Member.PASSWORD', 'Password')), LiteralField::create('forgotPassword', sprintf('<p id="ForgotPassword"><a href="%s" target="_top">%s</a></p>', $this->getExternalLink('lostpassword'), _t('CMSMemberLoginForm.BUTTONFORGOTPASSWORD', "Forgot password?")))); if (Security::config()->autologin_enabled) { $fields->push(new CheckboxField("Remember", _t('Member.REMEMBERME', "Remember me next time?"))); } // Determine returnurl to redirect to parent page $logoutLink = $this->getExternalLink('logout'); if ($returnURL = $controller->getRequest()->requestVar('BackURL')) { $logoutLink = Controller::join_links($logoutLink, '?BackURL=' . urlencode($returnURL)); } // Make actions $actions = new FieldList(FormAction::create('dologin', _t('CMSMemberLoginForm.BUTTONLOGIN', "Log back in")), LiteralField::create('doLogout', sprintf('<p id="doLogout"><a href="%s" target="_top">%s</a></p>', $logoutLink, _t('CMSMemberLoginForm.BUTTONLOGOUT', "Log out")))); parent::__construct($controller, $name, $fields, $actions); }
public function callback() { $redirectUri = 'http' . (isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] ? 's' : '' : '') . '://' . $_SERVER['HTTP_HOST'] . '/GoogleAuthenticatorController/callback'; $client = new Google_Client(); $client->setClientId(GOOGLE_AUTHENTICATOR_CLIENT_ID); $client->setClientSecret(GOOGLE_AUTHENTICATOR_CLIENT_SECRET); $client->setRedirectUri($redirectUri); $client->addScope("email"); if (isset($_GET['code'])) { $client->authenticate($_GET['code']); $_SESSION['google_accesstoken'] = $client->getAccessToken(); header('Location: ' . filter_var($redirectUri, FILTER_SANITIZE_URL)); } if (isset($_SESSION['google_accesstoken']) && $_SESSION['google_accesstoken']) { $client->setAccessToken($_SESSION['google_accesstoken']); } $form = new GoogleAuthenticatorLoginForm($this, 'LoginForm'); if ($client->getAccessToken() && !$client->isAccessTokenExpired()) { $_SESSION['google_accesstoken'] = $client->getAccessToken(); $token_data = $client->verifyIdToken()->getAttributes(); $email = $token_data['payload']['email']; $member = Member::get()->filter(array('Email' => $email))->first(); if (isset($_SESSION['BackURL']) && $_SESSION['BackURL'] && Director::is_site_url($_SESSION['BackURL'])) { $backURL = $_SESSION['BackURL']; } if ($member) { $member->logIn(); if ($backURL) { return $this->redirect($backURL); } if (Security::config()->default_login_dest) { return $this->redirect(Director::absoluteBaseURL() . Security::config()->default_login_dest); } return Controller::curr()->redirectBack(); } else { $form->sessionMessage("The Google account {$email} is not authorised to access the system.", 'bad'); } } else { $form->sessionMessage("There is an error authenticating with Google. Please try again.", 'bad'); } $loginLink = Director::absoluteURL('/Security/login'); if ($backURL) { $loginLink .= '?BackURL=' . urlencode($backURL); } $loginLink .= '#GoogleAuthenticatorLoginForm_LoginForm_tab'; return $this->redirect($loginLink); }
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 = new ChangePasswordForm($this->controller, 'ChangePasswordForm'); $cp->sessionMessage(_t('Member.PASSWORDEXPIRED', 'Your password has expired. Please choose a new one.'), 'good'); return $this->controller->redirect('Security/changepassword'); } // Absolute redirection URLs may cause spoofing if (!empty($_REQUEST['BackURL'])) { $url = $_REQUEST['BackURL']; if (Director::is_site_url($url)) { $url = Director::absoluteURL($url); } else { // Spoofing attack, redirect to homepage instead of spoofing url $url = Director::absoluteBaseURL(); } return $this->controller->redirect($url); } // If a default login dest has been set, redirect to that. if ($url = Security::config()->default_login_dest) { $url = Controller::join_links(Director::absoluteBaseURL(), $url); return $this->controller->redirect($url); } // Redirect the user to the page where they came from $member = Member::currentUser(); if ($member) { $firstname = Convert::raw2xml($member->FirstName); if (!empty($data['Remember'])) { Session::set('SessionForms.MemberLoginForm.Remember', '1'); $member->logIn(true); } else { $member->logIn(); } Session::set('Security.Message.message', _t('Member.WELCOMEBACK', "Welcome Back, {firstname}", array('firstname' => $firstname))); Session::set("Security.Message.type", "good"); } // Do checks of pagetypes to see where we were and where to go then for the rest redirect to baseurl // $url = "/resources/"; $url = "/resources/"; $url = Controller::join_links(Director::absoluteBaseURL(), $url); return $this->controller->redirect($url); }
public function __construct($controller, $name, $fields = null, $actions = null, $checkCurrentUser = true) { $form_action_url = Controller::join_links(BASE_URL, "Security", $name); $lost_password_url = Controller::join_links(BASE_URL, "Security", "lostpassword"); if (isset($_REQUEST['BackURL'])) { $backURL = $_REQUEST['BackURL']; } else { $backURL = Session::get('BackURL'); } $fields = new FieldList(HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this), TextField::create('Identity', 'Username or Email'), PasswordField::create("Password", _t('Member.PASSWORD', 'Password'))); if (Security::config()->autologin_enabled) { $fields->push(new CheckboxField("Remember", _t('Member.REMEMBERME', "Remember me?"))); } $actions = new FieldList(FormAction::create('dologin', 'Login'), LiteralField::create('forgotPassword', '<p id="ForgotPassword"><a href="' . $lost_password_url . '">' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>')); // LoginForm does its magic parent::__construct($controller, $name, $fields, $actions); $this->setAttribute("action", $form_action_url); }
/** * Event handler called before writing to the database. */ public function onBeforeWrite() { if ($this->SetPassword) { $this->Password = $this->SetPassword; } // If a member with the same "unique identifier" already exists with a different ID, don't allow merging. // Note: This does not a full replacement for safeguards in the controller layer (e.g. in a registration form), // but rather a last line of defense against data inconsistencies. $identifierField = Member::config()->unique_identifier_field; if ($this->{$identifierField}) { // Note: Same logic as Member_Validator class $idClause = $this->ID ? sprintf(" AND \"Member\".\"ID\" <> %d", (int) $this->ID) : ''; $existingRecord = DataObject::get_one('Member', sprintf("\"%s\" = '%s' %s", $identifierField, Convert::raw2sql($this->{$identifierField}), $idClause)); if ($existingRecord) { throw new ValidationException(new ValidationResult(false, _t('Member.ValidationIdentifierFailed', 'Can\'t overwrite existing member #{id} with identical identifier ({name} = {value}))', 'Values in brackets show "fieldname = value", usually denoting an existing email address', array('id' => $existingRecord->ID, 'name' => $identifierField, 'value' => $this->{$identifierField})))); } } // We don't send emails out on dev/tests sites to prevent accidentally spamming users. // However, if TestMailer is in use this isn't a risk. if ((Director::isLive() || Email::mailer() instanceof TestMailer) && $this->isChanged('Password') && $this->record['Password'] && $this->config()->notify_password_change) { $e = Member_ChangePasswordEmail::create(); $e->populateTemplate($this); $e->setTo($this->Email); $e->send(); } // The test on $this->ID is used for when records are initially created. // Note that this only works with cleartext passwords, as we can't rehash // existing passwords. if (!$this->ID && $this->Password || $this->isChanged('Password')) { // Password was changed: encrypt the password according the settings $encryption_details = Security::encrypt_password($this->Password, $this->Salt, $this->PasswordEncryption ? $this->PasswordEncryption : Security::config()->password_encryption_algorithm, $this); // Overwrite the Password property with the hashed value $this->Password = $encryption_details['password']; $this->Salt = $encryption_details['salt']; $this->PasswordEncryption = $encryption_details['algorithm']; // If we haven't manually set a password expiry if (!$this->isChanged('PasswordExpiry')) { // then set it for us if (self::config()->password_expiry_days) { $this->PasswordExpiry = date('Y-m-d', time() + 86400 * self::config()->password_expiry_days); } else { $this->PasswordExpiry = null; } } } // save locale if (!$this->Locale) { $this->Locale = i18n::get_locale(); } parent::onBeforeWrite(); }
/** * @return SS_HTTPResponse */ protected function getRedirect() { // Absolute redirection URLs may cause spoofing if (Session::get('BackURL') && Director::is_site_url(Session::get('BackURL'))) { return $this->redirect(Session::get('BackURL')); } // Spoofing attack, redirect to homepage instead of spoofing url if (Session::get('BackURL') && !Director::is_site_url(Session::get('BackURL'))) { return $this->redirect(Director::absoluteBaseURL()); } // If a default login dest has been set, redirect to that. if (Security::config()->default_login_dest) { return $this->redirect(Director::absoluteBaseURL() . Security::config()->default_login_dest); } // fallback to redirect back to home page return $this->redirect(Director::absoluteBaseURL()); }
public function install($config) { ?> <html> <head> <meta charset="utf-8"/> <title>Installing SilverStripe...</title> <link rel="stylesheet" type="text/css" href="<?php echo FRAMEWORK_NAME; ?> /dev/install/css/install.css"/> <script src="<?php echo FRAMEWORK_NAME; ?> /thirdparty/jquery/jquery.js"></script> </head> <body> <div class="install-header"> <div class="inner"> <div class="brand"> <span class="logo"></span> <h1>SilverStripe</h1> </div> </div> </div> <div id="Navigation"> </div> <div class="clear"><!-- --></div> <div class="main"> <div class="inner"> <h2>Installing SilverStripe...</h2> <p>I am now running through the installation steps (this should take about 30 seconds)</p> <p>If you receive a fatal error, refresh this page to continue the installation</p> <ul> <?php $webserver = $this->findWebserver(); $isIIS = $this->isIIS(); $isApache = $this->isApache(); flush(); if (isset($config['stats'])) { if (file_exists(FRAMEWORK_NAME . '/silverstripe_version')) { $silverstripe_version = file_get_contents(FRAMEWORK_NAME . '/silverstripe_version'); } else { $silverstripe_version = "unknown"; } $phpVersion = urlencode(phpversion()); $encWebserver = urlencode($webserver); $dbType = $config['db']['type']; // Try to determine the database version from the helper $databaseVersion = $config['db']['type']; $helper = $this->getDatabaseConfigurationHelper($dbType); if ($helper && method_exists($helper, 'getDatabaseVersion')) { $versionConfig = $config['db'][$dbType]; $versionConfig['type'] = $dbType; $databaseVersion = urlencode($dbType . ': ' . $helper->getDatabaseVersion($versionConfig)); } $url = "http://ss2stat.silverstripe.com/Installation/add?SilverStripe={$silverstripe_version}&PHP={$phpVersion}&Database={$databaseVersion}&WebServer={$encWebserver}"; if (isset($_SESSION['StatsID']) && $_SESSION['StatsID']) { $url .= '&ID=' . $_SESSION['StatsID']; } @($_SESSION['StatsID'] = file_get_contents($url)); } if (file_exists('mysite/_config.php')) { // Truncate the contents of _config instead of deleting it - we can't re-create it because Windows handles permissions slightly // differently to UNIX based filesystems - it takes the permissions from the parent directory instead of retaining them $fh = fopen('mysite/_config.php', 'wb'); fclose($fh); } // Escape user input for safe insertion into PHP file $theme = isset($_POST['template']) ? addcslashes($_POST['template'], "\\'") : 'simple'; $locale = isset($_POST['locale']) ? addcslashes($_POST['locale'], "\\'") : 'en_US'; $type = addcslashes($config['db']['type'], "\\'"); $dbConfig = $config['db'][$type]; $dbConfig = array_map(create_function('$v', 'return addcslashes($v, "\\\'");'), $dbConfig); if (!isset($dbConfig['path'])) { $dbConfig['path'] = ''; } if (!$dbConfig) { echo "<p style=\"color: red\">Bad config submitted</p><pre>"; print_r($config); echo "</pre>"; die; } // Write the config file global $usingEnv; if ($usingEnv) { $this->statusMessage("Setting up 'mysite/_config.php' for use with _ss_environment.php..."); $this->writeToFile("mysite/_config.php", <<<PHP <?php global \$project; \$project = 'mysite'; global \$database; \$database = '{$dbConfig['database']}'; require_once('conf/ConfigureFromEnv.php'); // Set the site locale i18n::set_locale('{$locale}'); PHP ); } else { $this->statusMessage("Setting up 'mysite/_config.php'..."); // Create databaseConfig $lines = array($lines[] = "\t'type' => '{$type}'"); foreach ($dbConfig as $key => $value) { $lines[] = "\t'{$key}' => '{$value}'"; } $databaseConfigContent = implode(",\n", $lines); $this->writeToFile("mysite/_config.php", <<<PHP <?php global \$project; \$project = 'mysite'; global \$databaseConfig; \$databaseConfig = array( {$databaseConfigContent} ); // Set the site locale i18n::set_locale('{$locale}'); PHP ); } $this->statusMessage("Setting up 'mysite/_config/config.yml'"); $this->writeToFile("mysite/_config/config.yml", <<<YML --- Name: mysite After: - 'framework/*' - 'cms/*' --- # YAML configuration for SilverStripe # See http://doc.silverstripe.org/framework/en/topics/configuration # Caution: Indentation through two spaces, not tabs SSViewer: theme: '{$theme}' YML ); if (!$this->checkModuleExists('cms')) { $this->writeToFile("mysite/code/RootURLController.php", <<<PHP <?php class RootURLController extends Controller { \tpublic function index() { \t\techo "<html>Your site is now set up. Start adding controllers to mysite to get started.</html>"; \t} } PHP ); } // Write the appropriate web server configuration file for rewriting support if ($this->hasRewritingCapability()) { if ($isApache) { $this->statusMessage("Setting up '.htaccess' file..."); $this->createHtaccess(); } elseif ($isIIS) { $this->statusMessage("Setting up 'web.config' file..."); $this->createWebConfig(); } } // Load the SilverStripe runtime $_SERVER['SCRIPT_FILENAME'] = dirname(realpath($_SERVER['SCRIPT_FILENAME'])) . '/' . FRAMEWORK_NAME . '/main.php'; chdir(FRAMEWORK_NAME); // Rebuild the manifest $_GET['flush'] = true; // Show errors as if you're in development mode $_SESSION['isDev'] = 1; $this->statusMessage("Building database schema..."); require_once 'core/Core.php'; // Build database $con = new Controller(); $con->pushCurrent(); global $databaseConfig; DB::connect($databaseConfig); $dbAdmin = new DatabaseAdmin(); $dbAdmin->init(); $dbAdmin->doBuild(true); // Create default administrator user and group in database // (not using Security::setDefaultAdmin()) $adminMember = Security::findAnAdministrator(); $adminMember->Email = $config['admin']['username']; $adminMember->Password = $config['admin']['password']; $adminMember->PasswordEncryption = Security::config()->encryption_algorithm; try { $this->statusMessage('Creating default CMS admin account...'); $adminMember->write(); } catch (Exception $e) { $this->statusMessage(sprintf('Warning: Default CMS admin account could not be created (error: %s)', $e->getMessage())); } // Syncing filesystem (so /assets/Uploads is available instantly, see ticket #2266) // show a warning if there was a problem doing so try { $this->statusMessage('Creating initial filesystem assets...'); Filesystem::sync(); } catch (Exception $e) { $this->statusMessage(sprintf('Warning: Creating initial filesystem assets failed (error: %s)', $e->getMessage())); } $_SESSION['username'] = $config['admin']['username']; $_SESSION['password'] = $config['admin']['password']; if (!$this->errors) { if (isset($_SERVER['HTTP_HOST']) && $this->hasRewritingCapability()) { $this->statusMessage("Checking that friendly URLs work..."); $this->checkRewrite(); } else { require_once 'core/startup/ParameterConfirmationToken.php'; $token = new ParameterConfirmationToken('flush'); $params = http_build_query($token->params()); $destinationURL = 'index.php/' . ($this->checkModuleExists('cms') ? "home/successfullyinstalled?{$params}" : "?{$params}"); echo <<<HTML \t\t\t\t<li>SilverStripe successfully installed; I am now redirecting you to your SilverStripe site...</li> \t\t\t\t<script> \t\t\t\t\tsetTimeout(function() { \t\t\t\t\t\twindow.location = "{$destinationURL}"; \t\t\t\t\t}, 2000); \t\t\t\t</script> \t\t\t\t<noscript> \t\t\t\t<li><a href="{$destinationURL}">Click here to access your site.</a></li> \t\t\t\t</noscript> HTML; } } return $this->errors; }
/** * 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 void */ 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 = new ChangePasswordForm($this->controller, 'ChangePasswordForm'); $cp->sessionMessage('Your password has expired. Please choose a new one.', 'good'); return $this->controller->redirect('Security/changepassword'); } // Absolute redirection URLs may cause spoofing if (isset($_REQUEST['BackURL']) && $_REQUEST['BackURL'] && Director::is_site_url($_REQUEST['BackURL'])) { return $this->controller->redirect($_REQUEST['BackURL']); } // Spoofing attack, redirect to homepage instead of spoofing url if (isset($_REQUEST['BackURL']) && $_REQUEST['BackURL'] && !Director::is_site_url($_REQUEST['BackURL'])) { return $this->controller->redirect(Director::absoluteBaseURL()); } // If a default login dest has been set, redirect to that. if (Security::config()->default_login_dest) { return $this->controller->redirect(Director::absoluteBaseURL() . Security::config()->default_login_dest); } // Redirect the user to the page where he 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(); }
public function testSuccessfulLoginAttempts() { Security::config()->login_recording = true; /* SUCCESSFUL ATTEMPTS ARE LOGGED */ $this->doTestLoginForm('*****@*****.**', '1nitialPassword'); $attempt = DataObject::get_one('LoginAttempt', array('"LoginAttempt"."Email"' => '*****@*****.**')); $member = DataObject::get_one('Member', array('"Member"."Email"' => '*****@*****.**')); $this->assertTrue(is_object($attempt)); $this->assertEquals($attempt->Status, 'Success'); $this->assertEquals($attempt->Email, '*****@*****.**'); $this->assertEquals($attempt->Member(), $member); }
/** * 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 singleton('Member')->extend('authenticationFailedUnknownUser', $data); } } $attempt->Email = $email; $attempt->IP = Controller::curr()->getRequest()->getIP(); $attempt->write(); }
/** * Method to authenticate an user * * @param array $RAW_data Raw data to authenticate the user * @param Form $form Optional: If passed, better error messages can be * produced by using * {@link Form::sessionMessage()} * @return bool|Member Returns FALSE if authentication fails, otherwise * the member object * @see Security::setDefaultAdmin() */ public static function authenticate($RAW_data, Form $form = null) { if (array_key_exists('Email', $RAW_data) && $RAW_data['Email']) { $SQL_user = Convert::raw2sql($RAW_data['Email']); } else { return false; } $isLockedOut = false; $result = null; // Default login (see Security::setDefaultAdmin()) if (Security::check_default_admin($RAW_data['Email'], $RAW_data['Password'])) { $member = Security::findAnAdministrator(); } else { $member = DataObject::get_one("Member", "\"" . Member::config()->unique_identifier_field . "\" = '{$SQL_user}' AND \"Password\" IS NOT NULL"); if ($member) { $result = $member->checkPassword($RAW_data['Password']); } else { $result = new ValidationResult(false, _t('Member.ERRORWRONGCRED')); } if ($member && !$result->valid()) { $member->registerFailedLogin(); $member = false; } } // Optionally record every login attempt as a {@link LoginAttempt} object /** * TODO We could handle this with an extension */ if (Security::config()->login_recording) { $attempt = new LoginAttempt(); if ($member) { // 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) $existingMember = DataObject::get_one("Member", "\"" . Member::config()->unique_identifier_field . "\" = '{$SQL_user}'"); if ($existingMember) { $attempt->MemberID = $existingMember->ID; // Audit logging hook $existingMember->extend('authenticationFailed'); } else { // Audit logging hook singleton('Member')->extend('authenticationFailedUnknownUser', $RAW_data); } $attempt->Status = 'Failure'; } if (is_array($RAW_data['Email'])) { user_error("Bad email passed to MemberAuthenticator::authenticate(): {$RAW_data['Email']}", E_USER_WARNING); return false; } $attempt->Email = $RAW_data['Email']; $attempt->IP = Controller::curr()->getRequest()->getIP(); $attempt->write(); } // Legacy migration to precision-safe password hashes. // A login-event with cleartext passwords is the only time // when we can rehash passwords to a different hashing algorithm, // bulk-migration doesn't work due to the nature of hashing. // See PasswordEncryptor_LegacyPHPHash class. if ($member && self::$migrate_legacy_hashes && array_key_exists($member->PasswordEncryption, self::$migrate_legacy_hashes)) { $member->Password = $RAW_data['Password']; $member->PasswordEncryption = self::$migrate_legacy_hashes[$member->PasswordEncryption]; $member->write(); } if ($member) { Session::clear('BackURL'); } else { if ($form && $result) { $form->sessionMessage($result->message(), 'bad'); } } return $member; }
public function testDefaultPasswordEncryptionDoesntChangeExistingMembers() { $member = new Member(); $member->Password = '******'; $member->PasswordEncryption = 'sha1_v2.4'; $member->write(); $origAlgo = Security::config()->password_encryption_algorithm; Security::config()->password_encryption_algorithm = 'none'; $member->Password = '******'; $member->write(); $this->assertEquals($member->PasswordEncryption, 'sha1_v2.4'); $result = $member->checkPassword('mynewpassword'); $this->assertTrue($result->valid()); Security::config()->password_encryption_algorithm = $origAlgo; }
/** * @param Member * @param OpauthIdentity * @param int $mode One or more AUTH_FLAGs. */ protected function loginAndRedirect(Member $member, OpauthIdentity $identity, $mode) { // Back up the BackURL as Member::logIn regenerates the session $backURL = Session::get('BackURL'); // Check if we can log in: $canLogIn = $member->canLogIn(); if (!$canLogIn->valid()) { $extendedURLs = $this->extend('getCantLoginBackURL', $member, $identity, $canLogIn, $mode); if (count($extendedURLs)) { $redirectURL = array_pop($extendedURLs); $this->redirect($redirectURL, 302); return; } Security::permissionFailure($this, $canLogIn->message()); return; } // Decide where to go afterwards... if (!empty($backURL)) { $redirectURL = $backURL; } else { $redirectURL = Security::config()->default_login_dest; } $extendedURLs = $this->extend('getSuccessBackURL', $member, $identity, $redirectURL, $mode); if (count($extendedURLs)) { $redirectURL = array_pop($extendedURLs); } $member->logIn(); // Clear any identity ID Session::clear('OpauthIdentityID'); // Clear the BackURL Session::clear('BackURL'); return $this->redirect($redirectURL); }