diff --git a/modules/adfs/config-templates/adfs-idp-hosted.php b/modules/adfs/config-templates/adfs-idp-hosted.php
new file mode 100644
index 0000000000000000000000000000000000000000..bba2ac08c25c0a2cae70b2de6e6dafe99a6d7b59
--- /dev/null
+++ b/modules/adfs/config-templates/adfs-idp-hosted.php
@@ -0,0 +1,11 @@
+<?php
+
+$config = array(
+
+	'key' =>  'server.pem',
+	'cert' => 'server.crt',
+	'auth' => 'auth/login.php',
+
+);
+
+?>
diff --git a/modules/adfs/config-templates/adfs-sp-remote.php b/modules/adfs/config-templates/adfs-sp-remote.php
new file mode 100644
index 0000000000000000000000000000000000000000..669a747bd04d74ce77d0492af5584d72ad1e0608
--- /dev/null
+++ b/modules/adfs/config-templates/adfs-sp-remote.php
@@ -0,0 +1,19 @@
+<?php
+
+$config = array( 
+
+	'urn:federation:localhost:adfs' => array(
+
+		'prp' => 'https://localhost/adfs/ls/',
+		'simplesaml.nameidattribute' => 'uid',
+		'authproc' => array(
+			50 => array(
+				'class' => 'core:AttributeLimit',
+				'cn', 'mail', 'uid'
+			),
+		),
+	),
+
+);
+
+?>
diff --git a/modules/adfs/default-disable b/modules/adfs/default-disable
new file mode 100644
index 0000000000000000000000000000000000000000..fa0bd82e2df7bd79d57593d35bc53c1f9d3ef71f
--- /dev/null
+++ b/modules/adfs/default-disable
@@ -0,0 +1,3 @@
+This file indicates that the default state of this module
+is disabled. To enable, create a file named enable in the
+same directory as this file.
diff --git a/modules/adfs/www/idp/prp.php b/modules/adfs/www/idp/prp.php
new file mode 100644
index 0000000000000000000000000000000000000000..dd5155803089a14e0ba6393090b6690b6742e44e
--- /dev/null
+++ b/modules/adfs/www/idp/prp.php
@@ -0,0 +1,256 @@
+<?php
+/**
+ * ADFS PRP IDP protocol support for simpleSAMLphp.
+ *
+ * @author Hans Zandbelt, SURFnet BV. <hans.zandbelt@surfnet.nl>
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+
+$config = SimpleSAML_Configuration::getInstance();
+$adfsconfig = SimpleSAML_Configuration::getConfig('adfs-idp-hosted.php');
+$session = SimpleSAML_Session::getInstance();
+
+SimpleSAML_Logger::info('ADFS - IdP.SSOService: Accessing ADFS IdP endpoint SSOService');
+
+try {
+	if (array_key_exists('entityId', $config)) {
+		$idpentityid = $config['entityId'];
+	} else {
+		$idpentityid = 'urn:federation:' . SimpleSAML_Utilities::getSelfHost() . ':idp';
+	}
+} catch (Exception $exception) {
+	SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception);
+}
+
+SimpleSAML_Logger::info('ADFS - IdP.SSOService: Accessing ADFS IdP endpoint SSOService');
+
+function ADFS_GenerateResponse($issuer, $target, $nameid, $attributes) {
+#	$nameid = 'hans@surfnet.nl';
+	$issueInstant = SimpleSAML_Utilities::generateTimestamp();
+	$notBefore = SimpleSAML_Utilities::generateTimestamp(time() - 30);
+	$assertionExpire = SimpleSAML_Utilities::generateTimestamp(time() + 60 * 5);
+	$assertionID = SimpleSAML_Utilities::generateID();
+	$nameidFormat = 'http://schemas.xmlsoap.org/claims/UPN';
+	$result =
+'<wst:RequestSecurityTokenResponse xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust">
+   <wst:RequestedSecurityToken>
+     <saml:Assertion Issuer="' . $issuer . '" IssueInstant="' . $issueInstant . '" AssertionID="' . $assertionID . '" MinorVersion="1" MajorVersion="1" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
+       <saml:Conditions NotOnOrAfter="' . $assertionExpire . '" NotBefore="' . $notBefore . '">
+         <saml:AudienceRestrictionCondition>
+           <saml:Audience>' . $target .'</saml:Audience>
+         </saml:AudienceRestrictionCondition>
+       </saml:Conditions>
+       <saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified" AuthenticationInstant="' . $issueInstant . '">
+         <saml:Subject>
+           <saml:NameIdentifier Format="' . $nameidFormat . '">' . $nameid . '</saml:NameIdentifier>
+         </saml:Subject>
+       </saml:AuthenticationStatement>
+       <saml:AttributeStatement>
+         <saml:Subject>
+           <saml:NameIdentifier Format="' . $nameidFormat . '">' . $nameid . '</saml:NameIdentifier>
+         </saml:Subject>';
+	foreach ($attributes as $name => $values) {
+		$result .= '<saml:Attribute AttributeNamespace="http://schemas.xmlsoap.org/claims" AttributeName="' . $name .'">';
+		foreach ($values as $value) {
+			$result .= '<saml:AttributeValue>' . $value . '</saml:AttributeValue>';
+		}
+		$result .= '</saml:Attribute>';
+	}
+	$result .= '
+       </saml:AttributeStatement>
+     </saml:Assertion>
+   </wst:RequestedSecurityToken>
+   <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><wsa:EndpointReference xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
+     <wsa:Address>' . $target . '</wsa:Address>
+   </wsa:EndpointReference></wsp:AppliesTo>
+ </wst:RequestSecurityTokenResponse>';
+	return $result;
+}
+
+function ADFS_SignResponse($response, $key, $cert) {
+	$objXMLSecDSig = new XMLSecurityDSig();
+	$objXMLSecDSig->idKeys = array('AssertionID');	
+	$objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);	
+	$responsedom = new DOMDocument();
+	$responsedom->loadXML(str_replace ("\r", "", $response));
+	$firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0);
+	$objXMLSecDSig->addReferenceList(array($firstassertionroot), XMLSecurityDSig::SHA1,
+		array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N),
+		array('id_name' => 'AssertionID'));
+	$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
+	$objKey->loadKey($key, TRUE);
+	$objXMLSecDSig->sign($objKey);
+	if ($cert) {
+		$public_cert = file_get_contents($cert);
+		$objXMLSecDSig->add509Cert($public_cert, TRUE);
+	}
+	$newSig = $responsedom->importNode($objXMLSecDSig->sigNode, TRUE);
+	$firstassertionroot->appendChild($newSig);	
+	return $responsedom->saveXML();
+}
+
+function ADFS_PostResponse($url, $wresult, $wctx) {
+	print '
+<body onload="document.forms[0].submit()"><form method="post" action="' . $url . '">
+	<input type="hidden" name="wa" value="wsignin1.0">
+	<input type="hidden" name="wresult" value="' . htmlspecialchars($wresult) . '">
+	<input type="hidden" name="wctx" value="' . htmlspecialchars($wctx) . '">
+	<noscript><input type="submit" value="Continue"></noscript>
+</form></body>';
+	exit;
+}
+
+if (isset($_GET['wa'])) {
+
+	if ($_GET['wa'] == 'wsignin1.0') {
+		try {
+			// accomodate for disfunctional $_GET "windows" slash decoding in PHP
+			$wctx = $_GET['wctx'];
+			foreach (split('&', $_SERVER['REQUEST_URI']) as $e) {
+				$a = split('=', $e);
+				if ($a[0] == 'wctx') $wctx = urldecode($a[1]);
+			}
+			$requestid = $wctx;
+			$issuer = $_GET['wtrealm'];
+			$requestcache = array(
+				'RequestID' => $requestid,
+				'Issuer' => $issuer,
+				'RelayState' => $requestid
+			);
+
+			$spentityid = $requestcache['Issuer'];
+		
+			SimpleSAML_Logger::info('ADFS - IdP.SSOService: Incoming Authentication request: '.$issuer.' id '.$requestid);
+	
+		} catch(Exception $exception) {
+			SimpleSAML_Utilities::fatalError($session->getTrackID(), 'PROCESSAUTHNREQUEST', $exception);
+		}
+	}
+
+} elseif(isset($_GET['RequestID'])) {
+
+	try {
+	
+		SimpleSAML_Logger::info('ADFS - IdP.SSOService: Got incoming authentication ID');
+		
+		$authId = $_GET['RequestID'];
+		$requestcache = $session->getAuthnRequest('adfs', $authId);
+		if (!$requestcache) {
+			throw new Exception('Could not retrieve cached RequestID = ' . $authId);
+		}
+		
+	} catch(Exception $exception) {
+		SimpleSAML_Utilities::fatalError($session->getTrackID(), 'CACHEAUTHNREQUEST', $exception);
+	}
+	
+} elseif(isset($_REQUEST[SimpleSAML_Auth_ProcessingChain::AUTHPARAM])) {
+
+	$authProcId = $_REQUEST[SimpleSAML_Auth_ProcessingChain::AUTHPARAM];
+	$authProcState = SimpleSAML_Auth_ProcessingChain::fetchProcessedState($authProcId);
+	$requestcache = $authProcState['core:adfs-idp:requestcache'];
+
+} else {
+	SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SSOSERVICEPARAMS');
+}
+
+if(SimpleSAML_Auth_Source::getById($adfsconfig->getValue('auth')) !== NULL) {
+	$authSource = TRUE;
+	$authority = $adfsconfig->getValue('auth');
+} else {
+	$authSource = FALSE;
+	$authority = $adfsconfig->getValue('authority');
+}
+
+if (!$session->isValid($authority) ) {
+
+	SimpleSAML_Logger::info('ADFS - IdP.SSOService: Will go to authentication module ' . $adfsconfig->getValue('auth'));
+
+	$authId = SimpleSAML_Utilities::generateID();
+	$session->setAuthnRequest('adfs', $authId, $requestcache);
+
+	$redirectTo = SimpleSAML_Utilities::selfURLNoQuery() . '?RequestID=' . urlencode($authId);
+
+	if($authSource) {
+
+		SimpleSAML_Auth_Default::initLogin($adfsconfig->getValue('auth'), $redirectTo, NULL, NULL);
+	} else {
+		$authurl = '/' . $config->getBaseURL() . $adfsconfig->getValue('auth');
+
+		SimpleSAML_Utilities::redirect($authurl, array(
+		       'RelayState' => $redirectTo,
+		       'AuthId' => $authId,
+		       'protocol' => 'adfs',
+		));
+	}
+
+} else {
+
+	try {
+	
+		$spentityid = $requestcache['Issuer'];
+		$spmetadata = SimpleSAML_Configuration::getConfig('adfs-sp-remote.php');
+		$spmetadata = SimpleSAML_Configuration::loadFromArray($spmetadata->getValue($spentityid));
+
+		$sp_name = $spmetadata->getValue('name', $spentityid);
+
+		SimpleSAML_Logger::info('ADFS - IdP.SSOService: Sending back AuthnResponse to ' . $spentityid);
+		
+		$attributes = $session->getAttributes();
+		
+		if (!isset($authProcState)) {
+
+			$idpap = $adfsconfig->getValue('authproc');
+			if ($idpap) $idpap = array('authproc' => $idpap); else $idpap = array();
+			
+			$spap = $spmetadata->getValue('authproc');
+			if ($spap) $spap = array('authproc' => $spap); else $spap = array();
+			
+			$pc = new SimpleSAML_Auth_ProcessingChain($idpap, $spap, 'idp');
+
+			$authProcState = array(
+				'core:adfs-idp:requestcache' => $requestcache,
+				'ReturnURL' => SimpleSAML_Utilities::selfURLNoQuery(),
+				'Attributes' => $attributes,
+				'Destination' => $spap,
+				'Source' => $idpap,
+				'isPassive' => false,
+			);
+
+			$previousSSOTime = $session->getData('adfs-idp-ssotime', $spentityid);
+			if ($previousSSOTime !== NULL) {
+				$authProcState['PreviousSSOTimestamp'] = $previousSSOTime;
+			}
+
+			try {
+				$pc->processState($authProcState);
+			} catch (SimpleSAML_Error_NoPassive $e) {
+				SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $exception);
+			}
+
+			$requestcache['AuthProcState'] = $authProcState;
+		}
+
+		$attributes = $authProcState['Attributes'];
+
+		$session->setData('adfs-idp-ssotime', $spentityid, time(),
+			SimpleSAML_Session::DATA_TIMEOUT_LOGOUT);
+
+		$requestID = NULL; $relayState = NULL;
+		if (array_key_exists('RequestID', $requestcache)) $requestID = $requestcache['RequestID'];
+		if (array_key_exists('RelayState', $requestcache)) $relayState = $requestcache['RelayState'];
+
+		$nameid = $session->getNameID();
+
+		$response = ADFS_GenerateResponse($idpentityid, $spentityid, $nameid['value'], $attributes);
+		$wresult = ADFS_SignResponse($response, $config->getPathValue('certdir') . $adfsconfig->getValue('key'), $config->getPathValue('certdir') . $adfsconfig->getValue('cert'));
+
+		ADFS_PostResponse($spmetadata->getValue('prp'), $wresult, $relayState);
+		
+	} catch(Exception $exception) {
+		SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $exception);
+	}
+	
+}
+
+?>