Completed
Push — master ( a3cce1...d6fbcc )
by Marcel
09:39
created

SsoController   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Test Coverage

Coverage 3.41%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 89
c 3
b 0
f 0
dl 0
loc 148
ccs 3
cts 88
cp 0.0341
rs 10
wmc 14

3 Methods

Rating   Name   Duplication   Size   Complexity  
B confirm() 0 48 6
B saml() 0 83 7
A __construct() 0 2 1
1
<?php
2
3
namespace App\Controller;
4
5
use App\Entity\ServiceProvider;
6
use App\Repository\ServiceProviderRepositoryInterface;
7
use App\Saml\AttributeValueProvider;
8
use App\Security\Voter\ServiceProviderVoter;
9
use App\Service\ServiceProviderConfirmationService;
10
use LightSaml\Binding\SamlPostResponse;
11
use LightSaml\Idp\Builder\Profile\WebBrowserSso\Idp\SsoIdpReceiveAuthnRequestProfileBuilder;
12
use LightSaml\SymfonyBridgeBundle\Bridge\Container\BuildContainer;
13
use SchulIT\LightSamlIdpBundle\Builder\Profile\WebBrowserSso\Idp\SsoIdpSendResponseProfileBuilderFactory;
14
use SchulIT\LightSamlIdpBundle\RequestStorage\RequestStorageInterface;
15
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
16
use Symfony\Component\HttpFoundation\RedirectResponse;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
20
use Symfony\Component\Routing\Annotation\Route;
21
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
22
23
class SsoController extends AbstractController {
24
25
    private const CSRF_TOKEN_ID = '_confirmation_token';
26
    private $confirmationService;
27
28 1
    public function __construct(ServiceProviderConfirmationService $confirmationService) {
29 1
        $this->confirmationService = $confirmationService;
30 1
    }
31
32
    /**
33
     * @Route("/idp/saml", name="idp_saml")
34
     */
35
    public function saml(RequestStorageInterface $requestStorage, AttributeValueProvider $attributeValueProvider,
36
                         SsoIdpReceiveAuthnRequestProfileBuilder $receiveBuilder,
37
                         SsoIdpSendResponseProfileBuilderFactory $sendResponseBuilder,
38
                         CsrfTokenManagerInterface $tokenManager, ServiceProviderRepositoryInterface $serviceProviderRepository,
39
                         BuildContainer $buildContainer) {
40
        if($requestStorage->has() !== true) {
41
            return $this->redirectToRoute('dashboard');
42
        }
43
44
        $requestStorage->load();
45
46
        $context = $receiveBuilder->buildContext();
47
        $action = $receiveBuilder->buildAction();
48
49
        $action->execute($context);
50
51
        $partyContext = $context->getPartyEntityContext();
52
        $endpoint = $context->getEndpoint();
53
        $message = $context->getInboundMessage();
54
55
        // check authorization
56
        $serviceProvider = $serviceProviderRepository
57
            ->findOneByEntityId($partyContext->getEntityId());
58
59
        if($serviceProvider === null) {
60
            throw new BadRequestHttpException('The issusing service provider does not exist.');
61
        }
62
63
        if(!$this->isGranted(ServiceProviderVoter::ENABLED, $serviceProvider)) {
64
            $requestStorage->clear();
65
66
            return $this->render('sso/denied.html.twig', [
67
                'service' => $serviceProvider
68
            ], new Response(null, Response::HTTP_FORBIDDEN));
69
        }
70
71
        $sendBuilder = $sendResponseBuilder->build(
72
            [new \LightSaml\Idp\Builder\Action\Profile\SingleSignOn\Idp\SsoIdpAssertionActionBuilder($buildContainer)],
73
            $partyContext->getEntityDescriptor()->getEntityID()
74
        );
75
        $sendBuilder->setPartyEntityDescriptor($partyContext->getEntityDescriptor());
76
        $sendBuilder->setPartyTrustOptions($partyContext->getTrustOptions());
77
        $sendBuilder->setEndpoint($endpoint);
78
        $sendBuilder->setMessage($message);
79
80
        $context = $sendBuilder->buildContext();
81
        $action = $sendBuilder->buildAction();
82
83
        $action->execute($context);
84
85
        $requestStorage->clear();
86
87
        $response = $context->getHttpResponseContext()->getResponse();
88
89
        $type = $this->confirmationService->needsConfirmation($this->getUser(), $serviceProvider) ? 'confirm' : 'redirect';
90
        $token = $tokenManager->getToken(static::CSRF_TOKEN_ID);
91
92
        if ($response instanceof SamlPostResponse) {
93
            $data = $response->getData();
94
            $destination = $response->getDestination();
95
            $attributes = $attributeValueProvider->getValuesForUser($this->getUser(), $serviceProvider->getEntityId());
96
97
            return $this->render('sso/' . $type . '_post.html.twig', [
98
                'service' => $serviceProvider,
99
                'data' => $data,
100
                'destination' => $destination,
101
                'attributes' => $attributes,
102
                'csrf_token' => $token->getValue()
103
            ]);
104
        } else if ($response instanceof RedirectResponse) {
105
            $destination = $response->getTargetUrl();
106
107
            $attributes = $attributeValueProvider->getValuesForUser($this->getUser(), $serviceProvider->getEntityId());
108
109
            return $this->render('sso/' . $type . '_uri.html.twig', [
110
                'service' => $serviceProvider,
111
                'destination' => $destination,
112
                'attributes' => $attributes,
113
                'csrf_token' => $token->getValue()
114
            ]);
115
        }
116
117
        throw new \RuntimeException('Unsupported Binding!');
118
    }
119
120
    /**
121
     * @Route("/idp/saml/confirm/{uuid}", name="confirm_redirect")
122
     */
123
    public function confirm(Request $request, ServiceProvider $serviceProvider, AttributeValueProvider $attributeValueProvider, CsrfTokenManagerInterface $tokenManager) {
124
        $type = $request->request->get('type');
125
        $destination = $request->request->get('destination');
126
        $data = $request->request->get('data', [ ]);
127
        $token = $request->request->get('_csrf_token');
128
129
        if($this->isCsrfTokenValid(static::CSRF_TOKEN_ID, $token) !== true) {
130
            $token = $tokenManager->refreshToken(static::CSRF_TOKEN_ID);
131
132
            if ($type === 'post') {
133
                $attributes = $attributeValueProvider->getValuesForUser($this->getUser(), $serviceProvider->getEntityId());
134
135
                return $this->render('sso/confirm_post.html.twig', [
136
                    'service' => $serviceProvider,
137
                    'data' => $data,
138
                    'destination' => $destination,
139
                    'attributes' => $attributes,
140
                    'csrf_token' => $token->getValue()
141
                ]);
142
            } else if ($type === 'redirect') {
143
                $attributes = $attributeValueProvider->getValuesForUser($this->getUser(), $serviceProvider->getEntityId());
144
145
                return $this->render('sso/confirm_uri.html.twig', [
146
                    'service' => $serviceProvider,
147
                    'destination' => $destination,
148
                    'attributes' => $attributes,
149
                    'csrf_token' => $token->getValue()
150
                ]);
151
            }
152
        } else {
153
            $this->confirmationService->saveConfirmation($this->getUser(), $serviceProvider);
154
155
            if($type === 'post') {
156
                return $this->render('sso/redirect_post.html.twig', [
157
                    'service' => $serviceProvider,
158
                    'data' => $data,
159
                    'destination' => $destination
160
                ]);
161
            } else if($type === 'redirect') {
162
                return $this->render('sso/redirect_uri.html.twig', [
163
                    'service' => $serviceProvider,
164
                    'destination' => $destination,
165
                    'csrf_token' => $token->getValue()
166
                ]);
167
            }
168
        }
169
170
        return $this->redirectToRoute('dashboard');
171
    }
172
}