Failed Conditions
Push — issue#767 ( b130a3...4d8d6b )
by Guilherme
11:45 queued 06:37
created

ClientRegistrationController   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 135
ccs 0
cts 94
cp 0
rs 10
c 0
b 0
f 0
wmc 18

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getDetailsAction() 0 14 2
B handleFormErrors() 0 28 4
A checkRegistrationAccessToken() 0 11 3
A getClientOr404() 0 9 2
A parseJsonRequest() 0 6 3
A getClientManager() 0 3 1
B registerAction() 0 24 3
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
    public function registerAction(Request $request)
33
    {
34
        $this->parseJsonRequest($request);
35
        $clientManager = $this->getClientManager();
36
37
        $data = new ClientMetadata();
38
        $form = $this->createForm(new ClientMetadataForm($clientManager), $data, ['cascade_validation' => true]);
39
40
        $form->handleRequest($request);
41
        if ($form->isValid()) {
42
            $metadata = $form->getData();
43
            try {
44
                $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
            return $this->view($metadata->fromClient($client), 201);
52
        } else {
53
            $error = $this->handleFormErrors($form->getErrors(true));
54
55
            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
    private function handleFormErrors($errors)
84
    {
85
        foreach ($errors as $error) {
86
            $cause = $error->getCause();
87
            $value = $cause->getInvalidValue();
88
            $propertyRegex = '/^data\\.([a-zA-Z0-9_]+).*$/';
89
            $property = preg_replace(
90
                $propertyRegex,
91
                '$1',
92
                $cause->getPropertyPath()
93
            );
94
            //$property      = str_replace('data.', '', $cause->getPropertyPath());
95
96
            switch ($property) {
97
                case 'redirect_uris':
98
                    return new DynamicRegistrationException(
99
                        'Invalid redirect URIs: '.$cause->getMessage(),
100
                        DynamicRegistrationException::ERROR_INVALID_REDIRECT_URI
101
                    );
102
                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
                    return new DynamicRegistrationException(
109
                        "Invalid value for '{$property}'='{$value}': {$cause->getMessage()}",
110
                        DynamicRegistrationException::ERROR_INVALID_CLIENT_METADATA
111
                    );
112
            }
113
        }
114
    }
115
116
    private function parseJsonRequest(Request $request)
117
    {
118
        $request->setFormat('json', 'application/json');
119
        if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
120
            $data = json_decode($request->getContent(), true);
121
            $request->request->replace(is_array($data) ? $data : []);
122
        }
123
    }
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
    private function getClientManager()
158
    {
159
        return $this->get('lc.client_manager');
160
    }
161
}
162