Oauth2BaseEditClientAction::configureClient()   F
last analyzed

Complexity

Conditions 32
Paths > 20000

Size

Total Lines 149
Code Lines 101

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 1056

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 101
c 1
b 0
f 0
dl 0
loc 149
ccs 0
cts 108
cp 0
rs 0
cc 32
nc 552960
nop 1
crap 1056

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace rhertogh\Yii2Oauth2Server\controllers\console\client\base;
4
5
use League\OAuth2\Server\Grant\GrantTypeInterface;
6
use rhertogh\Yii2Oauth2Server\controllers\console\Oauth2ClientController;
7
use rhertogh\Yii2Oauth2Server\helpers\DiHelper;
8
use rhertogh\Yii2Oauth2Server\interfaces\models\Oauth2ClientInterface;
9
use rhertogh\Yii2Oauth2Server\Oauth2Module;
10
use yii\helpers\ArrayHelper;
11
12
/**
13
 * @property Oauth2ClientController $controller
14
 */
15
class Oauth2BaseEditClientAction extends Oauth2BaseClientAction
16
{
17
    /**
18
     * @param Oauth2ClientInterface $client
19
     * @param string $defaultScopes
20
     * @return void
21
     * @throws \yii\base\InvalidConfigException
22
     * @throws \yii\db\Exception
23
     */
24
    public function editClient($client, $defaultScopes = '')
25
    {
26
        $controller = $this->controller;
27
        $module = $controller->module;
28
29
        $this->configureClient($client);
30
31
        $scopes = $this->getScopes($client, $defaultScopes);
32
33
        $transaction = $client::getDb()->beginTransaction();
34
        try {
35
            $client
36
                ->persist()
37
                ->syncClientScopes($scopes, $module->getScopeRepository());
38
            $transaction->commit();
39
        } catch (\Exception $e) {
40
            $transaction->rollBack();
41
            throw $e;
42
        }
43
    }
44
45
    /**
46
     * @param Oauth2ClientInterface $client
47
     * @throws \yii\base\InvalidConfigException
48
     * @throws \yii\db\Exception
49
     */
50
    protected function configureClient($client)
51
    {
52
        $controller = $this->controller;
53
        $module = $controller->module;
54
55
        $identifier = $controller->identifier;
56
        if (
57
            empty($identifier)
58
            || !$this->clientIdentifierValidator($controller->identifier, $clientIdentifierValidatorError)
59
        ) {
60
            if (!empty($clientIdentifierValidatorError)) {
61
                $controller->stdout($clientIdentifierValidatorError . PHP_EOL);
62
            }
63
            $identifier = $controller->prompt('Client Identifier?', [
64
                'required' => true,
65
                'default' => $client->getIdentifier(),
66
                'validator' => [$this, 'clientIdentifierValidator'],
67
            ]);
68
        }
69
        $client->setIdentifier($identifier);
70
71
        $name = $controller->name;
72
        if (empty($name)) {
73
            $name = $controller->prompt('Client Name?', [
74
                'required' => true,
75
                'default' => $client->getName(),
76
            ]);
77
        }
78
        $client->setName($name);
79
80
        $type = $controller->type;
81
        if (empty($type)) {
82
            $clientTypeOptions = [
83
                Oauth2ClientInterface::TYPE_CONFIDENTIAL => 'Confidential',
84
                Oauth2ClientInterface::TYPE_PUBLIC => 'Public',
85
            ];
86
            $clientTypeOptionsWithDetails = [
87
                Oauth2ClientInterface::TYPE_CONFIDENTIAL => 'Confidential: Identifies the client via a shared secret.'
88
                    . ' Note: This should only be trusted in case the client can store the secret securely'
89
                    . ' (e.g. another server).',
90
                Oauth2ClientInterface::TYPE_PUBLIC => 'Public: In case the client can not store a secret securely'
91
                    . ' it should be declared public (e.g. web- or mobile applications).',
92
            ];
93
            if ($controller->interactive) {
94
                $controller->stdout('Client Type options:' . PHP_EOL);
95
                foreach ($clientTypeOptions as $key => $value) {
96
                    $controller->stdout(" $key - $value" . PHP_EOL);
97
                }
98
            }
99
            $type = $controller->select(
100
                'Client Type?',
101
                $clientTypeOptionsWithDetails,
102
                $client->isConfidential()
103
                    ? Oauth2ClientInterface::TYPE_CONFIDENTIAL
104
                    : Oauth2ClientInterface::TYPE_PUBLIC
105
            );
106
        }
107
        $type = (int)$type;
108
        $client->setType($type);
109
110
        $grantTypes = $controller->grantTypes;
111
        if (empty($grantTypes)) {
112
            $availableGrantTypes = array_map(
113
                fn(GrantTypeInterface $grant) => $grant->getIdentifier(),
114
                $module->getAuthorizationServer()->getEnabledGrantTypes()
115
            );
116
117
            if ($controller->interactive) {
118
                $controller->stdout('Enable Grant Types:' . PHP_EOL);
119
            }
120
            $grantTypes = 0;
121
            foreach ($availableGrantTypes as $availableGrantType) {
122
                if (
123
                    $controller->confirm(
124
                        ' - ' . $availableGrantType,
125
                        (bool)($client->getGrantTypes() & Oauth2Module::getGrantTypeId($availableGrantType))
126
                    )
127
                ) {
128
                    $grantTypes |= Oauth2Module::getGrantTypeId($availableGrantType);
129
                }
130
            }
131
        }
132
        $client->setGrantTypes($grantTypes);
0 ignored issues
show
Bug introduced by
It seems like $grantTypes can also be of type string; however, parameter $grantTypes of rhertogh\Yii2Oauth2Serve...erface::setGrantTypes() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

132
        $client->setGrantTypes(/** @scrutinizer ignore-type */ $grantTypes);
Loading history...
133
134
        $redirectUrisRequired =
135
            (bool)($client->getGrantTypes() & (Oauth2Module::GRANT_TYPE_AUTH_CODE | Oauth2Module::GRANT_TYPE_IMPLICIT));
136
137
        $redirectURIs = $controller->redirectURIs;
138
        if (
139
            empty($controller->redirectURIs)
140
            && (
141
                $redirectUrisRequired
142
                || (
143
                    !$client->getIsNewRecord() && $client->getRedirectUri()
144
                )
145
            )
146
        ) {
147
            $redirectURIs = $controller->prompt('Client Redirect URIs (comma separated)?', [
148
                'required' => $redirectUrisRequired,
149
                'default' => implode(',', $client->getRedirectUri())
150
            ]);
151
            $redirectURIs = array_map('trim', explode(',', $redirectURIs));
152
        }
153
        $client->setRedirectUri($redirectURIs);
154
155
        if ($type == Oauth2ClientInterface::TYPE_CONFIDENTIAL && $client->getIsNewRecord()) {
156
            $secret = $controller->secret;
157
            if (!empty($secret) && !$client->validateNewSecret($secret, $error)) {
158
                $controller->stdout("Invalid secret: $error" . PHP_EOL);
159
                $secret = null;
160
            }
161
            if (empty($secret)) {
162
                $secret = $controller->prompt('Client Secret?', [
163
                    'required' => true,
164
                    'validator' => [$client, 'validateNewSecret'],
165
                ]);
166
            }
167
            $client->setSecret($secret, $module->getCryptographer());
168
        }
169
170
        if ($controller->allowVariableRedirectUriQuery !== null) {
171
            $client->setAllowVariableRedirectUriQuery((bool)$controller->allowVariableRedirectUriQuery);
172
        }
173
        if ($controller->allowGenericScopes !== null) {
174
            $client->setAllowGenericScopes((bool)$controller->allowGenericScopes);
175
        }
176
        if ($controller->exceptionOnInvalidScope !== null) {
177
            $client->setExceptionOnInvalidScope((bool)$controller->exceptionOnInvalidScope);
178
        }
179
        if ($controller->endUsersMayAuthorizeClient !== null) {
180
            $client->setEndUsersMayAuthorizeClient((bool)$controller->endUsersMayAuthorizeClient);
181
        }
182
        if ($controller->userAccountSelection !== null) {
183
            $client->setUserAccountSelection((int)$controller->userAccountSelection);
184
        }
185
        if ($controller->isAuthCodeWithoutPkceAllowed !== null) {
186
            $client->setAllowAuthCodeWithoutPkce((bool)$controller->isAuthCodeWithoutPkceAllowed);
187
        }
188
        if ($controller->skipAuthorizationIfScopeIsAllowed !== null) {
189
            $client->setSkipAuthorizationIfScopeIsAllowed((bool)$controller->skipAuthorizationIfScopeIsAllowed);
190
        }
191
        if ($controller->logoUri !== null) {
192
            $client->setLogoUri($controller->logoUri);
193
        }
194
        if ($controller->termsOfServiceUri !== null) {
195
            $client->setTermsOfServiceUri($controller->termsOfServiceUri);
196
        }
197
        if ($controller->contacts !== null) {
198
            $client->setContacts($controller->contacts);
199
        }
200
    }
201
202
    /**
203
     * @param Oauth2ClientInterface $client
204
     * @return string
205
     */
206
    protected function getScopes($client, $defaultScopes = '')
207
    {
208
        $controller = $this->controller;
209
        $scopes = $controller->scopes;
210
        if (!empty($scopes) && !$this->validateScope($scopes, $error)) {
211
            $controller->stdout("Invalid scopes: $error" . PHP_EOL);
212
            $scopes = null;
213
        }
214
        if (empty($scopes)) {
215
            if (!$client->getIsNewRecord()) {
216
                $clientScopes = $client->getClientScopes()->with('scope')->all();
0 ignored issues
show
Unused Code introduced by
The call to yii\db\ActiveQueryInterface::with() has too many arguments starting with 'scope'. ( Ignorable by Annotation )

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

216
                $clientScopes = $client->getClientScopes()->/** @scrutinizer ignore-call */ with('scope')->all();

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
217
                $defaultScopes = implode(' ', ArrayHelper::getColumn($clientScopes, 'scope.identifier'));
218
            }
219
            do {
220
                $scopes = $controller->prompt('Scopes (space separated)?', [
221
                    'default' => $defaultScopes
222
                ]);
223
                $scopes = implode(' ', array_filter(array_map('trim', explode(' ', $scopes))));
224
                $valid = $this->validateScope($scopes, $error);
225
                if (!$valid) {
226
                    $controller->stdout("Invalid scopes: $error" . PHP_EOL);
227
                    $scopes = null;
228
                }
229
            } while (!$valid);
230
        }
231
232
        return $scopes;
233
    }
234
235
    public function validateScope($scope, &$error)
236
    {
237
        $error = null;
238
        if (!empty($scope)) {
239
            $scopeRepository = $this->controller->module->getScopeRepository();
240
            $scopeIdentifiers = array_filter(array_map('trim', explode(' ', $scope)));
241
            $unknownScopeIdentifiers = [];
242
            foreach ($scopeIdentifiers as $scopeIdentifier) {
243
                if (empty($scopeRepository->getScopeEntityByIdentifier($scopeIdentifier))) {
244
                    $unknownScopeIdentifiers[] = $scopeIdentifier;
245
                }
246
            }
247
            if ($unknownScopeIdentifiers) {
248
                $error = 'Unknown identifiers: ' . implode(', ', $unknownScopeIdentifiers);
249
            }
250
        }
251
252
        return $error === null;
253
    }
254
255
    public function clientIdentifierValidator($input, &$error)
256
    {
257
        /** @var string|Oauth2ClientInterface $clientClass */
258
        $clientClass = DiHelper::getValidatedClassName(Oauth2ClientInterface::class);
259
        if ($clientClass::findByIdentifier($input)) {
260
            $error = 'A client with identifier "' . $input . '" already exists.';
261
            return false;
262
        }
263
        return true;
264
    }
265
}
266