Failed Conditions
Push — issue#767 ( 20b3b1 )
by Guilherme
10:48
created

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