public function getContent($key, $callback) { // Bypass rate limiting if flushing, or timeout isn't set $timeout = \Config::inst()->get(get_class(), 'lock_timeout'); if (isset($_GET['flush']) || !$timeout) { return parent::getContent($key, $callback); } // Generate result with rate limiting enabled $limitKey = $this->getCacheKey($key); $cache = $this->getCache(); if ($lockedUntil = $cache->load($limitKey)) { if (time() < $lockedUntil) { // Politely inform visitor of limit $response = new \SS_HTTPResponse_Exception('Too Many Requests.', 429); $response->getResponse()->addHeader('Retry-After', 1 + $lockedUntil - time()); throw $response; } } // Apply rate limit $cache->save(time() + $timeout, $limitKey); // Generate results $result = parent::getContent($key, $callback); // Reset rate limit with optional cooldown if ($cooldown = \Config::inst()->get(get_class(), 'lock_cooldown')) { // Set cooldown on successful query execution $cache->save(time() + $cooldown, $limitKey); } else { // Without cooldown simply disable lock $cache->remove($limitKey); } return $result; }
/** * @param string $permission * * @throws SS_HTTPResponse_Exception */ function init($permission = 'ADMIN') { // if the environment supports it, provide a basic auth challenge and see if it matches configured credentials if (defined('ENVCHECK_BASICAUTH_USERNAME') && defined('ENVCHECK_BASICAUTH_PASSWORD')) { if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { // authenticate the input user/pass with the configured credentials if (!($_SERVER['PHP_AUTH_USER'] == ENVCHECK_BASICAUTH_USERNAME && $_SERVER['PHP_AUTH_PW'] == ENVCHECK_BASICAUTH_PASSWORD)) { $response = new SS_HTTPResponse(null, 401); $response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\""); // Exception is caught by RequestHandler->handleRequest() and will halt further execution $e = new SS_HTTPResponse_Exception(null, 401); $e->setResponse($response); throw $e; } } else { $response = new SS_HTTPResponse(null, 401); $response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\""); // Exception is caught by RequestHandler->handleRequest() and will halt further execution $e = new SS_HTTPResponse_Exception(null, 401); $e->setResponse($response); throw $e; } } else { if (!$this->canAccess(null, $permission)) { return $this->httpError(403); } } }
/** * 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 = MoreAdminsAuthenticator::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; }
public function onAfterInit() { /* * Custom handler to redirect invalid url's to the home page, so we never have a 404 error * will first check if there is already a redirect provided for a specific page */ if ($this->owner->ErrorCode == 404) { $RedirectPage = $this->FindRedirectPage(); $response = new SS_HTTPResponse_Exception(); $response->getResponse()->redirect($RedirectPage ? $RedirectPage->Link() : "/", 301); throw $response; } }
/** * Gets the video by it's url * @param {string} $url Vidyard Video URL to lookup * @return {array} Array in which the first key is a file instance and the second key is the url */ protected function getVideoByURL($url) { //Get the video id $videoID = Vidyard::getVidyardCode($url); if (empty($videoID)) { $exception = new SS_HTTPResponse_Exception('Could not get the Video ID from the URL', 400); $exception->getResponse()->addHeader('X-Status', $exception->getMessage()); throw $exception; } //Retrieve and Check the api key $apiKey = Vidyard::config()->api_key; if (empty($apiKey)) { $exception = new SS_HTTPResponse_Exception('Vidyard.api_key is not set, please configure your api key see http://support.vidyard.com/articles/Public_Support/Using-the-Vidyard-dashboard-API/ for how to get your API key.', 401); $exception->getResponse()->addHeader('X-Status', $exception->getMessage()); throw $exception; } return array(new File(array('Title' => $videoID, 'Filename' => trim($url))), trim($url)); }
/** * 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 */ 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; } $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; }
/** * Gets the overview data from new relic */ public function overview_data() { //Purge Requirements Requirements::clear(); //If we're not configured properly return an error if (!$this->getIsConfigured()) { $msg = _t('NewRelicPerformanceReport.API_APP_CONFIG_ERROR', '_New Relic API Key or Application ID is missing, check configuration'); $e = new SS_HTTPResponse_Exception($msg, 400); $e->getResponse()->addHeader('Content-Type', 'text/plain'); $e->getResponse()->addHeader('X-Status', rawurlencode($msg)); throw $e; return; } //Build the base restful service object $service = new RestfulService('https://api.newrelic.com/v2/applications/' . Convert::raw2url($this->config()->application_id) . '/metrics/data.json', $this->config()->refresh_rate); $service->httpHeader('X-Api-Key:' . Convert::raw2url($this->config()->api_key)); //Perform the request $response = $service->request('', 'POST', 'names[]=HttpDispatcher&names[]=Apdex&names[]=EndUser/Apdex&names[]=Errors/all&names[]=EndUser&period=60'); //Retrieve the body $body = $response->getBody(); if (!empty($body)) { $this->response->addHeader('Content-Type', 'application/json; charset=utf-8'); return $body; } //Data failed to load $msg = _t('NewRelicPerformanceReport.DATA_LOAD_FAIL', '_Failed to retrieve data from New Relic'); $e = new SS_HTTPResponse_Exception($msg, 400); $e->getResponse()->addHeader('Content-Type', 'text/plain'); $e->getResponse()->addHeader('X-Status', rawurlencode($msg)); throw $e; }
/** * Confirm that the current page is valid. */ public function validate() { $parent = $this->getParent(); // The URL segment will conflict with a year/month/day/media format when numeric. if (is_numeric($this->URLSegment) || !$parent instanceof MediaHolder || $this->MediaTypeID && $parent->MediaTypeID != $this->MediaTypeID) { // Customise a validation error message. $message = is_numeric($this->URLSegment) ? '"URL Segment" must not be numeric!' : 'Invalid media holder!'; $error = new SS_HTTPResponse_Exception($message, 403); $error->getResponse()->addHeader('X-Status', rawurlencode($message)); // Allow extension customisation. $this->extend('validateMediaPage', $error); throw $error; } return parent::validate(); }
/** * Throws a HTTP error response encased in a {@link SS_HTTPResponse_Exception}, which is later caught in * {@link RequestHandler::handleAction()} and returned to the user. * * @param int $errorCode * @param string $errorMessage Plaintext error message * @uses SS_HTTPResponse_Exception */ public function httpError($errorCode, $errorMessage = null) { $e = new SS_HTTPResponse_Exception($errorMessage, $errorCode); // Error responses should always be considered plaintext, for security reasons $e->getResponse()->addHeader('Content-Type', 'text/plain'); throw $e; }
public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { try { $response = parent::handleRequest($request, $model); } catch (ValidationException $e) { // Nicer presentation of model-level validation errors $msgs = _t('LeftAndMain.ValidationError', 'Validation error') . ': ' . $e->getMessage(); $e = new SS_HTTPResponse_Exception($msgs, 403); $e->getResponse()->addHeader('Content-Type', 'text/plain'); $e->getResponse()->addHeader('X-Status', rawurlencode($msgs)); throw $e; } $title = $this->Title(); if (!$response->getHeader('X-Controller')) { $response->addHeader('X-Controller', $this->class); } if (!$response->getHeader('X-Title')) { $response->addHeader('X-Title', urlencode($title)); } // Prevent clickjacking, see https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options $this->response->addHeader('X-Frame-Options', 'SAMEORIGIN'); return $response; }
/** * Enable BasicAuth in a similar fashion as BasicAuth class * * @return boolean * @throws SS_HTTPResponse_Exception */ protected function basicAuth() { $username = self::config()->username; $password = self::config()->password; if (!$username || !$password) { return true; } $authHeader = null; if (isset($_SERVER['HTTP_AUTHORIZATION'])) { $authHeader = $_SERVER['HTTP_AUTHORIZATION']; } else { if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { $authHeader = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } } $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); } $authSuccess = false; if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { if ($_SERVER['PHP_AUTH_USER'] == $username && $_SERVER['PHP_AUTH_PW'] == $password) { $authSuccess = true; } } if (!$authSuccess) { $realm = "Enter your credentials"; $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; } return $authSuccess; }
/** * Prepare error for the front end * * @param string $message * @param int $code * @return SS_HTTPResponse_Exception */ protected function getErrorFor($message, $code = 400) { $exception = new SS_HTTPResponse_Exception($message, $code); $exception->getResponse()->addHeader('X-Status', $message); return $exception; }
protected function viewfile_getRemoteFileByURL($fileUrl) { $scheme = strtolower(parse_url($fileUrl, PHP_URL_SCHEME)); $allowed_schemes = self::config()->fileurl_scheme_whitelist; if (!$scheme || $allowed_schemes && !in_array($scheme, $allowed_schemes)) { $exception = new SS_HTTPResponse_Exception("This file scheme is not included in the whitelist", 400); $exception->getResponse()->addHeader('X-Status', $exception->getMessage()); throw $exception; } $domain = strtolower(parse_url($fileUrl, PHP_URL_HOST)); $allowed_domains = self::config()->fileurl_domain_whitelist; if (!$domain || $allowed_domains && !in_array($domain, $allowed_domains)) { $exception = new SS_HTTPResponse_Exception("This file hostname is not included in the whitelist", 400); $exception->getResponse()->addHeader('X-Status', $exception->getMessage()); throw $exception; } return array(new File(array('Title' => basename($fileUrl), 'Filename' => $fileUrl)), $fileUrl); }
public function respondWithError($args) { // Make args' keys lowercase $args = array_combine(array_map('strtolower', array_keys($args)), array_values($args)); // See if an exception is passed (no default) $exception = null; if (isset($args['exception'])) { $exception = $args['exception']; } // Get the default exception noun if set $exceptionNoun = self::$exception_noun; // Add defaults $args = array_merge(array('code' => 500, 'description' => null, 'body' => null, 'noun' => $exception && $exceptionNoun ? new $exceptionNoun($exception) : null), $args); // Default "response" which we build into. Not returned, because the exception has it's own response $response = new SS_HTTPResponse(); // If there's a formatter if ($args['noun'] && ($formatter = RESTFormatter::get_formatter($this->request))) { // Format the response. Revert back to default response if we got nothing. $response = $formatter->format($args['noun'], array('*')); if (!$response) { $response = new SS_HTTPResponse(); } } else { if ($exception) { $exception = $args['exception']; $response->setBody($exception->getMessage() . "\n"); $response->addHeader('Content-Type', 'text/plain'); } } // If a specific body was provided, use that if ($args['body']) { $response->setBody($args['body']); } // Build an exception with those details $e = new SS_HTTPResponse_Exception($response->getBody(), $args['code'], $args['description']); $exceptionResponse = $e->getResponse(); // Add user specified headers foreach ($response->getHeaders() as $k => $v) { $exceptionResponse->addHeader($k, $v); } throw $e; }