Completed
Push — master ( 7980e3...37c07d )
by Simon
11:26
created

JWTAuthenticator::authenticate()   D

Complexity

Conditions 9
Paths 64

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 4.909
c 0
b 0
f 0
cc 9
eloc 20
nc 64
nop 3
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)) {
0 ignored issues
show
Deprecated Code introduced by
The method Lcobucci\JWT\Token::verify() has been deprecated with message: This method will be removed on v4, new validation API should be used

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.

Loading history...
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')) {
0 ignored issues
show
Deprecated Code introduced by
The method Lcobucci\JWT\Token::getClaim() has been deprecated with message: This method will be removed on v4

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.

Loading history...
61
            /** @var Member $member */
62
            $member = Member::get()
63
                ->filter(['JWTUniqueID' => $parsedToken->getClaim('jti')])
0 ignored issues
show
Deprecated Code introduced by
The method Lcobucci\JWT\Token::getClaim() has been deprecated with message: This method will be removed on v4

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.

Loading history...
64
                ->byID($parsedToken->getClaim('uid'));
0 ignored issues
show
Deprecated Code introduced by
The method Lcobucci\JWT\Token::getClaim() has been deprecated with message: This method will be removed on v4

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.

Loading history...
65
        }
66
        if ($parsedToken->getClaim('uid') === 0 && $this->config()->get('anonymous_allowed')) {
0 ignored issues
show
Deprecated Code introduced by
The method Lcobucci\JWT\Token::getClaim() has been deprecated with message: This method will be removed on v4

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.

Loading history...
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
0 ignored issues
show
Deprecated Code introduced by
The method Lcobucci\JWT\Builder::setIssuer() has been deprecated with message: This method will be removed on v4, use issuedBy() instead

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.

Loading history...
Deprecated Code introduced by
The method Lcobucci\JWT\Builder::setAudience() has been deprecated with message: This method will be removed on v4, use canOnlyBeUsedBy() instead

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.

Loading history...
91
            // Configures the issuer (iss claim)
92
            ->setIssuer(Director::absoluteBaseURL())
0 ignored issues
show
Security Bug introduced by
It seems like \SilverStripe\Control\Director::absoluteBaseURL() targeting SilverStripe\Control\Director::absoluteBaseURL() can also be of type false; however, Lcobucci\JWT\Builder::setIssuer() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
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