-
Notifications
You must be signed in to change notification settings - Fork 26
/
SsoProvider.php
94 lines (72 loc) · 2.33 KB
/
SsoProvider.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
namespace Waterhole\Auth;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Laravel\Socialite\Contracts\Provider;
use Waterhole\Sso\Payload;
use Waterhole\Sso\WaterholeSso;
final class SsoProvider implements Provider
{
private ?SsoUser $user = null;
public function __construct(
private readonly Request $request,
private readonly string $url,
private readonly WaterholeSso $sso,
) {
}
public function redirect(): RedirectResponse
{
$this->storeNonce($nonce = $this->generateNonce());
$query = $this->sso->buildQuery($nonce, [
Payload::RETURN_URL => route('waterhole.sso.callback', ['provider' => 'sso']),
]);
return redirect($this->url . (str_contains($this->url, '?') ? '&' : '?') . $query);
}
public function user(): SsoUser
{
if ($this->user) {
return $this->user;
}
$payload = $this->request->query('payload');
$sig = $this->request->query('sig');
if (!$this->sso->validate($payload, $sig)) {
abort(400, 'Invalid signature');
}
$payload = $this->sso->parse($payload);
if (!$this->validateNonce($payload->getNonce())) {
abort(400, 'Invalid nonce');
}
$this->expireNonce();
if (!$this->validatePayload($payload)) {
abort(400, 'Invalid payload');
}
return $this->user = new SsoUser($payload);
}
private function generateNonce(): string
{
return Str::random();
}
private function storeNonce(string $nonce): void
{
$this->request->session()->put('sso_nonce', [
'nonce' => $nonce,
'expiry' => time() + 10 * 60,
]);
}
private function validateNonce(string $nonce): bool
{
$data = $this->request->session()->get('sso_nonce');
$storedNonce = $data['nonce'] ?? null;
$expiry = $data['expiry'] ?? null;
return $storedNonce === $nonce && time() < $expiry;
}
private function expireNonce(): void
{
$this->request->session()->forget('sso_nonce');
}
private function validatePayload(Payload $payload): bool
{
return $payload->get('identifier') && $payload->get('email') && $payload->get('name');
}
}