Completed
Push — feature/use-authn-request-acs-... ( c5e9ea...2f048b )
by
unknown
04:29 queued 02:17
created

ResponseContext   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 273
Duplicated Lines 4.4 %

Coupling/Cohesion

Components 3
Dependencies 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 30
c 1
b 0
f 0
lcom 3
cbo 6
dl 12
loc 273
rs 10

22 Methods

Rating   Name   Duplication   Size   Complexity  
A getDestination() 0 6 1
A getDestinationForAdfs() 0 6 1
A getIssuer() 0 4 1
A getIssueInstant() 0 4 1
A getInResponseTo() 0 4 1
A getExpectedInResponseTo() 0 4 1
A getRequiredLoa() 0 4 1
A getIdentityProvider() 0 4 1
A getServiceProvider() 0 10 2
A getRelayState() 0 4 1
B saveAssertion() 0 23 4
A reconstituteAssertion() 0 8 1
A getIdentityNameId() 0 4 1
A getNormalizedSchacHomeOrganization() 0 6 1
A getAuthenticatingIdp() 0 18 4
A saveSelectedSecondFactor() 0 6 1
A getSelectedSecondFactor() 0 4 1
A markSecondFactorVerified() 0 4 1
A isSecondFactorVerified() 0 4 2
A getResponseAction() 0 4 1
A responseSent() 0 5 1
A __construct() 12 12 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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\GatewayBundle\Saml;
20
21
use DateTime;
22
use DateTimeZone;
23
use DOMDocument;
24
use Psr\Log\LoggerInterface;
25
use SAML2\Assertion;
26
use Surfnet\SamlBundle\Entity\IdentityProvider;
27
use Surfnet\StepupGateway\GatewayBundle\Entity\SecondFactor;
28
use Surfnet\StepupGateway\GatewayBundle\Entity\ServiceProvider;
29
use Surfnet\StepupGateway\GatewayBundle\Saml\Proxy\ProxyStateHandler;
30
use Surfnet\StepupGateway\GatewayBundle\Service\SamlEntityService;
31
32
class ResponseContext
33
{
34
    /**
35
     * @var IdentityProvider
36
     */
37
    private $hostedIdentityProvider;
38
39
    /**
40
     * @var \Surfnet\StepupGateway\GatewayBundle\Service\SamlEntityService
41
     */
42
    private $samlEntityService;
43
44
    /**
45
     * @var ProxyStateHandler
46
     */
47
    private $stateHandler;
48
49
    /**
50
     * @var LoggerInterface
51
     */
52
    private $logger;
53
54
    /**
55
     * @var DateTime
56
     */
57
    private $generationTime;
58
59
    /**
60
     * @var IdentityProvider|null
61
     */
62
    private $authenticatingIdp;
63
64
    /**
65
     * @var ServiceProvider
66
     */
67
    private $targetServiceProvider;
68
69 View Code Duplication
    public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
70
        IdentityProvider $identityProvider,
71
        SamlEntityService $samlEntityService,
72
        ProxyStateHandler $stateHandler,
73
        LoggerInterface $logger
74
    ) {
75
        $this->hostedIdentityProvider = $identityProvider;
76
        $this->samlEntityService      = $samlEntityService;
77
        $this->stateHandler           = $stateHandler;
78
        $this->logger                 = $logger;
79
        $this->generationTime         = new DateTime('now', new DateTimeZone('UTC'));
80
    }
81
82
    /**
83
     * @return string
84
     */
85
    public function getDestination()
86
    {
87
        $requestAcsUrl = $this->stateHandler->getRequestAssertionConsumerServiceUrl();
88
89
        return $this->getServiceProvider()->determineAcsLocation($requestAcsUrl, $this->logger);
90
    }
91
92
    /**
93
     * @return string
94
     */
95
    public function getDestinationForAdfs()
96
    {
97
        $requestAcsUrl = $this->stateHandler->getRequestAssertionConsumerServiceUrl();
98
99
        return $this->getServiceProvider()->determineAcsLocationForAdfs($requestAcsUrl);
100
    }
101
102
    /**
103
     * @return null|string
104
     */
105
    public function getIssuer()
106
    {
107
        return $this->hostedIdentityProvider->getEntityId();
108
    }
109
110
    /**
111
     * @return int
112
     */
113
    public function getIssueInstant()
114
    {
115
        return $this->generationTime->getTimestamp();
116
    }
117
118
    /**
119
     * @return null|string
120
     */
121
    public function getInResponseTo()
122
    {
123
        return $this->stateHandler->getRequestId();
124
    }
125
126
    /**
127
     * @return null|string
128
     */
129
    public function getExpectedInResponseTo()
130
    {
131
        return $this->stateHandler->getGatewayRequestId();
132
    }
133
134
    /**
135
     * @return null|string
136
     */
137
    public function getRequiredLoa()
138
    {
139
        return $this->stateHandler->getRequiredLoaIdentifier();
140
    }
141
142
    /**
143
     * @return IdentityProvider
144
     */
145
    public function getIdentityProvider()
146
    {
147
        return $this->hostedIdentityProvider;
148
    }
149
150
    /**
151
     * @return null|ServiceProvider
152
     */
153
    public function getServiceProvider()
154
    {
155
        if (isset($this->targetServiceProvider)) {
156
            return $this->targetServiceProvider;
157
        }
158
159
        $serviceProviderId = $this->stateHandler->getRequestServiceProvider();
160
161
        return $this->targetServiceProvider = $this->samlEntityService->getServiceProvider($serviceProviderId);
162
    }
163
164
    /**
165
     * @return null|string
166
     */
167
    public function getRelayState()
168
    {
169
        return $this->stateHandler->getRelayState();
170
    }
171
172
    /**
173
     * @param Assertion $assertion
174
     */
175
    public function saveAssertion(Assertion $assertion)
176
    {
177
        // we pluck the NameId to make it easier to access it without having to reconstitute the assertion
178
        $nameId = $assertion->getNameId();
179
        if (!is_null($nameId->value)) {
180
            $this->stateHandler->saveIdentityNameId($nameId->value);
181
        }
182
183
        // same for the entityId of the authenticating Authority
184
        $authenticatingAuthorities = $assertion->getAuthenticatingAuthority();
185
        if (!empty($authenticatingAuthorities)) {
186
            $this->stateHandler->setAuthenticatingIdp(reset($authenticatingAuthorities));
187
        }
188
189
        // And also attempt to save the user's schacHomeOrganization
190
        $attributes = $assertion->getAttributes();
191
        if (!empty($attributes['urn:mace:terena.org:attribute-def:schacHomeOrganization'])) {
192
            $schacHomeOrganization = $attributes['urn:mace:terena.org:attribute-def:schacHomeOrganization'];
193
            $this->stateHandler->setSchacHomeOrganization(reset($schacHomeOrganization));
194
        }
195
196
        $this->stateHandler->saveAssertion($assertion->toXML()->ownerDocument->saveXML());
197
    }
198
199
    /**
200
     * @return Assertion
201
     */
202
    public function reconstituteAssertion()
203
    {
204
        $assertionAsXML    = $this->stateHandler->getAssertion();
205
        $assertionDocument = new DOMDocument();
206
        $assertionDocument->loadXML($assertionAsXML);
207
208
        return new Assertion($assertionDocument->documentElement);
209
    }
210
211
    /**
212
     * @return null|string
213
     */
214
    public function getIdentityNameId()
215
    {
216
        return $this->stateHandler->getIdentityNameId();
217
    }
218
219
    /**
220
     * Return the lower-cased schacHomeOrganization value from the assertion.
221
     *
222
     * Comparisons on SHO values should always be case insensitive. Stepup
223
     * configuration always contains SHO values lower-cased, so this getter
224
     * can be used to compare the SHO with configured values.
225
     *
226
     * @see StepUpAuthenticationService::resolveHighestRequiredLoa()
227
     *
228
     * @return null|string
229
     */
230
    public function getNormalizedSchacHomeOrganization()
231
    {
232
        return strtolower(
233
            $this->stateHandler->getSchacHomeOrganization()
234
        );
235
    }
236
237
    /**
238
     * @return null|IdentityProvider
239
     */
240
    public function getAuthenticatingIdp()
241
    {
242
        $entityId = $this->stateHandler->getAuthenticatingIdp();
243
244
        if (!$entityId) {
245
            return null;
246
        }
247
248
        if (isset($this->authenticatingIdp)) {
249
            return $this->authenticatingIdp;
250
        }
251
252
        $this->authenticatingIdp = $this->samlEntityService->hasIdentityProvider($entityId)
253
            ? $this->samlEntityService->getIdentityProvider($entityId)
254
            : null;
255
256
        return $this->authenticatingIdp;
257
    }
258
259
    /**
260
     * @param SecondFactor $secondFactor
261
     */
262
    public function saveSelectedSecondFactor(SecondFactor $secondFactor)
263
    {
264
        $this->stateHandler->setSelectedSecondFactorId($secondFactor->secondFactorId);
265
        $this->stateHandler->setSecondFactorVerified(false);
266
        $this->stateHandler->setPreferredLocale($secondFactor->displayLocale);
267
    }
268
269
    /**
270
     * @return null|string
271
     */
272
    public function getSelectedSecondFactor()
273
    {
274
        return $this->stateHandler->getSelectedSecondFactorId();
275
    }
276
277
    public function markSecondFactorVerified()
278
    {
279
        $this->stateHandler->setSecondFactorVerified(true);
280
    }
281
282
    /**
283
     * @return bool
284
     */
285
    public function isSecondFactorVerified()
286
    {
287
        return $this->stateHandler->getSelectedSecondFactorId() && $this->stateHandler->isSecondFactorVerified();
288
    }
289
290
    public function getResponseAction()
291
    {
292
        return $this->stateHandler->getResponseAction();
293
    }
294
295
    /**
296
     * Resets some state after the response is sent
297
     * (e.g. resets which second factor was selected and whether it was verified).
298
     */
299
    public function responseSent()
300
    {
301
        $this->stateHandler->setSelectedSecondFactorId(null);
302
        $this->stateHandler->setSecondFactorVerified(false);
303
    }
304
}
305