Module   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 261
Duplicated Lines 0 %

Test Coverage

Coverage 60.94%

Importance

Changes 0
Metric Value
eloc 96
dl 0
loc 261
ccs 39
cts 64
cp 0.6094
rs 10
c 0
b 0
f 0
wmc 20

11 Methods

Rating   Name   Duplication   Size   Complexity  
A bootstrap() 0 9 2
A urlRules() 0 14 1
A getRequest() 0 3 1
A getResponse() 0 3 1
A validateAuthorizeRequest() 0 5 1
A handleAuthorizeRequest() 0 12 1
A getServer() 0 3 1
A registerTranslations() 0 9 1
A t() 0 11 1
B initOauth2Server() 0 51 8
A beforeAction() 0 8 2
1
<?php
2
3
namespace roaresearch\yii2\oauth2server;
4
5
use OAuth2\{Request, Response};
6
use ReflectionClass;
7
use Yii;
8
use yii\{
9
    base\BootstrapInterface,
10
    base\InvalidConfigException,
11
    i18n\PhpMessageSource,
12
    web\UrlRule,
13
};
14
15
/**
16
 * For example,
17
 *
18
 * ```php
19
 * 'oauth2' => [
20
 *     'class' => 'roaresearch\yii2\oauth2server\Module',
21
 *     'tokenParamName' => 'accessToken',
22
 *     'tokenAccessLifetime' => 3600 * 24,
23
 *     'storageMap' => [
24
 *         'user_credentials' => 'common\models\User',
25
 *     ],
26
 *     'grantTypes' => [
27
 *         'user_credentials' => [
28
 *             'class' => 'OAuth2\GrantType\UserCredentials',
29
 *         ],
30
 *         'refresh_token' => [
31
 *             'class' => 'OAuth2\GrantType\RefreshToken',
32
 *             'always_issue_new_refresh_token' => true
33
 *         ]
34
 *     ]
35
 * ]
36
 * ```
37
 */
38
class Module extends \yii\base\Module implements BootstrapInterface
39
{
40
    /**
41
     * @var bool whether the oauth2 server was initialized
42
     */
43
    private bool $serverInitialized = false;
44
45
    /**
46
     * @inheritdoc
47
     */
48
    public $controllerNamespace = controllers::class;
49
50
    /**
51
     * @var array Model's map
52
     */
53
    public array $modelMap = [];
54
55
    /**
56
     * @var array Storage's map
57
     */
58
    public array $storageMap = [];
59
60
    /**
61
     * @var array GrantTypes collection
62
     */
63
    public array $grantTypes = [];
64
65
    /**
66
     * @var string name of access token parameter
67
     */
68
    public string $tokenParamName;
69
70
    /**
71
     * @var int max access lifetime in seconds
72
     */
73
    public int $tokenAccessLifetime;
74
75
    /**
76
     * @var array Model's map
77
     */
78
    protected array $defaultModelMap = [
79
        'OauthClients' => models\OauthClients::class,
80
        'OauthAccessTokens' => models\OauthAccessTokens::class,
81
        'OauthAuthorizationCodes' => models\OauthAuthorizationCodes::class,
82
        'OauthRefreshTokens' => models\OauthRefreshTokens::class,
83
        'OauthScopes' => models\OauthScopes::class,
84
    ];
85
86
    /**
87
     * @var array Storage's map
88
     */
89
    protected array $defaultStorageMap = [
90
        'access_token' => storage\Pdo::class,
91
        'authorization_code' => storage\Pdo::class,
92
        'client_credentials' => storage\Pdo::class,
93
        'client' => storage\Pdo::class,
94
        'refresh_token' => storage\Pdo::class,
95
        'user_credentials' => storage\Pdo::class,
96
        'public_key' => storage\Pdo::class,
97
        'jwt_bearer' => storage\Pdo::class,
98
        'scope' => storage\Pdo::class,
99
    ];
100
101
    /**
102
     * @inheritdoc
103
     */
104
    public function urlRules(): array
105
    {
106
        return [
107
            [
108
                'class' => UrlRule::class,
109
                'pattern' => $this->getUniqueId() . '/<action:\w+>',
110
                'route' => $this->getUniqueId() . '/rest/<action>',
111
                'verb' => ['POST'],
112
            ],
113
            [
114
                'class' => UrlRule::class,
115
                'pattern' => $this->getUniqueId() . '/<action:\w+>',
116
                'route' => $this->getUniqueId() . '/rest/options',
117
                'verb' => ['OPTIONS'],
118
            ],
119
        ];
120
    }
121
122
    /**
123
     * Initializes the oauth2 server and its dependencies.
124
     */
125 9
    public function initOauth2Server(): void
126
    {
127 9
        if ($this->serverInitialized) {
128 5
            return;
129
        }
130
131 9
        $this->serverInitialized = true;
132 9
        $this->modelMap = array_merge($this->defaultModelMap, $this->modelMap);
133 9
        $this->storageMap = array_merge($this->defaultStorageMap, $this->storageMap);
134 9
        foreach ($this->modelMap as $name => $definition) {
135 9
            Yii::$container->set(models::class . '\\' . $name, $definition);
136
        }
137
138 9
        foreach ($this->storageMap as $name => $definition) {
139 9
            Yii::$container->set($name, $definition);
140
        }
141
142 9
        $storages = [];
143 9
        foreach(array_keys($this->storageMap) as $name) {
144 9
            $storages[$name] = Yii::$container->get($name);
145
        }
146
147 9
        $grantTypes = [];
148 9
        foreach($this->grantTypes as $name => $options) {
149 9
            if(!isset($storages[$name]) || empty($options['class'])) {
150
                throw new InvalidConfigException(
151
                    'Invalid grant types configuration.'
152
                );
153
            }
154
155 9
            $class = $options['class'];
156 9
            unset($options['class']);
157
158 9
            $reflection = new ReflectionClass($class);
159 9
            $config = array_merge([0 => $storages[$name]], [$options]);
160
161 9
            $instance = $reflection->newInstanceArgs($config);
162 9
            $grantTypes[$name] = $instance;
163
        }
164
165 9
        $this->set('server', Yii::$container->get(Server::class, [
166
            $this,
167
            $storages,
168
            [
169 9
                'token_param_name' => $this->tokenParamName,
170 9
                'access_lifetime' => $this->tokenAccessLifetime,
171
            ],
172
            $grantTypes
173
        ]));
174 9
        $this->set('request', Request::createFromGlobals());
175 9
        $this->set('response', new Response());
176
    }
177
178
    /**
179
     * @inheritdoc
180
     */
181 5
    public function beforeAction($action): bool
182
    {
183 5
        if (!parent::beforeAction($action)) {
184
            return false;
185
        }
186 5
        $this->initOauth2Server();
187
188 5
        return true;
189
    }
190
191
    /**
192
     * @inheritdoc
193
     */
194
    public function bootstrap($app): void
195
    {
196
        if ($app instanceof \yii\web\Application) {
197
            $app->getUrlManager()->addRules($this->urlRules());
198
        } else {
199
            $this->controllerNamespace = commands::class;
0 ignored issues
show
Bug introduced by
The type roaresearch\yii2\oauth2server\commands 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...
200
        }
201
202
        $this->registerTranslations($app);
203
    }
204
205
    /**
206
     * Gets Oauth2 Server
207
     *
208
     * @return Server
209
     */
210 9
    public function getServer(): Server
211
    {
212 9
        return $this->get('server');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('server') could return the type mixed|null which is incompatible with the type-hinted return roaresearch\yii2\oauth2server\Server. Consider adding an additional type-check to rule them out.
Loading history...
213
    }
214
215
    /**
216
     * Gets Oauth2 Response
217
     *
218
     * @return Response
219
     */
220 9
    public function getResponse(): Response
221
    {
222 9
        return $this->get('response');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('response') could return the type mixed|null which is incompatible with the type-hinted return OAuth2\Response. Consider adding an additional type-check to rule them out.
Loading history...
223
    }
224
225
    /**
226
     * Gets Oauth2 Request
227
     *
228
     * @return Request
229
     */
230 9
    public function getRequest(): Request
231
    {
232 9
        return $this->get('request');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->get('request') could return the type mixed|null which is incompatible with the type-hinted return OAuth2\Request. Consider adding an additional type-check to rule them out.
Loading history...
233
    }
234
235
    /**
236
     * @return bool
237
     */
238
    public function validateAuthorizeRequest(): bool
239
    {
240
        return $this->getServer()->validateAuthorizeRequest(
241
            $this->getRequest(),
242
            $this->getResponse(),
243
        );
244
    }
245
246
    /**
247
     * @param bool $authorized
248
     */
249
    public function handleAuthorizeRequest(
250
        bool $authorized,
251
        string|int $user_id
252
    ): Response {
253
        $this->getServer()->handleAuthorizeRequest(
254
            $this->getRequest(),
255
            $response = $this->getResponse(),
256
            $authorized,
257
            $user_id
258
        );
259
260
        return $response;
261
    }
262
263
    /**
264
     * Register translations for this module
265
     */
266
    public function registerTranslations($app): void
267
    {
268
        $route = 'roaresearch/yii2/oauth2/';
269
270
        $app->get('i18n')->translations[$route . '*'] ??= [
271
            'class' => PhpMessageSource::class,
272
            'basePath' => __DIR__ . '/messages',
273
            'fileMap' => [
274
                $route . 'oauth2server' => 'oauth2server.php',
275
            ],
276
        ];
277
    }
278
279
    /**
280
     * Translate module message
281
     *
282
     * @param string $category
283
     * @param string $message
284
     * @param array $params
285
     * @param ?string $language
286
     * @return string
287
     */
288 3
    public static function t(
289
        string $category,
290
        string $message,
291
        array $params = [],
292
        ?string $language = null
293
    ): string {
294 3
        return Yii::t(
295
            'roaresearch/yii2/oauth2/' . $category,
296
            $message,
297
            $params,
298
            $language
299
        );
300
    }
301
}
302