ProxyResponseFactory::createNewAuthnResponse()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 2
dl 0
loc 12
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Copyright 2015 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\SamlStepupProviderBundle\Saml;
20
21
use DateInterval;
22
use DateTime;
23
use DateTimeZone;
24
use Psr\Log\LoggerInterface;
25
use SAML2\Assertion;
26
use SAML2\Constants;
27
use SAML2\Response;
28
use SAML2\Response as SAMLResponse;
29
use SAML2\XML\saml\Issuer;
30
use SAML2\XML\saml\SubjectConfirmation;
31
use SAML2\XML\saml\SubjectConfirmationData;
32
use Surfnet\SamlBundle\Entity\IdentityProvider;
33
use Surfnet\StepupGateway\GatewayBundle\Saml\AssertionSigningService;
34
35
/**
36
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
37
 */
38
class ProxyResponseFactory
39
{
40
    /**
41
     * @var \Psr\Log\LoggerInterface
42
     */
43
    private $logger;
44
45
    /**
46
     * @var \Surfnet\SamlBundle\Entity\IdentityProvider
47
     */
48
    private $hostedIdentityProvider;
49
50
    /**
51
     * @var \Surfnet\StepupGateway\SamlStepupProviderBundle\Saml\StateHandler
52
     */
53
    private $stateHandler;
54
55
    /**
56
     * @var \Surfnet\StepupGateway\GatewayBundle\Saml\AssertionSigningService
57
     */
58
    private $assertionSigningService;
59
60
    /**
61
     * @var \DateTime
62
     */
63
    private $currentTime;
64
65
    public function __construct(
66
        LoggerInterface $logger,
67
        IdentityProvider $hostedIdentityProvider,
68
        StateHandler $stateHandler,
69
        AssertionSigningService $assertionSigningService,
70
        DateTime $now = null
71
    ) {
72
        $this->logger                  = $logger;
73
        $this->hostedIdentityProvider  = $hostedIdentityProvider;
74
        $this->stateHandler            = $stateHandler;
75
        $this->assertionSigningService = $assertionSigningService;
76
77
        $this->currentTime = is_null($now) ? new DateTime('now', new DateTimeZone('UTC')): $now;
78
    }
79
80
    /**
81
     * @param Assertion $assertion
82
     * @param string $destination
83
     * @return Response
84
     */
85
    public function createProxyResponse(Assertion $assertion, $destination)
86
    {
87
        $newAssertion = new Assertion();
88
        $newAssertion->setNotBefore($this->currentTime->getTimestamp());
89
        $newAssertion->setNotOnOrAfter($this->getTimestamp('PT5M'));
90
        $newAssertion->setAttributes($assertion->getAttributes());
91
        $issuerVo = new Issuer();
92
        $issuerVo->setValue($this->hostedIdentityProvider->getEntityId());
0 ignored issues
show
Bug introduced by
It seems like $this->hostedIdentityProvider->getEntityId() can also be of type null; however, parameter $value of SAML2\XML\saml\NameIDType::setValue() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

92
        $issuerVo->setValue(/** @scrutinizer ignore-type */ $this->hostedIdentityProvider->getEntityId());
Loading history...
93
        $newAssertion->setIssuer($issuerVo);
94
        $newAssertion->setIssueInstant($this->getTimestamp());
95
96
        $this->assertionSigningService->signAssertion($newAssertion);
97
        $this->addSubjectConfirmationFor($newAssertion, $destination);
98
99
        $newAssertion->setNameId($assertion->getNameId());
100
        $newAssertion->setValidAudiences([$this->stateHandler->getRequestServiceProvider()]);
101
102
        $this->addAuthenticationStatementTo($newAssertion, $assertion);
103
104
        return $this->createNewAuthnResponse($newAssertion, $destination);
105
    }
106
107
    /**
108
     * @param Assertion $newAssertion
109
     * @param string $destination
110
     */
111
    private function addSubjectConfirmationFor(Assertion $newAssertion, $destination): void
112
    {
113
        $confirmation = new SubjectConfirmation();
114
        $confirmation->setMethod(Constants::CM_BEARER);
115
116
        $confirmationData = new SubjectConfirmationData();
117
        $confirmationData->setInResponseTo($this->stateHandler->getRequestId());
118
        $confirmationData->setRecipient($destination);
119
        $confirmationData->setNotOnOrAfter($newAssertion->getNotOnOrAfter());
120
121
        $confirmation->setSubjectConfirmationData($confirmationData);
122
123
        $newAssertion->setSubjectConfirmation([$confirmation]);
124
    }
125
126
    /**
127
     * @param Assertion $newAssertion
128
     * @param Assertion $assertion
129
     */
130
    private function addAuthenticationStatementTo(Assertion $newAssertion, Assertion $assertion): void
131
    {
132
        $newAssertion->setAuthnInstant($assertion->getAuthnInstant());
133
        $newAssertion->setAuthnContextClassRef($assertion->getAuthnContextClassRef());
134
        $newAssertion->setAuthenticatingAuthority($assertion->getAuthenticatingAuthority());
135
    }
136
137
    /**
138
     * @param Assertion $newAssertion
139
     * @param string $destination
140
     * @return SAMLResponse
141
     */
142
    private function createNewAuthnResponse(Assertion $newAssertion, $destination)
143
    {
144
        $response = new SAMLResponse();
145
        $response->setAssertions([$newAssertion]);
146
        $issuerVo = new Issuer();
147
        $issuerVo->setValue($this->hostedIdentityProvider->getEntityId());
0 ignored issues
show
Bug introduced by
It seems like $this->hostedIdentityProvider->getEntityId() can also be of type null; however, parameter $value of SAML2\XML\saml\NameIDType::setValue() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

147
        $issuerVo->setValue(/** @scrutinizer ignore-type */ $this->hostedIdentityProvider->getEntityId());
Loading history...
148
        $response->setIssuer($issuerVo);
149
        $response->setIssueInstant($this->getTimestamp());
150
        $response->setDestination($destination);
151
        $response->setInResponseTo($this->stateHandler->getRequestId());
152
153
        return $response;
154
    }
155
156
    /**
157
     * @param string $interval a DateInterval compatible interval to skew the time with
158
     * @return int
159
     */
160
    private function getTimestamp($interval = null)
161
    {
162
        $time = clone $this->currentTime;
163
164
        if ($interval) {
165
            $time->add(new DateInterval($interval));
166
        }
167
168
        return $time->getTimestamp();
169
    }
170
}
171