Issues (40)

php-src/Application/UI/OAuth2Presenter.php (1 issue)

Severity
1
<?php
2
3
namespace kalanis\Restful\Application\UI;
4
5
6
use Nette\Http\Url;
7
use kalanis\OAuth2\Application\IOAuthPresenter;
8
use kalanis\OAuth2\Exceptions\InvalidGrantException;
9
use kalanis\OAuth2\Exceptions\InvalidStateException;
10
use kalanis\OAuth2\Exceptions\OAuthException;
11
use kalanis\OAuth2\Exceptions\UnauthorizedClientException;
12
use kalanis\OAuth2\Exceptions\UnsupportedResponseTypeException;
13
use kalanis\OAuth2\Grant\GrantContext;
14
use kalanis\OAuth2\Grant\GrantType;
15
use kalanis\OAuth2\Grant\IGrant;
16
use kalanis\OAuth2\Storage\AuthorizationCodes\AuthorizationCodeFacade;
17
use kalanis\OAuth2\Storage\Clients\IClient;
18
use kalanis\OAuth2\Storage\Clients\IClientStorage;
19
use kalanis\OAuth2\Storage\Exceptions\TokenException;
20
use Traversable;
21
22
23
/**
24
 * OAuth2Presenter
25
 * @package kalanis\Restful\Application
26
 */
27
class OAuth2Presenter extends ResourcePresenter implements IOAuthPresenter
28
{
29
30
    #[\Nette\DI\Attributes\Inject]
31
    protected AuthorizationCodeFacade $authorizationCode;
32
33
    #[\Nette\DI\Attributes\Inject]
34
    public IClientStorage $clientStorage;
35
36
    #[\Nette\DI\Attributes\Inject]
37
    public GrantContext $grantContext;
38
39
    protected IClient $client;
40
41
    /**
42
     * Issue an authorization code
43
     * @param string $responseType
44
     * @param string $redirectUrl
45
     * @param string|null $scope
46
     * @throws UnauthorizedClientException
47
     * @throws UnsupportedResponseTypeException
48
     * @return void
49
     *
50
     */
51
    public function issueAuthorizationCode(string $responseType, string $redirectUrl, ?string $scope = null): void
52
    {
53
        try {
54
            if ('code' !== $responseType) {
55
                throw new UnsupportedResponseTypeException;
56
            }
57
            if (!$this->client->getId()) {
58
                throw new UnauthorizedClientException;
59
            }
60
61
            $scope = array_filter(explode(',', str_replace(' ', ',', strval($scope))));
62
            $code = $this->authorizationCode->create($this->client, $this->user->getId(), $scope);
63
            $data = ['code' => $code->getAuthorizationCode()];
64
            $this->oauthResponse($data, $redirectUrl);
65
        } catch (OAuthException $e) {
66
            $this->oauthError($e);
67
        } catch (TokenException) {
68
            $this->oauthError(new InvalidGrantException());
69
        }
70
    }
71
72
    /**
73
     * Send OAuth response
74
     * @param array<string, mixed>|Traversable<string, mixed> $data
75
     * @param string|null $redirectUrl
76
     * @param int $code
77
     */
78
    public function oauthResponse(iterable $data, ?string $redirectUrl = null, int $code = 200): void
0 ignored issues
show
The parameter $code is not used and could be removed. ( Ignorable by Annotation )

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

78
    public function oauthResponse(iterable $data, ?string $redirectUrl = null, /** @scrutinizer ignore-unused */ int $code = 200): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
79
    {
80
        if ($data instanceof Traversable) {
81
            $data = iterator_to_array($data);
82
        }
83
        $data = (array) $data;
84
85
        // Redirect, if there is URL
86
        if (!is_null($redirectUrl)) {
87
            $url = new Url($redirectUrl);
88
            if ('token' == $this->getParameter('response_type')) {
89
                $url->setFragment(http_build_query($data));
90
            } else {
91
                $url->appendQuery($data);
92
            }
93
            $this->redirectUrl($url);
94
        }
95
96
        // else send JSON response
97
        foreach ($data as $key => $value) {
98
            $this->resource->$key = $value;
99
        }
100
        $this->sendResource(null);
101
    }
102
103
    /**
104
     * Provide OAuth2 error response (redirect or at least JSON)
105
     * @param OAuthException $exception
106
     */
107
    public function oauthError(OAuthException $exception): void
108
    {
109
        $error = ['error' => $exception->getKey(), 'error_description' => $exception->getMessage()];
110
        $redirect = $this->getParameter('redirect_uri');
111
        $this->oauthResponse($error, is_null($redirect) ? null : strval($redirect), $exception->getCode());
112
    }
113
114
    /**
115
     * Issue an access token
116
     * @param string|null $grantType
117
     * @param string|null $redirectUrl
118
     */
119
    public function issueAccessToken(?string $grantType = null, ?string $redirectUrl = null): void
120
    {
121
        try {
122
            if (!is_null($grantType)) {
123
                $grantType = $this->grantContext->getGrantType($grantType);
124
            } else {
125
                $grantType = $this->getGrantType();
126
            }
127
128
            $response = $grantType->getAccessToken();
129
            $this->oauthResponse($response, $redirectUrl);
130
        } catch (OAuthException $e) {
131
            $this->oauthError($e);
132
        } catch (TokenException) {
133
            $this->oauthError(new InvalidGrantException);
134
        }
135
    }
136
137
    /**
138
     * Get grant type
139
     * @throws UnsupportedResponseTypeException
140
     */
141
    public function getGrantType(): IGrant
142
    {
143
        $request = $this->getHttpRequest();
144
        $grantType = strval($request->getPost(GrantType::GRANT_TYPE_KEY));
145
        try {
146
            return $this->grantContext->getGrantType($grantType);
147
        } catch (InvalidStateException $e) {
148
            throw new UnsupportedResponseTypeException('Trying to use unknown grant type ' . $grantType, $e);
149
        }
150
    }
151
152
    /**
153
     * On presenter startup
154
     */
155
    protected function startup(): void
156
    {
157
        parent::startup();
158
        $clientId = $this->getParameter(GrantType::CLIENT_ID_KEY);
159
        $clientSecret = $this->getParameter(GrantType::CLIENT_SECRET_KEY);
160
        $client = $this->clientStorage->getClient(
161
            is_numeric($clientId) ? intval($clientId) : strval($clientId),
162
            is_null($clientSecret) ? null : strval($clientSecret)
163
        );
164
        if (!$client) {
165
            throw new \LogicException('Cannot load client info');
166
        }
167
        $this->client = $client;
168
    }
169
}
170