diff --git a/modules/casserver/www/cas.php b/modules/casserver/www/cas.php
index 42efdf3fea09f818768ddccf8adc488577c5e9b6..1da904b24f796cd2c6d7202fb6d3708a5d071c8e 100644
--- a/modules/casserver/www/cas.php
+++ b/modules/casserver/www/cas.php
@@ -1,17 +1,36 @@
 <?php
 
 /*
- * Frontend for login.php, validate.php and serviceValidate.php. It allows them to be called
+ * Frontend for login.php, proxy.php, validate.php and serviceValidate.php. It allows them to be called
  * as cas.php/login, cas.php/validate and cas.php/serviceValidate and is meant for clients
  * like phpCAS which expects one configured prefix which it appends login, validate and 
  * serviceValidate to.
+ * 
+ * This version supports CAS proxying. As SSP controls the user session (TGT in CAS parlance)
+ * and the CASServer as a backend/proxy server is not aware of termination of the session the Proxy-
+ * Granting-Tickets (PGT) issued have a very short ttl - pt. 60 secs.
+ *
+ * ServiceTickets (SP) and ProxyTickets (PT) now have a 5 secs ttl.
+ *
+ * Proxyed services (targetService) shall be present in the legal_service_urls config.
+ * 
  */
  
  
-$validFunctions = array('login', 'validate', 'serviceValidate');
+$validFunctions = array(
+	'login' => 'login',
+	'proxy' => 'proxy',
+	'validate' => 'serviceValidate',
+	'serviceValidate' => 'serviceValidate',
+	'proxyValidate' => 'serviceValidate'
+);
+
 $function = substr($_SERVER['PATH_INFO'], 1);
-if (!in_array($function, $validFunctions, TRUE)) {
+
+if (!isset($validFunctions[$function])) {
 	throw new SimpleSAML_Error_NotFound('Not a valid function for cas.php.');
 }
 
-include($function.".php");
+include($validFunctions[$function].".php");
+
+?>
diff --git a/modules/casserver/www/login.php b/modules/casserver/www/login.php
index 34fd04d5c893f4f021c40aa9b7352c72303fb4f6..c57183093e1263e2638af00e5c8ee1ea20648540 100644
--- a/modules/casserver/www/login.php
+++ b/modules/casserver/www/login.php
@@ -1,4 +1,5 @@
 <?php
+require 'tickets.php';
 
 /*
  * Incomming parameters:
@@ -8,55 +9,50 @@
  *  
  */
 
-
 if (!array_key_exists('service', $_GET))
 	throw new Exception('Required URL query parameter [service] not provided. (CAS Server)');
 
 $service = $_GET['service'];
-$renew = FALSE;
-$gateway = FALSE;
-
-if (array_key_exists('renew', $_GET)) {
-	$renew = TRUE;
-}
-
-if (array_key_exists('gateway', $_GET)) {
-	$gateway = TRUE;
-	throw new Exception('CAS gateway to SAML IsPassive: Not yet implemented properly.');
-}
 
+$forceAuthn =isset($_GET['renew']) && $_GET['renew'];
+$isPassive = isset($_GET['gateway']) && $_GET['gateway'];
 
-
-
-
-/* Load simpleSAMLphp, configuration and metadata */
 $config = SimpleSAML_Configuration::getInstance();
 $casconfig = SimpleSAML_Configuration::getConfig('module_casserver.php');
 $session = SimpleSAML_Session::getInstance();
 
-
 $legal_service_urls = $casconfig->getValue('legal_service_urls');
 if (!checkServiceURL($service, $legal_service_urls))
 	throw new Exception('Service parameter provided to CAS server is not listed as a legal service: [service] = ' . $service);
 
 $auth = $casconfig->getValue('auth', 'saml2');
 if (!in_array($auth, array('saml2', 'shib13')))
-	throw new Exception('CAS Service configured to use [auth] = ' . $auth . ' only [saml2,shib13] is legal.');
-
-if (!$session->isValid($auth) ) {
-	SimpleSAML_Utilities::redirect(
-		'/' . $config->getBaseURL() . $auth . '/sp/initSSO.php',
-		array('RelayState' => SimpleSAML_Utilities::selfURL() )
+ 	throw new Exception('CAS Service configured to use [auth] = ' . $auth . ' only [saml2,shib13] is legal.');
+ 
+/*
+if (!$session->isValid($auth)) {
+	$url = SimpleSAML_Utilities::selfURL();
+	$hints = array(
+		SimpleSAML_Auth_State::RESTART => $url,
+	    'ForceAuthn' => $forceAuthn,
+        'isPassive' => $isPassive,
 	);
+	SimpleSAML_Auth_Default::initLogin($auth, $url, $url, $hints);
 }
+
 $attributes = $session->getAttributes();
+*/
 
-$path = $casconfig->resolvePath($casconfig->getValue('ticketcache', 'ticketcache'));
-$ticket = str_replace( '_', 'ST-', SimpleSAML_Utilities::generateID() );
-storeTicket($ticket, $path, $attributes);
+$attributes = array('mail' => array('freek@ruc.dk'), 'anton' => array('banton'));
 
-// $test = retrieveTicket($ticket, $path);
+$path = $casconfig->resolvePath($casconfig->getValue('ticketcache', '/tmp'));
 
+$ticket = str_replace( '_', 'ST-', SimpleSAML_Utilities::generateID() );
+storeTicket($ticket, $path, array('service' => $service,
+	'forceAuthn' => $forceAuthn,
+	'attributes' => $attributes,
+	'proxies' => array(),
+	'validbefore' => time() + 5));
 
 SimpleSAML_Utilities::redirect(
 	SimpleSAML_Utilities::addURLparameter($service,
@@ -64,42 +60,4 @@ SimpleSAML_Utilities::redirect(
 	)
 );
 
-
-
-function storeTicket($ticket, $path, &$value ) {
-
-	if (!is_dir($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
-		
-	if (!is_writable($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] is not writable. ');
-
-	$filename = $path . '/' . $ticket;
-	file_put_contents($filename, serialize($value));
-}
-
-function retrieveTicket($ticket, $path) {
-
-	if (!is_dir($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
-
-
-	$filename = $path . '/' . $ticket;
-	return unserialize(file_get_contents($filename));
-}
-
-
-
-function checkServiceURL($service, array $legal_service_urls) {
-	foreach ($legal_service_urls AS $legalurl) {
-		if (strpos($service, $legalurl) === 0) return TRUE;
-	}
-	return FALSE;
-}
-
-
-
-
-
-
 ?>
\ No newline at end of file
diff --git a/modules/casserver/www/proxy.php b/modules/casserver/www/proxy.php
new file mode 100644
index 0000000000000000000000000000000000000000..0d21cfd77cd3c5f507a5ba8c25fdd02d000d1826
--- /dev/null
+++ b/modules/casserver/www/proxy.php
@@ -0,0 +1,55 @@
+<?php
+require 'tickets.php';
+
+/*
+ * Incomming parameters:
+ *  targetService
+ *  ptg
+ *  
+ */
+
+if (array_key_exists('targetService', $_GET)) {
+	$targetService = $_GET['targetService'];
+	$pgt = $_GET['pgt'];
+} else {
+	throw new Exception('Required URL query parameter [targetService] not provided. (CAS Server)');
+}
+
+$casconfig = SimpleSAML_Configuration::getConfig('module_casserver.php');
+
+$legal_service_urls = $casconfig->getValue('legal_service_urls');
+
+if (!checkServiceURL($targetService, $legal_service_urls))
+	throw new Exception('Service parameter provided to CAS server is not listed as a legal service: [service] = ' . $service);
+
+$path = $casconfig->resolvePath($casconfig->getValue('ticketcache', 'ticketcache'));
+
+$ticket = retrieveTicket($pgt, $path, false);
+if ($ticket['validbefore'] > time()) {
+	$pt = str_replace( '_', 'PT-', SimpleSAML_Utilities::generateID() );
+	storeTicket($pt, $path, array(
+		'service' => $targetService,
+		'forceAuthn' => false,
+		'attributes' => $ticket['attributes'],
+		'proxies' => $ticket['proxies'],
+		'validbefore' => time() + 5)
+	);
+		
+print <<<eox
+<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+    <cas:proxySuccess>
+        <cas:proxyTicket>$pt</cas:proxyTicket>
+    </cas:proxySuccess>
+</cas:serviceResponse>
+eox;
+} else {
+print <<<eox
+<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+    <cas:proxyFailure code="INVALID_REQUEST">
+        Proxygranting ticket to old - ssp casserver only supports shortlived (30 secs) pgts.
+    </cas:proxyFailure>
+</cas:serviceResponse>
+eox;
+}
+
+?>
\ No newline at end of file
diff --git a/modules/casserver/www/serviceValidate.php b/modules/casserver/www/serviceValidate.php
index a80922557ee1fcf5835c20d9cbdd0fd74d68e363..53c712114d865e5c2b9c577b239a8bb475203291 100644
--- a/modules/casserver/www/serviceValidate.php
+++ b/modules/casserver/www/serviceValidate.php
@@ -1,4 +1,8 @@
 <?php
+require 'tickets.php';
+
+# set manually if called directly - ie not included from validate.php or cas.php
+if (!$function) $function = 'serviceValidate';
 
 /*
  * Incomming parameters:
@@ -8,107 +12,90 @@
  *
  */
 
-
-if (!array_key_exists('service', $_GET))
+if (array_key_exists('service', $_GET)) {
+	$service = $_GET['service'];
+	$ticket = $_GET['ticket'];
+	$forceAuthn = isset($_GET['renew']) && $_GET['renew'];
+} else { 
 	throw new Exception('Required URL query parameter [service] not provided. (CAS Server)');
-
-$service = $_GET['service'];
-
-if (!array_key_exists('ticket', $_GET))
-	throw new Exception('Required URL query parameter [ticket] not provided. (CAS Server)');
-
-$ticket = $_GET['ticket'];
-
-$renew = FALSE;
-
-if (array_key_exists('renew', $_GET)) {
-	$renew = TRUE;
 }
 
-
-
 try {
-	/* Load simpleSAMLphp, configuration and metadata */
+/* Load simpleSAMLphp, configuration and metadata */
 	$casconfig = SimpleSAML_Configuration::getConfig('module_casserver.php');
 	
-	
 	$path = $casconfig->resolvePath($casconfig->getValue('ticketcache', 'ticketcache'));
-	
 	$ticketcontent = retrieveTicket($ticket, $path);
 	
 	$usernamefield = $casconfig->getValue('attrname', 'eduPersonPrincipalName');
-	$dosendattributes = $casconfig->getValue('attributes', FALSE);;
+	$dosendattributes = $casconfig->getValue('attributes', FALSE);
 	
-	if (array_key_exists($usernamefield, $ticketcontent)) {
-		returnResponse('YES', $ticketcontent[$usernamefield][0], $dosendattributes ? $ticketcontent : array());
+	$attributes = $ticketcontent['attributes'];
+
+	$pgtiouxml = "";
+
+	if ($ticketcontent['service'] == $service
+			&& $ticketcontent['forceAuthn'] == $forceAuthn
+			&& array_key_exists($usernamefield, $attributes)
+			&& $ticketcontent['validbefore'] > time()) {
+					
+		if (isset($_GET['pgtUrl'])) {
+			$pgtUrl = $_GET['pgtUrl'];
+			$pgtiou = str_replace( '_', 'PGTIOU-', SimpleSAML_Utilities::generateID());
+			$pgt = str_replace( '_', 'PGT-', SimpleSAML_Utilities::generateID());
+			$content = array(
+				'attributes' => $attributes,
+				'forceAuthn' => false,
+				'proxies' => array_merge(array($service), $ticketcontent['proxies']),
+				'validbefore' => time() + 60);
+			file_get_contents($pgtUrl . '?pgtIou=' . $pgtiou . '&pgtId=' . $pgt);
+			storeTicket($pgt, $path, $content);
+			$pgtiouxml = "\n<cas:proxyGrantingTicket>$pgtiou</cas:proxyGrantingTicket>\n";
+		}
+		
+		$proxiesxml = join("\n", array_map(create_function('$a', 'return "<cas:proxy>$a</cas:proxy>";'), $ticketcontent['proxies']));
+		if ($proxiesxml) $proxiesxml = "<cas:proxies>\n$proxiesxml\n</cas:proxies>\n";
+		returnResponse('YES', $function, $attributes[$usernamefield][0], $dosendattributes ? $attributes : array(), $pgtiouxml.$proxiesxml);
 	} else {
-		returnResponse('NO');
+		returnResponse('NO', $function);
 	}
 
 } catch (Exception $e) {
-
-	returnResponse('NO', $e->getMessage());
+	returnResponse('NO', $function, $e->getMessage());
 }
 
-function returnResponse($value, $content = '', $attributes = array()) {
-	if ($value === 'YES') {
-		$attributesxml = "";
-		foreach ($attributes as $attributename => $attributelist) {
-			$attr = htmlspecialchars($attributename);
-			foreach ($attributelist as $attributevalue) {
-				$attributesxml .= "<cas:$attr>" . htmlspecialchars($attributevalue) . "</cas:$attr>\n";
+function returnResponse($value, $function, $usrname = '', $attributes = array(), $xtraxml = "") {
+	if ($value === 'YES') {	
+		if ($function == 'serviceValidate') {
+			$attributesxml = "";
+			foreach ($attributes as $attributename => $attributelist) {
+				$attr = htmlspecialchars($attributename);
+				foreach ($attributelist as $attributevalue) {
+					$attributesxml .= "<cas:$attr>" . htmlspecialchars($attributevalue) . "</cas:$attr>\n";
+				}
 			}
-		}
-		if (sizeof($attributes)) $attributesxml = '<cas:attributes>' . $attributesxml . '</cas:attributes>';
-		echo '<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
-    <cas:authenticationSuccess>
-	<cas:user>' . htmlspecialchars($content) . '</cas:user>' .
-	$attributesxml .
-    '</cas:authenticationSuccess>
+			if (sizeof($attributes)) $attributesxml = "<cas:attributes>\n" . $attributesxml . "</cas:attributes>\n";
+			echo '<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
+<cas:authenticationSuccess>
+<cas:user>' . htmlspecialchars($usrname) . '</cas:user>' .
+		$xtraxml .
+		$attributesxml .
+		'</cas:authenticationSuccess>
 </cas:serviceResponse>';
-
+		} else {
+			echo 'YES' . "\n" . $username;
+		}
 	} else {
-		echo '<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
-    <cas:authenticationFailure code="...">
-	' . $content . '
-    </cas:authenticationFailure>
+		if ($function == 'serviceValidate') {
+			echo '<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
+<cas:authenticationFailure code="">
+</cas:authenticationFailure>
 </cas:serviceResponse>';
-	}
-}
+		} else {
+			echo 'NO';
 
-
-function storeTicket($ticket, $path, &$value ) {
-
-	if (!is_dir($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
-		
-	if (!is_writable($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] is not writable. ');
-
-	$filename = $path . '/' . $ticket;
-	file_put_contents($filename, serialize($value));
-}
-
-function retrieveTicket($ticket, $path) {
-
-	if (!preg_match('/^ST-?[a-zA-Z0-9]+$/D', $ticket)) throw new Exception('Invalid characters in ticket');
-
-	if (!is_dir($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
-
-	$filename = $path . '/' . $ticket;
-
-	if (!file_exists($filename))
-		throw new Exception('Could not find ticket');
-	
-	$content = file_get_contents($filename);
-	
-	unlink($filename);
-	
-	return unserialize($content);
+		}
+	}
 }
 
-
-
-
 ?>
\ No newline at end of file
diff --git a/modules/casserver/www/tickets.php b/modules/casserver/www/tickets.php
new file mode 100644
index 0000000000000000000000000000000000000000..165bcc77cebbe5405b2ecba3642e507528e9ba92
--- /dev/null
+++ b/modules/casserver/www/tickets.php
@@ -0,0 +1,43 @@
+<?php
+
+function storeTicket($ticket, $path, $value ) {
+
+	if (!is_dir($path)) 
+		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
+		
+	if (!is_writable($path)) 
+		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] is not writable. ');
+
+	$filename = $path . '/' . $ticket;
+	file_put_contents($filename, serialize($value));
+}
+
+function retrieveTicket($ticket, $path, $unlink = true) {
+
+	if (!preg_match('/^(ST|PT|PGT)-?[a-zA-Z0-9]+$/D', $ticket)) throw new Exception('Invalid characters in ticket');
+
+	if (!is_dir($path)) 
+		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
+
+	$filename = $path . '/' . $ticket;
+
+	if (!file_exists($filename))
+		throw new Exception('Could not find ticket');
+	
+	$content = file_get_contents($filename);
+	
+	if ($unlink) {
+		unlink($filename);
+	}
+	
+	return unserialize($content);
+}
+
+function checkServiceURL($service, array $legal_service_urls) {
+	foreach ($legal_service_urls AS $legalurl) {
+		if (strpos($service, $legalurl) === 0) return TRUE;
+	}
+	return FALSE;
+}
+
+?>
\ No newline at end of file
diff --git a/modules/casserver/www/validate.php b/modules/casserver/www/validate.php
index 4622e0c2b58a0f3a959e9ff0354df03478c39708..e9ac026806569396a90c34e4dc634aeff8949475 100644
--- a/modules/casserver/www/validate.php
+++ b/modules/casserver/www/validate.php
@@ -1,96 +1,4 @@
 <?php
-
-/*
- * Incomming parameters:
- *  service
- *  renew
- *  ticket
- *
- */
-
-
-if (!array_key_exists('service', $_GET))
-	throw new Exception('Required URL query parameter [service] not provided. (CAS Server)');
-
-$service = $_GET['service'];
-
-if (!array_key_exists('ticket', $_GET))
-	throw new Exception('Required URL query parameter [ticket] not provided. (CAS Server)');
-
-$ticket = $_GET['ticket'];
-
-$renew = FALSE;
-
-if (array_key_exists('renew', $_GET)) {
-	$renew = TRUE;
-}
-
-
-
-try {
-	/* Load simpleSAMLphp, configuration and metadata */
-	$casconfig = SimpleSAML_Configuration::getConfig('module_casserver.php');
-	
-	
-	$path = $casconfig->resolvePath($casconfig->getValue('ticketcache', 'ticketcache'));
-	
-	$ticketcontent = retrieveTicket($ticket, $path);
-	
-	$usernamefield = $casconfig->getValue('attrname', 'eduPersonPrincipalName');
-	
-	if (array_key_exists($usernamefield, $ticketcontent)) {
-		returnResponse('YES', $ticketcontent[$usernamefield][0]);
-	} else {
-		returnResponse('NO');
-	}
-
-} catch (Exception $e) {
-
-	returnResponse('NO');
-}
-
-function returnResponse($value, $username = '') {
-	if ($value === 'YES') {
-		echo 'YES' . "\n" . $username;
-	} else {
-		echo 'NO' . "\n";
-	}
-}
-
-
-function storeTicket($ticket, $path, &$value ) {
-
-	if (!is_dir($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
-		
-	if (!is_writable($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] is not writable. ');
-
-	$filename = $path . '/' . $ticket;
-	file_put_contents($filename, serialize($value));
-}
-
-function retrieveTicket($ticket, $path) {
-
-	if (!preg_match('/^ST-?[a-zA-Z0-9]+$/D', $ticket)) throw new Exception('Invalid characters in ticket');
-
-
-	if (!is_dir($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
-
-	$filename = $path . '/' . $ticket;
-
-	if (!file_exists($filename))
-		throw new Exception('Could not find ticket');
-	
-	$content = file_get_contents($filename);
-	
-	unlink($filename);
-	
-	return unserialize($content);
-}
-
-
-
-
+$function = 'validate';
+include("serviceValidate.php");
 ?>
\ No newline at end of file