/**
  * @param Request $request
  * @param Closure $next
  *
  * @return array|mixed|string
  */
 public function handle($request, Closure $next)
 {
     //  Allow console requests through
     if (env('DF_IS_VALID_CONSOLE_REQUEST', false)) {
         return $next($request);
     }
     try {
         static::setExceptions();
         if (static::isAccessAllowed()) {
             return $next($request);
         } elseif (static::isException($request)) {
             //API key and/or (non-admin) user logged in, but if access is still not allowed then check for exception case.
             return $next($request);
         } else {
             $apiKey = Session::getApiKey();
             $token = Session::getSessionToken();
             if (empty($apiKey) && empty($token)) {
                 throw new BadRequestException('Bad request. No token or api key provided.');
             } elseif (true === Session::get('token_expired')) {
                 throw new UnauthorizedException(Session::get('token_expired_msg'));
             } elseif (!Session::isAuthenticated()) {
                 throw new UnauthorizedException('Unauthorized.');
             } else {
                 throw new ForbiddenException('Access Forbidden.');
             }
         }
     } catch (\Exception $e) {
         return ResponseFactory::getException($e, $request);
     }
 }
Example #2
0
 /**
  * Handle an incoming request.
  *
  * @param  \Illuminate\Http\Request $request
  * @param  \Closure                 $next
  *
  * @return mixed
  */
 public function handle($request, Closure $next)
 {
     //Get the Console API Key
     $consoleApiKey = AccessCheck::getConsoleApiKey($request);
     // Get limits
     if (config('df.standalone') === true || $consoleApiKey === Managed::getConsoleKey()) {
         return $next($request);
     } else {
         $limits = Managed::getLimits();
         // The limits array comes across from the console as a bunch of Std Objects, need to turn it back
         // into an array
         $limits['api'] = (array) $limits['api'];
         foreach (array_keys($limits['api']) as $key) {
             $limits['api'][$key] = (array) $limits['api'][$key];
         }
     }
     if (!empty($limits) && is_null($this->_getServiceName()) === false) {
         $this->_inUnitTest = \Config::get('api_limits_test');
         $userName = $this->_getUser(Session::getCurrentUserId());
         $userRole = $this->_getRole(Session::getRoleId());
         $apiName = $this->_getApiKey(Session::getApiKey());
         $serviceName = $this->_getServiceName();
         $clusterName = Managed::getClusterName();
         // Build the list of API Hits to check
         $apiKeysToCheck = ['cluster.default' => 0, 'instance.default' => 0];
         $serviceKeys[$serviceName] = 0;
         if (is_null($userRole) === false) {
             $serviceKeys[$serviceName . '.' . $userRole] = 0;
         }
         if (is_null($userName) === false) {
             $serviceKeys[$serviceName . '.' . $userName] = 0;
         }
         if (is_null($apiName) === false) {
             $apiKeysToCheck[$apiName] = 0;
             if (is_null($userRole) === false) {
                 $apiKeysToCheck[$apiName . '.' . $userRole] = 0;
             }
             if (is_null($userName) === false) {
                 $apiKeysToCheck[$apiName . '.' . $userName] = 0;
             }
             foreach ($serviceKeys as $key => $value) {
                 $apiKeysToCheck[$apiName . '.' . $key] = $value;
             }
         }
         if (is_null($clusterName) === false) {
             $apiKeysToCheck[$clusterName] = 0;
             if (is_null($userRole) === false) {
                 $apiKeysToCheck[$clusterName . '.' . $userRole] = 0;
             }
             if (is_null($userName) === false) {
                 $apiKeysToCheck[$clusterName . '.' . $userName] = 0;
             }
             foreach ($serviceKeys as $key => $value) {
                 $apiKeysToCheck[$clusterName . '.' . $key] = $value;
             }
         }
         if (is_null($userName) === false) {
             $apiKeysToCheck[$userName] = 0;
         }
         if (is_null($userRole) === false) {
             $apiKeysToCheck[$userRole] = 0;
         }
         $apiKeysToCheck = array_merge($apiKeysToCheck, $serviceKeys);
         $timePeriods = ['minute', 'hour', 'day', '7-day', '30-day'];
         $overLimit = false;
         try {
             foreach (array_keys($apiKeysToCheck) as $key) {
                 foreach ($timePeriods as $period) {
                     $keyToCheck = $key . '.' . $period;
                     if (array_key_exists($keyToCheck, $limits['api']) === true) {
                         $cacheValue = \Cache::get($keyToCheck, 0);
                         $cacheValue++;
                         \Cache::put($keyToCheck, $cacheValue, $limits['api'][$keyToCheck]['period']);
                         if ($cacheValue > $limits['api'][$keyToCheck]['limit']) {
                             $overLimit = true;
                         }
                     }
                 }
             }
         } catch (\Exception $e) {
             return ResponseFactory::getException(new InternalServerErrorException('Unable to update cache'), $request);
         }
         if ($overLimit === true) {
             return ResponseFactory::getException(new TooManyRequestsException('Specified connection limit exceeded'), $request);
         }
     }
     return $next($request);
 }
 /**
  * Handle an incoming request.
  *
  * @param  \Illuminate\Http\Request $request
  * @param  \Closure                 $next
  *
  * @return mixed
  */
 public function handle(Request $request, Closure $next)
 {
     /**
      * It is assumed, if you get this far, that ClusterServiceProvider was registered via
      * the ManagedInstance bootstrapper. If not, you're in a world of shit.
      *
      * We use provider's service() method because Facades are not loaded yet
      */
     $_cluster = ClusterServiceProvider::service();
     //  Get limits or bail
     if (!$_cluster instanceof ProvidesManagedLimits || empty($limits = $_cluster->getLimits())) {
         return $next($request);
     }
     $this->testing = config('api_limits_test', 'testing' == env('APP_ENV'));
     if (!empty($limits)) {
         $userName = $this->getUser(Session::getCurrentUserId());
         $userRole = $this->getRole(Session::getRoleId());
         $apiName = $this->getApiKey(Session::getApiKey());
         $clusterName = $_cluster->getClusterId();
         $instanceName = $_cluster->getInstanceName();
         $serviceName = $this->getServiceName($request);
         $limits = json_encode($limits);
         //TODO: Update dfe-console to properly set this, but right now, we want to touch as few files as possible
         if (!$this->testing) {
             $limits = str_replace(['cluster.default', 'instance.default'], [$clusterName, $clusterName . '.' . $instanceName], $limits);
         }
         //  Convert to an array
         $limits = json_decode($limits, true);
         //  Build the list of API Hits to check
         $apiKeysToCheck = [$clusterName . '.' . $instanceName => 0];
         $serviceKeys = [];
         if ($serviceName) {
             $serviceKeys[$serviceName] = 0;
             $userRole && ($serviceKeys[$serviceName . '.' . $userRole] = 0);
             $userName && ($serviceKeys[$serviceName . '.' . $userName] = 0);
         }
         if ($apiName) {
             $apiKeysToCheck[$clusterName . '.' . $instanceName . '.' . $apiName] = 0;
             $userRole && ($apiKeysToCheck[$clusterName . '.' . $instanceName . '.' . $apiName . '.' . $userRole] = 0);
             $userName && ($apiKeysToCheck[$clusterName . '.' . $instanceName . '.' . $apiName . '.' . $userName] = 0);
             foreach ($serviceKeys as $key => $value) {
                 $apiKeysToCheck[$apiName . '.' . $key] = $value;
             }
         }
         if ($clusterName) {
             $apiKeysToCheck[$clusterName] = 0;
             $userRole && ($apiKeysToCheck[$clusterName . '.' . $instanceName . '.' . $userRole] = 0);
             $userName && ($apiKeysToCheck[$clusterName . '.' . $instanceName . '.' . $userName] = 0);
             foreach ($serviceKeys as $key => $value) {
                 $apiKeysToCheck[$clusterName . '.' . $instanceName . '.' . $key] = $value;
             }
         }
         /* Per Ben, we want to increment every limit they hit, not stop after the first one */
         $overLimit = [];
         try {
             foreach (array_keys($apiKeysToCheck) as $key) {
                 foreach ($this->periods as $period) {
                     $_checkKey = $key . '.' . $period;
                     /** @noinspection PhpUndefinedMethodInspection */
                     if (array_key_exists($_checkKey, $limits['api'])) {
                         $_limit = $limits['api'][$_checkKey];
                         // For any cache drivers that make use of the cache prefix, we need to make sure we use
                         // a prefix that every instance can see.  But first, grab the current value
                         $dfCachePrefix = env('DF_CACHE_PREFIX');
                         putenv('DF_CACHE_PREFIX' . '=' . 'df_limits');
                         $_ENV['DF_CACHE_PREFIX'] = $_SERVER['DF_CACHE_PREFIX'] = 'df_limits';
                         //  Increment counter
                         $cacheValue = $this->cache()->get($_checkKey, 0);
                         $cacheValue++;
                         if ($cacheValue > $_limit['limit']) {
                             // Push the name of the rule onto the over-limit array so we can give the name in the 429 error message
                             $overLimit[] = array_get($_limit, 'name', $_checkKey);
                         } else {
                             // Only increment the counter if we are not over the limit.  Fixes DFE-205
                             $this->cache()->put($_checkKey, $cacheValue, $_limit['period']);
                         }
                         // And now set it back
                         putenv('DF_CACHE_PREFIX' . '=' . $dfCachePrefix);
                         $_ENV['DF_CACHE_PREFIX'] = $_SERVER['DF_CACHE_PREFIX'] = $dfCachePrefix;
                     }
                 }
             }
         } catch (\Exception $_ex) {
             return ResponseFactory::getException(new InternalServerErrorException('Unable to update cache: ' . $_ex->getMessage()), $request);
         }
         if ($overLimit) {
             /* Per Ben, we want to increment every limit they hit, not stop after the first one */
             return ResponseFactory::getException(new TooManyRequestsException('API limit(s) exceeded: ' . implode(', ', $overLimit)), $request);
         }
     }
     return $next($request);
 }