BaseGrant::getClient()   B
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 17
nc 4
nop 0
dl 0
loc 29
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
namespace PHPHub\OAuth;
4
5
use League\OAuth2\Server\Entity\AccessTokenEntity;
6
use League\OAuth2\Server\Entity\ClientEntity;
7
use League\OAuth2\Server\Entity\RefreshTokenEntity;
8
use League\OAuth2\Server\Entity\SessionEntity;
9
use League\OAuth2\Server\Event\ClientAuthenticationFailedEvent;
10
use League\OAuth2\Server\Event\UserAuthenticationFailedEvent;
11
use League\OAuth2\Server\Exception\InvalidClientException;
12
use League\OAuth2\Server\Exception\InvalidCredentialsException;
13
use League\OAuth2\Server\Exception\InvalidRequestException;
14
use League\OAuth2\Server\Exception\ServerErrorException;
15
use League\OAuth2\Server\Grant\AbstractGrant;
16
use League\OAuth2\Server\Util\SecureKey;
17
use Symfony\Component\HttpFoundation\Request;
18
19
abstract class BaseGrant extends AbstractGrant
20
{
21
    /**
22
     * Grant identifier.
23
     *
24
     * @var string
25
     */
26
    protected $identifier = null;
27
28
    /**
29
     * Response type.
30
     *
31
     * @var string
32
     */
33
    protected $responseType;
34
35
    /**
36
     * Callback to authenticate a user's name and password.
37
     *
38
     * @var callable
39
     */
40
    protected $callback;
41
42
    /**
43
     * Access token expires in override.
44
     *
45
     * @var int
46
     */
47
    protected $accessTokenTTL;
48
49
    /**
50
     * Set the callback to verify a user's username and password.
51
     *
52
     * @param callable $callback The callback function
53
     */
54
    public function setVerifyCredentialsCallback(callable $callback)
55
    {
56
        $this->callback = $callback;
57
    }
58
59
    /**
60
     * Return the callback function.
61
     *
62
     * @return callable
63
     *
64
     * @throws
65
     */
66
    protected function getVerifyCredentialsCallback()
67
    {
68
        if (is_null($this->callback) || ! is_callable($this->callback)) {
69
            throw new ServerErrorException('Null or non-callable callback set on Password grant');
70
        }
71
72
        return $this->callback;
73
    }
74
75
    /**
76
     * Complete the password grant.
77
     *
78
     * @return array
79
     *
80
     * @throws
81
     */
82
    public function completeFlow()
83
    {
84
        $client = $this->getClient();
85
86
        $userId = $this->getUserId($this->server->getRequest(), $this->getVerifyCredentialsCallback());
87
88
        if ($userId === false) {
89
            $this->server->getEventEmitter()->emit(new UserAuthenticationFailedEvent($this->server->getRequest()));
90
            throw new InvalidCredentialsException();
91
        }
92
93
        // Create a new session
94
        $session = new SessionEntity($this->server);
95
        $session->setOwner('user', $userId);
96
        $session->associateClient($client);
97
98
        // Generate an access token
99
        $accessToken = new AccessTokenEntity($this->server);
100
        $accessToken->setId(SecureKey::generate());
101
        $accessToken->setExpireTime($this->getAccessTokenTTL() + time());
102
103
        $this->server->getTokenType()->setSession($session);
104
        $this->server->getTokenType()->setParam('access_token', $accessToken->getId());
105
        $this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL());
106
107
        // Save everything
108
        $session->save();
109
        $accessToken->setSession($session);
110
        $accessToken->save();
111
112
        // Associate a refresh token if set
113
        if ($this->server->hasGrantType('refresh_token')) {
114
            $refreshToken = new RefreshTokenEntity($this->server);
115
            $refreshToken->setId(SecureKey::generate());
116
            $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface League\OAuth2\Server\Grant\GrantTypeInterface as the method getRefreshTokenTTL() does only exist in the following implementations of said interface: League\OAuth2\Server\Grant\RefreshTokenGrant.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
117
            $this->server->getTokenType()->setParam('refresh_token', $refreshToken->getId());
118
119
            $refreshToken->setAccessToken($accessToken);
120
            $refreshToken->save();
121
        }
122
123
        return $this->server->getTokenType()->generateResponse();
124
    }
125
126
    /**
127
     * 根据请求的 client_id 和 client_secret 获取 ClientEntity.
128
     *
129
     * @throws InvalidClientException
130
     * @throws InvalidRequestException
131
     *
132
     * @return ClientEntity
133
     */
134
    protected function getClient()
135
    {
136
        // Get the required params
137
        $clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser());
138
        if (is_null($clientId)) {
139
            throw new InvalidRequestException('client_id');
140
        }
141
142
        $clientSecret = $this->server->getRequest()->request->get('client_secret',
143
            $this->server->getRequest()->getPassword());
144
        if (is_null($clientSecret)) {
145
            throw new InvalidRequestException('client_secret');
146
        }
147
148
        // Validate client ID and client secret
149
        $client = $this->server->getClientStorage()->get(
150
            $clientId,
151
            $clientSecret,
152
            null,
153
            $this->getIdentifier()
154
        );
155
156
        if (($client instanceof ClientEntity) === false) {
157
            $this->server->getEventEmitter()->emit(new ClientAuthenticationFailedEvent($this->server->getRequest()));
158
            throw new InvalidClientException();
159
        }
160
161
        return $client;
162
    }
163
164
    /**
165
     * 获取 UserId.
166
     *
167
     * @param $request
168
     * @param $verifier
169
     *
170
     * @return int
171
     */
172
    abstract public function getUserId(Request $request, $verifier);
173
}
174