1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Cortex\Auth\Http\Controllers\Frontarea; |
6
|
|
|
|
7
|
|
|
use Illuminate\Http\Request; |
8
|
|
|
use Illuminate\Validation\ValidationException; |
9
|
|
|
use Illuminate\Foundation\Auth\ThrottlesLogins; |
10
|
|
|
use Cortex\Foundation\Http\Controllers\AbstractController; |
11
|
|
|
use Cortex\Auth\Http\Requests\Frontarea\AuthenticationRequest; |
12
|
|
|
|
13
|
|
|
class AuthenticationController extends AbstractController |
14
|
|
|
{ |
15
|
|
|
use ThrottlesLogins; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* {@inheritdoc} |
19
|
|
|
*/ |
20
|
|
|
protected $middlewareWhitelist = [ |
21
|
|
|
'logout', |
22
|
|
|
]; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Create a new authentication controller instance. |
26
|
|
|
*/ |
27
|
|
|
public function __construct() |
28
|
|
|
{ |
29
|
|
|
parent::__construct(); |
30
|
|
|
|
31
|
|
|
$this->middleware($this->getGuestMiddleware())->except($this->middlewareWhitelist); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Show the login form. |
36
|
|
|
* |
37
|
|
|
* @return \Illuminate\View\View |
38
|
|
|
*/ |
39
|
|
|
public function form() |
40
|
|
|
{ |
41
|
|
|
// Remember previous URL for later redirect back |
42
|
|
|
session()->put('url.intended', url()->previous()); |
43
|
|
|
|
44
|
|
|
return view('cortex/auth::frontarea.pages.authentication'); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Process to the login form. |
49
|
|
|
* |
50
|
|
|
* @param \Cortex\Auth\Http\Requests\Frontarea\AuthenticationRequest $request |
51
|
|
|
* |
52
|
|
|
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse |
53
|
|
|
*/ |
54
|
|
|
public function login(AuthenticationRequest $request) |
55
|
|
|
{ |
56
|
|
|
// Prepare variables |
57
|
|
|
$loginField = get_login_field($request->input($this->username())); |
|
|
|
|
58
|
|
|
$credentials = [ |
59
|
|
|
'is_active' => true, |
60
|
|
|
$loginField => $request->input('loginfield'), |
61
|
|
|
'password' => $request->input('password'), |
62
|
|
|
]; |
63
|
|
|
|
64
|
|
|
// If the class is using the ThrottlesLogins trait, we can automatically throttle |
65
|
|
|
// the login attempts for this application. We'll key this by the username and |
66
|
|
|
// the IP address of the client making these requests into this application. |
67
|
|
|
if ($this->hasTooManyLoginAttempts($request)) { |
68
|
|
|
$this->fireLockoutEvent($request); |
69
|
|
|
|
70
|
|
|
return $this->sendLockoutResponse($request); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
if (auth()->guard($this->getGuard())->attempt($credentials, $request->filled('remember'))) { |
|
|
|
|
74
|
|
|
return $this->sendLoginResponse($request); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
// If the login attempt was unsuccessful we will increment the number of attempts |
78
|
|
|
// to login and redirect the user back to the login form. Of course, when this |
79
|
|
|
// user surpasses their maximum number of attempts they will get locked out. |
80
|
|
|
$this->incrementLoginAttempts($request); |
81
|
|
|
|
82
|
|
|
return $this->sendFailedLoginResponse($request); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Logout currently logged in user. |
87
|
|
|
* |
88
|
|
|
* @param \Illuminate\Http\Request $request |
89
|
|
|
* |
90
|
|
|
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse |
91
|
|
|
*/ |
92
|
|
|
public function logout(Request $request) |
93
|
|
|
{ |
94
|
|
|
$this->processLogout($request); |
95
|
|
|
|
96
|
|
|
return intend([ |
97
|
|
|
'url' => route('frontarea.home'), |
98
|
|
|
'with' => ['warning' => trans('cortex/auth::messages.auth.logout')], |
99
|
|
|
]); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Send the response after the user was authenticated. |
104
|
|
|
* |
105
|
|
|
* @param \Illuminate\Http\Request $request |
106
|
|
|
* |
107
|
|
|
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse |
108
|
|
|
*/ |
109
|
|
|
protected function sendLoginResponse(Request $request) |
110
|
|
|
{ |
111
|
|
|
$user = auth()->guard($this->getGuard())->user(); |
|
|
|
|
112
|
|
|
|
113
|
|
|
$twofactor = $user->getTwoFactor(); |
114
|
|
|
$totpStatus = $twofactor['totp']['enabled'] ?? false; |
115
|
|
|
$phoneStatus = $twofactor['phone']['enabled'] ?? false; |
116
|
|
|
|
117
|
|
|
$request->session()->regenerate(); |
|
|
|
|
118
|
|
|
$this->clearLoginAttempts($request); |
119
|
|
|
|
120
|
|
|
// Enforce TwoFactor authentication |
121
|
|
|
if ($totpStatus || $phoneStatus) { |
122
|
|
|
$this->processLogout($request); |
123
|
|
|
|
124
|
|
|
$request->session()->put('cortex.auth.twofactor', ['user_id' => $user->getKey(), 'remember' => $request->filled('remember'), 'totp' => $totpStatus, 'phone' => $phoneStatus]); |
|
|
|
|
125
|
|
|
|
126
|
|
|
$route = $totpStatus |
127
|
|
|
? route('frontarea.verification.phone.verify') |
128
|
|
|
: route('frontarea.verification.phone.request'); |
129
|
|
|
|
130
|
|
|
return intend([ |
131
|
|
|
'url' => $route, |
132
|
|
|
'with' => ['warning' => trans('cortex/auth::messages.verification.twofactor.totp.required')], |
133
|
|
|
]); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
return intend([ |
137
|
|
|
'intended' => route('frontarea.home'), |
138
|
|
|
'with' => ['success' => trans('cortex/auth::messages.auth.login')], |
139
|
|
|
]); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Get the failed login response instance. |
144
|
|
|
* |
145
|
|
|
* @param \Illuminate\Http\Request $request |
146
|
|
|
* |
147
|
|
|
* @throws ValidationException |
148
|
|
|
* |
149
|
|
|
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse |
150
|
|
|
*/ |
151
|
|
|
protected function sendFailedLoginResponse(Request $request) |
|
|
|
|
152
|
|
|
{ |
153
|
|
|
throw ValidationException::withMessages([ |
154
|
|
|
$this->username() => [trans('cortex/auth::messages.auth.failed')], |
155
|
|
|
]); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Redirect the user after determining they are locked out. |
160
|
|
|
* |
161
|
|
|
* @param \Illuminate\Http\Request $request |
162
|
|
|
* |
163
|
|
|
* @throws \Illuminate\Validation\ValidationException |
164
|
|
|
* |
165
|
|
|
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse |
166
|
|
|
*/ |
167
|
|
|
protected function sendLockoutResponse(Request $request) |
168
|
|
|
{ |
169
|
|
|
$seconds = $this->limiter()->availableIn( |
170
|
|
|
$this->throttleKey($request) |
171
|
|
|
); |
172
|
|
|
|
173
|
|
|
throw ValidationException::withMessages([ |
174
|
|
|
$this->username() => [trans('cortex/auth::messages.auth.lockout', ['seconds' => $seconds])], |
175
|
|
|
])->status(423); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Process logout. |
180
|
|
|
* |
181
|
|
|
* @param \Illuminate\Http\Request $request |
182
|
|
|
* |
183
|
|
|
* @return void |
184
|
|
|
*/ |
185
|
|
|
protected function processLogout(Request $request): void |
186
|
|
|
{ |
187
|
|
|
auth()->guard($this->getGuard())->logout(); |
|
|
|
|
188
|
|
|
|
189
|
|
|
$request->session()->invalidate(); |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* Get the login username to be used by the controller. |
194
|
|
|
* |
195
|
|
|
* @return string |
196
|
|
|
*/ |
197
|
|
|
protected function username() |
198
|
|
|
{ |
199
|
|
|
return 'loginfield'; |
200
|
|
|
} |
201
|
|
|
} |
202
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.