/** * Require basic authentication. Will request a username and password if none is given. * * Used by {@link Controller::init()}. * * @param string $realm * @param string|array $permissionCode * @return Member $member */ static function requireLogin($realm, $permissionCode) { if (!Security::database_is_ready() || Director::is_cli()) { return true; } 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) { $authenticated = true; } } // If we've failed the authentication mechanism, then show the login form if (!isset($authenticated)) { header("WWW-Authenticate: Basic realm=\"{$realm}\""); header($_SERVER['SERVER_PROTOCOL'] . ' 401 Unauthorized'); if (isset($_SERVER['PHP_AUTH_USER'])) { echo _t('BasicAuth.ERRORNOTREC', "That username / password isn't recognised"); } else { echo _t('BasicAuth.ENTERINFO', "Please enter a username and password."); } die; } if (!Permission::checkMember($member->ID, $permissionCode)) { header("WWW-Authenticate: Basic realm=\"{$realm}\""); header($_SERVER['SERVER_PROTOCOL'] . ' 401 Unauthorized'); if (isset($_SERVER['PHP_AUTH_USER'])) { echo _t('BasicAuth.ERRORNOTADMIN', "That user is not an administrator."); } die; } return $member; }
protected function logVisit() { if (!Security::database_is_ready()) { return; } DB::query(sprintf('UPDATE "Member" SET "LastVisited" = %s, "NumVisit" = "NumVisit" + 1 WHERE "ID" = %d', DB::get_conn()->now(), $this->owner->ID)); }
/** * Require basic authentication. Will request a username and password if none is given. * * Used by {@link Controller::init()}. * * @throws SS_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 $member */ public static function requireLogin($realm, $permissionCode = null, $tryUsingSessionLogin = true) { $isRunningTests = class_exists('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 SS_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 SS_HTTPResponse_Exception(null, 401); $e->setResponse($response); throw $e; } if ($permissionCode && !Permission::checkMember($member->ID, $permissionCode)) { $response = new SS_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 SS_HTTPResponse_Exception(null, 401); $e->setResponse($response); throw $e; } return $member; }
function populateDefaults() { parent::populateDefaults(); $this->Title = _t("OrderStatusLog.ORDERDISPATCHED", "Order Dispatched"); $this->DispatchedOn = date('Y-m-d'); if (Security::database_is_ready()) { if (Member::currentUser()) { $this->DispatchedBy = Member::currentUser()->getTitle(); } } }
function init() { parent::init(); // We allow access to this controller regardless of live-status or ADMIN permission only // if on CLI or with the database not ready. The latter makes it less errorprone to do an // initial schema build without requiring a default-admin login. // Access to this controller is always allowed in "dev-mode", or of the user is ADMIN. $canAccess = Director::isDev() || !Security::database_is_ready() || Director::is_cli() && !SapphireTest::is_running_test() || Permission::check("ADMIN"); if (!$canAccess) { return Security::permissionFailure($this, "This page is secured and you need administrator rights to access it. " . "Enter your credentials below and we will send you right along."); } }
/** * Updates the database schema, creating tables & fields as necessary. */ function build() { if (Director::isLive() && Security::database_is_ready() && (!Member::currentUser() || !Member::currentUser()->isAdmin())) { Security::permissionFailure($this, "This page is secured and you need administrator rights to access it. " . "Enter your credentials below and we will send you right along."); return; } // The default time limit of 30 seconds is normally not enough if (ini_get("safe_mode") != "1") { set_time_limit(600); } $this->doBuild(isset($_REQUEST['quiet']) || isset($_REQUEST['from_installer'])); }
/** * Initialisation function that is run before any action on the controller is called. * * @uses BasicAuth::requireLogin() */ public function init() { if ($this->basicAuthEnabled) { BasicAuth::protect_site_if_necessary(); } // Directly access the session variable just in case the Group or Member tables don't yet exist if (Member::config()->log_last_visited) { Deprecation::notice('4.0', 'Member::$LastVisited is deprecated. From 4.0 onwards you should implement this as a custom extension'); if (Session::get('loggedInAs') && Security::database_is_ready() && ($member = Member::currentUser())) { DB::prepared_query(sprintf('UPDATE "Member" SET "LastVisited" = %s WHERE "ID" = ?', DB::get_conn()->now()), array($member->ID)); } } // This is used to test that subordinate controllers are actually calling parent::init() - a common bug $this->baseInitCalled = true; }
/** * Initialisation function that is run before any action on the controller is called. * * @uses BasicAuth::requireLogin() */ function init() { if($this->basicAuthEnabled) BasicAuth::protect_site_if_necessary(); // Directly access the session variable just in case the Group or Member tables don't yet exist if(Session::get('loggedInAs') && Security::database_is_ready()) { $member = Member::currentUser(); if($member) { if(!headers_sent()) Cookie::set("PastMember", true, 90, null, null, false, true); DB::query("UPDATE \"Member\" SET \"LastVisited\" = " . DB::getConn()->now() . " WHERE \"ID\" = $member->ID", null); } } // This is used to test that subordinate controllers are actually calling parent::init() - a common bug $this->baseInitCalled = true; }
/** * Initialisation function that is run before any action on the controller is called. * * @uses BasicAuth::requireLogin() */ function init() { if ($this->basicAuthEnabled) { BasicAuth::protect_site_if_necessary(); } // Directly access the session variable just in case the Group or Member tables don't yet exist if (Session::get('loggedInAs') && Security::database_is_ready()) { if ($member = Member::currentUser()) { if (!headers_sent()) { Cookie::set("PastMember", true); } DB::query("UPDATE Member SET LastVisited = NOW() WHERE ID = {$member->ID}", null); } } // This is used to test that subordinate controllers are actually calling parent::init() - a common bug $this->baseInitCalled = true; }
public function init() { parent::init(); // We allow access to this controller regardless of live-status or ADMIN permission only // if on CLI or with the database not ready. The latter makes it less errorprone to do an // initial schema build without requiring a default-admin login. // Access to this controller is always allowed in "dev-mode", or of the user is ADMIN. $isRunningTests = class_exists('SapphireTest', false) && SapphireTest::is_running_test(); $canAccess = Director::isDev() || !Security::database_is_ready() || Director::is_cli() && !$isRunningTests || Permission::check("ADMIN"); if (!$canAccess) { return Security::permissionFailure($this, "This page is secured and you need administrator rights to access it. " . "Enter your credentials below and we will send you right along."); } //render the debug view $renderer = Object::create('DebugView'); $renderer->writeHeader(); $renderer->writeInfo(_t("Shop.DEVTOOLSTITLE", "Shop Development Tools"), Director::absoluteBaseURL()); }
/** * Require basic authentication. Will request a username and password if none is given. * * Used by {@link Controller::init()}. * * @throws SS_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 $member */ public static function requireLogin($realm, $permissionCode = null, $tryUsingSessionLogin = true) { $isRunningTests = class_exists('SapphireTest', false) && SapphireTest::is_running_test(); if (!Security::database_is_ready() || Director::is_cli() && !$isRunningTests) { return true; } $matches = array(); if (isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $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 SS_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 SS_HTTPResponse_Exception(null, 401); $e->setResponse($response); throw $e; } if ($permissionCode && !Permission::checkMember($member->ID, $permissionCode)) { $response = new SS_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 SS_HTTPResponse_Exception(null, 401); $e->setResponse($response); throw $e; } return $member; }
/** * Initialisation function that is run before any action on the controller is called. * * @uses BasicAuth::requireLogin() */ function init() { // Test and development sites should be secured, via basic-auth if(Director::isTest() && $this->basicAuthEnabled && Security::database_is_ready()) { BasicAuth::requireLogin("SilverStripe test website. Use your CMS login", "ADMIN"); } // Directly access the session variable just in case the Group or Member tables don't yet exist if(Session::get('loggedInAs') && Security::database_is_ready()) { if($member = Member::currentUser()) { Cookie::set("PastMember", true); DB::query("UPDATE Member SET LastVisited = NOW() WHERE ID = $member->ID", null); } } // This is used to test that subordinate controllers are actually calling parent::init() - a common bug $this->baseInitCalled = true; }
/** * Updates the database schema, creating tables & fields as necessary. */ function build() { if(Director::isLive() && Security::database_is_ready() && !Director::is_cli() && !Permission::check("ADMIN")) { Security::permissionFailure($this, "This page is secured and you need administrator rights to access it. " . "Enter your credentials below and we will send you right along."); return; } // The default time limit of 30 seconds is normally not enough if(ini_get("safe_mode") != "1") { set_time_limit(600); } // Get all our classes ManifestBuilder::create_manifest_file(); require(MANIFEST_FILE); $this->doBuild(isset($_REQUEST['quiet']) || isset($_REQUEST['from_installer']), !isset($_REQUEST['dont_populate'])); }
function init() { parent::init(); // We allow access to this controller regardless of live-status or ADMIN permission only // if on CLI or with the database not ready. The latter makes it less errorprone to do an // initial schema build without requiring a default-admin login. // Access to this controller is always allowed in "dev-mode", or of the user is ADMIN. $isRunningTests = (class_exists('SapphireTest', false) && SapphireTest::is_running_test()); $canAccess = ( Director::isDev() || !Security::database_is_ready() // We need to ensure that DevelopmentAdminTest can simulate permission failures when running // "dev/tests" from CLI. || (Director::is_cli() && !$isRunningTests) || Permission::check("ADMIN") ); if(!$canAccess) { return Security::permissionFailure($this, "This page is secured and you need administrator rights to access it. " . "Enter your credentials below and we will send you right along."); } }
/** * This function will return true if the site is in a test environment. * For information about environment types, see {@link Director::set_environment_type()}. */ static function isTest() { // Use ?isTest=1 to get test access on the live server, or explicitly set your environment if (isset($_GET['isTest'])) { if (Security::database_is_ready()) { BasicAuth::requireLogin("SilverStripe developer access. Use your CMS login", "ADMIN"); $_SESSION['isTest'] = $_GET['isTest']; } else { return true; } } if (self::isDev()) { return false; } if (self::$environment_type) { return self::$environment_type == 'test'; } // Check if we are running on one of the test servers if (isset($_SERVER['HTTP_HOST']) && in_array($_SERVER['HTTP_HOST'], Director::$test_servers)) { return true; } return false; }
unset($_GET['flush']); } else { $chain->setSuppression(false); } // Load in core require_once 'core/Core.php'; // Connect to database require_once 'model/DB.php'; global $databaseConfig; if ($databaseConfig) { DB::connect($databaseConfig); } // Then if a flush was requested, redirect to it if ($token->parameterProvided() && !$token->tokenProvided()) { // First, check if we're in dev mode, or the database doesn't have any security data $canFlush = Director::isDev() || !Security::database_is_ready(); // Otherwise, we start up the session if needed, then check for admin if (!$canFlush) { if (!isset($_SESSION) && Session::request_contains_session_id()) { Session::start(); } if (Permission::check('ADMIN')) { $canFlush = true; } else { $loginPage = Director::absoluteURL(Config::inst()->get('Security', 'login_url')); $loginPage .= "?BackURL=" . urlencode($_SERVER['REQUEST_URI']); header('location: ' . $loginPage, true, 302); die; } } // And if we can flush, reload with an authority token
public function setUp() { // We cannot run the tests on this abstract class. if (get_class($this) == "SapphireTest") { $this->skipTest = true; } if ($this->skipTest) { $this->markTestSkipped(sprintf('Skipping %s ', get_class($this))); return; } // Mark test as being run $this->originalIsRunningTest = self::$is_running_test; self::$is_running_test = true; // i18n needs to be set to the defaults or tests fail i18n::set_locale(i18n::default_locale()); i18n::config()->date_format = null; i18n::config()->time_format = null; // Set default timezone consistently to avoid NZ-specific dependencies date_default_timezone_set('UTC'); // Remove password validation $this->originalMemberPasswordValidator = Member::password_validator(); $this->originalRequirements = Requirements::backend(); Member::set_password_validator(null); Config::inst()->update('Cookie', 'report_errors', false); if (class_exists('RootURLController')) { RootURLController::reset(); } if (class_exists('Translatable')) { Translatable::reset(); } Versioned::reset(); DataObject::reset(); if (class_exists('SiteTree')) { SiteTree::reset(); } Hierarchy::reset(); if (Controller::has_curr()) { Controller::curr()->setSession(Injector::inst()->create('Session', array())); } Security::$database_is_ready = null; // Add controller-name auto-routing Config::inst()->update('Director', 'rules', array('$Controller//$Action/$ID/$OtherID' => '*')); $fixtureFile = static::get_fixture_file(); $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; // Set up email $this->originalMailer = Email::mailer(); $this->mailer = new TestMailer(); Email::set_mailer($this->mailer); Config::inst()->remove('Email', 'send_all_emails_to'); // Todo: this could be a special test model $this->model = DataModel::inst(); // Set up fixture if ($fixtureFile || $this->usesDatabase || !self::using_temp_db()) { if (substr(DB::get_conn()->getSelectedDatabase(), 0, strlen($prefix) + 5) != strtolower(sprintf('%stmpdb', $prefix))) { //echo "Re-creating temp database... "; self::create_temp_db(); //echo "done.\n"; } singleton('DataObject')->flushCache(); self::empty_temp_db(); foreach ($this->requireDefaultRecordsFrom as $className) { $instance = singleton($className); if (method_exists($instance, 'requireDefaultRecords')) { $instance->requireDefaultRecords(); } if (method_exists($instance, 'augmentDefaultRecords')) { $instance->augmentDefaultRecords(); } } if ($fixtureFile) { $pathForClass = $this->getCurrentAbsolutePath(); $fixtureFiles = is_array($fixtureFile) ? $fixtureFile : array($fixtureFile); $i = 0; foreach ($fixtureFiles as $fixtureFilePath) { // Support fixture paths relative to the test class, rather than relative to webroot // String checking is faster than file_exists() calls. $isRelativeToFile = strpos('/', $fixtureFilePath) === false || preg_match('/^\\.\\./', $fixtureFilePath); if ($isRelativeToFile) { $resolvedPath = realpath($pathForClass . '/' . $fixtureFilePath); if ($resolvedPath) { $fixtureFilePath = $resolvedPath; } } $fixture = Injector::inst()->create('YamlFixture', $fixtureFilePath); $fixture->writeInto($this->getFixtureFactory()); $this->fixtures[] = $fixture; // backwards compatibility: Load first fixture into $this->fixture if ($i == 0) { $this->fixture = $fixture; } $i++; } } $this->logInWithPermission("ADMIN"); } // Preserve memory settings $this->originalMemoryLimit = ini_get('memory_limit'); // turn off template debugging Config::inst()->update('SSViewer', 'source_file_comments', false); // Clear requirements Requirements::clear(); }
/** * Log the user in if the "remember login" cookie is set * * The <i>remember login token</i> will be changed on every successful * auto-login. */ public static function autoLogin() { // Don't bother trying this multiple times if (!class_exists('SapphireTest') || !SapphireTest::is_running_test()) { self::$_already_tried_to_auto_log_in = true; } if (strpos(Cookie::get('alc_enc'), ':') === false || Session::get("loggedInAs") || !Security::database_is_ready()) { return; } if (strpos(Cookie::get('alc_enc'), ':') && Cookie::get('alc_device') && !Session::get("loggedInAs")) { list($uid, $token) = explode(':', Cookie::get('alc_enc'), 2); $deviceID = Cookie::get('alc_device'); $member = Member::get()->byId($uid); $rememberLoginHash = null; // check if autologin token matches if ($member) { $hash = $member->encryptWithUserSettings($token); $rememberLoginHash = RememberLoginHash::get()->filter(array('MemberID' => $member->ID, 'DeviceID' => $deviceID, 'Hash' => $hash))->First(); if (!$rememberLoginHash) { $member = null; } else { // Check for expired token $expiryDate = new DateTime($rememberLoginHash->ExpiryDate); $now = SS_Datetime::now(); $now = new DateTime($now->Rfc2822()); if ($now > $expiryDate) { $member = null; } } } if ($member) { self::session_regenerate_id(); Session::set("loggedInAs", $member->ID); // This lets apache rules detect whether the user has logged in if (Member::config()->login_marker_cookie) { Cookie::set(Member::config()->login_marker_cookie, 1, 0, null, null, false, true); } if ($rememberLoginHash) { $rememberLoginHash->renew(); $tokenExpiryDays = Config::inst()->get('RememberLoginHash', 'token_expiry_days'); Cookie::set('alc_enc', $member->ID . ':' . $rememberLoginHash->getToken(), $tokenExpiryDays, null, null, false, true); } $member->write(); // Audit logging hook $member->extend('memberAutoLoggedIn'); } } }
function testDatabaseIsReadyWithInsufficientMemberColumns() { // Assumption: The database has been built correctly by the test runner, // and has all columns present in the ORM DB::getConn()->renameField('Member', 'Email', 'Email_renamed'); // Email column is now missing, which means we're not ready to do permission checks $this->assertFalse(Security::database_is_ready()); // Rebuild the database (which re-adds the Email column), and try again $this->resetDBSchema(true); $this->assertTrue(Security::database_is_ready()); }
/** * This function will return true if the site is in a test environment. * For information about environment types, see {@link Director::set_environment_type()}. * * @param $skipDatabase Skips database checks for current login permissions if set to TRUE, * which is useful for checks happening before the database is functional. */ public static function isTest($skipDatabase = false) { // Use ?isTest=1 to get test access on the live server, or explicitly set your environment if (!$skipDatabase && isset($_GET['isTest'])) { if (Security::database_is_ready()) { BasicAuth::requireLogin("SilverStripe developer access. Use your CMS login", "ADMIN"); $_SESSION['isTest'] = $_GET['isTest']; } else { return true; } } if (self::isDev($skipDatabase)) { return false; } if (Config::inst()->get('Director', 'environment_type')) { return Config::inst()->get('Director', 'environment_type') == 'test'; } // Check if we are running on one of the test servers $testServers = (array) Config::inst()->get('Director', 'test_servers'); if (isset($_SERVER['HTTP_HOST']) && in_array($_SERVER['HTTP_HOST'], $testServers)) { return true; } return false; }
/** * standard SS method */ function populateDefaults() { parent::populateDefaults(); //can only run after first dev/build if (Security::database_is_ready()) { $controller = Controller::curr(); if ($controller instanceof DatabaseAdmin) { //cant do this now. } else { if ($this->EcomConfig()->ShopPricesAreTaxExclusive) { $this->InclusiveOrExclusive = "Exclusive"; } else { $this->InclusiveOrExclusive = "Inclusive"; } } } }
/** * standard SS method */ function populateDefaults() { parent::populateDefaults(); if (Security::database_is_ready()) { $this->AuthorID = Member::currentUserID(); } }
function silverstripe_main($chain) { global $token; if (isset($_GET['flush']) && !$token->tokenProvided()) { unset($_GET['flush']); } else { $chain->setSuppression(false); } /** * Include Sapphire's core code */ require_once "core/Core.php"; if (function_exists('mb_http_output')) { mb_http_output('UTF-8'); mb_internal_encoding('UTF-8'); } Session::start(); if (isset($_GET['debug_profile'])) { Profiler::init(); Profiler::mark('all_execution'); Profiler::mark('main.php init'); } // Connect to database require_once "core/model/DB.php"; global $databaseConfig; if (isset($_GET['debug_profile'])) { Profiler::mark('DB::connect'); } if ($databaseConfig) { DB::connect($databaseConfig); } if (isset($_GET['debug_profile'])) { Profiler::unmark('DB::connect'); } if ($token->parameterProvided() && !$token->tokenProvided()) { // First, check if we're in dev mode, or the database doesn't have any security data $canFlush = Director::isDev() || !Security::database_is_ready(); // Otherwise, we start up the session if needed, then check for admin if (!$canFlush) { if (!isset($_SESSION) && (isset($_COOKIE[session_name()]) || isset($_REQUEST[session_name()]))) { Session::start(); } if (Permission::check('ADMIN')) { $canFlush = true; } else { $loginPage = Director::absoluteURL('Security/login'); $loginPage .= "?BackURL=" . urlencode($_SERVER['REQUEST_URI']); header('location: ' . $loginPage, true, 302); die; } } // And if we can flush, reload with an authority token if ($canFlush) { $token->reloadWithToken(); } } }
/** * Checks the database is in a state to perform security checks. * See {@link DatabaseAdmin->init()} for more information. * * @return bool */ public static function database_is_ready() { // Used for unit tests if (self::$force_database_is_ready !== NULL) { return self::$force_database_is_ready; } if (self::$database_is_ready) { return self::$database_is_ready; } $requiredTables = ClassInfo::dataClassesFor('Member'); $requiredTables[] = 'Group'; $requiredTables[] = 'Permission'; foreach ($requiredTables as $table) { // Skip test classes, as not all test classes are scaffolded at once if (is_subclass_of($table, 'TestOnly')) { continue; } // if any of the tables aren't created in the database if (!ClassInfo::hasTable($table)) { return false; } // HACK: DataExtensions aren't applied until a class is instantiated for // the first time, so create an instance here. singleton($table); // if any of the tables don't have all fields mapped as table columns $dbFields = DB::field_list($table); if (!$dbFields) { return false; } $objFields = DataObject::database_fields($table, false); $missingFields = array_diff_key($objFields, $dbFields); if ($missingFields) { return false; } } self::$database_is_ready = true; return true; }
/** * Log the user in if the "remember login" cookie is set * * The <i>remember login token</i> will be changed on every successful * auto-login. */ public static function autoLogin() { // Don't bother trying this multiple times self::$_already_tried_to_auto_log_in = true; if (strpos(Cookie::get('alc_enc'), ':') === false || Session::get("loggedInAs") || !Security::database_is_ready()) { return; } list($uid, $token) = explode(':', Cookie::get('alc_enc'), 2); $member = DataObject::get_by_id("Member", $uid); // check if autologin token matches if ($member) { $hash = $member->encryptWithUserSettings($token); if (!$member->RememberLoginToken || $member->RememberLoginToken !== $hash) { $member = null; } } if ($member) { self::session_regenerate_id(); Session::set("loggedInAs", $member->ID); // This lets apache rules detect whether the user has logged in if (Member::config()->login_marker_cookie) { Cookie::set(Member::config()->login_marker_cookie, 1, 0, null, null, false, true); } $generator = new RandomGenerator(); $token = $generator->randomToken('sha1'); $hash = $member->encryptWithUserSettings($token); $member->RememberLoginToken = $hash; Cookie::set('alc_enc', $member->ID . ':' . $token, 90, null, null, false, true); $member->write(); // Audit logging hook $member->extend('memberAutoLoggedIn'); } }
// Connect to database require_once 'model/DB.php'; global $databaseConfig; if ($databaseConfig) { DB::connect($databaseConfig); } // Check if a token is requesting a redirect if (!$reloadToken) { return; } // Otherwise, we start up the session if needed if (!isset($_SESSION) && Session::request_contains_session_id()) { Session::start(); } // Next, check if we're in dev mode, or the database doesn't have any security data, or we are admin if (Director::isDev() || !Security::database_is_ready() || Permission::check('ADMIN')) { return $reloadToken->reloadWithToken(); } // Fail and redirect the user to the login page $loginPage = Director::absoluteURL(Config::inst()->get('Security', 'login_url')); $loginPage .= "?BackURL=" . urlencode($_SERVER['REQUEST_URI']); header('location: ' . $loginPage, true, 302); die; })->thenIfErrored(function () use($reloadToken) { if ($reloadToken) { $reloadToken->reloadWithToken(); } })->execute(); global $databaseConfig; // Redirect to the installer if no database is selected if (!isset($databaseConfig) || !isset($databaseConfig['database']) || !$databaseConfig['database']) {
/** * Log permission failures (where the status is set after init of page). */ public function onAfterInit() { // Suppress errors if dev/build necessary if (!\Security::database_is_ready()) { return false; } $currentMember = \Member::currentUser(); if (!($currentMember && $currentMember->exists())) { return false; } $statusCode = $this->owner->getResponse()->getStatusCode(); if (substr($statusCode, 0, 1) == '4') { $this->logPermissionDenied($statusCode, $currentMember); } }
/** * @deprecated Use Security::database_is_ready() instead. */ static function ready() { user_error("ClassInfo::ready() deprectaed - use Security::database_is_ready()", E_USER_NOTICE); return Security::database_is_ready(); }
public function testDatabaseIsReadyWithInsufficientMemberColumns() { $old = Security::$force_database_is_ready; Security::$force_database_is_ready = null; Security::$database_is_ready = false; DataObject::clear_classname_spec_cache(); // Assumption: The database has been built correctly by the test runner, // and has all columns present in the ORM DB::get_schema()->renameField('Member', 'Email', 'Email_renamed'); // Email column is now missing, which means we're not ready to do permission checks $this->assertFalse(Security::database_is_ready()); // Rebuild the database (which re-adds the Email column), and try again $this->resetDBSchema(true); $this->assertTrue(Security::database_is_ready()); Security::$force_database_is_ready = $old; }