diff --git a/www/aselect/handler.php b/www/aselect/handler.php
index 3c4d0262364b0855069a97729708d0234b396bfc..0cecd8951c7ae7d1b28e0300505d9a721654bcae 100644
--- a/www/aselect/handler.php
+++ b/www/aselect/handler.php
@@ -1,53 +1,63 @@
 <?php
 
-// Work-in-Progress:
-//
-// This code can be used:
-//   a. to hook up an A-Select Agent or a "local" A-Select server
-//      (=SP) and bridge to a SAML 2.0 IdP, 
-// or
-//   b. as a bridge from simpleSAMLphp local/bridge "auth" to a
-//      "remote" A-Select server.
-//
-// Connect A-Select Agent:
-//   configure the agent.xml as follows (example):
-//     <aselect-server-id>default.aselect.org</aselect-server-id>
-//     <url>https://localhost/simplesaml/aselect/handler.php</url>
-//
-// Connect "local" A-Select Server:
-//   configure simpleSAMLphp as a "remote" aselect server as follows (example):
-//			<organization id="simplSAMLphp"
-//				server="localhost"
-//				friendly_name="simpleSAMLphp (TEST)"
-//				resourcegroup="remote_simplsamlphp_resources" />
-//
-//			<resourcegroup id="remote_simplsamlphp_resources"
-//				interval="30">
-//				<resource id="simpleSAMLphp1">
-//					<url>https://localhost/simplesaml/aselect/handler.php</url>
-//				</resource>
-//			</resourcegroup>
-//
-// Bridge to "remote" A-Select Server:
-//   configure simpleSAMLphp as a "local" aselect server as follows (example):
-//			<organization id="simplSAMLphp" server="localhost">
-//				<level>1</level>
-//				<forced_authenticate>false</forced_authenticate>
-//				<attribute_policy>policyA</attribute_policy>
-//			</organization>
-//
-//   set the "auth" handler in the idp-hosted metadata as follows:
-//		'auth'				=>	'aselect/handler.php?request=bridge',
-//
-// TODO:
-// - extend config possibilities and move it to config/config.php
-//   and metadata/aselect-sp-hosted.php
-// - add robustness/error-handling/error-reporting
-// - generic bridging
-// - check the crypto related stuff (is encrypting rid enough?)
-// - more checks on parameters (really needed?)
+/**
+ * A-Select protocol support for simpleSAMLphp
+ *
+ * @author Hans Zandbelt, SURFnet BV. <hans.zandbelt@surfnet.nl>
+ * @package simpleSAMLphp
+ * @version $Id$
+ * 
+ * This code can be used:
+ *   a. to hook up an A-Select Agent or a "local" A-Select server
+ *      (=SP) and bridge to a SAML 2.0 IdP, 
+ * or
+ *   b. as a bridge from simpleSAMLphp local/bridge "auth" to a
+ *      "remote" A-Select server.
+ *
+ * Connect A-Select Agent:
+ *   configure the agent.xml as follows (example):
+ *     <aselect-server-id>default.aselect.org</aselect-server-id>
+ *     <url>https: *localhost/simplesaml/aselect/handler.php</url>
+ *
+ * Connect "local" A-Select Server:
+ *   configure simpleSAMLphp as a "remote" aselect server as follows (example):
+ *			<organization id="simplSAMLphp"
+ *				server="localhost"
+ *				friendly_name="simpleSAMLphp (TEST)"
+ *				resourcegroup="remote_simplsamlphp_resources" />
+ *
+ *			<resourcegroup id="remote_simplsamlphp_resources"
+ *				interval="30">
+ *				<resource id="simpleSAMLphp1">
+ *					<url>https: *localhost/simplesaml/aselect/handler.php</url>
+ *				</resource>
+ *			</resourcegroup>
+ *
+ * Bridge to "remote" A-Select Server:
+ *   configure simpleSAMLphp as a "local" aselect server as follows (example):
+ *			<organization id="simplSAMLphp" server="localhost">
+ *				<level>1</level>
+ *				<forced_authenticate>false</forced_authenticate>
+ *				<attribute_policy>policyA</attribute_policy>
+ *			</organization>
+ *
+ *   set the "auth" handler in the idp-hosted metadata as follows:
+ *		'auth'				=>	'aselect/handler.php?request=bridge',
+ *
+ * TODO:
+ * - extend config possibilities and move it to metadata/aselect-*-*.php
+ * - add robustness/error-handling/error-reporting
+ * - generic bridging
+ * - check the crypto related stuff (is encrypting rid enough?)
+ * - more checks on parameters (really needed?)
+ *
+ * - factor out common, app/local server and remote server code
+ * - use xmlseclibs or plain openssl, not both
+ * - preload configured keys from their respective files
+ */
 
 require_once('../../www/_include.php');
+require_once('xmlseclibs.php');
 require_once('SimpleSAML/Logger.php');
 require_once('SimpleSAML/Configuration.php');
 require_once('SimpleSAML/Metadata/MetaDataStorageHandler.php');
@@ -58,9 +68,9 @@ $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
 
 $as_config = array(
 	'server_id' => 'default.aselect.org',
-	'organization_id' => 'simplSAMLphp',
+	'organization_id' => 'simpleSAMLphp',
 	'authsp_level' => '10',
-	'authsp' => 'simplSAMLphp',
+	'authsp' => 'simpleSAMLphp',
 	'app_level' => '10',
 	'tgt_exp_time' => '1194590521000',
 	'metadata' => $metadata->getMetaData('localhost', 'saml20-sp-hosted'),
@@ -71,18 +81,63 @@ $as_config = array(
 	'logout_url' => '/' . $config->getValue('baseurlpath') . 'logout.html',
 	'remote_server_id' => 'default.aselect.org',
 	'remote_organization_id' => 'testorg',
-	'remote_server_url' => 'https://localhost/aselectserver/server'
+	'remote_server_url' => 'https://localhost/aselectserver/server',
+	'require_signing' => true,
+	'verify_certificate' => $config->getBaseDir() . '/cert/aselect.crt',
+	'sign_requests' => true,
+	'sign_certificate' => $config->getBaseDir() . '/cert/agent.key'
 );
 
 if ($_GET['local_rid']) session_id($_GET['local_rid']); else if ($_GET['rid']) session_id($_GET['rid']);
 
 session_start();
 
+function as_verify_signature($parms, $publickey) {
+	global $as_config, $logger, $config;	
+	$signature = base64_decode($_GET['signature']);
+	$data = '';
+	foreach ($parms as $p) {
+		if (array_key_exists($p, $_GET)) $data .= $_GET[$p];
+	}
+	if (!file_exists($publickey)) {
+		throw new Exception('Could not find public key file [' . $publickey . '] which is needed to verify the signature.');
+	}
+	$xmlseckey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'public'));
+	$xmlseckey->loadKey($publickey,TRUE);
+	if (openssl_verify ($data, $signature, $xmlseckey->key) != 1) {
+		$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Signature verification failed: '. openssl_error_string());
+		throw new Exception('Signature verification failed: ' . openssl_error_string());
+	}
+	$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Signature on request succesfully verified.');
+}
+
 // handle authenticate request from an agent or a local server
 function as_request_authenticate() {
-	global $as_config;
+	global $as_config, $logger;
+	$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'local_as_url: ' . $_GET['local_as_url']);
+	
+	//required_level=1
+	//signature=mEAywVj%2BMsiK6gcnw6QGKuDWpu5rnDYfgk8yYHzmvSReIhs%2F3H79kAY3ZA53Bm03Npmh6TYPQWRduQrvFvvTrGTQbpw3L0qdGz4X8sfM2ax2UPzhfMU3KtRLN13TPzDakpsPuXtT36t1zuKUsTO127ZRG2itCMGm3WDV%2Futk%2FIA%3D
+	//forced_logon=false
+	//local_as_url=https%3A%2F%2Flocalhost%2Faselectserver%2Fserver%3Flocal_rid%3D86E16F83BEFA1AA0
+	//request=authenticate
+	//local_organization=testorg
+	//a-select-server=localhost
+	
+	// harmonize signature verification between app and local server requests:
+	// app: a-select-server, app_id, app_url, country, forced_logon, language, remote_organization, uid
+	// server: a-select-server, country, forced_logon, language, local_as_url, local_organization, required_level, uid
+	if ($as_config['require_signing']) {
+		as_verify_signature(array(
+				'a-select-server','app_id', 'app_url', 'country',
+				'forced_logon', 'language', 'local_as_url', 'remote_organization',
+				'local_organization', 'required_level', 'uid'
+			),
+			$as_config['verify_certificate']
+		);
+	}
 	$_SESSION['return_url'] = array_key_exists('app_url', $_GET) ? $_GET['app_url'] : $_GET['local_as_url'];
-	$_SESSION['app_id'] = $_GET['app_id'];
+	$_SESSION['app_id'] = $_GET['app_id'];	
 	print 'result_code=0000' . 
           '&a-select-server=' . $as_config['server_id'] .
           '&rid=' . session_id() . 
@@ -111,7 +166,7 @@ function as_request_return() {
 	//TODO; why does xmlseclibs not work!?
 	//$credentials = $xmlseckey->encryptData($rid);
 	if (openssl_public_encrypt($rid, $credentials, $xmlseckey->key) == FALSE) {
-		$logger->log(LOG_INFO, '1', 'aselect', 'handler', 'request', 'access', 'Could not encrypt aselect_credentials: ' . $rid . ' : ' . openssl_error_string());
+		$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Could not encrypt aselect_credentials: ' . $rid . ' : ' . openssl_error_string());
 		throw new Exception("Could not encrypt credentials!");	
 	}
 	$redirect = $_SESSION['return_url'];
@@ -130,6 +185,16 @@ function as_request_return() {
 // handle verify credentials request from agent or local server
 function as_request_verify_credentials() {
 	global $as_config, $config, $logger;
+	// harmonize signature verification between app and local server requests:
+	// app: a-select-server, aselect_credentials, rid
+	// server: a-select-server, aselect_credentials, local_organization, rid
+	if ($as_config['require_signing']) {
+		as_verify_signature(array(
+				'a-select-server','aselect_credentials', 'local_organization', 'rid'
+			),
+			$as_config['verify_certificate']		
+		);
+	}
 	// NB: accomodate for weird a-select behaviour: agent and local a-select server pass in credentials in different ways...
 	$credentials = array_key_exists('local_organization', $_GET) ? base64_decode(urldecode($_GET['aselect_credentials'])) : base64_decode($_GET['aselect_credentials']);
 	$privatekey = $config->getBaseDir() . '/cert/' . $as_config['metadata']['privatekey'];
@@ -141,11 +206,11 @@ function as_request_verify_credentials() {
 	//TODO; why does xmlseclibs not work!?
 	//$decrypted = $xmlseckey->decryptData($credentials);
 	if (openssl_private_decrypt($credentials, $decrypted, $xmlseckey->key) == FALSE) {
-		$logger->log(LOG_INFO, '1', 'aselect', 'handler', 'request', 'access', 'Could not decrypt aselect_credentials: ' . $credentials . ' : ' . openssl_error_string());
+		$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Could not decrypt aselect_credentials: ' . $credentials . ' : ' . openssl_error_string());
 		throw new Exception("Could not decrypt credentials!");
 	}
 	if ($decrypted != session_id()) {
-		$logger->log(LOG_INFO, '1', 'aselect', 'handler', 'request', 'access', 'Credentials incorrect or tampered with: ' . $decrypted . ' != ' . session_id());
+		$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Credentials incorrect or tampered with: ' . $decrypted . ' != ' . session_id());
 		throw new Exception("Incorrect credentials!");
 	}
 	$session = SimpleSAML_Session::getInstance();
@@ -156,9 +221,10 @@ function as_request_verify_credentials() {
 			$serialized .= urlencode($name) . '=' . urlencode($value);
 		}
 	}
+	$nameid = $session->getNameID();
 	print 'result_code=0000' .
 		'&app_id=' . $_SESSION['app_id'] . 
-		'&uid=' . $session->getNameID() .
+		'&uid=' . $nameid['value'] .
 		'&organization=' . $as_config['organization_id'] .
 		'&authsp_level=' . $as_config['authsp_level'] .
 		'&authsp=' . $as_config['authsp'] .
@@ -185,11 +251,12 @@ function as_call($url) {
 	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
 	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 	curl_setopt($ch, CURLOPT_URL, $url);
+	$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Outgoing request: ' . $url);
 	$result = curl_exec($ch);
 	$error = curl_error($ch);
 	curl_close($ch);
 	if ($result == FALSE) {
-		$logger->log(LOG_INFO, '1', 'aselect', 'handler', 'request', 'access', 'Request on remote server failed [' . $url . '] : ' . $error);
+		$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Request on remote server failed [' . $url . '] : ' . $error);
 		throw new Exception('Request on remote server failed: ' . $error);
 	}
 	$parms = array();
@@ -198,25 +265,53 @@ function as_call($url) {
 		$parms[$a[0]] = urldecode($a[1]);
 	}
 	if ($parms['result_code'] != '0000') {
-		$logger->log(LOG_INFO, '1', 'aselect', 'handler', 'request', 'access', 'Request on remote server returned error: ' . $result);
+		$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Request on remote server returned error: ' . $result);
 		throw new Exception('Request on remote server returned error: ' . $result);
 	}
 	return $parms;
 }
 
+// calculate signature on request parameters
+function as_compute_signature($parms, $privatekey) {
+	if (!file_exists($privatekey)) {
+		throw new Exception('Could not find private key file [' . $privatekey . '] which is needed to sign the request.');
+	}
+	$xmlseckey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
+	$xmlseckey->loadKey($privatekey,TRUE);
+	$data = '';
+	foreach ($parms as $p) $data .= $p;
+	$signature = '';
+	if (openssl_sign($data, $signature, $xmlseckey->key) != TRUE) {
+		$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Signing request failed: '. openssl_error_string());
+		throw new Exception('Signing request failed: ' . openssl_error_string());
+	}
+	return urlencode(base64_encode($signature));
+}
+
 // handle bridged authentication request from simpleSAMLphp to remote server
 function as_request_bridge() {
 	global $as_config, $logger;
 	// perform authenticate
 	$_SESSION['relaystate'] = $_GET['RelayState'];
+	$local_as_url = $_SERVER['PHP_SELF'] .
+						'?request=bridge_return' .
+						'&local_rid=' . session_id();
 	$url = $as_config['remote_server_url'] .
 		'?request=authenticate' .
 		'&required_level=' . $as_config['app_level'] .
 		'&local_organization=' . $as_config['organization_id'] .
 		'&a-select-server=' . $as_config['remote_server_id'] .
-		'&local_as_url=' . urlencode($_SERVER['PHP_SELF'] .
-						'?request=bridge_return' .
-						'&local_rid=' . session_id());
+		'&local_as_url=' . urlencode($local_as_url);
+	if ($as_config['sign_requests']) {		
+		$url .= '&signature=' . as_compute_signature(array(
+						$as_config['remote_server_id'],
+						$local_as_url,
+						$as_config['organization_id'],
+						$as_config['app_level']
+					),
+					$as_config['sign_certificate']
+				);
+	}
 	$parms = as_call($url);
 	header('Location: ' .
 		$parms['as_url'] .
@@ -231,7 +326,7 @@ function as_request_bridge_return() {
 		||
 		(array_key_exists('rid', $_GET) == FALSE))
 		{
-		$logger->log(LOG_INFO, '1', 'aselect', 'handler', 'request', 'access', 'Error on return from login at remote server!');
+		$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', 'Error on return from login at remote server!');
 		throw new Exception('Error on return from login at remote server!');		
 	}
 	$url = $as_config['remote_server_url'] .
@@ -240,10 +335,20 @@ function as_request_bridge_return() {
 		'&local_organization=' . $as_config['organization_id'] .
 		'&a-select-server=' . $as_config['remote_server_id'] .
 		'&aselect_credentials=' . $_GET['aselect_credentials'];
+	if ($as_config['sign_requests']) {		
+		$url .= '&signature=' . as_compute_signature(array(
+						$as_config['remote_server_id'],
+						$_GET['aselect_credentials'],
+						$as_config['organization_id'],
+						$_GET['rid']
+					),
+					$as_config['sign_certificate']
+				);
+	}
 	$parms = as_call($url);
 	
-	SimpleSAML_Session::init('aselect', $_GET['rid'], true);
-	$session = SimpleSAML_Session::getInstance();
+	$session = SimpleSAML_Session::getInstance(true);
+	$session->setAuthenticated(true, 'aselect');
 	
 	if (array_key_exists('attributes', $parms)) {
 		$parm = base64_decode($parms['attributes']);
@@ -263,7 +368,7 @@ function as_request_bridge_return() {
 
 // demultiplex incoming request
 try {
-	$logger->log(LOG_INFO, '1', 'aselect', 'handler', 'request', 'access', $_SERVER['REQUEST_URI']);
+	$logger->log(LOG_NOTICE, '1', 'aselect', 'handler', 'request', 'access', $_SERVER['REQUEST_URI']);
 	if ($_GET['request']) {
 		$handler = 'as_request_' . $_GET['request'];
 		$handler();