diff --git a/modules/core/docs/authproc_attributevaluemap.txt b/modules/core/docs/authproc_attributevaluemap.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cf7468a5f4ff2b9537777c08d3ad1dd2e1b89427
--- /dev/null
+++ b/modules/core/docs/authproc_attributevaluemap.txt
@@ -0,0 +1,83 @@
+`core:AttributeValueMap`
+===================
+
+Filter that creates a target attribute based on one or more value(s) in source attribute.
+
+%replace can be used to replace all existing values in target with new ones (any existing values will be lost)
+%keep can be used to keep the source attribute, otherwise it will be removed.
+
+Examples
+--------
+
+Add student affiliation based on LDAP groupmembership.
+Will add eduPersonAffiliation containing value "student" if memberOf attribute contains
+either 'cn=student,o=some,o=organization,dc=org' or 'cn=student,o=other,o=organization,dc=org'.
+'memberOf' attribute will be removed (use %keep, to keep it) and existing values in
+'eduPersonAffiliation' will be merged (use %replace to replace them).
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:AttributeValueMap',
+            'sourceattribute' => 'memberOf',
+            'targetattribute' => 'eduPersonAffiliation',
+            'values' => array(
+                'student' => array(
+                    'cn=student,o=some,o=organization,dc=org',
+                    'cn=student,o=other,o=organization,dc=org',
+                ),
+            ),
+        ),
+    )
+
+Multiple assignments.
+Add student, employee and both affiliation based on LDAP groupmembership in memberOf attribute.
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:AttributeValueMap',
+            'sourceattribute' => 'memberOf',
+            'targetattribute' => 'eduPersonAffiliation',
+            'values' => array(
+                'student' => array(
+                    'cn=student,o=some,o=organization,dc=org',
+                    'cn=student,o=other,o=organization,dc=org',
+                ),
+                'employee' => array(
+                    'cn=employees,o=some,o=organization,dc=org',
+                    'cn=employee,o=other,o=organization,dc=org',
+                    'cn=workers,o=any,o=organization,dc=org',
+                ),
+                'both' => array(
+                    'cn=student,o=some,o=organization,dc=org',
+                    'cn=student,o=other,o=organization,dc=org',
+                    'cn=employees,o=some,o=organization,dc=org',
+                    'cn=employee,o=other,o=organization,dc=org',
+                    'cn=workers,o=any,o=organization,dc=org',
+                ),
+            ),
+        ),
+    )
+
+Replace and Keep.
+Replace any existing 'affiliation' attribute values and keep 'groups' attribute.
+    
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:AttributeValueMap',
+            'sourceattribute' => 'groups',
+            'targetattribute' => 'affiliation',
+            '%replace',
+            '%keep',
+            'values' => array(
+                'student' => array(
+                    'cn=student,o=some,o=organization,dc=org',
+                    'cn=student,o=other,o=organization,dc=org',
+                ),
+                'employee' => array(
+                    'cn=employees,o=some,o=organization,dc=org',
+                    'cn=employee,o=other,o=organization,dc=org',
+                    'cn=workers,o=any,o=organization,dc=org',
+                ),
+            ),
+        ),
+    )
diff --git a/modules/core/lib/Auth/Process/AttributeValueMap.php b/modules/core/lib/Auth/Process/AttributeValueMap.php
new file mode 100644
index 0000000000000000000000000000000000000000..231f2d327ea7611d8179048ca43bd0dd4008e78f
--- /dev/null
+++ b/modules/core/lib/Auth/Process/AttributeValueMap.php
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * Filter to create target attribute based on value(s) in source attribute
+ *
+ * @author Martin van Es, m7
+ * @package simpleSAMLphp
+ */
+class sspmod_core_Auth_Process_AttributeValueMap extends SimpleSAML_Auth_ProcessingFilter {
+
+    /**
+    * The attributename we should assign values to (ie target)
+    */
+    private $targetattribute;
+
+    /**
+    * The attributename we should create values from
+    */
+    private $sourceattribute;
+
+    /**
+    * The required $sourceattribute values and target affiliations
+    */
+    private $values = array();
+    
+    /**
+    * Wether $sourceattribute should be kept
+    */
+    private $keep = false;
+
+    /**
+    * Wether $target attribute values should be replaced by new values
+    */
+    private $replace = false;
+    
+    /**
+    * Initialize this filter.
+    *
+    * @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)');
+
+        /* Validate configuration. */
+        foreach ($config as $name => $value) {
+            if (is_int($name)) {
+                // check if this is an option
+                if ($value === '%replace') {
+                        $this->replace = true;
+                } elseif ($value === '%keep') {
+                        $this->keep = true;
+                } else {
+                        throw new SimpleSAML_Error_Exception('Unknown flag : ' . var_export($value, true));
+                }
+                continue;
+            }
+
+            // Set targetattribute
+            if ($name === 'targetattribute') {
+                $this->targetattribute = $value;
+            }
+
+            // Set sourceattribute
+            if ($name === 'sourceattribute') {
+                $this->sourceattribute = $value;
+            }
+        
+            // Set values
+            if ($name === 'values') {
+                $this->values = $value;
+            }
+        }
+    }
+
+
+    /**
+        * Apply filter to add groups attribute.
+        *
+        * @param array &$request  The current request
+        */
+    public function process(&$request) {
+        SimpleSAML_Logger::debug('AttributeValueMap - process');
+
+        assert('is_array($request)');
+        assert('array_key_exists("Attributes", $request)');
+        $attributes =& $request['Attributes'];
+
+        // Make sure sourceattribute exists
+        assert('array_key_exists($this->sourceattribute, $attributes)');
+        // Make sure the targetattribute is set
+        assert('is_string($this->targetattribute)');
+        
+        $sourceattribute = $attributes[$this->sourceattribute];
+        $targetvalues = array();
+
+        if (is_array($sourceattribute)) {
+            foreach ($this->values as $value => $require) {
+                if (count(array_intersect($require, $sourceattribute)) > 0) {
+                    SimpleSAML_Logger::debug('AttributeValueMap - intersect match for ' . $value);
+                    $targetvalues[] = $value;
+                }
+            }
+        }
+
+        if (count($targetvalues) > 0) {
+            if ($this->replace or !@is_array($attributes[$this->targetattribute])) {
+                $attributes[$this->targetattribute] = $targetvalues;
+            } else {
+                $attributes[$this->targetattribute] = array_unique(array_merge($attributes[$this->targetattribute], $targetvalues));
+            }
+        }
+
+        if (!$this->keep) {
+            unset($attributes[$this->sourceattribute]);
+        }
+    }
+}
diff --git a/tests/modules/core/lib/Auth/Process/AttributeValueMapTest.php b/tests/modules/core/lib/Auth/Process/AttributeValueMapTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..426f2bad080007cc1c87dafd9bb0c3c051995701
--- /dev/null
+++ b/tests/modules/core/lib/Auth/Process/AttributeValueMapTest.php
@@ -0,0 +1,196 @@
+<?php
+
+/**
+ * Test for the core:AttributeValueMap filter.
+ */
+class Test_Core_Auth_Process_AttributeValueMap extends PHPUnit_Framework_TestCase
+{
+
+    /**
+     * Helper function to run the filter with a given configuration.
+     *
+     * @param array $config  The filter configuration.
+     * @param array $request  The request state.
+     * @return array  The state array after processing.
+     */
+    private static function processFilter(array $config, array $request) {
+        $filter = new sspmod_core_Auth_Process_AttributeValueMap($config, null);
+        $filter->process($request);
+        return $request;
+    }
+
+    /**
+     * Test the most basic functionality.
+     */
+    public function testBasic() {
+        $config = array(
+            'sourceattribute' => 'memberOf',
+            'targetattribute' => 'eduPersonAffiliation',
+            'values' => array(
+                'member' => array(
+                    'theGroup',
+                    'otherGroup',
+                ),
+            ),
+        );
+        $request = array(
+            'Attributes' => array(
+                'memberOf' => array('theGroup'),
+            ),
+        );
+        $result = self::processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $this->assertArrayNotHasKey('memberOf', $attributes);
+        $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
+        $this->assertEquals($attributes['eduPersonAffiliation'], array('member'));
+    }
+
+    /**
+     * Test basic functionality, remove duplicates
+     */
+    public function testNoDuplicates() {
+        $config = array(
+            'sourceattribute' => 'memberOf',
+            'targetattribute' => 'eduPersonAffiliation',
+            'values' => array(
+                'member' => array(
+                    'theGroup',
+                    'otherGroup',
+                ),
+            ),
+        );
+        $request = array(
+            'Attributes' => array(
+                'memberOf' => array('theGroup', 'otherGroup'),
+                'eduPersonAffiliation' => array('member', 'someValue'),
+            ),
+        );
+        $result = self::processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $this->assertArrayNotHasKey('memberOf', $attributes);
+        $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
+        $this->assertEquals($attributes['eduPersonAffiliation'], array('member', 'someValue'));
+    }
+
+    /**
+     * Test the %replace functionality.
+     */
+    public function testReplace() {
+        $config = array(
+            'sourceattribute' => 'memberOf',
+            'targetattribute' => 'eduPersonAffiliation',
+            '%replace',
+            'values' => array(
+                'member' => array(
+                    'theGroup',
+                    'otherGroup',
+                ),
+            ),
+        );
+        $request = array(
+            'Attributes' => array(
+                'memberOf' => array('theGroup'),
+                'eduPersonAffiliation' => array('someValue'),                
+            ),
+        );
+        $result = self::processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $this->assertArrayNotHasKey('memberOf', $attributes);
+        $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
+        $this->assertEquals($attributes['eduPersonAffiliation'], array('member'));
+    }
+
+    /**
+     * Test the %keep functionality.
+     */
+    public function testKeep() {
+        $config = array(
+            'sourceattribute' => 'memberOf',
+            'targetattribute' => 'eduPersonAffiliation',
+            '%keep',
+            'values' => array(
+                'member' => array(
+                    'theGroup',
+                    'otherGroup',
+                ),
+            ),
+        );
+        $request = array(
+            'Attributes' => array(
+                'memberOf' => array('theGroup'),
+                'eduPersonAffiliation' => array('someValue'),                
+            ),
+        );
+        $result = self::processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $this->assertArrayHasKey('memberOf', $attributes);
+        $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
+        $this->assertEquals($attributes['eduPersonAffiliation'], array('someValue','member'));
+    }
+
+    /**
+     * Test unknown flag Exception
+     *
+     * @expectedException Exception
+     */
+    public function testUnknownFlag() {
+        $config = array(
+            '%test',
+            'values' => array(
+                'member' => array(
+                    'theGroup',
+                ),
+            ),
+        );
+        $request = array(
+            'Attributes' => array(
+                'memberOf' => array('theGroup'),
+            ),
+        );
+        $result = self::processFilter($config, $request);
+    }
+
+    /**
+     * Test missing Source attribute
+     *
+     * @expectedException Exception
+     */
+    public function testMissingSourceAttribute() {
+        $config = array(
+            'targetattribute' => 'affiliation',
+            'values' => array(
+                'member' => array(
+                    'theGroup',
+                ),
+            ),
+        );
+        $request = array(
+            'Attributes' => array(
+                'memberOf' => array('theGroup'),
+            ),
+        );
+        $result = self::processFilter($config, $request);
+    }
+
+    /**
+     * Test missing Target attribute
+     *
+     * @expectedException Exception
+     */
+    public function testMissingTargetAttribute() {
+        $config = array(
+            'sourceattribute' => 'memberOf',
+            'values' => array(
+                'member' => array(
+                    'theGroup',
+                ),
+            ),
+        );
+        $request = array(
+            'Attributes' => array(
+                'memberOf' => array('theGroup'),
+            ),
+        );
+        $result = self::processFilter($config, $request);
+    }
+}