Completed
Push — develop ( a2c65d...283ac2 )
by Kristijan
13s
created

Redis::setJti()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 1
nc 1
nop 5
1
<?php
2
3
namespace OAuth2\Storage;
4
5
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
6
7
/**
8
 * redis storage for all storage types
9
 *
10
 * To use, install "predis/predis" via composer
11
 *
12
 * Register client:
13
 * <code>
14
 *  $storage = new OAuth2\Storage\Redis($redis);
15
 *  $storage->setClientDetails($client_id, $client_secret, $redirect_uri);
16
 * </code>
17
 */
18
class Redis implements AuthorizationCodeInterface,
19
    AccessTokenInterface,
20
    ClientCredentialsInterface,
21
    UserCredentialsInterface,
22
    RefreshTokenInterface,
23
    JwtBearerInterface,
24
    ScopeInterface,
25
    OpenIDAuthorizationCodeInterface
26
{
27
28
    private $cache;
29
30
    /* The redis client */
31
    protected $redis;
32
33
    /* Configuration array */
34
    protected $config;
35
36
    /**
37
     * Redis Storage!
38
     *
39
     * @param \Predis\Client $redis
0 ignored issues
show
Bug introduced by
The type Predis\Client was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
40
     * @param array          $config
41
     */
42
    public function __construct($redis, $config=array())
43
    {
44
        $this->redis = $redis;
45
        $this->config = array_merge(array(
46
            'client_key' => 'oauth_clients:',
47
            'access_token_key' => 'oauth_access_tokens:',
48
            'refresh_token_key' => 'oauth_refresh_tokens:',
49
            'code_key' => 'oauth_authorization_codes:',
50
            'user_key' => 'oauth_users:',
51
            'jwt_key' => 'oauth_jwt:',
52
            'scope_key' => 'oauth_scopes:',
53
        ), $config);
54
    }
55
56
    protected function getValue($key)
57
    {
58
        if ( isset($this->cache[$key]) ) {
59
            return $this->cache[$key];
60
        }
61
        $value = $this->redis->get($key);
62
        if ( isset($value) ) {
63
            return json_decode($value, true);
64
        } else {
65
            return false;
66
        }
67
    }
68
69
    protected function setValue($key, $value, $expire=0)
70
    {
71
        $this->cache[$key] = $value;
72
        $str = json_encode($value);
73
        if ($expire > 0) {
74
            $seconds = $expire - time();
75
            $ret = $this->redis->setex($key, $seconds, $str);
76
        } else {
77
            $ret = $this->redis->set($key, $str);
78
        }
79
80
        // check that the key was set properly
81
        // if this fails, an exception will usually thrown, so this step isn't strictly necessary
82
        return is_bool($ret) ? $ret : $ret->getPayload() == 'OK';
83
    }
84
85
    protected function expireValue($key)
86
    {
87
        unset($this->cache[$key]);
88
89
        return $this->redis->del($key);
90
    }
91
92
    /* AuthorizationCodeInterface */
93
    public function getAuthorizationCode($code)
94
    {
95
        return $this->getValue($this->config['code_key'] . $code);
96
    }
97
98
    public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
99
    {
100
        return $this->setValue(
101
            $this->config['code_key'] . $authorization_code,
102
            compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
103
            $expires
104
        );
105
    }
106
107
    public function expireAuthorizationCode($code)
108
    {
109
        $key = $this->config['code_key'] . $code;
110
        unset($this->cache[$key]);
111
112
        return $this->expireValue($key);
113
    }
114
115
    /* UserCredentialsInterface */
116
    public function checkUserCredentials($username, $password)
117
    {
118
        $user = $this->getUserDetails($username);
119
120
        return $user && $user['password'] === $password;
121
    }
122
123
    public function getUserDetails($username)
124
    {
125
        return $this->getUser($username);
126
    }
127
128
    public function getUser($username)
129
    {
130
        if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) {
131
            return false;
132
        }
133
134
        // the default behavior is to use "username" as the user_id
135
        return array_merge(array(
136
            'user_id' => $username,
137
        ), $userInfo);
138
    }
139
140
    public function setUser($username, $password, $first_name = null, $last_name = null)
141
    {
142
        return $this->setValue(
143
            $this->config['user_key'] . $username,
144
            compact('username', 'password', 'first_name', 'last_name')
145
        );
146
    }
147
148
    /* ClientCredentialsInterface */
149
    public function checkClientCredentials($client_id, $client_secret = null)
150
    {
151
        if (!$client = $this->getClientDetails($client_id)) {
152
            return false;
153
        }
154
155
        return isset($client['client_secret'])
156
            && $client['client_secret'] == $client_secret;
157
    }
158
159
    public function isPublicClient($client_id)
160
    {
161
        if (!$client = $this->getClientDetails($client_id)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $client is dead and can be removed.
Loading history...
162
            return false;
163
        }
164
165
        return empty($result['client_secret']);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result seems to never exist and therefore empty should always be true.
Loading history...
166
    }
167
168
    /* ClientInterface */
169
    public function getClientDetails($client_id)
170
    {
171
        return $this->getValue($this->config['client_key'] . $client_id);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getValue($...ent_key'] . $client_id) also could return the type false which is incompatible with the return type mandated by OAuth2\Storage\ClientInterface::getClientDetails() of array.
Loading history...
172
    }
173
174
    public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
175
    {
176
        return $this->setValue(
177
            $this->config['client_key'] . $client_id,
178
            compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id')
179
        );
180
    }
181
182
    public function checkRestrictedGrantType($client_id, $grant_type)
183
    {
184
        $details = $this->getClientDetails($client_id);
185
        if (isset($details['grant_types'])) {
186
            $grant_types = explode(' ', $details['grant_types']);
187
188
            return in_array($grant_type, (array) $grant_types);
189
        }
190
191
        // if grant_types are not defined, then none are restricted
192
        return true;
193
    }
194
195
    /* RefreshTokenInterface */
196
    public function getRefreshToken($refresh_token)
197
    {
198
        return $this->getValue($this->config['refresh_token_key'] . $refresh_token);
199
    }
200
201
    public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
202
    {
203
        return $this->setValue(
204
            $this->config['refresh_token_key'] . $refresh_token,
205
            compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'),
206
            $expires
207
        );
208
    }
209
210
    public function unsetRefreshToken($refresh_token)
211
    {
212
        return $this->expireValue($this->config['refresh_token_key'] . $refresh_token);
213
    }
214
215
    /* AccessTokenInterface */
216
    public function getAccessToken($access_token)
217
    {
218
        return $this->getValue($this->config['access_token_key'].$access_token);
219
    }
220
221
    public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
222
    {
223
        return $this->setValue(
224
            $this->config['access_token_key'].$access_token,
225
            compact('access_token', 'client_id', 'user_id', 'expires', 'scope'),
226
            $expires
227
        );
228
    }
229
230
    public function unsetAccessToken($access_token)
231
    {
232
        return $this->expireValue($this->config['access_token_key'] . $access_token);
233
    }
234
235
    /* ScopeInterface */
236
    public function scopeExists($scope)
237
    {
238
        $scope = explode(' ', $scope);
239
240
        $result = $this->getValue($this->config['scope_key'].'supported:global');
241
242
        $supportedScope = explode(' ', (string) $result);
243
244
        return (count(array_diff($scope, $supportedScope)) == 0);
245
    }
246
247
    public function getDefaultScope($client_id = null)
248
    {
249
        if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) {
250
            $result = $this->getValue($this->config['scope_key'].'default:global');
251
        }
252
253
        return $result;
254
    }
255
256
    public function setScope($scope, $client_id = null, $type = 'supported')
257
    {
258
        if (!in_array($type, array('default', 'supported'))) {
259
            throw new \InvalidArgumentException('"$type" must be one of "default", "supported"');
260
        }
261
262
        if (is_null($client_id)) {
263
            $key = $this->config['scope_key'].$type.':global';
264
        } else {
265
            $key = $this->config['scope_key'].$type.':'.$client_id;
266
        }
267
268
        return $this->setValue($key, $scope);
269
    }
270
271
    /*JWTBearerInterface */
272
    public function getClientKey($client_id, $subject)
273
    {
274
        if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) {
275
            return false;
276
        }
277
278
        if (isset($jwt['subject']) && $jwt['subject'] == $subject) {
279
            return $jwt['key'];
280
        }
281
282
        return null;
283
    }
284
285
    public function setClientKey($client_id, $key, $subject = null)
286
    {
287
        return $this->setValue($this->config['jwt_key'] . $client_id, array(
288
            'key' => $key,
289
            'subject' => $subject
290
        ));
291
    }
292
293
    public function getClientScope($client_id)
294
    {
295
        if (!$clientDetails = $this->getClientDetails($client_id)) {
296
            return false;
297
        }
298
299
        if (isset($clientDetails['scope'])) {
300
            return $clientDetails['scope'];
301
        }
302
303
        return null;
304
    }
305
306
    public function getJti($client_id, $subject, $audience, $expiration, $jti)
307
    {
308
        //TODO: Needs redis implementation.
309
        throw new \Exception('getJti() for the Redis driver is currently unimplemented.');
310
    }
311
312
    public function setJti($client_id, $subject, $audience, $expiration, $jti)
313
    {
314
        //TODO: Needs redis implementation.
315
        throw new \Exception('setJti() for the Redis driver is currently unimplemented.');
316
    }
317
}
318