Completed
Push — schachomeorg-case-insensitive-... ( bff6c9 )
by
unknown
02:15
created

ResponseContext::getSchacHomeOrganization()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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