Completed
Push — issue#666 ( 5bb037...827179 )
by Guilherme
04:30 queued 33s
created

AuthorizeController::removeRemoteScope()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 5
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 10
ccs 0
cts 0
cp 0
crap 6
rs 9.4285
1
<?php
2
/**
3
 * This file is part of the login-cidadao project or it's bundles.
4
 *
5
 * (c) Guilherme Donato <guilhermednt on github>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace LoginCidadao\OpenIDBundle\Controller;
12
13
use FOS\OAuthServerBundle\Event\OAuthEvent;
14
use LoginCidadao\CoreBundle\Model\PersonInterface;
15
use LoginCidadao\OpenIDBundle\Event\AuthorizationEvent;
16
use LoginCidadao\OpenIDBundle\LoginCidadaoOpenIDEvents;
17
use LoginCidadao\OpenIDBundle\Manager\ClientManager;
18
use LoginCidadao\OpenIDBundle\Manager\ScopeManager;
19
use LoginCidadao\OAuthBundle\Service\OrganizationService;
20
use LoginCidadao\OAuthBundle\Model\OrganizationInterface;
21
use LoginCidadao\OAuthBundle\Model\ClientInterface;
22
use LoginCidadao\OpenIDBundle\Validator\SectorIdentifierUriChecker;
23
use LoginCidadao\RemoteClaimsBundle\Model\RemoteClaimInterface;
24
use OAuth2\Server;
25
use OAuth2\ServerBundle\Entity\Scope;
26
use OAuth2\ServerBundle\Controller\AuthorizeController as BaseController;
27
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
28
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
29
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
30
use Symfony\Component\EventDispatcher\EventDispatcher;
31
use Symfony\Component\HttpFoundation\JsonResponse;
32
use Symfony\Component\HttpFoundation\Request;
33
34
class AuthorizeController extends BaseController
35
{
36
37
    /**
38
     * @Route("/openid/connect/authorize", name="_authorize_handle")
39
     * @Method({"POST"})
40
     */
41
    public function handleAuthorizeAction()
42
    {
43
        $request = $this->getRequest();
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Bundle\Framework...ontroller::getRequest() has been deprecated with message: since version 2.4, to be removed in 3.0. Ask Symfony to inject the Request object into your controller method instead by type hinting it in the method's signature.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
44
        $implodedScope = implode(' ', $request->request->get('scope'));
45
        $request->request->set('scope', $implodedScope);
46
47
        $isAuthorized = $request->request->has('accepted')
48
            || !$request->request->has('rejected');
49
50
        $response = $this->handleAuthorize($this->getOAuth2Server(), $isAuthorized);
51
52
        $event = new OAuthEvent(
53
            $this->getUser(),
54
            $this->getClient($request), $isAuthorized
55
        );
56
        $this->get('event_dispatcher')->dispatch(OAuthEvent::POST_AUTHORIZATION_PROCESS, $event);
57
58
        return $response;
59
    }
60
61
    /**
62
     * Render the Authorization fragment
63
     *
64
     * @Template()
65
     * @param Request $request
66
     * @return array
67
     *
68
     * @deprecated
69
     */
70
    public function authorizeAction(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

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

Loading history...
71
    {
72
        throw new \RuntimeException('This class should not be used!');
73
        $client = $this->getClient($request);
0 ignored issues
show
Unused Code introduced by
$client = $this->getClient($request); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
74
75
        $scope = explode(' ', $request->get('scope'));
76
        if (array_search('public_profile', $scope) === false) {
77
            $scope[] = 'public_profile';
78
        }
79
80
        /** @var ScopeManager $scopeManager */
81
        $scopeManager = $this->get('oauth2.scope_manager');
82
        $scopes = array_map(
83
            function (Scope $value) {
84
                return $value->getScope();
85
            },
86
            $scopeManager->findScopesByScopes($scope)
87
        );
88
89
        /** @var OrganizationService $organizationService */
90
        $organizationService = $this->get('organization');
91
        $warnUntrusted = $this->shouldWarnUntrusted($client);
92
        $metadata = $this->getMetadata($client);
93
        $organization = $organizationService->getOrganization($metadata);
94
95
        $qs = [
96
            'client_id' => $client->getPublicId(),
97
            'scope' => $scope,
98
            'response_type' => $request->get('response_type'),
99
            'redirect_uri' => $request->get('redirect_uri'),
100
            'state' => $request->get('state'),
101
            'nonce' => $request->get('nonce'),
102
        ];
103
104
        return [
105
            'qs' => $qs,
106
            'scopes' => $scopes,
107
            'client' => $client,
108
            'warnUntrusted' => $warnUntrusted,
109
            'metadata' => $metadata,
110
            'organization' => $organization,
111
        ];
112
    }
113
114
    /**
115
     * @Route("/openid/connect/authorize", name="_authorize_validate")
116
     * @Method({"GET"})
117
     * @Template("LoginCidadaoOpenIDBundle:Authorize:authorize.html.twig")
118
     */
119
    public function validateAuthorizeAction()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
120
    {
121
        $request = $this->getRequest();
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Bundle\Framework...ontroller::getRequest() has been deprecated with message: since version 2.4, to be removed in 3.0. Ask Symfony to inject the Request object into your controller method instead by type hinting it in the method's signature.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
122
        $client = $this->getClient($request);
123
124
        if (!$client instanceof \FOS\OAuthServerBundle\Model\ClientInterface) {
125
            return parent::validateAuthorizeAction();
126
        }
127
128
        /** @var PersonInterface $person */
129
        $person = $this->getUser();
130
131
        /** @var EventDispatcher $dispatcher */
132
        $dispatcher = $this->get('event_dispatcher');
133
134
        $event = new OAuthEvent($person, $client);
135
        $dispatcher->dispatch(OAuthEvent::PRE_AUTHORIZATION_PROCESS, $event);
136
137
        $isAuthorized = $event->isAuthorizedClient();
138
        $askConsent = $request->get('prompt', null) == 'consent';
139
140
        if ($isAuthorized && !$askConsent) {
141
            return $this->handleAuthorize($this->getOAuth2Server(), $isAuthorized);
142
        }
143
144
        $remoteClaims = [];
145
        if (!$isAuthorized) {
146
            $authEvent = new AuthorizationEvent($person, $client, $request->get('scope'));
147
            $dispatcher->dispatch(LoginCidadaoOpenIDEvents::NEW_AUTHORIZATION_REQUEST, $authEvent);
148
            $remoteClaims = $authEvent->getRemoteClaims();
149
        }
150
151
        /** @var OrganizationService $organizationService */
152
        $organizationService = $this->get('organization');
153
        $warnUntrusted = $this->shouldWarnUntrusted($client);
154
        $metadata = $this->getMetadata($client);
155
        $organization = $organizationService->getOrganization($metadata);
156
157
        // Call the lib's original Controller
158
        $parentResponse = parent::validateAuthorizeAction();
159
        $parentResponse['scopes'] = $this->removeRemoteScope($parentResponse['scopes']);
160
161
        $response = array_merge([
162
            'qs' => [
163
                'client_id' => $client->getPublicId(),
164
                'scope' => $parentResponse['scopes'],
165
                'response_type' => $request->get('response_type'),
166
                'redirect_uri' => $request->get('redirect_uri'),
167
                'state' => $request->get('state'),
168
                'nonce' => $request->get('nonce'),
169
            ],
170
            'remoteClaims' => $remoteClaims,
171
            'client' => $client,
172
            'metadata' => $metadata,
173
            'organization' => $organization,
174
            'warnUntrusted' => $warnUntrusted,
175
        ], $parentResponse);
176
177
        return $response;
178
    }
179
180
    private function handleAuthorize(Server $server, $isAuthorized)
181
    {
182
        /** @var \OAuth2\Request $request */
183
        $request = $this->get('oauth2.request');
184
185
        /** @var \OAuth2\Response $response */
186
        $response = $this->get('oauth2.response');
187
188
        return $server->handleAuthorizeRequest(
189
            $request,
190
            $response,
191
            $isAuthorized,
192
            $this->getUser()->getId()
193
        );
194
    }
195
196
    private function getClient($fullId)
197
    {
198
        if ($fullId instanceof Request) {
199
            $fullId = $fullId->get('client_id');
200
        }
201
202
        /** @var ClientManager $clientManager */
203
        $clientManager = $this->get('lc.client_manager');
204
205
        return $clientManager->getClientById($fullId);
206
    }
207
208
    private function shouldWarnUntrusted(ClientInterface $client = null)
209
    {
210
        $warnUntrusted = $this->getParameter('warn_untrusted');
211
212
        if ($client) {
213
            $metadata = $this->getMetadata($client);
214
215
            if ($metadata && $metadata->getOrganization() instanceof OrganizationInterface) {
216
                $isTrusted = $metadata->getOrganization()->isTrusted();
217
            } else {
218
                $isTrusted = false;
219
            }
220
        } else {
221
            $isTrusted = false;
222
        }
223
224
        if ($isTrusted || !$warnUntrusted) {
225
            return false; // do not warn
226
        }
227
228
        return true; // warn
229
    }
230
231
    private function getMetadata(ClientInterface $client = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
232
    {
233
        if (!$client) {
234
            return null;
235
        }
236
237
        $repo = $this->getDoctrine()->getRepository('LoginCidadaoOpenIDBundle:ClientMetadata');
238
239
        return $repo->findOneBy(['client' => $client]);
240
    }
241
242
    /**
243
     * @return SectorIdentifierUriChecker
244
     */
245
    private function getSectorIdentifierUriChecker()
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
246
    {
247
        return $this->get('checker.sector_identifier_uri');
248
    }
249
250
    /**
251
     * @return object|Server
252
     */
253
    private function getOAuth2Server()
254
    {
255
        return $this->get('oauth2.server');
256
    }
257
258
    /**
259
     * @param array $scopes
260
     * @return array
261
     */
262
    private function removeRemoteScope(array $scopes)
263
    {
264
        return array_filter($scopes, function ($scope) {
265
            if (preg_match('/^tag:/', $scope) === 1) {
266
                return false;
267
            }
268
269
            return true;
270
        });
271
    }
272
}
273