File: HTTPPost.php

package info (click to toggle)
simplesamlphp 1.19.7-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 42,920 kB
  • sloc: php: 202,044; javascript: 14,867; xml: 2,700; sh: 225; perl: 82; makefile: 70; python: 5
file content (156 lines) | stat: -rw-r--r-- 5,320 bytes parent folder | download | duplicates (3)
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<?php

declare(strict_types=1);

/**
 * Implementation of the Shibboleth 1.3 HTTP-POST binding.
 *
 * @author Andreas Åkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
 * @package SimpleSAMLphp
 * @deprecated This class will be removed in a future release
 */

namespace SimpleSAML\Bindings\Shib13;

use SAML2\DOMDocumentFactory;
use SimpleSAML\Configuration;
use SimpleSAML\Metadata\MetaDataStorageHandler;
use SimpleSAML\Utils;
use SimpleSAML\XML\Shib13\AuthnResponse;
use SimpleSAML\XML\Signer;

class HTTPPost
{
    /**
     * @var \SimpleSAML\Configuration
     */
    private $configuration;

    /**
     * @var \SimpleSAML\Metadata\MetaDataStorageHandler
     */
    private $metadata;


    /**
     * Constructor for the \SimpleSAML\Bindings\Shib13\HTTPPost class.
     *
     * @param \SimpleSAML\Configuration                   $configuration The configuration to use.
     * @param \SimpleSAML\Metadata\MetaDataStorageHandler $metadatastore A store where to find metadata.
     */
    public function __construct(
        Configuration $configuration,
        MetaDataStorageHandler $metadatastore
    ) {
        $this->configuration = $configuration;
        $this->metadata = $metadatastore;
    }


    /**
     * Send an authenticationResponse using HTTP-POST.
     *
     * @param string                    $response The response which should be sent.
     * @param \SimpleSAML\Configuration $idpmd The metadata of the IdP which is sending the response.
     * @param \SimpleSAML\Configuration $spmd The metadata of the SP which is receiving the response.
     * @param string|null               $relayState The relaystate for the SP.
     * @param string                    $shire The shire which should receive the response.
     * @return void
     */
    public function sendResponse(
        $response,
        Configuration $idpmd,
        Configuration $spmd,
        $relayState,
        $shire
    ) {
        Utils\XML::checkSAMLMessage($response, 'saml11');

        $privatekey = Utils\Crypto::loadPrivateKey($idpmd, true);
        $publickey = Utils\Crypto::loadPublicKey($idpmd, true);

        $responsedom = DOMDocumentFactory::fromString(str_replace("\r", "", $response));

        $responseroot = $responsedom->getElementsByTagName('Response')->item(0);
        $firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0);

        /* Determine what we should sign - either the Response element or the Assertion. The default is to sign the
         * Assertion, but that can be overridden by the 'signresponse' option in the SP metadata or
         * 'saml20.signresponse' in the global configuration.
         *
         * TODO: neither 'signresponse' nor 'shib13.signresponse' are valid options any longer. Remove!
         */
        if ($spmd->hasValue('signresponse')) {
            $signResponse = $spmd->getBoolean('signresponse');
        } else {
            $signResponse = $this->configuration->getBoolean('shib13.signresponse', true);
        }

        // check if we have an assertion to sign. Force to sign the response if not
        if ($firstassertionroot === null) {
            $signResponse = true;
        }

        $signer = new Signer([
            'privatekey_array' => $privatekey,
            'publickey_array'  => $publickey,
            'id'               => ($signResponse ? 'ResponseID' : 'AssertionID'),
        ]);

        if ($idpmd->hasValue('certificatechain')) {
            $signer->addCertificate($idpmd->getString('certificatechain'));
        }

        if ($signResponse) {
            // sign the response - this must be done after encrypting the assertion
            // we insert the signature before the saml2p:Status element
            $statusElements = Utils\XML::getDOMChildren($responseroot, 'Status', '@saml1p');
            assert(count($statusElements) === 1);
            $signer->sign($responseroot, $responseroot, $statusElements[0]);
        } else {
            // Sign the assertion
            $signer->sign($firstassertionroot, $firstassertionroot);
        }

        $response = $responsedom->saveXML();

        Utils\XML::debugSAMLMessage($response, 'out');

        Utils\HTTP::submitPOSTData($shire, [
            'TARGET'       => $relayState,
            'SAMLResponse' => base64_encode($response),
        ]);
    }


    /**
     * Decode a received response.
     *
     * @param array $post POST data received.
     * @return \SimpleSAML\XML\Shib13\AuthnResponse The response decoded into an object.
     * @throws \Exception If there is no SAMLResponse parameter.
     */
    public function decodeResponse($post)
    {
        assert(is_array($post));

        if (!array_key_exists('SAMLResponse', $post)) {
            throw new \Exception('Missing required SAMLResponse parameter.');
        }
        $rawResponse = $post['SAMLResponse'];
        $samlResponseXML = base64_decode($rawResponse);

        Utils\XML::debugSAMLMessage($samlResponseXML, 'in');

        Utils\XML::checkSAMLMessage($samlResponseXML, 'saml11');

        $samlResponse = new AuthnResponse();
        $samlResponse->setXML($samlResponseXML);

        if (array_key_exists('TARGET', $post)) {
            $samlResponse->setRelayState($post['TARGET']);
        }

        return $samlResponse;
    }
}