From 366ad253e9be07c4c84042737b351e58d0016946 Mon Sep 17 00:00:00 2001
From: Olav Morken <olav.morken@uninett.no>
Date: Mon, 20 Sep 2010 08:40:23 +0000
Subject: [PATCH] saml:SP: Process multiple assertions in response.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2557 44740490-163a-0410-bde0-09ae8108e29a
---
 modules/saml/www/sp/saml2-acs.php | 66 +++++++++++++++++++------------
 1 file changed, 41 insertions(+), 25 deletions(-)

diff --git a/modules/saml/www/sp/saml2-acs.php b/modules/saml/www/sp/saml2-acs.php
index 35fc6f60f..7fa449357 100644
--- a/modules/saml/www/sp/saml2-acs.php
+++ b/modules/saml/www/sp/saml2-acs.php
@@ -47,41 +47,57 @@ SimpleSAML_Logger::debug('Received SAML2 Response from ' . var_export($idp, TRUE
 $idpMetadata = $source->getIdPmetadata($idp);
 
 try {
-	$assertion = sspmod_saml_Message::processResponse($spMetadata, $idpMetadata, $response);
-	if (count($assertion) > 1) {
-		throw new SimpleSAML_Error_Exception('More than one assertion in received response.');
-	}
-	$assertion = $assertion[0];
+	$assertions = sspmod_saml_Message::processResponse($spMetadata, $idpMetadata, $response);
 } catch (sspmod_saml_Error $e) {
 	/* The status of the response wasn't "success". */
 	$e = $e->toException();
 	SimpleSAML_Auth_State::throwException($state, $e);
 }
 
-/* Check for duplicate assertion (replay attack). */
-$store = SimpleSAML_Store::getInstance();
-if ($store !== FALSE) {
-	$aID = $assertion->getId();
-	if ($store->get('saml.AssertionReceived', $aID) !== NULL) {
-		$e = new SimpleSAML_Error_Exception('Received duplicate assertion.');
-		SimpleSAML_Auth_State::throwException($state, $e);
-	}
 
-	$notOnOrAfter = $assertion->getNotOnOrAfter();
-	if ($notOnOrAfter === NULL) {
-		$notOnOrAfter = time() + 24*60*60;
-	} else {
-		$notOnOrAfter += 60; /* We allow 60 seconds clock skew, so add it here also. */
+$authenticatingAuthority = NULL;
+$nameId = NULL;
+$sessionIndex = NULL;
+$expire = NULL;
+$attributes = array();
+foreach ($assertions as $assertion) {
+
+	/* Check for duplicate assertion (replay attack). */
+	$store = SimpleSAML_Store::getInstance();
+	if ($store !== FALSE) {
+		$aID = $assertion->getId();
+		if ($store->get('saml.AssertionReceived', $aID) !== NULL) {
+			$e = new SimpleSAML_Error_Exception('Received duplicate assertion.');
+			SimpleSAML_Auth_State::throwException($state, $e);
+		}
+
+		$notOnOrAfter = $assertion->getNotOnOrAfter();
+		if ($notOnOrAfter === NULL) {
+			$notOnOrAfter = time() + 24*60*60;
+		} else {
+			$notOnOrAfter += 60; /* We allow 60 seconds clock skew, so add it here also. */
+		}
+
+		$store->set('saml.AssertionReceived', $aID, TRUE, $notOnOrAfter);
 	}
 
-	$store->set('saml.AssertionReceived', $aID, TRUE, $notOnOrAfter);
-}
 
+	if ($authenticatingAuthority === NULL) {
+		$authenticatingAuthority = $assertion->getAuthenticatingAuthority();
+	}
+	if ($nameId === NULL) {
+		$nameId = $assertion->getNameId();
+	}
+	if ($sessionIndex === NULL) {
+		$sessionIndex = $assertion->getSessionIndex();
+	}
+	if ($expire === NULL) {
+		$expire = $assertion->getSessionNotOnOrAfter();
+	}
 
-$nameId = $assertion->getNameId();
-$sessionIndex = $assertion->getSessionIndex();
+	$attributes = array_merge($attributes, $assertion->getAttributes());
+}
 
-$expire = $assertion->getSessionNotOnOrAfter();
 if ($expire === NULL) {
 	/* Just expire the logout associtaion 24 hours into the future. */
 	$expire = time() + 24*60*60;
@@ -98,9 +114,9 @@ $logoutState = array(
 	'saml:logout:SessionIndex' => $sessionIndex,
 	);
 $state['LogoutState'] = $logoutState;
-$state['saml:AuthenticatingAuthority'] = $assertion->getAuthenticatingAuthority();
+$state['saml:AuthenticatingAuthority'] = $authenticatingAuthority;
 $state['saml:AuthenticatingAuthority'][] = $idp;
 $state['PersistentAuthData'][] = 'saml:AuthenticatingAuthority';
 
-$source->handleResponse($state, $idp, $assertion->getAttributes());
+$source->handleResponse($state, $idp, $attributes);
 assert('FALSE');
-- 
GitLab