Passed
Push — issue#767 ( 376594...d97dbe )
by Guilherme
08:41
created

ClientRegistrationController::parseJsonRequest()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 1
dl 0
loc 6
ccs 5
cts 5
cp 1
crap 3
rs 9.4285
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
class ClientRegistrationController extends FOSRestController
26
{
27
28
    /**
29
     * @REST\Post("/openid/connect/register", name="oidc_dynamic_registration", defaults={"_format"="json"})
30
     * @REST\View(templateVar="client")
31
     */
32 3
    public function registerAction(Request $request)
33
    {
34 3
        $this->parseJsonRequest($request);
35 3
        $clientManager = $this->getClientManager();
36
37 3
        $data = new ClientMetadata();
38 3
        $form = $this->createForm(new ClientMetadataForm($clientManager), $data, ['cascade_validation' => true]);
39
40 3
        $form->handleRequest($request);
41 3
        if ($form->isValid()) {
42 1
            $metadata = $form->getData();
43
            try {
44 1
                $client = $clientManager->register($metadata);
45
            } catch (UniqueConstraintViolationException $e) {
46
                $error = new DynamicRegistrationException('Client already exists', 400);
47
48
                return $this->view($error->getData(), $error->getCode());
49
            }
50
51 1
            return $this->view($metadata->fromClient($client), 201);
52
        } else {
53 2
            $error = $this->handleFormErrors($form->getErrors(true));
54
55 2
            return $this->view($error->getData(), 400);
56
        }
57
    }
58
59
    /**
60
     * @REST\Get("/openid/connect/register/{clientId}", name="oidc_get_client_details", defaults={"_format"="json"})
61
     * @REST\View(templateVar="client")
62
     */
63
    public function getDetailsAction(Request $request, $clientId)
64
    {
65
        try {
66
            $client = $this->getClientOr404($clientId);
67
        } catch (DynamicRegistrationException $e) {
68
            return $this->view($e->getData(), 400);
69
        }
70
        $this->checkRegistrationAccessToken($request, $client);
71
72
        $context = SerializationContext::create()->setGroups("client_metadata");
73
74
        $view = $this->view($client->getMetadata())->setSerializationContext($context);
75
76
        return $this->handleView($view);
77
    }
78
79
    /**
80
     * @param \Symfony\Component\Form\FormError[] $errors
81
     * @return DynamicRegistrationException
82
     */
83 2
    private function handleFormErrors($errors)
84
    {
85 2
        foreach ($errors as $error) {
86 2
            $cause = $error->getCause();
87 2
            $value = $cause->getInvalidValue();
88 2
            $propertyRegex = '/^data\\.([a-zA-Z0-9_]+).*$/';
89 2
            $property = preg_replace(
90 2
                $propertyRegex,
91 2
                '$1',
92 2
                $cause->getPropertyPath()
93
            );
94
            //$property      = str_replace('data.', '', $cause->getPropertyPath());
95
96
            switch ($property) {
97 2
                case 'redirect_uris':
98 1
                    return new DynamicRegistrationException(
99 1
                        'Invalid redirect URIs: '.$cause->getMessage(),
100 1
                        DynamicRegistrationException::ERROR_INVALID_REDIRECT_URI
101
                    );
102 1
                case 'sector_identifier_uri':
103
                    return new DynamicRegistrationException(
104
                        "Invalid value for '{$property}': {$cause->getMessage()}",
105
                        DynamicRegistrationException::ERROR_INVALID_CLIENT_METADATA
106
                    );
107
                default:
108 1
                    return new DynamicRegistrationException(
109 1
                        "Invalid value for '{$property}'='{$value}': {$cause->getMessage()}",
110 1
                        DynamicRegistrationException::ERROR_INVALID_CLIENT_METADATA
111
                    );
112
            }
113
        }
114
    }
115
116 3
    private function parseJsonRequest(Request $request)
117
    {
118 3
        $request->setFormat('json', 'application/json');
119 3
        if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
120 3
            $data = json_decode($request->getContent(), true);
121 3
            $request->request->replace(is_array($data) ? $data : []);
122
        }
123 3
    }
124
125
    /**
126
     * @param string $clientId
127
     * @return ClientInterface
128
     */
129
    private function getClientOr404($clientId)
130
    {
131
        $client = $this->getClientManager()->getClientById($clientId);
132
133
        if (!$client instanceof ClientInterface) {
0 ignored issues
show
introduced by
$client is always a sub-type of LoginCidadao\OAuthBundle\Model\ClientInterface.
Loading history...
134
            throw $this->createNotFoundException('Client not found.');
135
        }
136
137
        return $client;
138
    }
139
140
    private function checkRegistrationAccessToken(Request $request, Client $client)
141
    {
142
        $raw = $request->get(
143
            'access_token',
144
            $request->headers->get('authorization')
145
        );
146
147
        $token = str_replace('Bearer ', '', $raw);
148
        $metadata = $client->getMetadata();
149
        if (!$token || $metadata->getRegistrationAccessToken() !== $token) {
150
            throw $this->createAccessDeniedException();
151
        }
152
    }
153
154
    /**
155
     * @return ClientManager|object
156
     */
157 3
    private function getClientManager()
158
    {
159 3
        return $this->get('lc.client_manager');
160
    }
161
}
162