Passed
Pull Request — master (#32)
by
unknown
02:19
created

Resolver::resolveRefreshToken()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 21
c 1
b 0
f 0
dl 0
loc 32
rs 8.9617
cc 6
nc 10
nop 0
1
<?php
2
3
4
namespace Firesphere\GraphQLJWT\Resolvers;
5
6
7
use Firesphere\GraphQLJWT\Authentication\CustomAuthenticatorRegistry;
8
use Firesphere\GraphQLJWT\Authentication\JWTAuthenticator;
9
use Firesphere\GraphQLJWT\Extensions\MemberExtension;
10
use Firesphere\GraphQLJWT\Helpers\HeaderExtractor;
11
use Firesphere\GraphQLJWT\Helpers\MemberTokenGenerator;
12
use Firesphere\GraphQLJWT\Model\JWTRecord;
13
use GraphQL\Type\Definition\ResolveInfo;
14
use Psr\Container\NotFoundExceptionInterface;
15
use SilverStripe\Control\Controller;
16
use SilverStripe\Control\HTTPRequest;
17
use SilverStripe\Core\Injector\Injector;
18
use OutOfBoundsException;
19
use BadMethodCallException;
20
use Exception;
21
use SilverStripe\ORM\ValidationResult;
22
use SilverStripe\Security\Authenticator;
23
use SilverStripe\Security\Member;
24
use SilverStripe\Security\Security;
25
use Generator;
26
27
/**
28
 * @todo Enum types should allow mapping to these constants (see enums.yml, duplicate code)
29
 */
30
class Resolver
31
{
32
    use MemberTokenGenerator;
33
    use HeaderExtractor;
34
35
    /**
36
     * Valid token
37
     */
38
    const STATUS_OK = 'OK';
39
40
    /**
41
     * Not a valid token
42
     */
43
    const STATUS_INVALID = 'INVALID';
44
45
    /**
46
     * Expired but can be renewed
47
     */
48
    const STATUS_EXPIRED = 'EXPIRED';
49
50
    /**
51
     * Expired and cannot be renewed
52
     */
53
    const STATUS_DEAD = 'DEAD';
54
55
    /**
56
     * Provided user / password were incorrect
57
     */
58
    const STATUS_BAD_LOGIN = 'BAD_LOGIN';
59
60
61
    /**
62
     * @return mixed
63
     * @throws \Exception
64
     */
65
    public static function resolveValidateToken()
66
    {
67
        /** @var JWTAuthenticator $authenticator */
68
        $authenticator = Injector::inst()->get(JWTAuthenticator::class);
69
        $request = Controller::curr()->getRequest();
70
        $token = static::getAuthorizationHeader($request);
71
72
        /** @var JWTRecord $record */
73
        list($record, $status) = $authenticator->validateToken($token, $request);
74
        $member = $status === self::STATUS_OK ? $record->Member() : null;
75
        return static::generateResponse($status, $member, $token);
76
    }
77
78
    /**
79
     * @return array
80
     * @throws NotFoundExceptionInterface
81
     * @throws BadMethodCallException
82
     * @throws OutOfBoundsException
83
     * @throws Exception
84
     */
85
    public static function resolveRefreshToken(): array
86
    {
87
        $authenticator = Injector::inst()->get(JWTAuthenticator::class);
88
        $request = Controller::curr()->getRequest();
89
        $token = static::getAuthorizationHeader($request);
90
91
        // Check status of existing token
92
        /** @var JWTRecord $record */
93
        list($record, $status) = $authenticator->validateToken($token, $request);
94
        $member = null;
95
        switch ($status) {
96
            case self::STATUS_OK:
97
            case self::STATUS_EXPIRED:
98
                $member = $record->Member();
99
                $renewable = true;
100
                break;
101
            case self::STATUS_DEAD:
102
            case self::STATUS_INVALID:
103
            default:
104
                $member = null;
105
                $renewable = false;
106
                break;
107
        }
108
109
        // Check if renewable
110
        if (!$renewable) {
111
            return static::generateResponse($status);
112
        }
113
114
        // Create new token for member
115
        $newToken = $authenticator->generateToken($request, $member);
116
        return static::generateResponse(self::STATUS_OK, $member, $newToken->__toString());
117
    }
118
119
120
    /**
121
     * @param mixed $object
122
     * @param array $args
123
     * @return array
124
     * @throws NotFoundExceptionInterface
125
     */
126
    public static function resolveCreateToken($object, array $args): array
0 ignored issues
show
Unused Code introduced by
The parameter $object is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

126
    public static function resolveCreateToken(/** @scrutinizer ignore-unused */ $object, array $args): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
127
    {
128
        // Authenticate this member
129
        $request = Controller::curr()->getRequest();
130
        $member = static::getAuthenticatedMember($args, $request);
131
132
        // Handle unauthenticated
133
        if (!$member) {
134
            return static::generateResponse(self::STATUS_BAD_LOGIN);
135
        }
136
137
        // Create new token from this member
138
        $authenticator = Injector::inst()->get(JWTAuthenticator::class);
139
        $token = $authenticator->generateToken($request, $member);
140
        return static::generateResponse(self::STATUS_OK, $member, $token->__toString());
141
    }
142
143
    /**
144
     * Get any authenticator we should use for logging in users
145
     *
146
     * @return Authenticator[]|Generator
147
     */
148
    protected static function getLoginAuthenticators(): Generator
149
    {
150
        // Check injected authenticators
151
        yield from CustomAuthenticatorRegistry::singleton()->getCustomAuthenticators();
152
153
        // Get other login handlers from Security
154
        $security = Security::singleton();
155
        yield from $security->getApplicableAuthenticators(Authenticator::LOGIN);
156
    }
157
158
    /**
159
     * Get an authenticated member from the given request
160
     *
161
     * @param array $args
162
     * @param HTTPRequest $request
163
     * @return Member|MemberExtension
164
     */
165
    protected static function getAuthenticatedMember(array $args, HTTPRequest $request): ?Member
166
    {
167
        // Normalise the casing for the authenticator
168
        $data = [
169
            'Email' => $args['email'],
170
            'Password' => $args['password'] ?? null,
171
        ];
172
        // Login with authenticators
173
        foreach (static::getLoginAuthenticators() as $authenticator) {
174
            $result = ValidationResult::create();
175
            $member = $authenticator->authenticate($data, $request, $result);
176
            if ($member && $result->isValid()) {
177
                return $member;
178
            }
179
        }
180
181
        return null;
182
    }
183
184
}
185