Passed
Push — master ( f52d5c...0b49e9 )
by Rutger
03:13
created

Oauth2BaseEditClientAction::configureClient()   F

Complexity

Conditions 31
Paths > 20000

Size

Total Lines 143
Code Lines 97

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 992

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 97
c 1
b 0
f 0
dl 0
loc 143
ccs 0
cts 105
cp 0
rs 0
cc 31
nc 276480
nop 1
crap 992

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\components\openidconnect\scope\Oauth2OidcScopeCollectionInterface;
9
use rhertogh\Yii2Oauth2Server\interfaces\models\Oauth2ClientInterface;
10
use rhertogh\Yii2Oauth2Server\interfaces\models\Oauth2ClientScopeInterface;
11
use rhertogh\Yii2Oauth2Server\Oauth2Module;
12
use Yii;
13
use yii\base\Action;
14
use yii\base\InvalidArgumentException;
15
use yii\console\ExitCode;
16
use yii\helpers\ArrayHelper;
17
use yii\helpers\Console;
18
19
/**
20
 * @property Oauth2ClientController $controller
21
 */
22
class Oauth2BaseEditClientAction extends Oauth2BaseClientAction
23
{
0 ignored issues
show
Coding Style introduced by
Opening brace must not be followed by a blank line
Loading history...
24
25
    /**
26
     * @param Oauth2ClientInterface $client
27
     * @param string $defaultScopes
28
     * @return void
29
     * @throws \yii\base\InvalidConfigException
30
     * @throws \yii\db\Exception
31
     */
32
    public function editClient($client, $defaultScopes = '')
33
    {
34
        $controller = $this->controller;
35
        $module = $controller->module;
36
37
        $this->configureClient($client);
38
39
        $scopes = $this->getScopes($client, $defaultScopes);
40
41
        $transaction = $client::getDb()->beginTransaction();
42
        try {
43
            $client
44
                ->persist()
45
                ->syncClientScopes($scopes, $module->getScopeRepository());
46
            $transaction->commit();
47
        } catch (\Exception $e) {
48
            $transaction->rollBack();
49
            throw $e;
50
        }
51
    }
52
53
    /**
54
     * @param Oauth2ClientInterface $client
55
     * @throws \yii\base\InvalidConfigException
56
     * @throws \yii\db\Exception
57
     */
58
    protected function configureClient($client)
59
    {
60
        $controller = $this->controller;
61
        $module = $controller->module;
62
63
        $identifier = $controller->identifier;
64
        if (
65
            empty($identifier)
66
            || !$this->clientIdentifierValidator($controller->identifier, $clientIdentifierValidatorError)
67
        ) {
68
            if (!empty($clientIdentifierValidatorError)) {
69
                $controller->stdout($clientIdentifierValidatorError . PHP_EOL);
70
            }
71
            $identifier = $controller->prompt('Client Identifier?', [
72
                'required' => true,
73
                'default' => $client->getIdentifier(),
74
                'validator' => [$this, 'clientIdentifierValidator'],
75
            ]);
76
        }
77
        $client->setIdentifier($identifier);
78
79
        $name = $controller->name;
80
        if (empty($name)) {
81
            $name = $controller->prompt('Client Name?', [
82
                'required' => true,
83
                'default' => $client->getName(),
84
            ]);
85
        }
86
        $client->setName($name);
87
88
        $type = $controller->type;
89
        if (empty($type)) {
90
            $clientTypeOptions = [
91
                Oauth2ClientInterface::TYPE_CONFIDENTIAL => 'Confidential',
92
                Oauth2ClientInterface::TYPE_PUBLIC => 'Public',
93
            ];
94
            $clientTypeOptionsWithDetails = [
95
                Oauth2ClientInterface::TYPE_CONFIDENTIAL => 'Confidential: Identifies the client via a shared secret.'
96
                    . ' Note: This should only be trusted in case the client can store the secret securely'
97
                    . ' (e.g. another server).',
98
                Oauth2ClientInterface::TYPE_PUBLIC => 'Public: In case the client can not store a secret securely'
99
                    . ' it should be declared public (e.g. web- or mobile applications).',
100
            ];
101
            if ($controller->interactive) {
102
                $controller->stdout('Client Type options:' . PHP_EOL);
103
                foreach ($clientTypeOptions as $key => $value) {
104
                    $controller->stdout(" $key - $value" . PHP_EOL);
105
                }
106
            }
107
            $type = $controller->select(
108
                'Client Type?',
109
                $clientTypeOptionsWithDetails,
110
            $client->isConfidential()
0 ignored issues
show
Unused Code introduced by
The call to yii\console\Controller::select() has too many arguments starting with $client->isConfidential(...tInterface::TYPE_PUBLIC. ( Ignorable by Annotation )

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

110
            /** @scrutinizer ignore-call */ 
111
            $type = $controller->select(

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...
111
                    ? Oauth2ClientInterface::TYPE_CONFIDENTIAL
112
                    : Oauth2ClientInterface::TYPE_PUBLIC
113
            );
114
        }
115
        $type = (int)$type;
116
        $client->setType($type);
117
118
        $grantTypes = $controller->grantTypes;
119
        if (empty($grantTypes)) {
120
            $availableGrantTypes = array_map(
121
                fn(GrantTypeInterface $grant) => $grant->getIdentifier(),
122
                $module->getAuthorizationServer()->getEnabledGrantTypes()
123
            );
124
125
            if ($controller->interactive) {
126
                $controller->stdout('Enable Grant Types:' . PHP_EOL);
127
            }
128
            $grantTypes = 0;
129
            foreach ($availableGrantTypes as $availableGrantType) {
130
                if ($controller->confirm(
0 ignored issues
show
Coding Style introduced by
The first expression of a multi-line control structure must be on the line after the opening parenthesis
Loading history...
131
                    ' - ' . $availableGrantType,
132
                        (bool)($client->getGrantTypes() & Oauth2Module::getGrantTypeId($availableGrantType))
133
                )) {
0 ignored issues
show
Coding Style introduced by
Each line in a multi-line control structure must be indented at least once; expected at least 20 spaces, but found 16
Loading history...
Coding Style introduced by
The closing parenthesis of a multi-line control structure must be on the line after the last expression
Loading history...
134
                    $grantTypes |= Oauth2Module::getGrantTypeId($availableGrantType);
135
                }
136
            }
137
        }
138
        $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

138
        $client->setGrantTypes(/** @scrutinizer ignore-type */ $grantTypes);
Loading history...
139
140
        $redirectUrisRequired =
141
            (bool)($client->getGrantTypes() & (Oauth2Module::GRANT_TYPE_AUTH_CODE | Oauth2Module::GRANT_TYPE_IMPLICIT));
142
143
        $redirectURIs = $controller->redirectURIs;
144
        if (
145
            empty($controller->redirectURIs)
146
            && (
147
                $redirectUrisRequired
148
                || (!$client->getIsNewRecord() && $client->getRedirectUri()
149
                )
150
            )
151
        ) {
152
            $redirectURIs = $controller->prompt('Client Redirect URIs (comma separated)?', [
153
                'required' => $redirectUrisRequired,
154
                'default' => implode(',', $client->getRedirectUri())
0 ignored issues
show
Bug introduced by
It seems like $client->getRedirectUri() can also be of type string; however, parameter $pieces of implode() does only seem to accept array, 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

154
                'default' => implode(',', /** @scrutinizer ignore-type */ $client->getRedirectUri())
Loading history...
155
            ]);
156
            $redirectURIs = array_map('trim', explode(',', $redirectURIs));
157
        }
158
        $client->setRedirectUri($redirectURIs);
159
160
        if ($type == Oauth2ClientInterface::TYPE_CONFIDENTIAL && $client->getIsNewRecord()) {
161
            $secret = $controller->secret;
162
            if (!empty($secret) && !$client->validateNewSecret($secret, $error)) {
163
                $controller->stdout("Invalid secret: $error" . PHP_EOL);
164
                $secret = null;
165
            }
166
            if (empty($secret)) {
167
                $secret = $controller->prompt('Client Secret?', [
168
                    'required' => true,
169
                    'validator' => [$client, 'validateNewSecret'],
170
                ]);
171
            }
172
            $client->setSecret($secret, $module->getEncryptor());
173
        }
174
175
        if ($controller->allowVariableRedirectUriQuery !== null) {
176
            $client->setAllowVariableRedirectUriQuery((bool)$controller->allowVariableRedirectUriQuery);
177
        }
178
        if ($controller->scopeAccess !== null) {
179
            $client->setScopeAccess((int)$controller->scopeAccess);
180
        }
181
        if ($controller->endUsersMayAuthorizeClient !== null) {
182
            $client->setEndUsersMayAuthorizeClient((bool)$controller->endUsersMayAuthorizeClient);
183
        }
184
        if ($controller->userAccountSelection !== null) {
185
            $client->setUserAccountSelection((int)$controller->userAccountSelection);
186
        }
187
        if ($controller->isAuthCodeWithoutPkceAllowed !== null) {
188
            $client->setAllowAuthCodeWithoutPkce((bool)$controller->isAuthCodeWithoutPkceAllowed);
189
        }
190
        if ($controller->skipAuthorizationIfScopeIsAllowed !== null) {
191
            $client->setSkipAuthorizationIfScopeIsAllowed((bool)$controller->skipAuthorizationIfScopeIsAllowed);
192
        }
193
        if ($controller->logoUri !== null) {
194
            $client->setLogoUri($controller->logoUri);
195
        }
196
        if ($controller->termsOfServiceUri !== null) {
197
            $client->setTermsOfServiceUri($controller->termsOfServiceUri);
198
        }
199
        if ($controller->contacts !== null) {
200
            $client->setContacts($controller->contacts);
201
        }
202
    }
203
204
    /**
205
     * @param Oauth2ClientInterface $client
206
     * @return string
207
     */
208
    protected function getScopes($client, $defaultScopes = '')
209
    {
210
        $controller = $this->controller;
211
        $scopes = $controller->scopes;
212
        if (!empty($scopes) && !$this->validateScope($scopes, $error)) {
213
            $controller->stdout("Invalid scopes: $error" . PHP_EOL);
214
            $scopes = null;
215
        }
216
        if (empty($scopes)) {
217
            if (!$client->getIsNewRecord()) {
218
                $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

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