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));
 }
Example #6
0
 /**
  * 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();
 }
Example #9
0
	/**
	 * 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;
	}
Example #10
0
 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;
 }
Example #13
0
 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;
 }