Example #1
0
 /**
  * @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 (true === Session::get('token_blacklisted')) {
                 throw new ForbiddenException(Session::get('token_blacklisted_msg'));
             } elseif (true === Session::get('token_invalid')) {
                 throw new BadRequestException('Invalid token: ' . Session::get('token_invalid_msg'), 401);
             } else {
                 if (!Role::getCachedInfo(Session::getRoleId(), 'is_active')) {
                     throw new ForbiddenException("Role is not active.");
                 } 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);
 }
Example #3
0
 /**
  * @param string $service   - API name of the service
  * @param string $component - API component/resource name
  * @param int    $requestor - Entity type requesting the service
  *
  * @returns array
  */
 public static function getServicePermissions($service, $component = null, $requestor = ServiceRequestorTypes::API)
 {
     if (static::isSysAdmin()) {
         return VerbsMask::NONE_MASK | VerbsMask::GET_MASK | VerbsMask::POST_MASK | VerbsMask::PUT_MASK | VerbsMask::PATCH_MASK | VerbsMask::DELETE_MASK;
     }
     $roleId = Session::getRoleId();
     if ($roleId && !Role::getCachedInfo($roleId, 'is_active')) {
         return false;
     }
     $services = ArrayUtils::clean(static::get('role.services'));
     $service = strval($service);
     $component = strval($component);
     //  If exact match found take it, otherwise follow up the chain as necessary
     //  All - Service - Component - Sub-component
     $allAllowed = VerbsMask::NONE_MASK;
     $allFound = false;
     $serviceAllowed = VerbsMask::NONE_MASK;
     $serviceFound = false;
     $componentAllowed = VerbsMask::NONE_MASK;
     $componentFound = false;
     $exactAllowed = VerbsMask::NONE_MASK;
     $exactFound = false;
     foreach ($services as $svcInfo) {
         $tempRequestors = ArrayUtils::get($svcInfo, 'requestor_mask', ServiceRequestorTypes::API);
         if (!($requestor & $tempRequestors)) {
             //  Requestor type not found in allowed requestors, skip access setting
             continue;
         }
         $tempService = strval(ArrayUtils::get($svcInfo, 'service'));
         $tempComponent = strval(ArrayUtils::get($svcInfo, 'component'));
         $tempCompStarPos = strpos($tempComponent, '*');
         $tempVerbs = ArrayUtils::get($svcInfo, 'verb_mask');
         if (0 == strcasecmp($service, $tempService)) {
             if (!empty($component)) {
                 if (0 == strcasecmp($component, $tempComponent)) {
                     // exact match
                     $exactAllowed |= $tempVerbs;
                     $exactFound = true;
                 } elseif ($tempCompStarPos && 0 == strcasecmp(substr($component, 0, $tempCompStarPos) . '*', $tempComponent)) {
                     $componentAllowed |= $tempVerbs;
                     $componentFound = true;
                 } elseif ('*' == $tempComponent) {
                     $serviceAllowed |= $tempVerbs;
                     $serviceFound = true;
                 }
             } else {
                 if (empty($tempComponent)) {
                     // exact match
                     $exactAllowed |= $tempVerbs;
                     $exactFound = true;
                 } elseif ('*' == $tempComponent) {
                     $serviceAllowed |= $tempVerbs;
                     $serviceFound = true;
                 }
             }
         } else {
             if (empty($tempService) && ('*' == $tempComponent || empty($tempComponent) && empty($component))) {
                 $allAllowed |= $tempVerbs;
                 $allFound = true;
             }
         }
     }
     if ($exactFound) {
         return $exactAllowed;
     } elseif ($componentFound) {
         return $componentAllowed;
     } elseif ($serviceFound) {
         return $serviceAllowed;
     } elseif ($allFound) {
         return $allAllowed;
     }
     return VerbsMask::NONE_MASK;
 }
 /**
  * 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);
 }