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