Failed Conditions
Push — issue#666 ( f415d0...521a08 )
by Guilherme
12:02
created

ClientRegistrationController::getHost()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 Doctrine\DBAL\Exception\UniqueConstraintViolationException;
14
use LoginCidadao\OAuthBundle\Entity\Client;
15
use JMS\Serializer\SerializationContext;
16
use LoginCidadao\OAuthBundle\Model\ClientInterface;
17
use LoginCidadao\OpenIDBundle\Manager\ClientManager;
18
use Symfony\Component\HttpFoundation\Request;
19
use FOS\RestBundle\Controller\FOSRestController;
20
use FOS\RestBundle\Controller\Annotations as REST;
21
use LoginCidadao\OpenIDBundle\Entity\ClientMetadata;
22
use LoginCidadao\OpenIDBundle\Form\ClientMetadataForm;
23
use LoginCidadao\OpenIDBundle\Exception\DynamicRegistrationException;
24
25
/**
26
 * Class ClientRegistrationController
27
 * @package LoginCidadao\OpenIDBundle\Controller
28
 * @codeCoverageIgnore
29
 */
30
class ClientRegistrationController extends FOSRestController
31
{
32
33
    /**
34
     * @REST\Post("/openid/connect/register", name="oidc_dynamic_registration", defaults={"_format"="json"})
35
     * @REST\View(templateVar="client")
36
     */
37
    public function registerAction(Request $request)
38
    {
39
        $this->parseJsonRequest($request);
40
        $clientManager = $this->getClientManager();
41
42
        $data = new ClientMetadata();
43
        $form = $this->createForm(new ClientMetadataForm($clientManager), $data, ['cascade_validation' => true]);
44
45
        $form->handleRequest($request);
46
        if ($form->isValid()) {
47
            $metadata = $form->getData();
48
            try {
49
                $client = $clientManager->register($metadata);
50
            } catch (UniqueConstraintViolationException $e) {
51
                $error = new DynamicRegistrationException('Client already exists', 400);
52
53
                return $this->view($error->getData(), $error->getCode());
54
            }
55
56
            return $this->view($metadata->fromClient($client), 201);
57
        } else {
58
            $error = $this->handleFormErrors($form->getErrors(true));
59
60
            return $this->view($error->getData(), 400);
61
        }
62
    }
63
64
    /**
65
     * @REST\Get("/openid/connect/register/{clientId}", name="oidc_get_client_details", defaults={"_format"="json"})
66
     * @REST\View(templateVar="client")
67
     */
68
    public function getDetailsAction(Request $request, $clientId)
69
    {
70
        try {
71
            $client = $this->getClientOr404($clientId);
72
        } catch (DynamicRegistrationException $e) {
73
            return $this->view($e->getData(), 400);
74
        }
75
        $this->checkRegistrationAccessToken($request, $client);
76
77
        $context = SerializationContext::create()->setGroups("client_metadata");
78
79
        $view = $this->view($client->getMetadata())->setSerializationContext($context);
80
81
        return $this->handleView($view);
82
    }
83
84
    /**
85
     * @param \Symfony\Component\Form\FormError[] $errors
86
     * @return DynamicRegistrationException
87
     */
88
    private function handleFormErrors($errors)
89
    {
90
        foreach ($errors as $error) {
91
            $cause = $error->getCause();
92
            $value = $cause->getInvalidValue();
93
            $propertyRegex = '/^data\\.([a-zA-Z0-9_]+).*$/';
94
            $property = preg_replace(
95
                $propertyRegex,
96
                '$1',
97
                $cause->getPropertyPath()
98
            );
99
            //$property      = str_replace('data.', '', $cause->getPropertyPath());
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
100
101
            switch ($property) {
102
                case 'redirect_uris':
103
                    return new DynamicRegistrationException(
104
                        'Invalid redirect URIs: '.$cause->getMessage(),
105
                        DynamicRegistrationException::ERROR_INVALID_REDIRECT_URI
106
                    );
107
                case 'sector_identifier_uri':
108
                    return new DynamicRegistrationException(
109
                        "Invalid value for '{$property}': {$cause->getMessage()}",
110
                        DynamicRegistrationException::ERROR_INVALID_CLIENT_METADATA
111
                    );
112
                default:
113
                    return new DynamicRegistrationException(
114
                        "Invalid value for '{$property}'='{$value}': {$cause->getMessage()}",
115
                        DynamicRegistrationException::ERROR_INVALID_CLIENT_METADATA
116
                    );
117
            }
118
        }
119
    }
120
121
    private function parseJsonRequest(Request $request)
122
    {
123
        $request->setFormat('json', 'application/json');
124
        if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
125
            $data = json_decode($request->getContent(), true);
126
            $request->request->replace(is_array($data) ? $data : []);
127
        }
128
    }
129
130
    /**
131
     * @param string $clientId
132
     * @return ClientInterface
133
     */
134
    private function getClientOr404($clientId)
135
    {
136
        /** @var ClientInterface|null $client */
137
        $client = $this->getClientManager()->getClientById($clientId);
138
139
        if (!$client instanceof ClientInterface) {
140
            throw $this->createNotFoundException('Client not found.');
141
        }
142
143
        return $client;
144
    }
145
146
    private function checkRegistrationAccessToken(Request $request, Client $client)
147
    {
148
        $raw = $request->get(
149
            'access_token',
150
            $request->headers->get('authorization')
151
        );
152
153
        $token = str_replace('Bearer ', '', $raw);
154
        $metadata = $client->getMetadata();
155
        if (!$token || $metadata->getRegistrationAccessToken() !== $token) {
156
            throw $this->createAccessDeniedException();
157
        }
158
    }
159
160
    /**
161
     * @return ClientManager|object
162
     */
163
    private function getClientManager()
164
    {
165
        return $this->get('lc.client_manager');
166
    }
167
}
168