Completed
Push — origin/release-2.x ( 3aa3b3 )
by
unknown
12:03
created

GssfController::renderInitiateForm()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.9713
c 0
b 0
f 0
cc 1
eloc 13
nc 1
nop 2
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\StepupSelfService\SelfServiceBundle\Controller\Registration;
20
21
use Exception;
22
use Surfnet\SamlBundle\Http\XMLResponse;
23
use Surfnet\SamlBundle\SAML2\AuthnRequestFactory;
24
use Surfnet\SamlBundle\SAML2\Response\Assertion\InResponseTo;
25
use Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\ViewConfig;
26
use Surfnet\StepupSelfService\SelfServiceBundle\Controller\Controller;
27
use Symfony\Component\HttpFoundation\Request;
28
use Symfony\Component\HttpFoundation\Response;
29
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
30
31
/**
32
 * Controls registration with Generic SAML Stepup Providers (GSSPs), yielding Generic SAML Second Factors (GSSFs).
33
 */
34
final class GssfController extends Controller
35
{
36
    /**
37
     * @param string $provider
38
     * @return array|Response
39
     */
40
    public function initiateAction($provider)
41
    {
42
        $this->assertSecondFactorEnabled($provider);
43
44
        return $this->renderInitiateForm($provider, []);
45
    }
46
47
    /**
48
     * @param string $provider
49
     * @return array|Response
50
     */
51
    public function authenticateAction($provider)
52
    {
53
        $this->assertSecondFactorEnabled($provider);
54
55
        $provider = $this->getProvider($provider);
56
57
        $authnRequest = AuthnRequestFactory::createNewRequest(
58
            $provider->getServiceProvider(),
59
            $provider->getRemoteIdentityProvider()
60
        );
61
62
        $stateHandler = $provider->getStateHandler();
63
        $stateHandler->setRequestId($authnRequest->getRequestId());
64
65
        /** @var \Surfnet\SamlBundle\Http\RedirectBinding $redirectBinding */
66
        $redirectBinding = $this->get('surfnet_saml.http.redirect_binding');
67
68
        $this->getLogger()->notice(sprintf(
69
            'Sending AuthnRequest with request ID: "%s" to GSSP "%s" at "%s"',
70
            $authnRequest->getRequestId(),
71
            $provider->getName(),
72
            $provider->getRemoteIdentityProvider()->getSsoUrl()
73
        ));
74
75
        return $redirectBinding->createRedirectResponseFor($authnRequest);
76
    }
77
78
    /**
79
     * @param Request $httpRequest
80
     * @param string  $provider
81
     * @return array|Response
82
     */
83
    public function consumeAssertionAction(Request $httpRequest, $provider)
84
    {
85
        $this->assertSecondFactorEnabled($provider);
86
87
        $provider = $this->getProvider($provider);
88
89
        $this->get('logger')->notice(
90
            sprintf('Received GSSP "%s" SAMLResponse through Gateway, attempting to process', $provider->getName())
91
        );
92
93
        try {
94
            /** @var \Surfnet\SamlBundle\Http\PostBinding $postBinding */
95
            $postBinding = $this->get('surfnet_saml.http.post_binding');
96
            $assertion = $postBinding->processResponse(
97
                $httpRequest,
98
                $provider->getRemoteIdentityProvider(),
99
                $provider->getServiceProvider()
100
            );
101
        } catch (Exception $exception) {
102
            $provider->getStateHandler()->clear();
103
104
            $this->getLogger()->error(
105
                sprintf('Could not process received Response, error: "%s"', $exception->getMessage())
106
            );
107
108
            return $this->renderInitiateForm(
109
                $provider->getName(),
110
                ['authenticationFailed' => true]
111
            );
112
        }
113
114
        $expectedResponseTo = $provider->getStateHandler()->getRequestId();
115
        $provider->getStateHandler()->clear();
116
117
        if (!InResponseTo::assertEquals($assertion, $expectedResponseTo)) {
118
            $this->getLogger()->critical(sprintf(
119
                'Received Response with unexpected InResponseTo, %s',
120
                ($expectedResponseTo ? 'expected "' . $expectedResponseTo . '"' : ' no response expected')
121
            ));
122
123
            return $this->renderInitiateForm(
124
                $provider->getName(),
125
                ['authenticationFailed' => true]
126
            );
127
        }
128
129
        $this->get('logger')->notice(
130
            sprintf('Processed GSSP "%s" SAMLResponse received through Gateway successfully', $provider->getName())
131
        );
132
133
        /** @var \Surfnet\StepupSelfService\SelfServiceBundle\Service\GssfService $service */
134
        $service = $this->get('surfnet_stepup_self_service_self_service.service.gssf');
135
        /** @var \Surfnet\SamlBundle\SAML2\Attribute\AttributeDictionary $attributeDictionary */
136
        $attributeDictionary = $this->get('surfnet_saml.saml.attribute_dictionary');
137
        $gssfId = $attributeDictionary->translate($assertion)->getNameID();
138
139
        $secondFactorId = $service->provePossession($this->getIdentity()->id, $provider->getName(), $gssfId);
140
141
        if ($secondFactorId) {
142
            $this->getLogger()->notice('GSSF possession has been proven successfully');
143
144
            return $this->redirectToRoute(
145
                'ss_registration_email_verification_email_sent',
146
                ['secondFactorId' => $secondFactorId]
147
            );
148
        }
149
150
        $this->getLogger()->error('Unable to prove GSSF possession');
151
152
        return $this->renderInitiateForm(
153
            $provider->getName(),
154
            ['proofOfPossessionFailed' => true]
155
        );
156
    }
157
158
    /**
159
     * @param string $provider
160
     * @return \Symfony\Component\HttpFoundation\Response
161
     */
162
    public function metadataAction($provider)
163
    {
164
        $this->assertSecondFactorEnabled($provider);
165
166
        $provider = $this->getProvider($provider);
167
168
        /** @var \Surfnet\SamlBundle\Metadata\MetadataFactory $factory */
169
        $factory = $this->get('gssp.provider.' . $provider->getName() . '.metadata.factory');
170
171
        return new XMLResponse($factory->generate());
172
    }
173
174
    /**
175
     * @param string $provider
176
     * @return \Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\Provider
177
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
178
     */
179
    private function getProvider($provider)
180
    {
181
        /** @var \Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\ProviderRepository $providerRepository */
182
        $providerRepository = $this->get('gssp.provider_repository');
183
184
        if (!$providerRepository->has($provider)) {
185
            $this->get('logger')->info(sprintf('Requested GSSP "%s" does not exist or is not registered', $provider));
186
187
            throw new NotFoundHttpException('Requested provider does not exist');
188
        }
189
190
        return $providerRepository->get($provider);
191
    }
192
193
    /**
194
     * @return \Psr\Log\LoggerInterface
195
     */
196
    private function getLogger()
197
    {
198
        return $this->get('logger');
199
    }
200
201
    /**
202
     * @param string $provider
203
     * @param array $parameters
204
     * @return Response
205
     */
206
    private function renderInitiateForm($provider, array $parameters = [])
207
    {
208
        /** @var ViewConfig $secondFactorConfig */
209
        $secondFactorConfig = $this->get("gssp.view_config.{$provider}");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $provider instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
210
211
        $form = $this->createForm(
212
            'ss_initiate_gssf',
213
            null,
214
            [
215
                'provider' => $provider,
216
                /** @Ignore from translation message extraction */
217
                'label' => $secondFactorConfig->getInitiateButton()
218
            ]
219
        );
220
        /** @var ViewConfig $secondFactorConfig */
221
        $templateParameters = array_merge(
222
            $parameters,
223
            ['form' => $form->createView(), 'provider' => $provider, 'secondFactorConfig' => $secondFactorConfig]
224
        );
225
        return $this->render(
226
            'SurfnetStepupSelfServiceSelfServiceBundle:Registration/Gssf:initiate.html.twig',
227
            $templateParameters
228
        );
229
    }
230
}
231