File: HTTPPost.php

package info (click to toggle)
simplesamlphp 1.14.11-1%2Bdeb9u2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 15,024 kB
  • sloc: php: 72,337; xml: 1,078; python: 376; sh: 220; perl: 185; makefile: 57
file content (147 lines) | stat: -rw-r--r-- 5,221 bytes parent folder | download
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
<?php


/**
 * Implementation of the Shibboleth 1.3 HTTP-POST binding.
 *
 * @author Andreas Åkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
 * @package SimpleSAMLphp
 */
class SimpleSAML_Bindings_Shib13_HTTPPost
{

    /**
     * @var SimpleSAML_Configuration
     */
    private $configuration = null;

    /**
     * @var SimpleSAML_Metadata_MetaDataStorageHandler
     */
    private $metadata = null;


    /**
     * 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(
        SimpleSAML_Configuration $configuration,
        SimpleSAML_Metadata_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.
     */
    public function sendResponse(
        $response,
        SimpleSAML_Configuration $idpmd,
        SimpleSAML_Configuration $spmd,
        $relayState,
        $shire
    ) {

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

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

        $responsedom = SAML2_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 SimpleSAML_XML_Signer(array(
            '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 = SimpleSAML\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();

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

        \SimpleSAML\Utils\HTTP::submitPOSTData($shire, array(
            '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);

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

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

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

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

        return $samlResponse;
    }
}