From 45a153427e1072828e430d5a51b49a8ea358743b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 19 Nov 2017 14:05:13 -0600 Subject: [PATCH] Add new API middleware --- app/Http/Kernel.php | 14 ++--- .../Middleware/API/AuthenticateIPAccess.php | 39 ++++++++++++++ app/Http/Middleware/API/AuthenticateKey.php | 44 ++++++++++++++-- app/Http/Middleware/API/SetSessionDriver.php | 52 +++++++++++++++++++ app/Providers/RouteServiceProvider.php | 14 ++--- 5 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 app/Http/Middleware/API/AuthenticateIPAccess.php create mode 100644 app/Http/Middleware/API/SetSessionDriver.php diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 79c6e9ecf..573a88120 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -11,15 +11,17 @@ use Pterodactyl\Http\Middleware\EncryptCookies; use Pterodactyl\Http\Middleware\VerifyCsrfToken; use Pterodactyl\Http\Middleware\VerifyReCaptcha; use Pterodactyl\Http\Middleware\AdminAuthenticate; -use Pterodactyl\Http\Middleware\HMACAuthorization; use Illuminate\Routing\Middleware\ThrottleRequests; use Pterodactyl\Http\Middleware\LanguageMiddleware; use Illuminate\Foundation\Http\Kernel as HttpKernel; +use Pterodactyl\Http\Middleware\API\AuthenticateKey; use Illuminate\Routing\Middleware\SubstituteBindings; use Pterodactyl\Http\Middleware\AccessingValidServer; +use Pterodactyl\Http\Middleware\API\SetSessionDriver; use Illuminate\View\Middleware\ShareErrorsFromSession; use Pterodactyl\Http\Middleware\RedirectIfAuthenticated; use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; +use Pterodactyl\Http\Middleware\API\AuthenticateIPAccess; use Pterodactyl\Http\Middleware\Daemon\DaemonAuthenticate; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Pterodactyl\Http\Middleware\Server\AuthenticateAsSubuser; @@ -42,10 +44,6 @@ class Kernel extends HttpKernel EncryptCookies::class, AddQueuedCookiesToResponse::class, TrimStrings::class, - - /* - * Custom middleware applied to all routes. - */ TrustProxies::class, ]; @@ -66,9 +64,11 @@ class Kernel extends HttpKernel RequireTwoFactorAuthentication::class, ], 'api' => [ - HMACAuthorization::class, 'throttle:60,1', - 'bindings', + SubstituteBindings::class, + SetSessionDriver::class, + AuthenticateKey::class, + AuthenticateIPAccess::class, ], 'daemon' => [ SubstituteBindings::class, diff --git a/app/Http/Middleware/API/AuthenticateIPAccess.php b/app/Http/Middleware/API/AuthenticateIPAccess.php new file mode 100644 index 000000000..b3d1d5c37 --- /dev/null +++ b/app/Http/Middleware/API/AuthenticateIPAccess.php @@ -0,0 +1,39 @@ +attributes->get('api_key'); + + if (is_null($model->allowed_ips) || empty($model->allowed_ips)) { + return $next($request); + } + + foreach ($model->allowed_ips as $ip) { + if (Range::parse($ip)->contains(new IP($request->ip()))) { + return $next($request); + } + } + + throw new AccessDeniedHttpException('This IP address does not have permission to access the API using these credentials.'); + } +} diff --git a/app/Http/Middleware/API/AuthenticateKey.php b/app/Http/Middleware/API/AuthenticateKey.php index da833d891..0bad6dcb2 100644 --- a/app/Http/Middleware/API/AuthenticateKey.php +++ b/app/Http/Middleware/API/AuthenticateKey.php @@ -4,10 +4,25 @@ namespace Pterodactyl\Http\Middleware\API; use Closure; use Illuminate\Http\Request; +use Illuminate\Auth\AuthManager; +use Symfony\Component\HttpKernel\Exception\HttpException; +use Pterodactyl\Exceptions\Repository\RecordNotFoundException; +use Illuminate\Contracts\Config\Repository as ConfigRepository; use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class AuthenticateKey { + /** + * @var \Illuminate\Auth\AuthManager + */ + private $auth; + + /** + * @var \Illuminate\Contracts\Config\Repository + */ + private $config; + /** * @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface */ @@ -17,9 +32,16 @@ class AuthenticateKey * AuthenticateKey constructor. * * @param \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface $repository + * @param \Illuminate\Auth\AuthManager $auth + * @param \Illuminate\Contracts\Config\Repository $config */ - public function __construct(ApiKeyRepositoryInterface $repository) - { + public function __construct( + ApiKeyRepositoryInterface $repository, + AuthManager $auth, + ConfigRepository $config + ) { + $this->auth = $auth; + $this->config = $config; $this->repository = $repository; } @@ -30,11 +52,23 @@ class AuthenticateKey * * @param \Illuminate\Http\Request $request * @param \Closure $next + * @return mixed */ public function handle(Request $request, Closure $next) { - $this->repository->findFirstWhere([ - '', - ]); + if (is_null($request->bearerToken())) { + throw new HttpException(401, null, null, ['WWW-Authenticate' => 'Bearer']); + } + + try { + $model = $this->repository->findFirstWhere([['token', '=', $request->bearerToken()]]); + } catch (RecordNotFoundException $exception) { + throw new AccessDeniedHttpException; + } + + $this->auth->guard()->loginUsingId($model->user_id); + $request->attributes->set('api_key', $model); + + return $next($request); } } diff --git a/app/Http/Middleware/API/SetSessionDriver.php b/app/Http/Middleware/API/SetSessionDriver.php new file mode 100644 index 000000000..9cc5d60e3 --- /dev/null +++ b/app/Http/Middleware/API/SetSessionDriver.php @@ -0,0 +1,52 @@ +app = $app; + $this->config = $config; + } + + /** + * Set the session for API calls to only last for the one request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle(Request $request, Closure $next) + { + if ($this->app->environment() !== 'production') { + $this->app->make(LaravelDebugbar::class)->disable(); + } + + $this->config->set('session.driver', 'array'); + + return $next($request); + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 57ae43fad..4d8f9b2b6 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -29,13 +29,9 @@ class RouteServiceProvider extends ServiceProvider */ public function map() { - Route::middleware(['api'])->prefix('/api/user') - ->namespace($this->namespace . '\API\User') - ->group(base_path('routes/api.php')); - - Route::middleware(['api'])->prefix('/api/admin') - ->namespace($this->namespace . '\API\Admin') - ->group(base_path('routes/api-admin.php')); +// Route::middleware(['api'])->prefix('/api/user') +// ->namespace($this->namespace . '\API\User') +// ->group(base_path('routes/api.php')); Route::middleware(['web', 'auth', 'csrf']) ->namespace($this->namespace . '\Base') @@ -53,6 +49,10 @@ class RouteServiceProvider extends ServiceProvider ->namespace($this->namespace . '\Server') ->group(base_path('routes/server.php')); + Route::middleware(['api'])->prefix('/api/admin') + ->namespace($this->namespace . '\API\Admin') + ->group(base_path('routes/api-admin.php')); + Route::middleware(['daemon'])->prefix('/api/remote') ->namespace($this->namespace . '\API\Remote') ->group(base_path('routes/api-remote.php'));