From ff3df0733e7ca3e810c348e0fc2fb2ccf7a9ba66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaime=20Pe=CC=81rez=20Crespo?= <jaime.perez@uninett.no>
Date: Wed, 11 Jan 2017 15:05:43 +0100
Subject: [PATCH] Update the SAML2 library and start using the new
 \SAML2\XML\saml\NameID objects.

This enables too the implementation of additional contact attributes, as requested in #509 to support the SIRTFI framework.
---
 composer.json                                 |  2 +-
 composer.lock                                 | 89 +++++++++----------
 modules/core/lib/Auth/Process/TargetedID.php  | 13 ++-
 modules/saml/docs/sp.md                       |  3 +-
 .../Process/PersistentNameID2TargetedID.php   |  3 +-
 modules/saml/lib/Auth/Source/SP.php           |  2 +-
 modules/saml/lib/BaseNameIDGenerator.php      | 11 +--
 modules/saml/lib/IdP/SAML2.php                | 11 ++-
 modules/saml/lib/SP/LogoutStore.php           | 17 +++-
 templates/includes/attributes.php             | 44 +++++----
 templates/status.php                          | 18 +++-
 .../lib/Auth/Source/Auth_Source_SP_Test.php   |  4 +-
 12 files changed, 123 insertions(+), 94 deletions(-)

diff --git a/composer.json b/composer.json
index fbe519d12..0801632ab 100644
--- a/composer.json
+++ b/composer.json
@@ -35,7 +35,7 @@
 		"ext-date": "*",
 		"ext-hash": "*",
 		"ext-json": "*",
-        "simplesamlphp/saml2": "dev-master#00e38f85b417be1e10a2d738dd2f5ea82edb472c as 2.2",
+        "simplesamlphp/saml2": "dev-master#f079abe36ab4101dfda654a087f8003a9673b952 as 2.4",
         "robrichards/xmlseclibs": "~2.0",
         "whitehat101/apr1-md5": "~1.0",
         "twig/twig": "~1.0",
diff --git a/composer.lock b/composer.lock
index 2b39605ee..39eccf6b7 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "8c00f782ce6ebb578fc1174355b01d62",
-    "content-hash": "5db285469a25f3c3a1e21975ac94c2e9",
+    "content-hash": "d457492f7cd0fcade4c93ef810d2794c",
     "packages": [
         {
             "name": "gettext/gettext",
@@ -65,7 +64,7 @@
                 "po",
                 "translation"
             ],
-            "time": "2016-08-01 18:09:57"
+            "time": "2016-08-01T18:09:57+00:00"
         },
         {
             "name": "gettext/languages",
@@ -119,7 +118,7 @@
                 "translations",
                 "unicode"
             ],
-            "time": "2015-03-27 11:32:41"
+            "time": "2015-03-27T11:32:41+00:00"
         },
         {
             "name": "jaimeperez/twig-configurable-i18n",
@@ -163,7 +162,7 @@
                 "translation",
                 "twig"
             ],
-            "time": "2016-10-03 12:34:15"
+            "time": "2016-10-03T12:34:15+00:00"
         },
         {
             "name": "psr/log",
@@ -210,7 +209,7 @@
                 "psr",
                 "psr-3"
             ],
-            "time": "2016-09-19 16:02:08"
+            "time": "2016-09-19T16:02:08+00:00"
         },
         {
             "name": "robrichards/xmlseclibs",
@@ -251,7 +250,7 @@
                 "xml",
                 "xmldsig"
             ],
-            "time": "2016-09-08 13:15:00"
+            "time": "2016-09-08T13:15:00+00:00"
         },
         {
             "name": "simplesamlphp/saml2",
@@ -259,12 +258,12 @@
             "source": {
                 "type": "git",
                 "url": "https://github.com/simplesamlphp/saml2.git",
-                "reference": "00e38f85b417be1e10a2d738dd2f5ea82edb472c"
+                "reference": "f079abe36ab4101dfda654a087f8003a9673b952"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/00e38f85b417be1e10a2d738dd2f5ea82edb472c",
-                "reference": "00e38f85b417be1e10a2d738dd2f5ea82edb472c",
+                "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/f079abe36ab4101dfda654a087f8003a9673b952",
+                "reference": "f079abe36ab4101dfda654a087f8003a9673b952",
                 "shasum": ""
             },
             "require": {
@@ -303,7 +302,7 @@
                 }
             ],
             "description": "SAML2 PHP library from SimpleSAMLphp",
-            "time": "2016-07-26 13:28:46"
+            "time": "2017-01-11 10:10:03"
         },
         {
             "name": "twig/extensions",
@@ -355,7 +354,7 @@
                 "i18n",
                 "text"
             ],
-            "time": "2016-09-22 16:50:57"
+            "time": "2016-09-22T16:50:57+00:00"
         },
         {
             "name": "twig/twig",
@@ -416,7 +415,7 @@
             "keywords": [
                 "templating"
             ],
-            "time": "2016-09-21 23:05:12"
+            "time": "2016-09-21T23:05:12+00:00"
         },
         {
             "name": "whitehat101/apr1-md5",
@@ -460,7 +459,7 @@
                 "MD5",
                 "apr1"
             ],
-            "time": "2015-02-11 11:06:42"
+            "time": "2015-02-11T11:06:42+00:00"
         }
     ],
     "packages-dev": [
@@ -516,7 +515,7 @@
                 "constructor",
                 "instantiate"
             ],
-            "time": "2015-06-14 21:17:01"
+            "time": "2015-06-14T21:17:01+00:00"
         },
         {
             "name": "guzzle/guzzle",
@@ -612,7 +611,7 @@
                 "web service"
             ],
             "abandoned": "guzzlehttp/guzzle",
-            "time": "2015-03-18 18:23:50"
+            "time": "2015-03-18T18:23:50+00:00"
         },
         {
             "name": "phpdocumentor/reflection-common",
@@ -666,7 +665,7 @@
                 "reflection",
                 "static analysis"
             ],
-            "time": "2015-12-27 11:43:31"
+            "time": "2015-12-27T11:43:31+00:00"
         },
         {
             "name": "phpdocumentor/reflection-docblock",
@@ -711,7 +710,7 @@
                 }
             ],
             "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
-            "time": "2016-09-30 07:12:33"
+            "time": "2016-09-30T07:12:33+00:00"
         },
         {
             "name": "phpdocumentor/type-resolver",
@@ -758,7 +757,7 @@
                     "email": "me@mikevanriel.com"
                 }
             ],
-            "time": "2016-06-10 07:14:17"
+            "time": "2016-06-10T07:14:17+00:00"
         },
         {
             "name": "phpspec/prophecy",
@@ -820,7 +819,7 @@
                 "spy",
                 "stub"
             ],
-            "time": "2016-06-07 08:13:47"
+            "time": "2016-06-07T08:13:47+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
@@ -882,7 +881,7 @@
                 "testing",
                 "xunit"
             ],
-            "time": "2015-10-06 15:47:00"
+            "time": "2015-10-06T15:47:00+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
@@ -929,7 +928,7 @@
                 "filesystem",
                 "iterator"
             ],
-            "time": "2015-06-21 13:08:43"
+            "time": "2015-06-21T13:08:43+00:00"
         },
         {
             "name": "phpunit/php-text-template",
@@ -970,7 +969,7 @@
             "keywords": [
                 "template"
             ],
-            "time": "2015-06-21 13:50:34"
+            "time": "2015-06-21T13:50:34+00:00"
         },
         {
             "name": "phpunit/php-timer",
@@ -1014,7 +1013,7 @@
             "keywords": [
                 "timer"
             ],
-            "time": "2016-05-12 18:03:57"
+            "time": "2016-05-12T18:03:57+00:00"
         },
         {
             "name": "phpunit/php-token-stream",
@@ -1063,7 +1062,7 @@
             "keywords": [
                 "tokenizer"
             ],
-            "time": "2015-09-15 10:49:45"
+            "time": "2015-09-15T10:49:45+00:00"
         },
         {
             "name": "phpunit/phpunit",
@@ -1135,7 +1134,7 @@
                 "testing",
                 "xunit"
             ],
-            "time": "2016-07-21 06:48:14"
+            "time": "2016-07-21T06:48:14+00:00"
         },
         {
             "name": "phpunit/phpunit-mock-objects",
@@ -1191,7 +1190,7 @@
                 "mock",
                 "xunit"
             ],
-            "time": "2015-10-02 06:51:40"
+            "time": "2015-10-02T06:51:40+00:00"
         },
         {
             "name": "satooshi/php-coveralls",
@@ -1249,7 +1248,7 @@
                 "github",
                 "test"
             ],
-            "time": "2016-01-20 17:35:46"
+            "time": "2016-01-20T17:35:46+00:00"
         },
         {
             "name": "sebastian/comparator",
@@ -1313,7 +1312,7 @@
                 "compare",
                 "equality"
             ],
-            "time": "2015-07-26 15:48:44"
+            "time": "2015-07-26T15:48:44+00:00"
         },
         {
             "name": "sebastian/diff",
@@ -1365,7 +1364,7 @@
             "keywords": [
                 "diff"
             ],
-            "time": "2015-12-08 07:14:41"
+            "time": "2015-12-08T07:14:41+00:00"
         },
         {
             "name": "sebastian/environment",
@@ -1415,7 +1414,7 @@
                 "environment",
                 "hhvm"
             ],
-            "time": "2016-08-18 05:49:44"
+            "time": "2016-08-18T05:49:44+00:00"
         },
         {
             "name": "sebastian/exporter",
@@ -1482,7 +1481,7 @@
                 "export",
                 "exporter"
             ],
-            "time": "2016-06-17 09:04:28"
+            "time": "2016-06-17T09:04:28+00:00"
         },
         {
             "name": "sebastian/global-state",
@@ -1533,7 +1532,7 @@
             "keywords": [
                 "global state"
             ],
-            "time": "2015-10-12 03:26:01"
+            "time": "2015-10-12T03:26:01+00:00"
         },
         {
             "name": "sebastian/recursion-context",
@@ -1586,7 +1585,7 @@
             ],
             "description": "Provides functionality to recursively process PHP variables",
             "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
-            "time": "2015-11-11 19:50:13"
+            "time": "2015-11-11T19:50:13+00:00"
         },
         {
             "name": "sebastian/version",
@@ -1621,7 +1620,7 @@
             ],
             "description": "Library that helps with managing the version number of Git-hosted PHP projects",
             "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2015-06-21 13:59:46"
+            "time": "2015-06-21T13:59:46+00:00"
         },
         {
             "name": "symfony/config",
@@ -1674,7 +1673,7 @@
             ],
             "description": "Symfony Config Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-27 18:50:07"
+            "time": "2016-08-27T18:50:07+00:00"
         },
         {
             "name": "symfony/console",
@@ -1734,7 +1733,7 @@
             ],
             "description": "Symfony Console Component",
             "homepage": "https://symfony.com",
-            "time": "2016-08-19 06:48:39"
+            "time": "2016-08-19T06:48:39+00:00"
         },
         {
             "name": "symfony/event-dispatcher",
@@ -1794,7 +1793,7 @@
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "https://symfony.com",
-            "time": "2016-07-28 16:56:28"
+            "time": "2016-07-28T16:56:28+00:00"
         },
         {
             "name": "symfony/filesystem",
@@ -1843,7 +1842,7 @@
             ],
             "description": "Symfony Filesystem Component",
             "homepage": "https://symfony.com",
-            "time": "2016-07-20 05:44:26"
+            "time": "2016-07-20T05:44:26+00:00"
         },
         {
             "name": "symfony/polyfill-mbstring",
@@ -1902,7 +1901,7 @@
                 "portable",
                 "shim"
             ],
-            "time": "2016-05-18 14:26:46"
+            "time": "2016-05-18T14:26:46+00:00"
         },
         {
             "name": "symfony/stopwatch",
@@ -1951,7 +1950,7 @@
             ],
             "description": "Symfony Stopwatch Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-29 05:41:56"
+            "time": "2016-06-29T05:41:56+00:00"
         },
         {
             "name": "symfony/yaml",
@@ -2000,7 +1999,7 @@
             ],
             "description": "Symfony Yaml Component",
             "homepage": "https://symfony.com",
-            "time": "2016-09-02 02:12:52"
+            "time": "2016-09-02T02:12:52+00:00"
         },
         {
             "name": "webmozart/assert",
@@ -2050,13 +2049,13 @@
                 "check",
                 "validate"
             ],
-            "time": "2016-08-09 15:02:57"
+            "time": "2016-08-09T15:02:57+00:00"
         }
     ],
     "aliases": [
         {
-            "alias": "2.2",
-            "alias_normalized": "2.2.0.0",
+            "alias": "2.4",
+            "alias_normalized": "2.4.0.0",
             "version": "9999999-dev",
             "package": "simplesamlphp/saml2"
         }
diff --git a/modules/core/lib/Auth/Process/TargetedID.php b/modules/core/lib/Auth/Process/TargetedID.php
index 4182cee55..a4d73e39c 100644
--- a/modules/core/lib/Auth/Process/TargetedID.php
+++ b/modules/core/lib/Auth/Process/TargetedID.php
@@ -124,23 +124,22 @@ class sspmod_core_Auth_Process_TargetedID extends SimpleSAML_Auth_ProcessingFilt
 
 		if ($this->generateNameId) {
 			// Convert the targeted ID to a SAML 2.0 name identifier element
-			$nameId = array(
-				'Format' => \SAML2\Constants::NAMEID_PERSISTENT,
-				'Value' => $uid,
-			);
+			$nameId = new \SAML2\XML\saml\NameID();
+			$nameId->value = $uid;
+			$nameId->Format = \SAML2\Constants::NAMEID_PERSISTENT;
 
 			if (isset($state['Source']['entityid'])) {
-				$nameId['NameQualifier'] = $state['Source']['entityid'];
+				$nameId->NameQualifier = $state['Source']['entityid'];
 			}
 			if (isset($state['Destination']['entityid'])) {
-				$nameId['SPNameQualifier'] = $state['Destination']['entityid'];
+				$nameId->SPNameQualifier = $state['Destination']['entityd'];
 			}
 
 			$doc = \SAML2\DOMDocumentFactory::create();
 			$root = $doc->createElement('root');
 			$doc->appendChild($root);
 
-			\SAML2\Utils::addNameId($root, $nameId);
+			$nameId->toXML($root);
 			$uid = $doc->saveXML($root->firstChild);
 		}
 
diff --git a/modules/saml/docs/sp.md b/modules/saml/docs/sp.md
index a291cd10a..31def6f69 100644
--- a/modules/saml/docs/sp.md
+++ b/modules/saml/docs/sp.md
@@ -65,8 +65,7 @@ All these parameters override the equivalent option from the configuration.
 
 `saml:NameID`
 :   Add a Subject element with a NameID to the SAML AuthnRequest for the IdP.
-    This is an associative array with the fields for the NameID.
-    Example: `array('Value' => 'user@example.org', 'Format' => SAML2\Constants::NAMEID_UNSPECIFIED)`
+    This must be a \SAML2\XML\saml\NameID object.
 
 :   *Note*: SAML 2 specific.
 
diff --git a/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php b/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php
index be61e1099..25ae97f1a 100644
--- a/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php
+++ b/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php
@@ -66,13 +66,14 @@ class sspmod_saml_Auth_Process_PersistentNameID2TargetedID extends SimpleSAML_Au
             return;
         }
 
+        /** @var \SAML2\XML\saml\NameID $nameID */
         $nameID = $state['saml:NameID'][\SAML2\Constants::NAMEID_PERSISTENT];
 
         if ($this->nameId) {
             $doc = \SAML2\DOMDocumentFactory::create();
             $root = $doc->createElement('root');
             $doc->appendChild($root);
-            \SAML2\Utils::addNameId($root, $nameID);
+            $nameID->toXML($root);
             $value = $doc->saveXML($root->firstChild);
         } else {
             $value = $nameID['Value'];
diff --git a/modules/saml/lib/Auth/Source/SP.php b/modules/saml/lib/Auth/Source/SP.php
index 728c97e87..c866a2de4 100644
--- a/modules/saml/lib/Auth/Source/SP.php
+++ b/modules/saml/lib/Auth/Source/SP.php
@@ -218,7 +218,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source {
 		}
 
 		if (isset($state['saml:NameID'])) {
-			if (!is_array($state['saml:NameID'])) {
+			if (!is_array($state['saml:NameID']) && !is_a($state['saml:NameID'], '\SAML2\XML\saml\NameID')) {
 				throw new SimpleSAML_Error_Exception('Invalid value of $state[\'saml:NameID\'].');
 			}
 			$ar->setNameId($state['saml:NameID']);
diff --git a/modules/saml/lib/BaseNameIDGenerator.php b/modules/saml/lib/BaseNameIDGenerator.php
index 24d6d209d..d14a8c250 100644
--- a/modules/saml/lib/BaseNameIDGenerator.php
+++ b/modules/saml/lib/BaseNameIDGenerator.php
@@ -87,26 +87,27 @@ abstract class sspmod_saml_BaseNameIDGenerator extends SimpleSAML_Auth_Processin
 			return;
 		}
 
-		$nameId = array('Value' => $value);
+		$nameId = new \SAML2\XML\saml\NameID();
+		$nameId->value = $value;
 
 		if ($this->nameQualifier === TRUE) {
 			if (isset($state['IdPMetadata']['entityid'])) {
-				$nameId['NameQualifier'] = $state['IdPMetadata']['entityid'];
+				$nameId->NameQualifier = $state['IdPMetadata']['entityid'];
 			} else {
 				SimpleSAML\Logger::warning('No IdP entity ID, unable to set NameQualifier.');
 			}
 		} elseif (is_string($this->nameQualifier)) {
-			$nameId['NameQualifier'] = $this->nameQualifier;
+			$nameId->NameQualifier = $this->nameQualifier;
 		}
 
 		if ($this->spNameQualifier === TRUE) {
 			if (isset($state['SPMetadata']['entityid'])) {
-				$nameId['SPNameQualifier'] = $state['SPMetadata']['entityid'];
+				$nameId->SPNameQualifier = $state['SPMetadata']['entityid'];
 			} else {
 				SimpleSAML\Logger::warning('No SP entity ID, unable to set SPNameQualifier.');
 			}
 		} elseif (is_string($this->spNameQualifier)) {
-			$nameId['SPNameQualifier'] = $this->spNameQualifier;
+			$nameId->SPNameQualifier = $this->spNameQualifier;
 		}
 
 		$state['saml:NameID'][$this->format] = $nameId;
diff --git a/modules/saml/lib/IdP/SAML2.php b/modules/saml/lib/IdP/SAML2.php
index e8521efd6..158cdd21b 100644
--- a/modules/saml/lib/IdP/SAML2.php
+++ b/modules/saml/lib/IdP/SAML2.php
@@ -974,7 +974,7 @@ class sspmod_saml_IdP_SAML2
 
         if (isset($state['saml:NameID'][$nameIdFormat])) {
             $nameId = $state['saml:NameID'][$nameIdFormat];
-            $nameId['Format'] = $nameIdFormat;
+            $nameId->Format = $nameIdFormat;
         } else {
             $spNameQualifier = $spMetadata->getString('SPNameQualifier', null);
             if ($spNameQualifier === null) {
@@ -995,11 +995,10 @@ class sspmod_saml_IdP_SAML2
                 }
             }
 
-            $nameId = array(
-                'Format'          => $nameIdFormat,
-                'Value'           => $nameIdValue,
-                'SPNameQualifier' => $spNameQualifier,
-            );
+            $nameId = new \SAML2\XML\saml\NameID();
+            $nameId->Format = $nameIdFormat;
+            $nameId->value = $nameIdValue;
+            $nameId->SPNameQualifier = $spNameQualifier;
         }
 
         $state['saml:idp:NameID'] = $nameId;
diff --git a/modules/saml/lib/SP/LogoutStore.php b/modules/saml/lib/SP/LogoutStore.php
index f56b2bedb..94b895ee1 100644
--- a/modules/saml/lib/SP/LogoutStore.php
+++ b/modules/saml/lib/SP/LogoutStore.php
@@ -152,11 +152,17 @@ class sspmod_saml_SP_LogoutStore {
 	/**
 	 * Register a new session in the datastore.
 	 *
+	 * Please observe the change of the signature in this method. Previously, the second parameter ($nameId) was forced
+	 * to be an array. However, it has no type restriction now, and the documentation states it must be a
+	 * \SAML2\XML\saml\NameID object. Currently, this function still accepts an array passed as $nameId, and will
+	 * silently convert it to a \SAML2\XML\saml\NameID object. This is done to keep backwards-compatibility, though will
+	 * no longer be possible in the future as the $nameId parameter will be required to be an object.
+	 *
 	 * @param string $authId  The authsource ID.
-	 * @param array $nameId  The NameID of the user.
+	 * @param \SAML2\XML\saml\NameID $nameId The NameID of the user.
 	 * @param string|NULL $sessionIndex  The SessionIndex of the user.
 	 */
-	public static function addSession($authId, array $nameId, $sessionIndex, $expire) {
+	public static function addSession($authId, $nameId, $sessionIndex, $expire) {
 		assert('is_string($authId)');
 		assert('is_string($sessionIndex) || is_null($sessionIndex)');
 		assert('is_int($expire)');
@@ -176,8 +182,11 @@ class sspmod_saml_SP_LogoutStore {
 			return;
 		}
 
-		/* Normalize NameID. */
-		ksort($nameId);
+		// serialize and anonymize the NameID
+        // TODO: remove this conditional statement
+		if (is_array($nameId)) {
+			$nameId = \SAML2\XML\saml\NameID::fromArray($nameId);
+		}
 		$strNameId = serialize($nameId);
 		$strNameId = sha1($strNameId);
 
diff --git a/templates/includes/attributes.php b/templates/includes/attributes.php
index b7539fa14..79aae3130 100644
--- a/templates/includes/attributes.php
+++ b/templates/includes/attributes.php
@@ -31,6 +31,26 @@ function present_assoc($attr)
     }
 }
 
+function present_eptid(\SimpleSAML\Locale\Translate $t, \SAML2\XML\saml\NameID $nameID)
+{
+    $eptid = array(
+        'NameID' => array($nameID->value),
+    );
+    if (!empty($nameID->Format)) {
+        $eptid[$t->t('{status:subject_format}')] = array($nameID->Format);
+    }
+    if (!empty($nameID->NameQualifier)) {
+        $eptid['NameQualifier'] = array($nameID->NameQualifier);
+    }
+    if (!empty($nameID->SPNameQualifier)) {
+        $eptid['SPNameQualifier'] = array($nameID->SPNameQualifier);
+    }
+    if (!empty($nameID->SPProvidedID)) {
+        $eptid['SPProvidedID'] = array($nameID->SPProvidedID);
+    }
+    return '<td class="attrvalue">'.present_assoc($eptid);
+}
+
 function present_attributes(SimpleSAML_XHTML_Template $t, $attributes, $nameParent)
 {
     $alternate = array('odd', 'even');
@@ -42,7 +62,8 @@ function present_attributes(SimpleSAML_XHTML_Template $t, $attributes, $namePare
 
     foreach ($attributes as $name => $value) {
         $nameraw = $name;
-        $name = $t->getTranslator()->getAttributeTranslation($parentStr.$nameraw);
+        $trans = $t->getTranslator();
+        $name = $trans->getAttributeTranslation($parentStr.$nameraw);
 
         if (preg_match('/^child_/', $nameraw)) {
             $parentName = preg_replace('/^child_/', '', $nameraw);
@@ -79,7 +100,7 @@ function present_attributes(SimpleSAML_XHTML_Template $t, $attributes, $namePare
                         '" /></td></tr>';
                 } elseif (is_a($value[0], 'DOMNodeList')) {
                     // try to see if we have a NameID here
-                    /** @var DOMNodeList $value[0] */
+                    /** @var DOMNodeList $value [0] */
                     $n = $value[0]->length;
                     for ($idx = 0; $idx < $n; $idx++) {
                         $elem = $value[0]->item($idx);
@@ -87,24 +108,13 @@ function present_attributes(SimpleSAML_XHTML_Template $t, $attributes, $namePare
                         if (!($elem->localName === 'NameID' && $elem->namespaceURI === \SAML2\Constants::NS_SAML)) {
                             continue;
                         }
-                        $nameID = new \SAML2\XML\saml\NameID($elem);
-                        $eptid = array(
-                            'NameID' => array($nameID->value),
-                        );
-                        if (!empty($nameID->Format)) {
-                            $eptid['Format'] = array($nameID->Format);
-                        }
-                        if (!empty($nameID->NameQualifier)) {
-                            $eptid['NameQualifier'] = array($nameID->NameQualifier);
-                        }
-                        if (!empty($nameID->SPNameQualifier)) {
-                            $eptid['SPNameQualifier'] = array($nameID->SPNameQualifier);
-                        }
-                        $str .= '<td class="attrvalue">';
-                        $str .= present_assoc($eptid);
+                        $str .= present_eptid($trans, new \SAML2\XML\saml\NameID($elem));
                         break; // we only support one NameID here
                     }
                     $str .= '</td></tr>';
+                } elseif (is_a($value[0], '\SAML2\XML\saml\NameID')) {
+                    $str .= present_eptid($trans, $value[0]);
+                    $str .= '</td></tr>';
                 } else {
                     $str .= '<td class="attrvalue">'.htmlspecialchars($value[0]).'</td></tr>';
                 }
diff --git a/templates/status.php b/templates/status.php
index 25b6e0207..798b546ac 100644
--- a/templates/status.php
+++ b/templates/status.php
@@ -35,15 +35,27 @@ echo(present_attributes($this, $attributes, ''));
 
 $nameid = $this->data['nameid'];
 if ($nameid !== false) {
+    /** @var \SAML2\XML\saml\NameID $nameid */
     echo "<h2>".$this->t('{status:subject_header}')."</h2>";
-    if (!isset($nameid['Value'])) {
+    if (is_null($nameid->value)) {
         $list = array("NameID" => array($this->t('{status:subject_notset}')));
         echo "<p>NameID: <span class=\"notset\">".$this->t('{status:subject_notset}')."</span></p>";
     } else {
         $list = array(
-            "NameId"                            => array($nameid['Value']),
-            $this->t('{status:subject_format}') => array($nameid['Format'])
+            "NameId"                            => array($nameid->value),
         );
+        if (!is_null($nameid->Format)) {
+            $list[$this->t('{status:subject_format}')] = array($nameid->Format);
+        }
+        if (!is_null($nameid->NameQualifier)) {
+            $list['NameQualifier'] = array($nameid->NameQualifier);
+        }
+        if (!is_null($nameid->SPNameQualifier)) {
+            $list['SPNameQualifier'] = array($nameid->SPNameQualifier);
+        }
+        if (!is_null($nameid->SPProvidedID)) {
+            $list['SPProvidedID'] = array($nameid->SPProvidedID);
+        }
     }
     echo(present_attributes($this, $list, ''));
 }
diff --git a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php
index aeaa357b8..c88def979 100644
--- a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php
+++ b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php
@@ -190,8 +190,8 @@ class SP_Test extends \PHPUnit_Framework_TestCase
         $ar = $this->createAuthnRequest($state);
 
         $nameID = $ar->getNameId();
-        $this->assertEquals($state['saml:NameID']['Value'], $nameID['Value']);
-        $this->assertEquals($state['saml:NameID']['Format'], $nameID['Format']);
+        $this->assertEquals($state['saml:NameID']['Value'], $nameID->value);
+        $this->assertEquals($state['saml:NameID']['Format'], $nameID->Format);
 
         /** @var $xml \DOMElement */
         $xml = $ar->toSignedXML();
-- 
GitLab