Skip to content

Commit 72acf06

Browse files
committed
Improve API auth to rate limit requests and verify they are root_admin
1 parent 2def94c commit 72acf06

File tree

1 file changed

+70
-10
lines changed

1 file changed

+70
-10
lines changed

app/Http/Controllers/API/AuthController.php

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@
33
namespace Pterodactyl\Http\Controllers\API;
44

55
use JWTAuth;
6+
use Hash;
7+
use Validator;
8+
69
use Tymon\JWTAuth\Exceptions\JWTException;
710

11+
use Dingo\Api\Exception\StoreResourceFailedException;
12+
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
13+
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
14+
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
15+
816
use Illuminate\Http\Request;
9-
use \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
10-
use \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
17+
use Illuminate\Foundation\Auth\ThrottlesLogins;
18+
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
1119

1220
use Pterodactyl\Transformers\UserTransformer;
1321
use Pterodactyl\Models;
@@ -18,6 +26,32 @@
1826
class AuthController extends BaseController
1927
{
2028

29+
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
30+
31+
/**
32+
* Lockout time for failed login requests.
33+
*
34+
* @var integer
35+
*/
36+
protected $lockoutTime = 120;
37+
38+
/**
39+
* After how many attempts should logins be throttled and locked.
40+
*
41+
* @var integer
42+
*/
43+
protected $maxLoginAttempts = 3;
44+
45+
/**
46+
* Create a new authentication controller instance.
47+
*
48+
* @return void
49+
*/
50+
public function __construct()
51+
{
52+
//
53+
}
54+
2155
/**
2256
* Authenticate
2357
*
@@ -29,16 +63,42 @@ class AuthController extends BaseController
2963
* @Response(200, body={"token": "<jwt-token>"})
3064
*/
3165
public function postLogin(Request $request) {
32-
$credentials = $request->only('email', 'password');
66+
67+
$validator = Validator::make($request->only(['email', 'password']), [
68+
'email' => 'required|email',
69+
'password' => 'required|min:8'
70+
]);
71+
72+
if ($validator->fails()) {
73+
throw new StoreResourceFailedException('Required authentication fields were invalid.', $validator->errors());
74+
}
75+
76+
$throttled = $this->isUsingThrottlesLoginsTrait();
77+
if ($throttled && $this->hasTooManyLoginAttempts($request)) {
78+
throw new TooManyRequestsHttpException('You have been login throttled for 120 seconds.');
79+
}
80+
81+
// Is the email & password valid?
82+
$user = Models\User::where('email', $request->input('email'))->first();
83+
if (!$user || !Hash::check($request->input('password'), $user->password)) {
84+
if ($throttled) {
85+
$this->incrementLoginAttempts($request);
86+
}
87+
throw new UnauthorizedHttpException('A user by those credentials was not found.');
88+
}
89+
90+
// @TODO: validate TOTP if enabled on account?
91+
// Perhaps this could be implemented in such a way that they login to their
92+
// account and generate a one time password that can be used? Would be a pain in
93+
// the butt for multiple API requests though. Maybe just included a 'totp' field
94+
// that can include the token for that timestamp. Would allow for programtic
95+
// generation of the code and API requests.
96+
if ($user->root_admin !== 1) {
97+
throw new UnauthorizedHttpException('This account does not have permission to interface this API.');
98+
}
3399

34100
try {
35-
$token = JWTAuth::attempt($credentials, [
36-
'permissions' => [
37-
'view_users' => true,
38-
'edit_users' => true,
39-
'delete_users' => false,
40-
]
41-
]);
101+
$token = JWTAuth::fromUser($user);
42102
if (!$token) {
43103
throw new UnauthorizedHttpException('');
44104
}

0 commit comments

Comments
 (0)