ResponseRenderingService   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 50
dl 0
loc 129
rs 10
c 1
b 0
f 0
wmc 9

6 Methods

Rating   Name   Duplication   Size   Complexity  
A renderRequesterFailureResponse() 0 12 1
A renderUnprocessableResponse() 0 10 1
A renderResponse() 0 6 1
A __construct() 0 12 1
A getResponseAsXML() 0 3 1
A renderSamlResponse() 0 34 4
1
<?php
2
3
/**
4
 * Copyright 2016 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\GatewayBundle\Service;
20
21
use Psr\Log\LoggerInterface;
22
use SAML2\Constants;
23
use SAML2\Response as SAMLResponse;
24
use Surfnet\StepupGateway\GatewayBundle\Saml\ResponseBuilder;
25
use Surfnet\StepupGateway\GatewayBundle\Saml\ResponseContext;
26
use Surfnet\StepupGateway\GatewayBundle\Sso2fa\CookieService;
27
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Adfs\ResponseHelper;
28
use Symfony\Component\HttpFoundation\Request;
29
use Symfony\Component\HttpFoundation\Response;
30
use Twig\Environment;
31
32
final class ResponseRenderingService
33
{
34
    /**
35
     * @var ResponseBuilder
36
     */
37
    private $responseBuilder;
38
39
    /**
40
     * @var Environment
41
     */
42
    private $templateEngine;
43
44
    private $responseHelper;
45
46
    private $logger;
47
48
    /**
49
     * @var CookieService
50
     */
51
    private $ssoCookieService;
52
53
    public function __construct(
54
        ResponseBuilder $responseBuilder,
55
        ResponseHelper $responseHelper,
56
        Environment $templateEngine,
57
        CookieService $cookieService,
58
        LoggerInterface $logger
59
    ) {
60
        $this->responseBuilder = $responseBuilder;
61
        $this->responseHelper = $responseHelper;
62
        $this->templateEngine = $templateEngine;
63
        $this->logger = $logger;
64
        $this->ssoCookieService = $cookieService;
65
    }
66
67
    /**
68
     * @param ResponseContext $context
69
     * @return Response
70
     */
71
    public function renderRequesterFailureResponse(ResponseContext $context, Request $request)
72
    {
73
        return $this->renderResponse(
74
            $context,
75
            $this->responseBuilder
76
                ->createNewResponse($context)
77
                ->setResponseStatus(
78
                    Constants::STATUS_REQUESTER,
79
                    Constants::STATUS_REQUEST_UNSUPPORTED
80
                )
81
                ->get(),
82
            $request
83
        );
84
    }
85
86
    public function renderUnprocessableResponse(ResponseContext $context, Request $request)
87
    {
88
        return $this->renderSamlResponse(
89
            $context,
90
            'unprocessable_response',
91
            $request,
92
            $this->responseBuilder
93
                ->createNewResponse($context)
94
                ->setResponseStatus(Constants::STATUS_RESPONDER)
95
                ->get()
96
        );
97
    }
98
99
    public function renderResponse(
100
        ResponseContext $context,
101
        SAMLResponse $response,
102
        Request $request
103
    ) {
104
        return $this->renderSamlResponse($context, 'consume_assertion', $request, $response);
105
    }
106
107
    /**
108
     * Based on a $view that is specified in the second parameter, render
109
     * a Response object that either results in an unprocessable response
110
     * or a regular POST-back to the SPs ACS location.
111
     *
112
     * When responding to an ADFS authentication, the additional ADFS
113
     * parameters (Context, AuthMethod) are added to the POST response data.
114
     * In this case, the SAMLResponse parameter is prepended with an
115
     * underscore. And finally the ACS location the SAMLResponse wil be sent
116
     * to, is updated to use the ACS location set in the original AuthNRequest.
117
     */
118
    private function renderSamlResponse(
119
        ResponseContext $context,
120
        string $view,
121
        Request $request,
122
        SAMLResponse $response
123
    ): Response {
124
        $parameters = [
125
            'acu' => $context->getDestination(),
126
            'response' => $this->getResponseAsXML($response),
127
            'relayState' => $context->getRelayState()
128
        ];
129
        $inResponseTo = $context->getInResponseTo();
130
        if ($this->responseHelper->isAdfsResponse($inResponseTo)) {
131
            $logMessage = 'Responding with additional ADFS parameters, in response to request: "%s", with view: "%s"';
132
            if (!$response->isSuccess()) {
133
                $logMessage = 'Responding with an AuthnFailed SamlResponse with ADFS parameters, in response to AR: "%s", with view: "%s"';
134
            }
135
            $this->logger->notice(sprintf($logMessage, $inResponseTo, $view));
136
            $adfsParameters = $this->responseHelper->retrieveAdfsParameters();
137
            $parameters['adfs'] = $adfsParameters;
138
            $parameters['acu'] = $context->getDestinationForAdfs();
139
        }
140
141
        $httpResponse = (new Response)->setContent(
142
            $this->templateEngine->render(
143
                '@default/gateway/'.$view.'.html.twig',
144
                $parameters
145
            )
146
        );
147
148
        if ($response->isSuccess()) {
149
            $this->ssoCookieService->handleSsoOn2faCookieStorage($context, $request, $httpResponse);
150
        }
151
        return $httpResponse;
152
    }
153
154
    /**
155
     * @param SAMLResponse $response
156
     * @return string
157
     */
158
    public function getResponseAsXML(SAMLResponse $response)
159
    {
160
        return base64_encode($response->toUnsignedXML()->ownerDocument->saveXML());
0 ignored issues
show
Bug introduced by
The method saveXML() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

160
        return base64_encode($response->toUnsignedXML()->ownerDocument->/** @scrutinizer ignore-call */ saveXML());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
161
    }
162
}
163