SOAP::getOutputToSend()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 3
nop 1
dl 0
loc 25
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\Binding;
6
7
use Exception;
8
use Nyholm\Psr7\Response;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
use SimpleSAML\SAML2\Binding;
12
use SimpleSAML\SAML2\Exception\Protocol\UnsupportedBindingException;
13
use SimpleSAML\SAML2\Type\SAMLAnyURIValue;
14
use SimpleSAML\SAML2\Utils;
15
use SimpleSAML\SAML2\XML\ecp\RequestAuthenticated;
16
use SimpleSAML\SAML2\XML\ecp\Response as ECPResponse;
17
use SimpleSAML\SAML2\XML\samlp\AbstractMessage;
18
use SimpleSAML\SAML2\XML\samlp\MessageFactory;
19
use SimpleSAML\SAML2\XML\samlp\Response as SAML2_Response;
20
use SimpleSAML\SOAP11\Type\MustUnderstandValue;
21
use SimpleSAML\SOAP11\Utils\XPath;
22
use SimpleSAML\SOAP11\XML\Body;
23
use SimpleSAML\SOAP11\XML\Envelope;
24
use SimpleSAML\SOAP11\XML\Header;
25
use SimpleSAML\XML\DOMDocumentFactory;
26
27
use function file_get_contents;
28
29
/**
30
 * Class which implements the SOAP binding.
31
 *
32
 * @package simplesamlphp/saml2
33
 */
34
class SOAP extends Binding implements SynchronousBindingInterface
35
{
36
    /**
37
     * @param \SimpleSAML\SAML2\XML\samlp\AbstractMessage $message
38
     * @throws \Exception
39
     * @return string|false The XML or false on error
40
     */
41
    public function getOutputToSend(AbstractMessage $message)
42
    {
43
        $header = new Header();
44
45
        // In the Artifact Resolution profile, this will be an ArtifactResolve
46
        // containing another message (e.g. a Response), however in the ECP
47
        // profile, this is the Response itself.
48
        if ($message instanceof SAML2_Response) {
49
            $requestAuthenticated = new RequestAuthenticated(
50
                MustUnderstandValue::fromBoolean(true),
51
            );
52
53
            $destination = $this->destination ?: $message->getDestination()?->getValue();
54
            if ($destination === null) {
0 ignored issues
show
introduced by
The condition $destination === null is always false.
Loading history...
55
                throw new Exception('No destination available for SOAP message.');
56
            }
57
            $response = new ECPResponse(SAMLAnyURIValue::fromString($destination));
58
            $header = new Header([$requestAuthenticated, $response]);
59
        }
60
61
        $env = new Envelope(
62
            new Body([$message]),
63
            $header,
64
        );
65
        return $env->toXML()->ownerDocument?->saveXML();
66
    }
67
68
69
    /**
70
     * Send a SAML 2 message using the SOAP binding.
71
     *
72
     * @param \SimpleSAML\SAML2\XML\samlp\AbstractMessage $message The message we should send.
73
     * @return \Psr\Http\Message\ResponseInterface
74
     */
75
    public function send(AbstractMessage $message): ResponseInterface
76
    {
77
        $xml = $this->getOutputToSend($message);
78
        Utils::getContainer()->debugMessage($xml, 'out');
79
80
        return new Response(200, ['Content-Type' => 'text/xml'], $xml);
81
    }
82
83
84
    /**
85
     * Receive a SAML 2 message sent using the HTTP-POST binding.
86
     *
87
     * @param \Psr\Http\Message\ServerRequestInterface $request
88
     * @return \SimpleSAML\SAML2\XML\samlp\AbstractMessage The received message.
89
     *
90
     * @throws \Exception If unable to receive the message
91
     */
92
    public function receive(/** @scrutinizer ignore-unused */ServerRequestInterface $request): AbstractMessage
93
    {
94
        $postText = $this->getInputStream();
95
96
        if (empty($postText)) {
97
            throw new UnsupportedBindingException('Invalid message received at AssertionConsumerService endpoint.');
98
        }
99
100
        $document = DOMDocumentFactory::fromString($postText);
101
        /** @var \DOMNode $xml */
102
        $xml = $document->firstChild;
103
        Utils::getContainer()->debugMessage($document->documentElement, 'in');
104
105
        $xpCache = XPath::getXPath($document->documentElement);
106
        /** @var \DOMElement[] $results */
107
        $results = XPath::xpQuery($xml, '/SOAP-ENV:Envelope/SOAP-ENV:Body/*[1]', $xpCache);
108
109
        return MessageFactory::fromXML($results[0]);
110
    }
111
112
113
    /**
114
     * @return string|false
115
     */
116
    protected function getInputStream()
117
    {
118
        return file_get_contents('php://input');
119
    }
120
}
121