Completed
Push — release-2.x ( 24442d...1c8792 )
by
unknown
04:35 queued 02:29
created

SecondFactorOnlyController   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 14
c 7
b 0
f 0
lcom 1
cbo 7
dl 0
loc 197
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
C ssoAction() 0 94 7
B respondAction() 0 84 6
A getResponseContext() 0 4 1
1
<?php
2
3
/**
4
 * Copyright 2014 SURFnet bv
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupGateway\SecondFactorOnlyBundle\Controller;
20
21
use Exception;
22
use Surfnet\SamlBundle\SAML2\AuthnRequest;
23
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Saml\ResponseFactory;
24
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Service\LoaAliasLookupService;
25
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
26
use Symfony\Component\HttpFoundation\Request;
27
use Symfony\Component\HttpFoundation\Response;
28
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
29
30
class SecondFactorOnlyController extends Controller
31
{
32
    /**
33
     * @param Request $httpRequest
34
     * @return Response
35
     */
36
    public function ssoAction(Request $httpRequest)
37
    {
38
        $logger = $this->get('logger');
39
40
        if (!$this->getParameter('second_factor_only')) {
41
            $logger->notice('Access to ssoAction denied, second_factor_only parameter set to false.');
42
43
            throw $this->createAccessDeniedException('Second Factor Only feature is disabled');
44
        }
45
46
        $logger->notice('Received AuthnRequest on second-factor-only endpoint, started processing');
47
48
        /** @var \Surfnet\SamlBundle\Http\RedirectBinding $redirectBinding */
49
        $bindingFactory = $this->get('second_factor_only.http.binding_factory');
50
51
        try {
52
            $logger->notice('Determine what type of Binding is used in the Request');
53
            $binding = $bindingFactory->build($httpRequest);
54
55
            /** @var \Surfnet\SamlBundle\SAML2\ReceivedAuthnRequest $originalRequest */
56
            $originalRequest = $binding->receiveSignedAuthnRequestFrom($httpRequest);
57
        } catch (Exception $e) {
58
            $logger->critical(sprintf('Could not process Request, error: "%s"', $e->getMessage()));
59
60
            return $this->render('SurfnetStepupGatewayGatewayBundle:Gateway:unrecoverableError.html.twig');
61
        }
62
63
        $originalRequestId = $originalRequest->getRequestId();
64
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
65
        $logger->notice(sprintf(
66
            'AuthnRequest processing complete, received AuthnRequest from "%s", request ID: "%s"',
67
            $originalRequest->getServiceProvider(),
68
            $originalRequest->getRequestId()
69
        ));
70
71
        // ADFS support
72
        $adfsHelper = $this->get('second_factor_only.adfs.request_helper');
73
        if ($adfsHelper->isAdfsRequest($httpRequest)) {
74
            $logger->notice('Received AuthnRequest from an ADFS');
75
            try {
76
                $httpRequest = $adfsHelper->transformRequest(
77
                    $httpRequest,
78
                    $originalRequest->getRequestId(),
79
                    $originalRequest->getAssertionConsumerServiceURL()
80
                );
81
            } catch (Exception $e) {
82
                $logger->critical(sprintf('Could not process ADFS Request, error: "%s"', $e->getMessage()));
83
                return $this->render('SurfnetStepupGatewayGatewayBundle:Gateway:unrecoverableError.html.twig');
84
            }
85
        }
86
87
        $stateHandler = $this->get('gateway.proxy.state_handler');
88
        $stateHandler
89
            ->setRequestId($originalRequestId)
90
            ->setRequestServiceProvider($originalRequest->getServiceProvider())
91
            ->setRelayState($httpRequest->get(AuthnRequest::PARAMETER_RELAY_STATE, ''))
92
            ->setResponseAction('SurfnetStepupGatewaySecondFactorOnlyBundle:SecondFactorOnly:respond')
93
            ->setResponseContextServiceId('second_factor_only.response_context');
94
95
        // Check if the NameID is provided and we may use it.
96
        $nameId = $originalRequest->getNameId();
97
        $secondFactorOnlyNameIdValidator = $this->get('second_factor_only.validate_nameid')->with($logger);
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $secondFactorOnlyNameIdValidator exceeds the maximum configured length of 30.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
98
        $serviceProviderMayUseSecondFactorOnly = $secondFactorOnlyNameIdValidator->validate(
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $serviceProviderMayUseSecondFactorOnly exceeds the maximum configured length of 30.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
99
            $originalRequest->getServiceProvider(),
100
            $nameId
101
        );
102
103
        if (!$serviceProviderMayUseSecondFactorOnly) {
104
            /** @var \Surfnet\StepupGateway\GatewayBundle\Service\ResponseRenderingService $responseRendering */
105
            $responseRendering = $this->get('second_factor_only.response_rendering');
106
107
            return $responseRendering->renderRequesterFailureResponse($this->getResponseContext());
108
        }
109
110
        $stateHandler->saveIdentityNameId($nameId);
111
112
        // Check if the requested Loa is provided and supported.
113
        $loaId = $this->get('second_factor_only.loa_resolution')->with($logger)->resolve(
114
            $originalRequest->getAuthenticationContextClassRef()
115
        );
116
117
        if (empty($loaId)) {
118
            /** @var \Surfnet\StepupGateway\GatewayBundle\Service\ResponseRenderingService $responseRendering */
119
            $responseRendering = $this->get('second_factor_only.response_rendering');
120
121
            return $responseRendering->renderRequesterFailureResponse($this->getResponseContext());
122
        }
123
124
        $stateHandler->setRequiredLoaIdentifier($loaId);
125
126
        $logger->notice('Forwarding to second factor controller for loa determination and handling');
127
128
        return $this->forward('SurfnetStepupGatewayGatewayBundle:SecondFactor:selectSecondFactorForVerification');
129
    }
130
131
    /**
132
     * @return Response
133
     */
134
    public function respondAction()
135
    {
136
        $responseContext = $this->getResponseContext();
137
        $originalRequestId = $responseContext->getInResponseTo();
138
139
        $logger = $this->get('surfnet_saml.logger')->forAuthentication($originalRequestId);
140
141
        if (!$this->getParameter('second_factor_only')) {
142
            $logger->notice(sprintf(
143
                'Access to %s denied, second_factor_only parameter set to false.',
144
                __METHOD__
145
            ));
146
            throw $this->createAccessDeniedException('Second Factor Only feature disabled');
147
        }
148
149
        $logger->notice('Creating second-factor-only Response');
150
151
        $selectedSecondFactorUuid = $this->getResponseContext()->getSelectedSecondFactor();
152
        if (!$selectedSecondFactorUuid) {
153
            $logger->error(
154
                'Cannot verify possession of an unknown second factor'
155
            );
156
157
            throw new BadRequestHttpException('Cannot verify possession of an unknown second factor.');
158
        }
159
160
        if (!$responseContext->isSecondFactorVerified()) {
161
            $logger->error('Second factor was not verified');
162
            throw new BadRequestHttpException(
163
                'Cannot verify possession of an unknown second factor.'
164
            );
165
        }
166
167
        $secondFactor = $this->get('gateway.service.second_factor_service')
168
            ->findByUuid($selectedSecondFactorUuid);
169
        $secondFactorTypeService = $this->get('surfnet_stepup.service.second_factor_type');
170
        $grantedLoa = $this->get('surfnet_stepup.service.loa_resolution')
171
            ->getLoaByLevel($secondFactor->getLoaLevel($secondFactorTypeService));
172
173
        /** @var LoaAliasLookupService $loaAliasLookup */
174
        $loaAliasLookup = $this->get('second_factor_only.loa_alias_lookup');
175
        $authnContextClassRef = $loaAliasLookup->findAliasByLoa($grantedLoa);
176
177
        /** @var ResponseFactory $response_factory */
178
        $responseFactory = $this->get('second_factor_only.saml_response_factory');
179
        $response = $responseFactory->createSecondFactorOnlyResponse(
180
            $responseContext->getIdentityNameId(),
181
            $responseContext->getServiceProvider(),
182
            $authnContextClassRef
183
        );
184
185
        $responseContext->responseSent();
186
187
        $logger->notice(sprintf(
188
            'Responding to request "%s" with newly created response "%s"',
189
            $responseContext->getInResponseTo(),
190
            $response->getId()
191
        ));
192
193
        $responseRendering = $this->get('second_factor_only.response_rendering');
194
195
        $adfsHelper = $this->get('second_factor_only.adfs.response_helper');
196
        if ($adfsHelper->isAdfsResponse($originalRequestId)) {
197
            $xmlResponse = $responseRendering->getResponseAsXML($response);
198
            try {
199
                $adfsParameters = $adfsHelper->retrieveAdfsParameters();
200
            } catch (Exception $e) {
201
                $logger->critical(sprintf('Could not process ADFS Response parameters, error: "%s"', $e->getMessage()));
202
                return $this->render('SurfnetStepupGatewayGatewayBundle:Gateway:unrecoverableError.html.twig');
203
            }
204
205
            $logger->notice('Sending ACS Response to ADFS plugin');
206
            return $this->render(
207
                '@SurfnetStepupGatewaySecondFactorOnly/Adfs/consumeAssertion.html.twig',
208
                [
209
                    'acu' => $adfsParameters->getAssertionConsumerServiceUrl(),
210
                    'samlResponse' => $xmlResponse,
211
                    'context' => $adfsParameters->getContext(),
212
                    'authMethod' => $adfsParameters->getAuthMethod(),
213
                ]
214
            );
215
        }
216
        return $responseRendering->renderResponse($responseContext, $response);
217
    }
218
219
    /**
220
     * @return \Surfnet\StepupGateway\GatewayBundle\Saml\ResponseContext
221
     */
222
    public function getResponseContext()
223
    {
224
        return $this->get('second_factor_only.response_context');
225
    }
226
}
227