Passed
Push — master ( ec27ff...f3e803 )
by Tim
02:29
created

SOAP::getInputStream()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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