diff --git a/docs/simplesamlphp-authproc.txt b/docs/simplesamlphp-authproc.txt
index da1500f0134219be7d48300defe5fa127ee44bd7..1dfd97ac85102ac7e76583422b3ed6e3d8c5de8f 100644
--- a/docs/simplesamlphp-authproc.txt
+++ b/docs/simplesamlphp-authproc.txt
@@ -147,6 +147,7 @@ The following filters are included in the simpleSAMLphp distribution:
 - [`saml:ExpectedAuthnContextClassRef`](./saml:authproc_expectedauthncontextclassref): Verify the user's authentication context.
 - [`saml:NameIDAttribute`](./saml:nameidattribute): Create an attribute based on the NameID we receive from the IdP.
 - [`saml:PersistentNameID`](./saml:nameid): Generate persistent NameID from an attribute.
+- [`saml:PersistentNameID2TargetedID`](./saml:nameid): Store persistent NameID as eduPersonTargetedID.
 - [`saml:TransientNameID`](./saml:nameid): Generate transient NameID.
 - [`smartattributes:SmartID`](./smartattributes:smartattributes): Generate user ID attribute based on several attributes.
 
diff --git a/modules/saml/docs/nameid.txt b/modules/saml/docs/nameid.txt
index 3feb648f25d898b9588ebc212685e9c817c56c8e..5da34e0f8e2dd22b39695d5ce39810823f337b90 100644
--- a/modules/saml/docs/nameid.txt
+++ b/modules/saml/docs/nameid.txt
@@ -77,6 +77,27 @@ This filter will only create new NameIDs when the SP specifies `AllowCreate="tru
 :   The name of the attribute we should use as the unique user ID.
 
 
+`saml:PersistentNameID2TargetedID`
+----------------------------------
+
+Stores a persistent NameID in the `eduPersonTargetedID`-attribute.
+
+This filter is not actually a NameID generation filter.
+Instead, it takes a persistent NameID and adds it as an attribute in the assertion.
+This can be used to set the `eduPersonTargetedID`-attribute to the same value as the persistent NameID.
+
+### Options
+
+`attribute`
+:   The name of the attribute we should store the result in.
+    The default is `eduPersonTargetedID`.
+
+`nameId`
+:   Whether the generated attribute should be an saml:NameID element.
+    The default is `TRUE`.
+
+
+
 Example
 -------
 
@@ -108,3 +129,29 @@ Storing persistent NameIDs in a SQL database:
             'attribute' => 'eduPersonPrincipalName',
         ),
     ),
+
+Generating Persistent NameID and eduPersonTargetedID.
+
+    'authproc' => array(
+        // Generate the persistent NameID.
+        2 => array(
+            'class' => 'saml:PersistentNameID',
+            'attribute' => 'eduPersonPrincipalName',
+        ),
+        // Add the persistent to the eduPersonTargetedID attribute
+        60 => array(
+            'class' => 'saml:PersistentNameID2TargetedID',
+            'attribute' => 'eduPersonTargetedID', // The default
+            'nameId' => TRUE, // The default
+        ),
+        // Use OID attribute names.
+        90 => array(
+            'class' => 'core:AttributeMap',
+            'name2oid',
+        ),
+    ),
+    // The URN attribute NameFormat for OID attributes.
+    'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
+    'attributeencodings' => array(
+        'urn:oid:1.3.6.1.4.1.5923.1.1.1.10' => 'raw', /* eduPersonTargetedID with oid NameFormat is a raw XML value */
+    ),
diff --git a/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php b/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php
new file mode 100644
index 0000000000000000000000000000000000000000..ac5929ea58c845b70b0f5d0bbfc55939bc41d210
--- /dev/null
+++ b/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * Authproc filter to create the eduPersonTargetedID attribute from the persistent NameID.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class sspmod_saml_Auth_Process_PersistentNameID2TargetedID extends SimpleSAML_Auth_ProcessingFilter {
+
+	/**
+	 * The attribute we should save the NameID in.
+	 *
+	 * @var string
+	 */
+	private $attribute;
+
+
+	/**
+	 * Whether we should insert it as an saml:NameID element.
+	 *
+	 * @var boolean
+	 */
+	private $nameId;
+
+
+	/**
+	 * Initialize this filter, parse configuration.
+	 *
+	 * @param array $config  Configuration information about this filter.
+	 * @param mixed $reserved  For future use.
+	 */
+	public function __construct($config, $reserved) {
+		parent::__construct($config, $reserved);
+		assert('is_array($config)');
+
+		if (isset($config['attribute'])) {
+			$this->attribute = (string)$config['attribute'];
+		} else {
+			$this->attribute = 'eduPersonTargetedID';
+		}
+
+		if (isset($config['nameId'])) {
+			$this->nameId = (bool)$config['nameId'];
+		} else {
+			$this->nameId = TRUE;
+		}
+	}
+
+
+	/**
+	 * Store a NameID to attribute.
+	 *
+	 * @param array &$state  The request state.
+	 */
+	public function process(&$state) {
+		assert('is_array($state)');
+
+		if (!isset($state['saml:NameID'][SAML2_Const::NAMEID_PERSISTENT])) {
+			SimpleSAML_Logger::warning('Unable to generate eduPersonTargetedID because no persistent NameID was available.');
+			return;
+		}
+
+		$nameID = $state['saml:NameID'][SAML2_Const::NAMEID_PERSISTENT];
+
+		if ($this->nameId) {
+			$doc = new DOMDocument();
+			$root = $doc->createElement('root');
+			$doc->appendChild($root);
+			SAML2_Utils::addNameId($root, $nameID);
+			$value = $doc->saveXML($root->firstChild);
+		} else {
+			$value = $nameID['Value'];
+		}
+
+		$state['Attributes'][$this->attribute] = array($value);
+	}
+
+}