summaryrefslogtreecommitdiffstats
path: root/lib/SAML2/HTTPArtifact.php
blob: 21646ff6469a2349aa15d0076048db47a630951d (plain)
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


/**
 * Class which implements the HTTP-Redirect binding.
 *
 * @author  Danny Bollaert, UGent AS. <danny.bollaert@ugent.be>
 * @package simpleSAMLphp
 * @version $Id$
 */
class SAML2_HTTPArtifact extends SAML2_Binding {

	private $spMetadata;

	/**
	 * Create the redirect URL for a message.
	 *
	 * @param SAML2_Message $message  The message.
	 * @return string  The URL the user should be redirected to in order to send a message.
	 */
	public function getRedirectURL(SAML2_Message $message) {

		$store = SimpleSAML_Store::getInstance();
		if ($store === FALSE) {
			throw new Exception('Unable to send artifact without a datastore configured.');
		}

		$generatedId = pack('H*', ((string)  SimpleSAML_Utilities::stringToHex(SimpleSAML_Utilities::generateRandomBytes(20))));
		$artifact = base64_encode("\x00\x04\x00\x00" . sha1($message->getIssuer(), TRUE) . $generatedId) ;
		$artifactData = $message->toUnsignedXML();
		$artifactDataString = $artifactData->ownerDocument->saveXML($artifactData);

		$store->set('artifact', $artifact, $artifactDataString, time() + 15*60);

		$params = array(
			'SAMLart' => $artifact,
		);
		$relayState = $message->getRelayState();
		if ($relayState !== NULL) {
			$params['RelayState'] = $relayState;
		}

		return SimpleSAML_Utilities::addURLparameter($message->getDestination(), $params);
	}


	/**
	 * Send a SAML 2 message using the HTTP-Redirect binding.
	 *
	 * Note: This function never returns.
	 *
	 * @param SAML2_Message $message  The message we should send.
	 */
	public function send(SAML2_Message $message) {

		$destination = $this->getRedirectURL($message);
		SimpleSAML_Utilities::redirect($destination);
	}


	/**
	 * Receive a SAML 2 message sent using the HTTP-Artifact binding.
	 *
	 * Throws an exception if it is unable receive the message.
	 *
	 * @return SAML2_Message  The received message.
	 */
	public function receive() {

		if (array_key_exists('SAMLart', $_REQUEST)) {
			$artifact = base64_decode($_REQUEST['SAMLart']);
			$endpointIndex =  bin2hex(substr($artifact,2,2));
			$sourceId = bin2hex(substr($artifact,4,20));

		}else{
			throw new Execption('Missing SAMLArt parameter.');
		}

		$metadataHandler = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();

		$idpmetadata = $metadataHandler->getMetaDataConfigForSha1($sourceId, 'saml20-idp-remote');


		$endpoint = NULL;
		foreach ($idpmetadata->getEndpoints('ArtifactResolutionService') as $ep) {
			if ($ep['index'] ===  hexdec($endpointIndex)) {
				$endpoint = $ep;
				break;
			}
		}

		if ($endpoint === NULL) {
			throw new Exception('No ArtifactResolutionService with the correct index.');
		}

		SimpleSAML_Logger::debug("ArtifactResolutionService endpoint being used is := " . $endpoint['Location']);

		//Construct the ArtifactResolve Request
		$ar = new SAML2_ArtifactResolve();

		/* Set the request attributes */

		$ar->setIssuer($this->spMetadata->getString('entityid'));
		$ar->setArtifact($_REQUEST['SAMLart']);
		$ar->setDestination($endpoint['Location']);

		/* Sign the request */
		sspmod_saml_Message::addSign($this->spMetadata, $idpmetadata, $ar); // Shoaib - moved from the SOAPClient.

		$soap = new SAML2_SOAPClient();

		// Send message through SoapClient
		$artifactResponse = $soap->send($ar, $this->spMetadata);

		if (!$artifactResponse->isSuccess()) {
			throw new Exception('Received error from ArtifactResolutionService.');
		}

		$xml = $artifactResponse->getAny();
		$samlresponse = SAML2_Message::fromXML($xml);
		$samlresponse->addValidator(array(get_class($this), 'validateSignature'), $artifactResponse);


		if (isset($_REQUEST['RelayState'])) {
			$samlresponse->setRelayState($_REQUEST['RelayState']);
		}

		return $samlresponse;
	}


	public function setSPMetadata($sp){
		$this->spMetadata = $sp;
	}


	/**
	 * A validator which returns TRUE if the ArtifactResponse was signed with the given key
	 *
	 * @return TRUE
	 */
	public static function validateSignature(SAML2_ArtifactResponse $message, XMLSecurityKey $key) {

		return $message->validate($key);
	}

}