ImplicitGrantTrait   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 133
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 3
dl 0
loc 133
ccs 43
cts 43
cp 1
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A implicitSetIntegration() 0 4 1
A implicitGetIntegration() 0 4 1
A implicitGetClientId() 0 4 1
A implicitGetRedirectUri() 0 4 1
A implicitGetScope() 0 6 2
A implicitGetState() 0 4 1
B implicitAskResourceOwnerForApproval() 0 45 5
A implicitReadStringValue() 0 5 3
1
<?php declare(strict_types=1);
2
3
namespace Limoncello\OAuthServer\GrantTraits;
4
5
/**
6
 * Copyright 2015-2019 [email protected]
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
use Limoncello\OAuthServer\Contracts\ClientInterface;
22
use Limoncello\OAuthServer\Contracts\Integration\ImplicitIntegrationInterface;
23
use Limoncello\OAuthServer\Exceptions\OAuthTokenRedirectException;
24
use Psr\Http\Message\ResponseInterface;
25
use function array_key_exists;
26
use function explode;
27
use function is_string;
28
use function strlen;
29
30
/**
31
 * Implements Implicit Grant.
32
 *
33
 * @package Limoncello\OAuthServer
34
 *
35
 * @link https://tools.ietf.org/html/rfc6749#section-1.3
36
 * @link https://tools.ietf.org/html/rfc6749#section-4.2
37
 */
38
trait ImplicitGrantTrait
39
{
40
    /**
41
     * @var ImplicitIntegrationInterface
42
     */
43
    private $implicitIntegration;
44 44
45
    /**
46 44
     * @param ImplicitIntegrationInterface $integration
47
     *
48
     * @return void
49
     */
50
    public function implicitSetIntegration(ImplicitIntegrationInterface $integration): void
51
    {
52 4
        $this->implicitIntegration = $integration;
53
    }
54 4
55
    /**
56
     * @return ImplicitIntegrationInterface
57
     */
58
    protected function implicitGetIntegration(): ImplicitIntegrationInterface
59
    {
60
        return $this->implicitIntegration;
61
    }
62 7
63
    /**
64 7
     * @param string[] $parameters
65
     *
66
     * @return string|null
67
     */
68
    protected function implicitGetClientId(array $parameters): ?string
69
    {
70
        return $this->implicitReadStringValue($parameters, 'client_id');
71
    }
72 7
73
    /**
74 7
     * @param string[] $parameters
75
     *
76
     * @return string|null
77
     */
78
    protected function implicitGetRedirectUri(array $parameters): ?string
79
    {
80
        return $this->implicitReadStringValue($parameters, 'redirect_uri');
81
    }
82 4
83
    /**
84 4
     * @param string[] $parameters
85
     *
86 4
     * @return string[]|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
87
     */
88
    protected function implicitGetScope(array $parameters): ?array
89
    {
90
        $scope = $this->implicitReadStringValue($parameters, 'scope');
91
92
        return empty($scope) === false ? explode(' ', $scope) : null;
93
    }
94 6
95
    /**
96 6
     * @param string[] $parameters
97
     *
98
     * @return string|null
99
     */
100
    protected function implicitGetState(array $parameters): ?string
101
    {
102
        return $this->implicitReadStringValue($parameters, 'state');
103
    }
104
105
    /**
106
     * @param string[]        $parameters
107 6
     * @param ClientInterface $client
108
     * @param string|null     $redirectUri
109
     * @param int|null        $maxStateLength
110
     *
111
     * @return ResponseInterface
112
     */
113 6
    protected function implicitAskResourceOwnerForApproval(
114 6
        array $parameters,
115 1
        ClientInterface $client,
116 1
        string $redirectUri = null,
117 1
        int $maxStateLength = null
118 1
    ): ResponseInterface {
119
        $state = $this->implicitGetState($parameters);
120
        if ($maxStateLength !== null && strlen($state) > $maxStateLength) {
121
            throw new OAuthTokenRedirectException(
122 5
                OAuthTokenRedirectException::ERROR_INVALID_REQUEST,
123 1
                $redirectUri,
124 1
                $state
125 1
            );
126 1
        }
127
128
        if ($client->isImplicitGrantEnabled() === false) {
129
            throw new OAuthTokenRedirectException(
130 4
                OAuthTokenRedirectException::ERROR_UNAUTHORIZED_CLIENT,
131
                $redirectUri,
132 4
                $state
133 4
            );
134 1
        }
135 1
136 1
        $scope = $this->implicitGetScope($parameters);
137 1
        list ($isScopeValid, $scopeList, $isScopeModified) =
138
            $this->implicitGetIntegration()->implicitValidateScope($client, $scope);
139
        if ($isScopeValid === false) {
140
            throw new OAuthTokenRedirectException(
141 3
                OAuthTokenRedirectException::ERROR_INVALID_SCOPE,
142 3
                $redirectUri,
143 3
                $state
144 3
            );
145 3
        }
146 3
147 3
        $response = $this->implicitGetIntegration()->implicitCreateAskResourceOwnerForApprovalResponse(
148
            $client,
149
            $redirectUri,
150 3
            $isScopeModified,
151
            $scopeList,
152
            $state,
153
            $parameters
154
        );
155
156
        return $response;
157
    }
158
159 7
    /**
160
     * @param array  $parameters
161 7
     * @param string $name
162 7
     *
163
     * @return null|string
164
     */
165
    private function implicitReadStringValue(array $parameters, string $name): ?string
166
    {
167
        return array_key_exists($name, $parameters) === true && is_string($value = $parameters[$name]) === true ?
168
            $value : null;
0 ignored issues
show
Bug introduced by
The variable $value does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
169
    }
170
}
171