From 72acf063538f3b383107f8c224f8c81970057529 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 12 Jan 2016 22:59:24 -0500 Subject: [PATCH] Improve API auth to rate limit requests and verify they are root_admin --- app/Http/Controllers/API/AuthController.php | 80 ++++++++++++++++++--- 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/API/AuthController.php b/app/Http/Controllers/API/AuthController.php index 6f95aa6c8..638a0afda 100644 --- a/app/Http/Controllers/API/AuthController.php +++ b/app/Http/Controllers/API/AuthController.php @@ -3,11 +3,19 @@ namespace Pterodactyl\Http\Controllers\API; use JWTAuth; +use Hash; +use Validator; + use Tymon\JWTAuth\Exceptions\JWTException; +use Dingo\Api\Exception\StoreResourceFailedException; +use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; +use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; +use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; + use Illuminate\Http\Request; -use \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; -use \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; +use Illuminate\Foundation\Auth\ThrottlesLogins; +use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers; use Pterodactyl\Transformers\UserTransformer; use Pterodactyl\Models; @@ -18,6 +26,32 @@ use Pterodactyl\Models; class AuthController extends BaseController { + use AuthenticatesAndRegistersUsers, ThrottlesLogins; + + /** + * Lockout time for failed login requests. + * + * @var integer + */ + protected $lockoutTime = 120; + + /** + * After how many attempts should logins be throttled and locked. + * + * @var integer + */ + protected $maxLoginAttempts = 3; + + /** + * Create a new authentication controller instance. + * + * @return void + */ + public function __construct() + { + // + } + /** * Authenticate * @@ -29,16 +63,42 @@ class AuthController extends BaseController * @Response(200, body={"token": ""}) */ public function postLogin(Request $request) { - $credentials = $request->only('email', 'password'); + + $validator = Validator::make($request->only(['email', 'password']), [ + 'email' => 'required|email', + 'password' => 'required|min:8' + ]); + + if ($validator->fails()) { + throw new StoreResourceFailedException('Required authentication fields were invalid.', $validator->errors()); + } + + $throttled = $this->isUsingThrottlesLoginsTrait(); + if ($throttled && $this->hasTooManyLoginAttempts($request)) { + throw new TooManyRequestsHttpException('You have been login throttled for 120 seconds.'); + } + + // Is the email & password valid? + $user = Models\User::where('email', $request->input('email'))->first(); + if (!$user || !Hash::check($request->input('password'), $user->password)) { + if ($throttled) { + $this->incrementLoginAttempts($request); + } + throw new UnauthorizedHttpException('A user by those credentials was not found.'); + } + + // @TODO: validate TOTP if enabled on account? + // Perhaps this could be implemented in such a way that they login to their + // account and generate a one time password that can be used? Would be a pain in + // the butt for multiple API requests though. Maybe just included a 'totp' field + // that can include the token for that timestamp. Would allow for programtic + // generation of the code and API requests. + if ($user->root_admin !== 1) { + throw new UnauthorizedHttpException('This account does not have permission to interface this API.'); + } try { - $token = JWTAuth::attempt($credentials, [ - 'permissions' => [ - 'view_users' => true, - 'edit_users' => true, - 'delete_users' => false, - ] - ]); + $token = JWTAuth::fromUser($user); if (!$token) { throw new UnauthorizedHttpException(''); }