/** * @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); } }
/** * 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); }
/** * @param Request $request * @param Closure $next * * @return array|mixed|string */ public function handle($request, Closure $next) { try { static::setExceptions(); //Get the api key. $apiKey = static::getApiKey($request); Session::setApiKey($apiKey); $appId = App::getAppIdByApiKey($apiKey); //Get the JWT. $token = static::getJwt($request); Session::setSessionToken($token); //Get the Console API Key $consoleApiKey = static::getConsoleApiKey($request); //Check for basic auth attempt. $basicAuthUser = $request->getUser(); $basicAuthPassword = $request->getPassword(); if (config('df.managed') && !empty($consoleApiKey) && $consoleApiKey === Managed::getConsoleKey()) { //DFE Console request return $next($request); } elseif (!empty($basicAuthUser) && !empty($basicAuthPassword)) { //Attempting to login using basic auth. Auth::onceBasic(); /** @var User $authenticatedUser */ $authenticatedUser = Auth::user(); if (!empty($authenticatedUser)) { $userId = $authenticatedUser->id; Session::setSessionData($appId, $userId); } else { throw new UnauthorizedException('Unauthorized. User credentials did not match.'); } } elseif (!empty($token)) { //JWT supplied meaning an authenticated user session/token. try { JWTAuth::setToken($token); /** @type Payload $payload */ $payload = JWTAuth::getPayload(); JWTUtilities::verifyUser($payload); $userId = $payload->get('user_id'); Session::setSessionData($appId, $userId); } catch (TokenExpiredException $e) { JWTUtilities::clearAllExpiredTokenMaps(); if (!static::isException($request)) { throw new UnauthorizedException($e->getMessage()); } } catch (TokenBlacklistedException $e) { throw new ForbiddenException($e->getMessage()); } catch (TokenInvalidException $e) { throw new BadRequestException('Invalid token: ' . $e->getMessage(), 401); } } elseif (!empty($apiKey)) { //Just Api Key is supplied. No authenticated session Session::setSessionData($appId); } elseif (static::isException($request)) { //Path exception. return $next($request); } else { throw new BadRequestException('Bad request. No token or api key provided.'); } 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 { if (!Session::isAuthenticated()) { throw new UnauthorizedException('Unauthorized.'); } else { throw new ForbiddenException('Access Forbidden.'); } } } catch (\Exception $e) { return ResponseFactory::getException($e, $request); } }
/** * @param Request $request * @param \Closure $next * * @return array|mixed|string */ public function handle(Request $request, \Closure $next) { if (!in_array($route = $request->getPathInfo(), ['/setup', '/setup_db'])) { try { $apiKey = static::getApiKey($request); Session::setApiKey($apiKey); $appId = App::getAppIdByApiKey($apiKey); //Get the JWT. $token = static::getJwt($request); Session::setSessionToken($token); //Check for basic auth attempt. $basicAuthUser = $request->getUser(); $basicAuthPassword = $request->getPassword(); if (!empty($basicAuthUser) && !empty($basicAuthPassword)) { //Attempting to login using basic auth. Auth::onceBasic(); /** @var User $authenticatedUser */ $authenticatedUser = Auth::user(); if (!empty($authenticatedUser)) { $userId = $authenticatedUser->id; Session::setSessionData($appId, $userId); } else { throw new UnauthorizedException('Unauthorized. User credentials did not match.'); } } elseif (!empty($token)) { //JWT supplied meaning an authenticated user session/token. /** * Note: All caught exception from JWT are stored in session variables. * These are later checked and handled appropriately in the AccessCheck middleware. * * This is to allow processing API calls that do not require any valid * authenticated session. For example POST user/session to login, * PUT user/session to refresh old JWT, GET system/environment etc. * * This also allows for auditing API calls that are called by not permitted/processed. * It also allows counting unauthorized API calls against Enterprise Console limits. */ try { JWTAuth::setToken($token); /** @type Payload $payload */ $payload = JWTAuth::getPayload(); JWTUtilities::verifyUser($payload); $userId = $payload->get('user_id'); Session::setSessionData($appId, $userId); } catch (TokenExpiredException $e) { JWTUtilities::clearAllExpiredTokenMaps(); Session::set('token_expired', true); Session::set('token_expired_msg', $e->getMessage()); } catch (TokenBlacklistedException $e) { Session::set('token_blacklisted', true); Session::set('token_blacklisted_msg', $e->getMessage()); } catch (TokenInvalidException $e) { Session::set('token_invalid', true); Session::set('token_invalid_msg', 'Invalid token: ' . $e->getMessage()); } } elseif (!empty($apiKey)) { //Just Api Key is supplied. No authenticated session Session::setSessionData($appId); } return $next($request); } catch (\Exception $e) { return ResponseFactory::getException($e, $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); }
/** * @param Request $request * @param \Closure $next * * @return array|mixed|string */ public function handle(Request $request, \Closure $next) { if (!in_array($route = $request->getPathInfo(), ['/setup', '/setup_db'])) { try { $apiKey = static::getApiKey($request); Session::setApiKey($apiKey); $appId = App::getAppIdByApiKey($apiKey); //Get the JWT. $token = static::getJwt($request); Session::setSessionToken($token); //Check for basic auth attempt. $basicAuthUser = $request->getUser(); $basicAuthPassword = $request->getPassword(); if (!empty($basicAuthUser) && !empty($basicAuthPassword)) { //Attempting to login using basic auth. Auth::onceBasic(); /** @var User $authenticatedUser */ $authenticatedUser = Auth::user(); if (!empty($authenticatedUser)) { $userId = $authenticatedUser->id; Session::setSessionData($appId, $userId); } else { throw new UnauthorizedException('Unauthorized. User credentials did not match.'); } } elseif (!empty($token)) { //JWT supplied meaning an authenticated user session/token. try { JWTAuth::setToken($token); /** @type Payload $payload */ $payload = JWTAuth::getPayload(); JWTUtilities::verifyUser($payload); $userId = $payload->get('user_id'); Session::setSessionData($appId, $userId); } catch (TokenExpiredException $e) { JWTUtilities::clearAllExpiredTokenMaps(); Session::set('token_expired', true); Session::set('token_expired_msg', $e->getMessage()); } catch (TokenBlacklistedException $e) { throw new ForbiddenException($e->getMessage()); } catch (TokenInvalidException $e) { throw new BadRequestException('Invalid token: ' . $e->getMessage(), 401); } } elseif (!empty($apiKey)) { //Just Api Key is supplied. No authenticated session Session::setSessionData($appId); } return $next($request); } catch (\Exception $e) { return ResponseFactory::getException($e, $request); } } return $next($request); }