Completed
Pull Request — develop (#225)
by
unknown
09:12 queued 07:20
created

MockRemoteVetController::ssoAction()   B

Complexity

Conditions 7
Paths 19

Size

Total Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 52
rs 8.1138
c 0
b 0
f 0
cc 7
nc 19
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright 2019 SURFnet B.V.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
namespace Surfnet\StepupSelfService\SelfServiceBundle\Mock\RemoteVetting;
19
20
use Exception;
21
use SAML2\Constants;
22
use SAML2\Response as SamlResponse;
23
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Response;
26
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
27
use Twig\Environment;
28
29
class MockRemoteVetController extends Controller
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...e\Controller\Controller has been deprecated with message: since Symfony 4.2, use "Symfony\Bundle\FrameworkBundle\Controller\AbstractController" instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
30
{
31
    /**
32
     * @var MockGateway
33
     */
34
    private $mockGateway;
35
    /**
36
     * @var Environment
37
     */
38
    private $twig;
39
40
    public function __construct(MockGateway $mockGateway, Environment $twig)
41
    {
42
        $this->mockGateway = $mockGateway;
43
        $this->twig = $twig;
44
    }
45
46
    /**
47
     * This is the sso action used to mock a RV IdP callout
48
     *
49
     * @param Request $request
50
     * @return string|Response
51
     */
52
    public function ssoAction(Request $request)
53
    {
54
        if (!in_array($this->getParameter('kernel.environment'), ['test', 'dev'])) {
55
            throw new Exception('Invalid environment encountered.');
56
        }
57
58
        try {
59
            $status = $request->get('status');
60
61
            // Check binding
62
            if (!$request->isMethod(Request::METHOD_GET) &&  !$status) {
63
                throw new BadRequestHttpException(sprintf(
64
                    'Could not receive AuthnRequest from HTTP Request: expected a GET method, got %s',
65
                    $request->getMethod()
66
                ));
67
            }
68
69
            // show possible saml response status to return
70
            if (!$status) {
71
                // Present response
72
                $body = $this->twig->render(
73
                    'dev/mock-acs.html.twig',
74
                    [
75
                        'action' => $request->getUri(),
76
                        'responses' => [
77
                            'success',
78
                            'user-cancelled',
79
                            'unknown',
80
                        ],
81
                    ]
82
                );
83
                return new Response($body);
84
            }
85
86
            // Parse available responses
87
            $response = $this->getSelectedResponse($request, $status);
88
89
            // Present response
90
            $body = $this->twig->render(
91
                'dev/mock-acs-post.html.twig',
92
                [
93
                    'response' => $response,
94
                ]
95
            );
96
97
            return new Response($body);
98
        } catch (BadRequestHttpException $e) {
99
            return new Response($e->getMessage(), $e->getStatusCode());
100
        } catch (Exception $e) {
101
            return new Response($e->getMessage(), 500);
102
        }
103
    }
104
105
    /**
106
     * @param Request $request
107
     * @param string $status
108
     * @return array
109
     */
110
    private function getSelectedResponse(Request $request, $status)
111
    {
112
        switch (true) {
113
            case ($status == 'success'):
114
                // Parse successful
115
                $rawAttributes = $request->get('attributes');
116
                $attributes = $this->parseAttributes($rawAttributes);
117
118
                $samlResponse = $this->mockGateway->handleSsoSuccess($request, $this->getFullRequestUri($request), $attributes);
119
                return $this->getResponseData($request, $samlResponse);
120
121 View Code Duplication
            case ($status == 'user-cancelled'):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
122
                // Parse user cancelled
123
                $samlResponse = $this->mockGateway->handleSsoFailure(
124
                    $request,
125
                    $this->getFullRequestUri($request),
126
                    Constants::STATUS_RESPONDER,
127
                    Constants::STATUS_AUTHN_FAILED,
128
                    'Authentication cancelled by user'
129
                );
130
                return $this->getResponseData($request, $samlResponse);
131
132 View Code Duplication
            case ($status == 'unknown'):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
133
                // Parse unknown
134
                $samlResponse = $this->mockGateway->handleSsoFailure(
135
                    $request,
136
                    $this->getFullRequestUri($request),
137
                    Constants::STATUS_RESPONDER,
138
                    Constants::STATUS_AUTHN_FAILED
139
                );
140
                return $this->getResponseData($request, $samlResponse);
141
            default:
142
                throw new BadRequestHttpException(sprintf(
143
                    'Could not create a response for status %s',
144
                    $status
145
                ));
146
        }
147
    }
148
149
    /**
150
     * @param Request $request
151
     * @param SamlResponse $samlResponse
152
     * @return array
153
     */
154
    private function getResponseData(Request $request, SamlResponse $samlResponse)
155
    {
156
        $rawResponse = $this->mockGateway->parsePostResponse($samlResponse);
157
158
        return [
159
            'acu' => $samlResponse->getDestination(),
160
            'rawResponse' => $rawResponse,
161
            'encodedResponse' => base64_encode($rawResponse),
162
            'relayState' => $request->request->get(MockGateway::PARAMETER_RELAY_STATE),
163
        ];
164
    }
165
166
    /**
167
     * @param Request $request
168
     * @return string
169
     */
170
    private function getFullRequestUri(Request $request)
171
    {
172
        return $request->getSchemeAndHttpHost() . $request->getBasePath() . $request->getPathInfo();
173
    }
174
175
    /**
176
     * @param string $data
177
     * @return array
178
     */
179
    private function parseAttributes($data)
180
    {
181
        json_decode($data);
182
        if (json_last_error() !== JSON_ERROR_NONE) {
183
            throw new BadRequestHttpException(sprintf(
184
                'Could not parse the attributes because no valid json was given %s',
185
                $data
186
            ));
187
        }
188
189
        $data = json_decode($data, true);
190
191
        $result = [];
192
        foreach ($data as $attr) {
193
            if (!array_key_exists('name', $attr)) {
194
                throw new BadRequestHttpException(sprintf(
195
                    'Could not parse the attributes because no valid name was given %s',
196
                    json_encode($data)
197
                ));
198
            }
199
            if (!array_key_exists('value', $attr)) {
200
                throw new BadRequestHttpException(sprintf(
201
                    'Could not parse the attributes because no valid value was given %s',
202
                    json_encode($data)
203
                ));
204
            }
205
206
            if (!is_array($attr['value'])) {
207
                throw new BadRequestHttpException(sprintf(
208
                    'Could not parse the attributes because a value should be an array with strings %s',
209
                    json_encode($data)
210
                ));
211
            }
212
213
            foreach ($attr['value'] as $value) {
214
                if (!is_string($value)) {
215
                    throw new BadRequestHttpException(sprintf(
216
                        'Could not parse the attributes because if a value is an array it should consist of strings %s',
217
                        json_encode($data)
218
                    ));
219
                }
220
            }
221
222
            $result[$attr['name']] = $attr['value'];
223
        }
224
225
        return $result;
226
    }
227
}
228