Passed
Push — master ( 0c43bc...4ec253 )
by Tim
02:55
created

ServiceProvider::receiveResponse()   D

Complexity

Conditions 16
Paths 206

Size

Total Lines 122
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 16
eloc 69
c 1
b 0
f 0
nc 206
nop 1
dl 0
loc 122
rs 4.6583

How to fix   Long Method    Complexity   

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
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\Entity;
6
7
use Exception;
8
use Psr\Http\Message\ServerRequestInterface;
9
use SimpleSAML\Assert\Assert;
10
use SimpleSAML\SAML2\{
11
    Binding,
12
    Metadata,
13
    MetadataProviderInterface,
14
    StateProviderInterface,
15
    StorageProviderInterface,
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\StorageProviderInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
    Utils,
17
};
18
use SimpleSAML\SAML2\Binding\HTTPArtifact;
19
use SimpleSAML\SAML2\Exception\{MetadataNotFoundException, RemoteException, RuntimeException};
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\Exception\RemoteException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use SimpleSAML\SAML2\Exception\Protocol\{RequestDeniedException, ResourceNotRecognizedException};
21
use SimpleSAML\SAML2\Process\Validator\ResponseValidator;
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\Process...dator\ResponseValidator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use SimpleSAML\SAML2\XML\saml\{
23
    Assertion,
24
    AttributeStatement,
25
    EncryptedAssertion,
26
    EncryptedAttribute,
27
    EncryptedID,
28
    Subject,
29
};
30
use SimpleSAML\SAML2\XML\samlp\Response;
31
use SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmFactory;
32
use SimpleSAML\XMLSecurity\Exception\SignatureVerificationFailedException;
33
use SimpleSAML\XMLSecurity\XML\{
34
    EncryptableElementInterface,
35
    EncryptedElementInterface,
36
    SignableElementInterface,
37
    SignedElementInterface,
38
};
39
40
use function sprintf;
41
42
/**
43
 * Class representing a SAML 2 Service Provider.
44
 *
45
 * @package simplesamlphp/saml2
46
 */
47
final class ServiceProvider
48
{
49
    protected ?StateProviderInterface $stateProvider = null;
50
    protected ?StorageProviderInterface $storageProvider = null;
51
    protected ?Metadata\IdentityProvider $idpMetadata = null;
52
53
54
    /**
55
     * @param bool $encryptedAssertions  Whether assertions must be encrypted
56
     * @param bool $disableScoping  Whether to send the samlp:Scoping element in requests
57
     * @param bool $enableUnsolicited  Whether to process unsolicited responses
58
     * @param bool $encryptNameId  Whether to encrypt the NameID sent
59
     * @param bool $signAuthnRequest  Whether to sign the AuthnRequest sent
60
     * @param bool $signLogout  Whether to sign the LogoutRequest/LogoutResponse sent
61
     * @param bool $validateLogout  Whether to validate the signature of LogoutRequest/LogoutResponse received
62
     */
63
    public function __construct(
64
        protected MetadataProviderInterface $metadataProvider,
65
        protected Metadata\ServiceProvider $spMetadata,
66
        protected readonly bool $encryptedAssertions = false,
67
        protected readonly bool $disableScoping = false,
68
        protected readonly bool $enableUnsolicited = false,
69
        protected readonly bool $encryptNameId = false,
70
        protected readonly bool $signAuthnRequest = false,
71
        protected readonly bool $signLogout = false,
72
        protected readonly bool $validateLogout = true,
73
        // Use with caution - will leave any form of signature verification or token decryption up to the implementer
74
        protected readonly bool $bypassResponseVerification = false,
75
        // Use with caution - will leave any form of constraint validation up to the implementer
76
        protected readonly bool $bypassConstraintValidation = false,
77
    ) {
78
    }
79
80
81
    /**
82
     */
83
    public function setStateProvider(StateProviderInterface $stateProvider): void
84
    {
85
        $this->stateProvider = $stateProvider;
86
    }
87
88
89
    /**
90
     */
91
    public function setStorageProvider(StorageProviderInterface $storageProvider): void
92
    {
93
        $this->storageProvider = $storageProvider;
94
    }
95
96
97
    /**
98
     * Receive a verified, and optionally validated Response.
99
     *
100
     * Upon receiving the response from the binding, the signature will be validated first.
101
     * Once the signature checks out, the assertions are decrypted, their signatures verified
102
     *  and then any encrypted NameID's and/or attributes are decrypted.
103
     *
104
     * @param \Psr\Http\Message\ServerRequestInterface $request
105
     * @return \SimpleSAML\SAML2\XML\samlp\Response The validated response.
106
     *
107
     * @throws \SimpleSAML\SAML2\Exception\Protocol\UnsupportedBindingException
108
     */
109
    public function receiveResponse(ServerRequestInterface $request): Response
110
    {
111
        $binding = Binding::getCurrentBinding($request);
112
113
        if ($binding instanceof HTTPArtifact) {
114
            if ($this->storageProvider === null) {
115
                throw new RuntimeException(
116
                    "A StorageProvider is required to use the HTTP-Artifact binding.",
117
                );
118
            }
119
120
            $artifact = $binding->receiveArtifact($request);
0 ignored issues
show
Bug introduced by
The method receiveArtifact() does not exist on SimpleSAML\SAML2\Binding\HTTPArtifact. Did you maybe mean receive()? ( Ignorable by Annotation )

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

120
            /** @scrutinizer ignore-call */ 
121
            $artifact = $binding->receiveArtifact($request);

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...
121
            $this->idpMetadata = $this->metadataProvider->getIdPMetadataForSha1($artifact->getSourceId());
122
123
            if ($this->idpMetadata === null) {
124
                throw new MetadataNotFoundException(sprintf(
125
                    'No metadata found for remote entity with SHA1 ID: %s',
126
                    $artifact->getSourceId(),
127
                ));
128
            }
129
130
            $binding->setIdpMetadata($this->idpMetadata);
0 ignored issues
show
Bug introduced by
The method setIdpMetadata() does not exist on SimpleSAML\SAML2\Binding\HTTPArtifact. ( Ignorable by Annotation )

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

130
            $binding->/** @scrutinizer ignore-call */ 
131
                      setIdpMetadata($this->idpMetadata);

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...
131
            $binding->setSPMetadata($this->spMetadata);
132
        }
133
134
        $rawResponse = $binding->receive($request);
135
        Assert::isInstanceOf($rawResponse, Response::class, ResourceNotRecognizedException::class); // Wrong type of msg
136
137
        // Will return a raw Response prior to any form of verification
138
        if ($this->bypassResponseVerification === true) {
139
            return $rawResponse;
140
        }
141
142
        // Fetch the metadata for the remote entity
143
        if (!($binding instanceof HTTPArtifact)) {
144
            $this->idpMetadata = $this->metadataProvider->getIdPMetadata($rawResponse->getIssuer()->getContent());
145
146
            if ($this->idpMetadata === null) {
147
                throw new MetadataNotFoundException(sprintf(
148
                    'No metadata found for remote entity with entityID: %s',
149
                    $rawResponse->getIssuer()->getContent(),
150
                ));
151
            }
152
        }
153
154
        // Verify the signature (if any)
155
        $verifiedResponse = $rawResponse->isSigned() ? $this->verifyElementSignature($rawResponse) : $rawResponse;
156
157
        $state = null;
158
        $stateId = $verifiedResponse->getInResponseTo();
0 ignored issues
show
Bug introduced by
The method getInResponseTo() does not exist on SimpleSAML\SAML2\XML\samlp\ArtifactResolve. ( Ignorable by Annotation )

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

158
        /** @scrutinizer ignore-call */ 
159
        $stateId = $verifiedResponse->getInResponseTo();

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...
Bug introduced by
The method getInResponseTo() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\AbstractStatusResponse. ( Ignorable by Annotation )

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

158
        /** @scrutinizer ignore-call */ 
159
        $stateId = $verifiedResponse->getInResponseTo();
Loading history...
Bug introduced by
The method getInResponseTo() does not exist on SimpleSAML\SAML2\XML\samlp\AbstractMessage. It seems like you code against a sub-type of SimpleSAML\SAML2\XML\samlp\AbstractMessage such as SimpleSAML\SAML2\XML\samlp\AbstractStatusResponse. ( Ignorable by Annotation )

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

158
        /** @scrutinizer ignore-call */ 
159
        $stateId = $verifiedResponse->getInResponseTo();
Loading history...
Bug introduced by
The method getInResponseTo() does not exist on SimpleSAML\SAML2\XML\samlp\LogoutRequest. ( Ignorable by Annotation )

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

158
        /** @scrutinizer ignore-call */ 
159
        $stateId = $verifiedResponse->getInResponseTo();

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...
Bug introduced by
The method getInResponseTo() does not exist on SimpleSAML\SAML2\XML\samlp\AuthnRequest. ( Ignorable by Annotation )

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

158
        /** @scrutinizer ignore-call */ 
159
        $stateId = $verifiedResponse->getInResponseTo();

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...
Bug introduced by
The method getInResponseTo() does not exist on SimpleSAML\SAML2\XML\samlp\AttributeQuery. ( Ignorable by Annotation )

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

158
        /** @scrutinizer ignore-call */ 
159
        $stateId = $verifiedResponse->getInResponseTo();

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...
159
160
        if (!empty($stateId)) {
161
            if ($this->stateProvider === null) {
162
                throw new RuntimeException(
163
                    "A StateProvider is required to correlate responses to their initial request.",
164
                );
165
            }
166
167
            // this should be a response to a request we sent earlier
168
            try {
169
                $state = $this->stateProvider::loadState($stateId, 'saml:sp:sso');
170
            } catch (RuntimeException $e) {
171
                // something went wrong,
172
                Utils::getContainer()->getLogger()->warning(sprintf(
173
                    'Could not load state specified by InResponseTo: %s; processing response as unsolicited.',
174
                    $e->getMessage(),
175
                ));
176
            }
177
        }
178
179
        $issuer = $verifiedResponse->getIssuer()->getContent();
0 ignored issues
show
Bug introduced by
The method getIssuer() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\AbstractMessage or SimpleSAML\SAML2\XML\saml\Assertion. ( Ignorable by Annotation )

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

179
        $issuer = $verifiedResponse->/** @scrutinizer ignore-call */ getIssuer()->getContent();
Loading history...
180
        if ($state === null) {
181
            if ($this->enableUnsolicited === false) {
182
                throw new RequestDeniedException('Unsolicited responses are denied by configuration.');
183
            }
184
        } else {
185
            // check that the issuer is the one we are expecting
186
            Assert::keyExists($state, 'ExpectedIssuer');
187
188
            if ($state['ExpectedIssuer'] !== $issuer) {
189
                throw new ResourceNotRecognizedException("Issuer doesn't match the one the AuthnRequest was sent to.");
190
            }
191
        }
192
193
        $this->idpMetadata = $this->metadataProvider->getIdPMetadata($issuer);
194
        if ($this->idpMetadata === null) {
195
            throw new MetadataNotFoundException(sprintf(
196
                'No metadata found for remote identity provider with entityID: %s',
197
                $issuer,
198
            ));
199
        }
200
201
        $responseValidator = ResponseValidator::createResponseValidator(
202
            $this->idpMetadata,
203
            $this->spMetadata,
204
            $binding,
205
        );
206
        $responseValidator->validate($verifiedResponse);
207
208
        // Decrypt and verify assertions, then rebuild the response.
209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->getAssertions());
0 ignored issues
show
Bug introduced by
The method getAssertions() does not exist on SimpleSAML\SAML2\XML\samlp\AttributeQuery. ( Ignorable by Annotation )

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

209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->/** @scrutinizer ignore-call */ getAssertions());

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...
Bug introduced by
The method getAssertions() does not exist on SimpleSAML\SAML2\XML\samlp\AbstractMessage. It seems like you code against a sub-type of SimpleSAML\SAML2\XML\samlp\AbstractMessage such as SimpleSAML\SAML2\XML\samlp\Response. ( Ignorable by Annotation )

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

209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->/** @scrutinizer ignore-call */ getAssertions());
Loading history...
Bug introduced by
The method getAssertions() does not exist on SimpleSAML\SAML2\XML\samlp\AuthnRequest. ( Ignorable by Annotation )

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

209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->/** @scrutinizer ignore-call */ getAssertions());

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...
Bug introduced by
The method getAssertions() does not exist on SimpleSAML\SAML2\XML\samlp\ArtifactResolve. ( Ignorable by Annotation )

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

209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->/** @scrutinizer ignore-call */ getAssertions());

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...
Bug introduced by
The method getAssertions() does not exist on SimpleSAML\SAML2\XML\samlp\LogoutResponse. ( Ignorable by Annotation )

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

209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->/** @scrutinizer ignore-call */ getAssertions());

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...
Bug introduced by
The method getAssertions() does not exist on SimpleSAML\SAML2\XML\samlp\LogoutRequest. ( Ignorable by Annotation )

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

209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->/** @scrutinizer ignore-call */ getAssertions());

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...
Bug introduced by
The method getAssertions() does not exist on SimpleSAML\SAML2\XML\samlp\ArtifactResponse. ( Ignorable by Annotation )

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

209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->/** @scrutinizer ignore-call */ getAssertions());

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...
Bug introduced by
The method getAssertions() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\Response. ( Ignorable by Annotation )

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

209
        $verifiedAssertions = $this->decryptAndVerifyAssertions($verifiedResponse->/** @scrutinizer ignore-call */ getAssertions());
Loading history...
210
        $decryptedResponse = new Response(
211
            $verifiedResponse->getStatus(),
0 ignored issues
show
Bug introduced by
The method getStatus() does not exist on SimpleSAML\SAML2\XML\samlp\LogoutRequest. ( Ignorable by Annotation )

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

211
            $verifiedResponse->/** @scrutinizer ignore-call */ 
212
                               getStatus(),

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...
Bug introduced by
The method getStatus() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\AbstractStatusResponse. ( Ignorable by Annotation )

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

211
            $verifiedResponse->/** @scrutinizer ignore-call */ 
212
                               getStatus(),
Loading history...
Bug introduced by
The method getStatus() does not exist on SimpleSAML\SAML2\XML\samlp\ArtifactResolve. ( Ignorable by Annotation )

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

211
            $verifiedResponse->/** @scrutinizer ignore-call */ 
212
                               getStatus(),

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...
Bug introduced by
The method getStatus() does not exist on SimpleSAML\SAML2\XML\samlp\AuthnRequest. ( Ignorable by Annotation )

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

211
            $verifiedResponse->/** @scrutinizer ignore-call */ 
212
                               getStatus(),

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...
Bug introduced by
The method getStatus() does not exist on SimpleSAML\SAML2\XML\samlp\AttributeQuery. ( Ignorable by Annotation )

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

211
            $verifiedResponse->/** @scrutinizer ignore-call */ 
212
                               getStatus(),

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...
Bug introduced by
The method getStatus() does not exist on SimpleSAML\SAML2\XML\samlp\AbstractMessage. It seems like you code against a sub-type of SimpleSAML\SAML2\XML\samlp\AbstractMessage such as SimpleSAML\SAML2\XML\samlp\AbstractStatusResponse. ( Ignorable by Annotation )

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

211
            $verifiedResponse->/** @scrutinizer ignore-call */ 
212
                               getStatus(),
Loading history...
212
            $verifiedResponse->getIssueInstant(),
0 ignored issues
show
Bug introduced by
The method getIssueInstant() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\AbstractMessage or SimpleSAML\SAML2\XML\saml\Assertion. ( Ignorable by Annotation )

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

212
            $verifiedResponse->/** @scrutinizer ignore-call */ 
213
                               getIssueInstant(),
Loading history...
213
            $verifiedResponse->getIssuer(),
214
            $verifiedResponse->getID(),
215
            $verifiedResponse->getVersion(),
0 ignored issues
show
Bug introduced by
The method getVersion() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\AbstractMessage. ( Ignorable by Annotation )

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

215
            $verifiedResponse->/** @scrutinizer ignore-call */ 
216
                               getVersion(),
Loading history...
216
            $verifiedResponse->getInResponseTo(),
217
            $verifiedResponse->getDestination(),
0 ignored issues
show
Bug introduced by
The method getDestination() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\AbstractMessage. ( Ignorable by Annotation )

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

217
            $verifiedResponse->/** @scrutinizer ignore-call */ 
218
                               getDestination(),
Loading history...
218
            $verifiedResponse->getConsent(),
0 ignored issues
show
Bug introduced by
The method getConsent() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\AbstractMessage. ( Ignorable by Annotation )

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

218
            $verifiedResponse->/** @scrutinizer ignore-call */ 
219
                               getConsent(),
Loading history...
219
            $verifiedResponse->getExtensions(),
0 ignored issues
show
Bug introduced by
The method getExtensions() does not exist on SimpleSAML\XMLSecurity\X...ignableElementInterface. It seems like you code against a sub-type of SimpleSAML\XMLSecurity\X...ignableElementInterface such as SimpleSAML\SAML2\XML\samlp\AbstractMessage or SimpleSAML\SAML2\XML\md\AbstractMetadataDocument. ( Ignorable by Annotation )

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

219
            $verifiedResponse->/** @scrutinizer ignore-call */ 
220
                               getExtensions(),
Loading history...
220
            $verifiedAssertions,
221
        );
222
223
224
        // Will return a verified and fully decrypted Response prior to any form of validation
225
        if ($this->bypassConstraintValidation === true) {
226
            return $decryptedResponse;
227
        }
228
229
        // TODO: Validate assertions
230
        return $decryptedResponse;
231
    }
232
233
234
    /**
235
     * Process the assertions and decrypt any encrypted elements inside.
236
     *
237
     * @param \SimpleSAML\SAML2\XML\saml\Assertion[] $unverifiedAssertions
238
     * @return \SimpleSAML\SAML2\XML\saml\Assertion[]
239
     *
240
     * @throws \SimpleSAML\SAML2\Exception\RuntimeException if none of the keys could be used to decrypt the element
241
     */
242
    protected function decryptAndVerifyAssertions(array $unverifiedAssertions): array
243
    {
244
        /**
245
         * See paragraph 6.2 of the SAML 2.0 core specifications for the applicable processing rules
246
         *
247
         * Long story short - Decrypt the assertion first, then validate it's signature
248
         * Once the signature is verified, decrypt any BaseID, NameID or Attribute that's encrypted
249
         */
250
        $verifiedAssertions = [];
251
        foreach ($unverifiedAssertions as $i => $assertion) {
252
            // Decrypt the assertions
253
            $decryptedAssertion = ($assertion instanceof EncryptedAssertion)
254
                ? $this->decryptElement($assertion)
255
                : $assertion;
256
257
            // Verify the signature on the assertions (if any)
258
            $verifiedAssertion = $this->verifyElementSignature($decryptedAssertion);
0 ignored issues
show
Bug introduced by
It seems like $decryptedAssertion can also be of type SimpleSAML\XMLSecurity\X...yptableElementInterface; however, parameter $element of SimpleSAML\SAML2\Entity\...erifyElementSignature() does only seem to accept SimpleSAML\XMLSecurity\XML\SignedElementInterface, 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

258
            $verifiedAssertion = $this->verifyElementSignature(/** @scrutinizer ignore-type */ $decryptedAssertion);
Loading history...
259
260
            // Decrypt the NameID and replace it inside the assertion's Subject
261
            $nameID = $verifiedAssertion->getSubject()?->getIdentifier();
262
263
            if ($nameID instanceof EncryptedID) {
264
                $decryptedNameID = $this->decryptElement($nameID);
265
                $subject = new Subject($decryptedNameID, $verifiedAssertion->getSubjectConfirmation());
0 ignored issues
show
Bug introduced by
The method getSubjectConfirmation() does not exist on SimpleSAML\SAML2\XML\saml\Assertion. Did you maybe mean getSubject()? ( Ignorable by Annotation )

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

265
                $subject = new Subject($decryptedNameID, $verifiedAssertion->/** @scrutinizer ignore-call */ getSubjectConfirmation());

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...
266
            } else {
267
                $subject = $verifiedAssertion->getSubject();
268
            }
269
270
            // Decrypt any occurrences of EncryptedAttribute and replace them inside the assertion's AttributeStatement
271
            $statements = $verifiedAssertion->getStatements();
272
            foreach ($verifiedAssertion->getStatements() as $j => $statement) {
273
                if ($statement instanceof AttributeStatement) {
274
                    $attributes = $statement->getAttributes();
275
                    if ($statement->hasEncryptedAttributes()) {
276
                        foreach ($statement->getEncryptedAttributes() as $encryptedAttribute) {
277
                            $attributes[] = $this->decryptElement($encryptedAttribute);
278
                        }
279
                    }
280
281
                    $statements[$j] = new AttributeStatement($attributes);
282
                }
283
            }
284
285
            // Rebuild the Assertion
286
            $verifiedAssertions[] = new Assertion(
287
                $verifiedAssertion->getIssuer(),
288
                $verifiedAssertion->getIssueInstant(),
289
                $verifiedAssertion->getID(),
290
                $subject,
291
                $verifiedAssertion->getConditions(),
292
                $statements,
293
            );
294
        }
295
296
        return $verifiedAssertions;
297
    }
298
299
300
    /**
301
     * Decrypt the given element using the decryption keys provided to us.
302
     *
303
     * @param \SimpleSAML\XMLSecurity\XML\EncryptedElementInterface $element
304
     * @return \SimpleSAML\XMLSecurity\EncryptableElementInterface
0 ignored issues
show
Bug introduced by
The type SimpleSAML\XMLSecurity\EncryptableElementInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
305
     *
306
     * @throws \SimpleSAML\SAML2\Exception\RuntimeException if none of the keys could be used to decrypt the element
307
     */
308
    protected function decryptElement(EncryptedElementInterface $element): EncryptableElementInterface
309
    {
310
        $factory = $this->spMetadata->getEncryptionAlgorithmFactory();
311
312
        $encryptionAlgorithm = ($factory instanceof EncryptionAlgorithmFactory)
313
            ? $element->getEncryptedData()->getEncryptionMethod()
314
            : $element->getEncryptedKey()->getEncryptionMethod();
315
316
        foreach ($this->spMetadata->getDecriptionKeys() as $decryptionKey) {
0 ignored issues
show
Bug introduced by
The method getDecriptionKeys() does not exist on SimpleSAML\SAML2\Metadata\ServiceProvider. Did you maybe mean getDecryptionKeys()? ( Ignorable by Annotation )

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

316
        foreach ($this->spMetadata->/** @scrutinizer ignore-call */ getDecriptionKeys() as $decryptionKey) {

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...
317
            $decryptor = $factory->getAlgorithm($encryptionAlgorithm, $decryptionKey);
0 ignored issues
show
Bug introduced by
It seems like $encryptionAlgorithm can also be of type null; however, parameter $algId of SimpleSAML\XMLSecurity\A...Factory::getAlgorithm() 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

317
            $decryptor = $factory->getAlgorithm(/** @scrutinizer ignore-type */ $encryptionAlgorithm, $decryptionKey);
Loading history...
Bug introduced by
It seems like $encryptionAlgorithm can also be of type null; however, parameter $algId of SimpleSAML\XMLSecurity\A...Factory::getAlgorithm() 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

317
            $decryptor = $factory->getAlgorithm(/** @scrutinizer ignore-type */ $encryptionAlgorithm, $decryptionKey);
Loading history...
318
            try {
319
                return $element->decrypt($decryptor);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $element->decrypt($decryptor) returns the type SimpleSAML\XML\ElementInterface which is incompatible with the type-hinted return SimpleSAML\XMLSecurity\X...yptableElementInterface.
Loading history...
320
            } catch (Exception $e) {
321
                continue;
322
            }
323
        }
324
325
        throw new RuntimeException(sprintf(
326
            'Unable to decrypt %s with any of the available keys.',
327
            $element::class,
328
        ));
329
    }
330
331
332
    /**
333
     * Verify the signature of an element using the available validation keys.
334
     *
335
     * @param \SimpleSAML\XMLSecurity\XML\SignedElementInterface $element
336
     * @return \SimpleSAML\XMLSecurity\XML\SignableElementInterface The validated element.
337
     *
338
     * @throws \SimpleSAML\XMLSecurity\Exception\SignatureVerificationFailedException
339
     */
340
    protected function verifyElementSignature(SignedElementInterface $element): SignableElementInterface
341
    {
342
        $factory = $this->spMetadata->getSignatureAlgorithmFactory();
343
        $signatureAlgorithm = $element->getSignature()->getSignedInfo()->getSignatureMethod()->getAlgorithm();
344
345
        foreach ($this->idpMetadata->getValidatingKeys() as $validatingKey) {
0 ignored issues
show
Bug introduced by
The method getValidatingKeys() 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

345
        foreach ($this->idpMetadata->/** @scrutinizer ignore-call */ getValidatingKeys() as $validatingKey) {

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...
346
            $verifier = $factory->getAlgorithm($signatureAlgorithm, $validatingKey);
347
348
            try {
349
                return $element->verify($verifier);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $element->verify($verifier) returns the type SimpleSAML\XMLSecurity\XML\SignedElementInterface which is incompatible with the type-hinted return SimpleSAML\XMLSecurity\X...ignableElementInterface.
Loading history...
350
            } catch (SignatureVerificationFailedException $e) {
351
                continue;
352
            }
353
        }
354
355
        throw new SignatureVerificationFailedException();
356
    }
357
}
358