1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Firesphere\GraphQLJWT; |
4
|
|
|
|
5
|
|
|
use BadMethodCallException; |
6
|
|
|
use Lcobucci\JWT\Builder; |
7
|
|
|
use Lcobucci\JWT\Parser; |
8
|
|
|
use Lcobucci\JWT\Signer\Hmac\Sha256; |
9
|
|
|
use Lcobucci\JWT\Token; |
10
|
|
|
use SilverStripe\Control\Director; |
11
|
|
|
use SilverStripe\Control\HTTPRequest; |
12
|
|
|
use SilverStripe\Core\Config\Configurable; |
13
|
|
|
use SilverStripe\GraphQL\Controller; |
14
|
|
|
use SilverStripe\ORM\ValidationException; |
15
|
|
|
use SilverStripe\ORM\ValidationResult; |
16
|
|
|
use SilverStripe\Security\Authenticator; |
17
|
|
|
use SilverStripe\Security\Member; |
18
|
|
|
use SilverStripe\Security\MemberAuthenticator\MemberAuthenticator; |
19
|
|
|
|
20
|
|
|
class JWTAuthenticator extends MemberAuthenticator |
21
|
|
|
{ |
22
|
|
|
use Configurable; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* JWT is stateless, therefore, we don't support anything but login |
26
|
|
|
* |
27
|
|
|
* @return int |
28
|
|
|
*/ |
29
|
|
|
public function supportedServices() |
30
|
|
|
{ |
31
|
|
|
return Authenticator::LOGIN | Authenticator::CMS_LOGIN; |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @param array $data |
36
|
|
|
* @param HTTPRequest $request |
37
|
|
|
* @param ValidationResult|null $result |
38
|
|
|
* @return Member|null |
39
|
|
|
* @throws BadMethodCallException |
40
|
|
|
* @throws \OutOfBoundsException |
41
|
|
|
*/ |
42
|
|
|
public function authenticate(array $data, HTTPRequest $request, ValidationResult &$result = null) |
43
|
|
|
{ |
44
|
|
|
if (!$result) { |
45
|
|
|
$result = new ValidationResult(); |
46
|
|
|
} |
47
|
|
|
$token = $data['token']; |
48
|
|
|
$parser = new Parser(); |
49
|
|
|
$parsedToken = $parser->parse((string)$token); |
50
|
|
|
$signer = new Sha256(); |
51
|
|
|
$signerKey = static::config()->get('signer_key'); |
52
|
|
|
$member = null; |
53
|
|
|
|
54
|
|
|
if (!$parsedToken->verify($signer, $signerKey)) { |
|
|
|
|
55
|
|
|
$result->addError('Invalid token'); |
56
|
|
|
} |
57
|
|
|
if ($parsedToken->isExpired()) { |
58
|
|
|
$result->addError('Token is expired, please renew your token with a refreshToken query'); |
59
|
|
|
} |
60
|
|
|
if ($parsedToken->getClaim('uid') > 0 && $parsedToken->getClaim('jti')) { |
|
|
|
|
61
|
|
|
/** @var Member $member */ |
62
|
|
|
$member = Member::get() |
63
|
|
|
->filter(['JWTUniqueID' => $parsedToken->getClaim('jti')]) |
|
|
|
|
64
|
|
|
->byID($parsedToken->getClaim('uid')); |
|
|
|
|
65
|
|
|
} |
66
|
|
|
if ($parsedToken->getClaim('uid') === 0 && $this->config()->get('anonymous_allowed')) { |
|
|
|
|
67
|
|
|
$member = Member::create(['ID' => 0, 'FirstName' => 'Anonymous']); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
return $result->isValid() ? $member : null; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @param Member $member |
75
|
|
|
* @return Token |
76
|
|
|
* @throws ValidationException |
77
|
|
|
* @throws BadMethodCallException |
78
|
|
|
*/ |
79
|
|
|
public function generateToken(Member $member) |
80
|
|
|
{ |
81
|
|
|
$config = static::config(); |
82
|
|
|
$signer = new Sha256(); |
83
|
|
|
$uniqueID = uniqid($config->get('prefix'), true); |
84
|
|
|
|
85
|
|
|
$request = Controller::curr()->getRequest(); |
86
|
|
|
$audience = $request->getHeader('Origin'); |
87
|
|
|
$signerKey = $config->get('signer_key'); |
88
|
|
|
|
89
|
|
|
$builder = new Builder(); |
90
|
|
|
$token = $builder |
|
|
|
|
91
|
|
|
// Configures the issuer (iss claim) |
92
|
|
|
->setIssuer(Director::absoluteBaseURL()) |
|
|
|
|
93
|
|
|
// Configures the audience (aud claim) |
94
|
|
|
->setAudience($audience) |
95
|
|
|
// Configures the id (jti claim), replicating as a header item |
96
|
|
|
->setId($uniqueID, true) |
97
|
|
|
// Configures the time that the token was issue (iat claim) |
98
|
|
|
->setIssuedAt(time()) |
99
|
|
|
// Configures the time that the token can be used (nbf claim) |
100
|
|
|
->setNotBefore(time() + $config->get('nbf_time')) |
101
|
|
|
// Configures the expiration time of the token (nbf claim) |
102
|
|
|
->setExpiration(time() + $config->get('nbf_expiration')) |
103
|
|
|
// Configures a new claim, called "uid" |
104
|
|
|
->set('uid', $member->ID) |
105
|
|
|
// Sign the key with the Signer's key @todo: support certificates |
106
|
|
|
->sign($signer, $signerKey); |
107
|
|
|
|
108
|
|
|
// Save the member if it's not anonymous |
109
|
|
|
if($member->ID > 0) { |
110
|
|
|
$member->JWTUniqueID = $uniqueID; |
111
|
|
|
$member->write(); |
112
|
|
|
} |
113
|
|
|
// Return the token |
114
|
|
|
return $token->getToken(); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.