public function preRequest(HTTPRequest $request, Session $session, DataModel $model) { // Bootstrap session so that Session::get() accesses the right instance $dummyController = new Controller(); $dummyController->setSession($session); $dummyController->setRequest($request); $dummyController->pushCurrent(); // Block non-authenticated users from setting the stage mode if (!Versioned::can_choose_site_stage($request)) { $permissionMessage = sprintf(_t("ContentController.DRAFT_SITE_ACCESS_RESTRICTION", 'You must log in with your CMS password in order to view the draft or archived content. ' . '<a href="%s">Click here to go back to the published site.</a>'), Convert::raw2xml(Controller::join_links(Director::baseURL(), $request->getURL(), "?stage=Live"))); // Force output since RequestFilter::preRequest doesn't support response overriding $response = Security::permissionFailure($dummyController, $permissionMessage); $session->inst_save(); $dummyController->popCurrent(); // Prevent output in testing if (class_exists('SilverStripe\\Dev\\SapphireTest', false) && SapphireTest::is_running_test()) { throw new HTTPResponse_Exception($response); } $response->output(); die; } Versioned::choose_site_stage(); $dummyController->popCurrent(); return true; }
protected function init() { parent::init(); $isRunningTests = class_exists('SilverStripe\\Dev\\SapphireTest', false) && SapphireTest::is_running_test(); $canAccess = Director::isDev() || Director::is_cli() && !$isRunningTests || Permission::check("ADMIN"); if (!$canAccess) { Security::permissionFailure($this); } }
/** * 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; }
protected 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('SilverStripe\\Dev\\SapphireTest', false) && SapphireTest::is_running_test(); $canAccess = Director::isDev() || !Security::database_is_ready() || Director::is_cli() && !$isRunningTests || Permission::check("ADMIN"); if (!$canAccess) { 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."); } }
/** * Force the site to run on SSL. * * To use, call from _config.php. For example: * <code> * if (Director::isLive()) Director::forceSSL(); * </code> * * If you don't want your entire site to be on SSL, you can pass an array of PCRE regular expression * patterns for matching relative URLs. For example: * <code> * if (Director::isLive()) Director::forceSSL(array('/^admin/', '/^Security/')); * </code> * * If you want certain parts of your site protected under a different domain, you can specify * the domain as an argument: * <code> * if (Director::isLive()) Director::forceSSL(array('/^admin/', '/^Security/'), 'secure.mysite.com'); * </code> * * Note that the session data will be lost when moving from HTTP to HTTPS. It is your responsibility * to ensure that this won't cause usability problems. * * CAUTION: This does not respect the site environment mode. You should check this * as per the above examples using Director::isLive() or Director::isTest() for example. * * @param array $patterns Array of regex patterns to match URLs that should be HTTPS. * @param string $secureDomain Secure domain to redirect to. Defaults to the current domain. * * @return bool|string String of URL when unit tests running, boolean FALSE if patterns don't match request URI. */ public static function forceSSL($patterns = null, $secureDomain = null) { // Calling from the command-line? if (!isset($_SERVER['REQUEST_URI'])) { return false; } $matched = false; if ($patterns) { $relativeURL = self::makeRelative(Director::absoluteURL($_SERVER['REQUEST_URI'])); // protect portions of the site based on the pattern foreach ($patterns as $pattern) { if (preg_match($pattern, $relativeURL)) { $matched = true; break; } } } else { // protect the entire site $matched = true; } if ($matched && !self::is_https()) { // if an domain is specified, redirect to that instead of the current domain if ($secureDomain) { $url = 'https://' . $secureDomain . $_SERVER['REQUEST_URI']; } else { $url = $_SERVER['REQUEST_URI']; } $destURL = str_replace('http:', 'https:', Director::absoluteURL($url)); // This coupling to SapphireTest is necessary to test the destination URL and to not interfere with tests if (class_exists('SilverStripe\\Dev\\SapphireTest', false) && SapphireTest::is_running_test()) { return $destURL; } else { self::force_redirect($destURL); return true; } } else { return false; } }
/** * Check that a valid file was given for upload (ignores file size) * * @return bool */ public function isValidUpload() { // Check file upload if ($this->tmpFile['error'] === UPLOAD_ERR_NO_FILE) { return false; } // Check if file is valid uploaded (with exception for unit testing) // Note that some "max file size" errors leave "temp_name" empty, so don't fail on this. $isRunningTests = class_exists('SilverStripe\\Dev\\SapphireTest', false) && SapphireTest::is_running_test(); if (!empty($this->tmpFile['tmp_name']) && !is_uploaded_file($this->tmpFile['tmp_name']) && !$isRunningTests) { return false; } 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 if (!class_exists('SilverStripe\\Dev\\SapphireTest', false) || !SapphireTest::is_running_test()) { self::$_already_tried_to_auto_log_in = true; } if (!Security::config()->autologin_enabled || 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); if (!$uid || !$token) { return; } $deviceID = Cookie::get('alc_device'); /** @var Member $member */ $member = Member::get()->byID($uid); /** @var RememberLoginHash $rememberLoginHash */ $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 = DBDatetime::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 = RememberLoginHash::config()->get('token_expiry_days'); Cookie::set('alc_enc', $member->ID . ':' . $rememberLoginHash->getToken(), $tokenExpiryDays, null, null, false, true); } $member->write(); // Audit logging hook $member->extend('memberAutoLoggedIn'); } } }