From 4a5d7d1dd4c69787d1c5c3f9f09f2efa3c29948d Mon Sep 17 00:00:00 2001
From: Enrique de la Hoz <enrique.delahoz@uah.es>
Date: Tue, 2 Dec 2008 11:26:24 +0000
Subject: [PATCH] Infocard Module Added:RP Support

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1041 44740490-163a-0410-bde0-09ae8108e29a
---
 .../config-template/config-login-infocard.php |  97 ++++++
 modules/InfoCard/default-disable              |   3 +
 .../InfoCard/dictionaries/logininfocard.php   | 186 +++++++++++
 modules/InfoCard/lib/Auth/Source/ICAuth.php   |  80 +++++
 modules/InfoCard/lib/RP/InfoCard.php          | 311 ++++++++++++++++++
 modules/InfoCard/lib/RP/LICENSE.txt           |  27 ++
 .../InfoCard/lib/RP/Zend_InfoCard_Claims.php  | 304 +++++++++++++++++
 .../RP/Zend_InfoCard_Xml_Assertion_Saml.php   | 272 +++++++++++++++
 .../lib/RP/Zend_InfoCard_Xml_Security.php     | 302 +++++++++++++++++
 .../Zend_InfoCard_Xml_Security_Transform.php  | 113 +++++++
 ..._Security_Transform_EnvelopedSignature.php |  55 ++++
 ...Card_Xml_Security_Transform_XmlExcC14N.php |  52 +++
 .../templates/default/login-infocard.php      |  58 ++++
 modules/InfoCard/www/login-infocard.php       |  54 +++
 .../www/resources/infocard_114x80.png         | Bin 0 -> 3821 bytes
 15 files changed, 1914 insertions(+)
 create mode 100644 modules/InfoCard/config-template/config-login-infocard.php
 create mode 100644 modules/InfoCard/default-disable
 create mode 100644 modules/InfoCard/dictionaries/logininfocard.php
 create mode 100644 modules/InfoCard/lib/Auth/Source/ICAuth.php
 create mode 100644 modules/InfoCard/lib/RP/InfoCard.php
 create mode 100644 modules/InfoCard/lib/RP/LICENSE.txt
 create mode 100644 modules/InfoCard/lib/RP/Zend_InfoCard_Claims.php
 create mode 100644 modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Assertion_Saml.php
 create mode 100644 modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security.php
 create mode 100644 modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform.php
 create mode 100644 modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature.php
 create mode 100644 modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform_XmlExcC14N.php
 create mode 100644 modules/InfoCard/templates/default/login-infocard.php
 create mode 100644 modules/InfoCard/www/login-infocard.php
 create mode 100644 modules/InfoCard/www/resources/infocard_114x80.png

diff --git a/modules/InfoCard/config-template/config-login-infocard.php b/modules/InfoCard/config-template/config-login-infocard.php
new file mode 100644
index 000000000..055fee0a7
--- /dev/null
+++ b/modules/InfoCard/config-template/config-login-infocard.php
@@ -0,0 +1,97 @@
+<?php
+
+/*
+* AUTHOR: Samuel Muñoz Hidalgo
+* EMAIL: samuel.mh@gmail.com
+* LAST REVISION: 1-DEC-08
+* DESCRIPTION: 'login-infocard' module configuration.
+
+
+-server_key:
+-server_crt:
+-IClogo: InfoCard logo (template's button)
+
+
+Definitions taken from:
+A Guide to Using the Identity Selector
+Interoperability Profile V1.5 within Web
+Applications and Browsers.
+Copyright Microsoft
+"
+-issuer (optional)
+	This parameter specifies the URL of the STS from which to obtain a token. If omitted, no
+	specific STS is requested. The special value
+	“http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self” specifies that the
+	token should come from a Self-issued Identity Provider.
+
+-issuerPolicy (optional)
+	This parameter specifies the URL of an endpoint from which the STS’s WS-SecurityPolicy
+	can be retrieved using WS-MetadataExchange. This endpoint must use HTTPS.
+
+-tokenType (optional)
+	This parameter specifies the type of the token to be requested from the STS as a URI. Th
+	parameter can be omitted if the STS and the Web site front-end have a mutual
+	understanding about what token type will be provided or if the Web site is willing to accep
+	any token type.
+
+-requiredClaims (optional)
+	This parameter specifies the types of claims that must be supplied by the identity. If
+	omitted, there are no required claims. The value of requiredClaims is a space-separate
+	list of URIs, each specifying a required claim type.
+
+-optionalClaims (optional)
+	This parameter specifies the types of optional claims that may be supplied by the identity
+	If omitted, there are no optional claims. The value of optionalClaims is a space-separat
+	list of URIs, each specifying a claim type that can be optionally submitted.
+
+-privacyUrl (optional)
+	This parameter specifies the URL of the human-readable Privacy Policy of the site, if
+	provided.
+"
+
+
+-Claims supported by the current schema
+	givenname
+	surname
+	emailaddress
+	streetaddress
+	locality
+	stateorprovince
+	postalcode
+	country
+	primaryphone
+	dateofbirth
+	privatepersonalid
+	gender
+	webpage
+
+*/
+
+
+$config = array (
+	
+	'server_key' => '/etc/apache2/ssl/idp.key',
+	'server_crt' => '/etc/apache2/ssl/idp.crt',
+	'IClogo' => 'resources/infocard_114x80.png',
+	
+
+	'InfoCard' => array(
+		'schema' => 'http://schemas.xmlsoap.org/ws/2005/05/identity',
+		'issuer' => 'https://sts/tokenservice.php',
+		'issuerPolicy' => '',
+		'privacyURL' => '',
+		'tokenType' => 'urn:oasis:names:tc:SAML:1.0:assertion',
+		'requiredClaims' => array(
+			'privatepersonalidentifier' => array('displayTag'=>"Id",         'description'=>"id"),
+			'givenname' =>                 array('displayTag'=>"Given Name", 'description'=>"etc"),
+			'surname' =>                   array('displayTag'=>"Surname",    'description'=>"apellidos"),
+			'emailaddress' =>              array('displayTag'=>"e-mail",     'description'=>"E-mail address")
+		),
+		'optionalClaims' => array(
+			'country' => array('displayTag'=>"country", 'description'=>"PaĂ­s"),
+			'webpage' => array('displayTag'=>"webpage", 'description'=>"Página web")
+		),
+	),
+);
+
+?>
\ No newline at end of file
diff --git a/modules/InfoCard/default-disable b/modules/InfoCard/default-disable
new file mode 100644
index 000000000..25615cb47
--- /dev/null
+++ b/modules/InfoCard/default-disable
@@ -0,0 +1,3 @@
+This file indicates that the default state of this module
+is enabled. To disable, create a file named disable in the
+same directory as this file.
diff --git a/modules/InfoCard/dictionaries/logininfocard.php b/modules/InfoCard/dictionaries/logininfocard.php
new file mode 100644
index 000000000..8d8dfa65c
--- /dev/null
+++ b/modules/InfoCard/dictionaries/logininfocard.php
@@ -0,0 +1,186 @@
+<?php
+
+/*
+* AUTHOR: Samuel Muñoz Hidalgo
+* EMAIL: samuel.mh@gmail.com
+* LAST REVISION: 1-DEC-08
+* DESCRIPTION: 'login-infocard' module dictionary.
+*/
+
+$lang = array(
+	'wrong_IC' => array (
+		'no' => '',
+		'nn' => '',
+		'da' => '',
+		'en' => 'Invalid InfoCard',
+		'de' => '',
+		'sv' => '',
+		'fi' => '',
+		'es' => 'InfoCard errĂłnea',
+		'fr' => '',
+		'nl' => '',
+		'lb' => '',
+		'sl' => '',
+		'hr' => '',
+		'hu' => '',
+		'pt' => '',
+		'pt-BR' => '',
+	),
+	'error_header' => array (
+		'no' => 'Feil',
+		'nn' => 'Feil',
+		'da' => 'Fejl',
+		'en' => 'Error',
+		'de' => 'Fehler',
+		'sv' => 'Fel',
+		'fi' => 'Virhe',
+		'es' => 'Error',
+		'fr' => 'Erreur',
+		'nl' => 'Fout',
+		'lb' => 'Fehler',
+		'sl' => 'Napaka',
+		'hr' => 'Greška',
+		'hu' => 'Hiba',
+		'pt' => 'Erro',
+		'pt-BR' => 'Erro',
+	),
+	'user_IC_header' => array (
+		'no' => '',
+		'nn' => '',
+		'da' => '',
+		'en' => 'Select an InfoCard',
+		'de' => '',
+		'sv' => '',
+		'fi' => '',
+		'es' => 'Seleccione una InfoCard',
+		'fr' => '',
+		'nl' => '',
+		'lb' => '',
+		'sl' => '',
+		'hr' => '',
+		'hu' => '',
+		'pt' => '',
+		'pt-BR' => '',
+	),
+	'user_IC_text' => array (
+		'no' => '',
+		'nn' => '',
+		'da' => '',
+		'en' => 'A service has requested you to authenticate yourself. Please click on the image below to start a session with an InfoCard.',
+		'de' => '',
+		'sv' => '',
+		'fi' => '',
+		'es' => 'Un servicio solicita que se autentique. Pinche en la imagen inferior para iniciar una sesiĂłn con una InfoCard.',
+		'fr' => '',
+		'nl' => '',
+		'lb' => '',
+		'sl' => '',
+		'hr' => '',
+		'hu' => '',
+		'pt' => '',
+		'pt-BR' => '',
+	),
+	'login_button' => array (
+		'no' => '',
+		'nn' => '',
+		'da' => '',
+		'en' => ' ',
+		'de' => '',
+		'sv' => '',
+		'fi' => '',
+		'es' => ' ',
+		'fr' => '',
+		'nl' => '',
+		'lb' => '',
+		'sl' => '',
+		'hr' => '',
+		'hu' => '',
+		'pt' => '',
+		'pt-BR' => '',
+	),
+	'help_header' => array (
+		'no' => '',
+		'nn' => '',
+		'da' => '',
+		'en' => 'HELP! What is an InfoCard?',
+		'de' => '',
+		'sv' => '',
+		'fi' => '',
+		'es' => '¡Ayuda! ¿Qué es una InfoCard?',
+		'fr' => '',
+		'nl' => '',
+		'lb' => '',
+		'sl' => '',
+		'hr' => '',
+		'hu' => '',
+		'pt' => '',
+		'pt-BR' => '',
+	),
+	'help_text' => array (
+		'no' => '',
+		'nn' => '',
+		'da' => '',
+		'en' => 'Information Cards (aka InfoCard) is a web authentication technology. Contact with your services provider in order to configure your computer and gives you and Information Card (identification virtual card).',
+		'de' => '',
+		'sv' => '',
+		'fi' => '',
+		'es' => 'Information Cards (alias Infocard) es una tecnología de autenticación web. Consulte con su proveedor de servicios para que le ayude a configurar su máquina y le expida una Information Card (tarjeta virtual de identificación).',
+		'fr' => '',
+		'nl' => '',
+		'lb' => '',
+		'sl' => '',
+		'hr' => '',
+		'hu' => '',
+		'pt' => '',
+		'pt-BR' => '',
+	),
+	'help_desk_link' => array (
+		'no' => 'Hjemmesiden til brukerstøtte',
+		'nn' => 'Heimeside for brukarstøtte',
+		'da' => 'Servicedesk',
+		'en' => 'Help desk homepage',
+		'de' => 'Seite des Helpdesk',
+		'sv' => 'Hemsida för helpdesk',
+		'es' => 'Página de soporte técnico',
+		'nl' => 'Helpdesk homepage',
+		'sl' => 'Spletna stran tehniÄŤne podpore uporabnikom.',
+		'hr' => 'Helpdesk stranice',
+		'hu' => 'Ügyfélszolgálat weboldala',
+		'pt' => 'Página do serviço de apoio ao utilizador',
+		'pt-BR' => 'Central de Ajuda',
+	),
+	'help_desk_email' => array (
+		'no' => 'Send e-post til brukerstøtte',
+		'nn' => 'Send epost til brukarstøtte',
+		'da' => 'Send en e-mail servicedesk',
+		'en' => 'Send e-mail to help desk',
+		'de' => 'Email an den Helpdesk senden',
+		'sv' => 'Skicka e-post till helpdesk',
+		'es' => 'Enviar correo electrónico al soporte técnico',
+		'nl' => 'Stuur een e-mail naar de helpdesk',
+		'sl' => 'Pošlji e-poštno sporočilo tehnični podpori.',
+		'hr' => 'Pošaljite e-mail helpdesk službi',
+		'hu' => 'Küldjön e-mailt az ügyfélszolgálatnak',
+		'pt' => 'Enviar um e-mail para o serviço de apoio ao utilizador',
+		'pt-BR' => 'Envie um e-mail para a Central de Ajuda.',
+	),
+	'contact_info' => array (
+		'no' => 'Kontaktinformasjon:',
+		'nn' => 'Kontaktinformasjon:',
+		'da' => 'Kontaktoplysninger',
+		'en' => 'Contact information:',
+		'de' => 'Kontakt',
+		'sv' => 'Kontaktinformation:',
+		'es' => 'InformaciĂłn de contacto:',
+		'nl' => 'Contact informatie',
+		'sl' => 'Kontakt',
+		'hr' => 'Kontakt podaci',
+		'hu' => 'Elérési információk',
+		'pt' => 'Contactos:',
+		'pt-BR' => 'Informações de Contato',
+	),
+
+);
+
+
+?>
\ No newline at end of file
diff --git a/modules/InfoCard/lib/Auth/Source/ICAuth.php b/modules/InfoCard/lib/Auth/Source/ICAuth.php
new file mode 100644
index 000000000..b16167bd6
--- /dev/null
+++ b/modules/InfoCard/lib/Auth/Source/ICAuth.php
@@ -0,0 +1,80 @@
+<?php
+/*
+* AUTHOR: Samuel Muñoz Hidalgo
+* EMAIL: samuel.mh@gmail.com
+* LAST REVISION: 1-DEC-08
+* DESCRIPTION:
+*  'login-infocard' module.
+*		Auth class
+*/
+
+class sspmod_InfoCard_Auth_Source_ICAuth extends SimpleSAML_Auth_Source {
+
+	//The string used to identify our states.
+	const STAGEID = 'sspmod_core_Auth_UserPassBase.state';
+
+
+	//The key of the AuthId field in the state.
+	const AUTHID = 'sspmod_core_Auth_UserPassBase.AuthId';
+
+	
+	public function __construct($info, $config) {
+		assert('is_array($info)');
+		assert('is_array($config)');
+
+		/* Call the parent constructor first, as required by the interface. */
+		parent::__construct($info, $config);
+	}
+	
+	
+	public function authenticate(&$state) {
+		assert('is_array($state)');
+
+		/* We are going to need the authId in order to retrieve this authentication source later. */
+		$state[self::AUTHID] = $this->authId;
+		$id = SimpleSAML_Auth_State::saveState($state, self::STAGEID);
+		$url = SimpleSAML_Module::getModuleURL('InfoCard/login-infocard.php');
+		SimpleSAML_Utilities::redirect($url, array('AuthState' => $id));
+	}
+	
+
+	public static function handleLogin($authStateId, $xmlToken) {
+		assert('is_string($authStateId)');
+		
+		/* Retrieve the authentication state. */
+		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
+
+		/* Find authentication source. */
+		assert('array_key_exists(self::AUTHID, $state)');
+		$source = SimpleSAML_Auth_Source::getById($state[self::AUTHID]);
+		if ($source === NULL) {
+			throw new Exception('Could not find authentication source with id ' . $state[self::AUTHID]);
+		}
+
+		$config = SimpleSAML_Configuration::getInstance();
+		$autoconfig = $config->copyFromBase('logininfocard', 'config-login-infocard.php');
+		$server_key = $autoconfig->getValue('server_key');
+		$server_crt = $autoconfig->getValue('server_crt');
+		$Infocard =   $autoconfig->getValue('InfoCard');
+
+		$infocard = new sspmod_InfoCard_RP_InfoCard();
+		$infocard->addCertificatePair($server_key,$server_crt);
+		$claims = $infocard->process($xmlToken);
+		if($claims->isValid()) {
+			$attributes = array();
+			foreach ($Infocard['requiredClaims'] as $claim => $data){
+				$attributes[$claim] = array($claims->$claim);
+			}
+			foreach ($Infocard['optionalClaims'] as $claim => $data){
+				$attributes[$claim] = array($claims->$claim);
+			}
+		$state['Attributes'] = $attributes;
+		SimpleSAML_Auth_Source::completeAuth($state);
+		} else {
+			return 'wrong_IC';
+		}
+	}
+
+}
+
+?>
\ No newline at end of file
diff --git a/modules/InfoCard/lib/RP/InfoCard.php b/modules/InfoCard/lib/RP/InfoCard.php
new file mode 100644
index 000000000..442629195
--- /dev/null
+++ b/modules/InfoCard/lib/RP/InfoCard.php
@@ -0,0 +1,311 @@
+<?php
+
+require_once 'Zend_InfoCard_Claims.php';
+
+class sspmod_InfoCard_RP_InfoCard
+{
+
+  const XENC_NS = "http://www.w3.org/2001/04/xmlenc#";
+  const XENC_ELEMENT_TYPE = "http://www.w3.org/2001/04/xmlenc#Element";
+  const XENC_ENC_ALGO = "http://www.w3.org/2001/04/xmlenc#aes256-cbc";
+  const XENC_KEYINFO_ENC_ALGO = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p";
+
+  const DSIG_NS = "http://www.w3.org/2000/09/xmldsig#";
+  const DSIG_RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
+  const DSIG_ENVELOPED_SIG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
+  const DSIG_SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1";
+
+  const CANON_EXCLUSIVE = "http://www.w3.org/2001/10/xml-exc-c14n#";
+
+  const WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
+  const WSSE_KEYID_VALUE_TYPE = "http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1";
+
+  const XMLSOAP_SELF_ISSUED = "http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self";
+
+  const XMLSOAP_CLAIMS_NS = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims';
+
+  const SAML_ASSERTION_1_0_NS = "urn:oasis:names:tc:SAML:1.0:assertion";
+  const SAML_ASSERTION_1_1_NS = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1";
+
+  protected $_private_key_file;
+  protected $_public_key_file;
+  protected $_password;
+  protected $_sxml;
+
+  public function __construct() {
+    if(!extension_loaded('mcrypt')) {
+      SimpleSAML_Logger::debug("Use of the InfoCard component requires the mcrypt extension to be enabled in PHP");
+    }
+
+    if(!extension_loaded('openssl')) {
+      SimpleSAML_Logger::debug("Use of the InfoCard component requires the openssl extension to be enabled in PHP");
+    }
+  }
+
+  public function addCertificatePair($private_key_file, $public_key_file, $password = null) {
+    $this->_private_key_file = $private_key_file;
+    $this->_public_key_file = $public_key_file;
+    $this->_password = $password;
+
+    if(!file_exists($this->_private_key_file)) {
+      SimpleSAML_Logger::debug("Private key file does not exists"); 
+    }
+
+    if(!file_exists($this->_public_key_file)) {
+      SimpleSAML_Logger::debug("Public key file does not exists"); 
+    }
+
+    if(!is_readable($this->_private_key_file)) {
+      SimpleSAML_Logger::debug("Private key file is not readable");
+    }
+
+    if(!is_readable($this->_public_key_file)) {
+      SimpleSAML_Logger::debug("Public key file is not readable"); 
+    }
+  }
+
+  public function process($xmlToken) {
+    if(strpos($xmlToken, "EncryptedData") === false ) {
+      return self::processUnSecureToken($xmlToken);
+    }
+    else {
+      return self::processSecureToken($xmlToken);
+    }
+  }
+
+  private function processSecureToken($xmlToken) {
+    $retval = new Zend_InfoCard_Claims();
+
+    try {
+      $this->_sxml = simplexml_load_string($xmlToken);
+      $decryptedToken = self::decryptToken($xmlToken);
+    }
+    catch(Exception $e) {
+      $retval->setError('Failed to extract assertion document');
+      SimpleSAML_Logger::debug('Failed to extract assertion document');
+      $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);
+      return $retval;
+    }
+
+    try {
+      $assertions = self::getAssertions($decryptedToken);    
+    }
+    catch(Exception $e) {
+       $retval->setError('Failure processing assertion document');
+     	 SimpleSAML_Logger::debug('Failure processing assertion document');
+       $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);
+       return $retval;
+    }
+
+    try {
+      $reference_id = self::ValidateSignature($assertions);
+      self::checkConditions($reference_id, $assertions);
+    }
+    catch(Exception $e) {
+      $retval->setError($e->getMessage());
+      $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);
+      return $retval;
+    }
+
+    return self::getClaims($retval, $assertions);
+  }
+
+  private function processUnsecureToken($xmlToken) {
+    $retval = new Zend_InfoCard_Claims();
+    
+    try {
+      $assertions = self::getAssertions($xmlToken);    
+    }
+    catch(Exception $e) {
+       $retval->setError('Failure processing assertion document');
+				SimpleSAML_Logger::debug('Failure processing assertion document');
+       $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);
+       return $retval;
+    }
+
+    return self::getClaims($retval, $assertions);
+  }
+
+  private function ValidateSignature($assertions) {
+    include_once 'Zend_InfoCard_Xml_Security.php';
+    $reference_id = Zend_InfoCard_Xml_Security::validateXMLSignature($assertions->asXML());
+    if(!$reference_id) {
+      SimpleSAML_Logger::debug("Failure Validating the Signature of the assertion document");
+    }
+
+    return $reference_id;
+  }
+
+  private function checkConditions($reference_id, $assertions) {
+    if($reference_id[0] == '#') {
+      $reference_id = substr($reference_id, 1);
+    } else {
+      SimpleSAML_Logger::debug("Reference of document signature does not reference the local document");
+    }
+
+    if($reference_id != $assertions->getAssertionID()) {
+      SimpleSAML_Logger::debug("Reference of document signature does not reference the local document");
+    }
+
+    $conditions = $assertions->getConditions();
+    if(is_array($condition_error = $assertions->validateConditions($conditions))) {
+      SimpleSAML_Logger::debug("Conditions of assertion document are not met: {$condition_error[1]} ({$condition_error[0]})");
+    }
+  }
+
+  private function getClaims($retval, $assertions) {
+    $attributes = $assertions->getAttributes();
+    $retval->setClaims($attributes);
+    if($retval->getCode() == 0) {
+      $retval->setCode(Zend_InfoCard_Claims::RESULT_SUCCESS);
+    }
+
+    return $retval;
+  }
+
+  private function getAssertions($strXmlData) {
+     $sxe = simplexml_load_string($strXmlData);
+     $namespaces = $sxe->getDocNameSpaces();
+     foreach($namespaces as $namespace) {
+       switch($namespace) {
+         case self::SAML_ASSERTION_1_0_NS:
+           include_once 'Zend_InfoCard_Xml_Assertion_Saml.php';
+           return simplexml_load_string($strXmlData, 'Zend_InfoCard_Xml_Assertion_Saml', null);
+       }
+     }
+
+     SimpleSAML_Logger::debug("Unable to determine Assertion type by Namespace");
+  }
+
+  private function decryptToken($xmlToken) {
+    if($this->_sxml['Type'] != self::XENC_ELEMENT_TYPE) {
+      SimpleSAML_Logger::debug("Unknown EncryptedData type found");
+    }
+
+    $this->_sxml->registerXPathNamespace('enc', self::XENC_NS);  
+    list($encryptionMethod) = $this->_sxml->xpath("//enc:EncryptionMethod");
+    if(!$encryptionMethod instanceof SimpleXMLElement) {
+      SimpleSAML_Logger::debug("EncryptionMethod node not found");
+    }
+
+    $encMethodDom = dom_import_simplexml($encryptionMethod);
+    if(!$encMethodDom instanceof DOMElement) {
+      SimpleSAML_Logger::debug("Failed to create DOM from EncryptionMethod node");
+    }
+
+    if(!$encMethodDom->hasAttribute("Algorithm")) {
+      SimpleSAML_Logger::debug("Unable to determine the encryption algorithm in the Symmetric enc:EncryptionMethod XML block");
+    }
+
+    $algo = $encMethodDom->getAttribute("Algorithm");
+    if($algo != self::XENC_ENC_ALGO) {
+      SimpleSAML_Logger::debug("Unsupported encryption algorithm");
+    }
+
+    $this->_sxml->registerXPathNamespace('ds', self::DSIG_NS);
+    list($keyInfo) = $this->_sxml->xpath("ds:KeyInfo");
+    if(!$keyInfo instanceof SimpleXMLElement) {
+      SimpleSAML_Logger::debug("KeyInfo node not found");
+    }
+
+    $keyInfo->registerXPathNamespace('enc', self::XENC_NS);  
+    list($encryptedKey) = $keyInfo->xpath("enc:EncryptedKey");
+    if(!$encryptedKey instanceof SimpleXMLElement) {
+      SimpleSAML_Logger::debug("EncryptedKey element not found in KeyInfo");
+    }
+
+    $encryptedKey->registerXPathNamespace('enc', self::XENC_NS);  
+    list($keyInfoEncryptionMethod) = $encryptedKey->xpath("enc:EncryptionMethod");
+    if(!$keyInfoEncryptionMethod instanceof SimpleXMLElement) {
+      SimpleSAML_Logger::debug("EncryptionMethod element not found in EncryptedKey");
+    }
+
+    $keyInfoEncMethodDom = dom_import_simplexml($keyInfoEncryptionMethod);
+    if(!$keyInfoEncMethodDom instanceof DOMElement) {
+      SimpleSAML_Logger::debug("Failed to create DOM from EncryptionMethod node");
+    }
+
+    if(!$keyInfoEncMethodDom->hasAttribute("Algorithm")) {
+      SimpleSAML_Logger::debug("Unable to determine the encryption algorithm in the Symmetric enc:EncryptionMethod XML block");
+    }
+
+    $keyInfoEncMethodAlgo = $keyInfoEncMethodDom->getAttribute("Algorithm");
+    if($keyInfoEncMethodAlgo != self::XENC_KEYINFO_ENC_ALGO) {
+      SimpleSAML_Logger::debug("Unsupported encryption algorithm");
+    }
+
+    $encryptedKey->registerXPathNamespace('ds', self::DSIG_NS);
+    $encryptedKey->registerXPathNamespace('wsse', self::WSSE_NS);
+    list($keyIdentifier) = $encryptedKey->xpath("ds:KeyInfo/wsse:SecurityTokenReference/wsse:KeyIdentifier");
+    if(!$keyIdentifier instanceof SimpleXMLElement) {
+      SimpleSAML_Logger::debug("KeyInfo/SecurityTokenReference/KeyIdentifier node not found in KeyInfo");
+    }
+
+    $keyIdDom =  dom_import_simplexml($keyIdentifier);
+    if(!$keyIdDom instanceof DOMElement) {
+      SimpleSAML_Logger::debug("Failed to create DOM from KeyIdentifier node");
+    }
+
+    if(!$keyIdDom->hasAttribute("ValueType")) {
+      SimpleSAML_Logger::debug("Unable to determine ValueType of KeyIdentifier");
+    }
+
+    $valueType = $keyIdDom->getAttribute("ValueType");
+    if($valueType != self::WSSE_KEYID_VALUE_TYPE) {
+      SimpleSAML_Logger::debug("Unsupported KeyIdentifier ValueType");
+    }
+
+    list($cipherValue) = $encryptedKey->xpath("enc:CipherData/enc:CipherValue");
+    if(!$cipherValue instanceof SimpleXMLElement) {
+      SimpleSAML_Logger::debug("CipherValue node found in EncryptedKey");
+    }
+
+    $base64DecodeSupportsStrictParam = version_compare(PHP_VERSION, '5.2.0', '>=');
+
+    if ($base64DecodeSupportsStrictParam) {
+      $keyCipherValueBase64Decoded = base64_decode($cipherValue, true);
+    } else {
+      $keyCipherValueBase64Decoded = base64_decode($cipherValue);
+    }
+
+    $private_key = openssl_pkey_get_private(array(file_get_contents($this->_private_key_file), $this->_password));
+    if(!$private_key) {
+      SimpleSAML_Logger::debug("Unable to load private key");
+    }
+    
+    $result = openssl_private_decrypt($keyCipherValueBase64Decoded, $symmetricKey, $private_key, OPENSSL_PKCS1_OAEP_PADDING);
+    openssl_free_key($private_key);
+
+    if(!$result) {
+      SimpleSAML_Logger::debug("Unable to decrypt symmetric key");
+    }
+
+    list($cipherValue) = $this->_sxml->xpath("enc:CipherData/enc:CipherValue");
+    if(!$cipherValue instanceof SimpleXMLElement) {
+      SimpleSAML_Logger::debug("CipherValue node found in EncryptedData");
+    }
+
+    if ($base64DecodeSupportsStrictParam) {
+      $keyCipherValueBase64Decoded = base64_decode($cipherValue, true);
+    } else {
+      $keyCipherValueBase64Decoded = base64_decode($cipherValue);
+    }
+
+    $mcrypt_iv = substr($keyCipherValueBase64Decoded, 0, 16);
+    $keyCipherValueBase64Decoded =  substr($keyCipherValueBase64Decoded, 16);
+    $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $symmetricKey, $keyCipherValueBase64Decoded, MCRYPT_MODE_CBC, $mcrypt_iv);
+
+    if(!$decrypted) {
+      SimpleSAML_Logger::debug("Unable to decrypt token");
+    }
+
+    $decryptedLength = strlen($decrypted);
+    $paddingLength = substr($decrypted, $decryptedLength -1, 1);
+    $decrypted = substr($decrypted, 0, $decryptedLength - ord($paddingLength));
+    $decrypted = rtrim($decrypted, "\0");
+
+    return $decrypted;
+  }
+}
+
+?>
diff --git a/modules/InfoCard/lib/RP/LICENSE.txt b/modules/InfoCard/lib/RP/LICENSE.txt
new file mode 100644
index 000000000..77a910f6a
--- /dev/null
+++ b/modules/InfoCard/lib/RP/LICENSE.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2005-2008, Zend Technologies USA, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    * Neither the name of Zend Technologies USA, Inc. nor the names of its
+      contributors may be used to endorse or promote products derived from this
+      software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/modules/InfoCard/lib/RP/Zend_InfoCard_Claims.php b/modules/InfoCard/lib/RP/Zend_InfoCard_Claims.php
new file mode 100644
index 000000000..321d1b149
--- /dev/null
+++ b/modules/InfoCard/lib/RP/Zend_InfoCard_Claims.php
@@ -0,0 +1,304 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Claims.php 9094 2008-03-30 18:36:55Z thomas $
+ */
+
+/**
+ * Result value of the InfoCard component, contains any error messages and claims
+ * from the processing of an information card.
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_InfoCard_Claims
+{
+    /**
+     * Successful validation and extraion of claims
+     */
+    const RESULT_SUCCESS = 1;
+
+    /**
+     * Indicates there was an error processing the XML document
+     */
+    const RESULT_PROCESSING_FAILURE = 2;
+
+    /**
+     * Indicates that the signature values within the XML document failed verification
+     */
+    const RESULT_VALIDATION_FAILURE = 3;
+
+    /**
+     * The default namespace to assume in these claims
+     *
+     * @var string
+     */
+    protected $_defaultNamespace  = null;
+
+    /**
+     * A boolean indicating if the claims should be consider "valid" or not based on processing
+     *
+     * @var bool
+     */
+    protected $_isValid = true;
+
+    /**
+     * The error message if any
+     *
+     * @var string
+     */
+    protected $_error = "";
+
+    /**
+     * An array of claims taken from the information card
+     *
+     * @var array
+     */
+    protected $_claims;
+
+    /**
+     * The result code of processing the information card as defined by the constants of this class
+     *
+     * @var integer
+     */
+    protected $_code;
+
+    /**
+     * Override for the safeguard which ensures that you don't use claims which failed validation.
+     * Used in situations when there was a validation error you'd like to ignore
+     *
+     * @return Zend_InfoCard_Claims
+     */
+    public function forceValid()
+    {
+        trigger_error("Forcing Claims to be valid although it is a security risk", E_USER_WARNING);
+        $this->_isValid = true;
+        return $this;
+    }
+
+    /**
+     * Retrieve the PPI (Private Personal Identifier) associated with the information card
+     *
+     * @return string the private personal identifier
+     */
+    public function getCardID()
+    {
+        return $this->getClaim('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier');
+    }
+
+    /**
+     * Retrieves the default namespace used in this information card. If a default namespace was not
+     * set, it figures out which one to consider 'default' by taking the first namespace sorted by use-count
+     * in claims
+     *
+     * @throws Exception
+     * @return string The default namespace
+     */
+    public function getDefaultNamespace()
+    {
+
+        if(is_null($this->_defaultNamespace)) {
+
+            $namespaces = array();
+            $leader = '';
+            foreach($this->_claims as $claim) {
+
+                if(!isset($namespaces[$claim['namespace']])) {
+                    $namespaces[$claim['namespace']] = 1;
+                } else {
+                    $namespaces[$claim['namespace']]++;
+                }
+
+                if(empty($leader) || ($namespaces[$claim['namespace']] > $leader)) {
+                    $leader = $claim['namespace'];
+                }
+            }
+
+            if(empty($leader)) {
+                throw new Exception("Failed to determine default namespace");
+            }
+
+            $this->setDefaultNamespace($leader);
+        }
+
+        return $this->_defaultNamespace;
+    }
+
+    /**
+     * Set the default namespace, overriding any existing default
+     *
+     * @throws Exception
+     * @param string $namespace The default namespace to use
+     * @return Zend_InfoCard_Claims
+     */
+    public function setDefaultNamespace($namespace)
+    {
+
+        foreach($this->_claims as $claim) {
+            if($namespace == $claim['namespace']) {
+                $this->_defaultNamespace = $namespace;
+                return $this;
+            }
+        }
+
+        throw new Exception("At least one claim must exist in specified namespace to make it the default namespace");
+    }
+
+    /**
+     * Indicates if this claim object contains validated claims or not
+     *
+     * @return bool
+     */
+    public function isValid()
+    {
+        return $this->_isValid;
+    }
+
+    /**
+     * Set the error message contained within the claims object
+     *
+     * @param string $error The error message
+     * @return Zend_InfoCard_Claims
+     */
+    public function setError($error)
+    {
+        $this->_error = $error;
+        $this->_isValid = false;
+        return $this;
+    }
+
+    /**
+     * Retrieve the error message contained within the claims object
+     *
+     * @return string The error message
+     */
+    public function getErrorMsg()
+    {
+        return $this->_error;
+    }
+
+    /**
+     * Set the claims for the claims object. Can only be set once and is done
+     * by the component itself. Internal use only.
+     *
+     * @throws Exception
+     * @param array $claims
+     * @return Zend_InfoCard_Claims
+     */
+    public function setClaims(Array $claims)
+    {
+        if(!is_null($this->_claims)) {
+            throw new Exception("Claim objects are read-only");
+        }
+
+        $this->_claims = $claims;
+        return $this;
+    }
+
+    /**
+     * Set the result code of the claims object.
+     *
+     * @throws Exception
+     * @param int $code The result code
+     * @return Zend_InfoCard_Claims
+     */
+    public function setCode($code)
+    {
+        switch($code) {
+            case self::RESULT_PROCESSING_FAILURE:
+            case self::RESULT_SUCCESS:
+            case self::RESULT_VALIDATION_FAILURE:
+                $this->_code = $code;
+                return $this;
+        }
+
+        throw new Exception("Attempted to set unknown error code");
+    }
+
+    /**
+     * Gets the result code of the claims object
+     *
+     * @return integer The result code
+     */
+    public function getCode()
+    {
+        return $this->_code;
+    }
+
+    /**
+     * Get a claim by providing its complete claim URI
+     *
+     * @param string $claimURI The complete claim URI to retrieve
+     * @return mixed The claim matching that specific URI or null if not found
+     */
+    public function getClaim($claimURI)
+    {
+        if($this->claimExists($claimURI)) {
+            return $this->_claims[$claimURI]['value'];
+        }
+
+        return null;
+    }
+
+    /**
+     * Indicates if a specific claim URI exists or not within the object
+     *
+     * @param string $claimURI The complete claim URI to check
+     * @return bool true if the claim exists, false if not found
+     */
+    public function claimExists($claimURI)
+    {
+        return isset($this->_claims[$claimURI]);
+    }
+
+    /**
+     * Magic helper function
+     * @throws Exception
+     */
+    public function __unset($k)
+    {
+        throw new Exception("Claim objects are read-only");
+    }
+
+    /**
+     * Magic helper function
+     */
+    public function __isset($k)
+    {
+        return $this->claimExists("{$this->getDefaultNamespace()}/$k");
+    }
+
+    /**
+     * Magic helper function
+     */
+    public function __get($k)
+    {
+        return $this->getClaim("{$this->getDefaultNamespace()}/$k");
+    }
+
+    /**
+     * Magic helper function
+     * @throws Exception
+     */
+    public function __set($k, $v)
+    {
+        throw new Exception("Claim objects are read-only");
+    }
+}
diff --git a/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Assertion_Saml.php b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Assertion_Saml.php
new file mode 100644
index 000000000..b82d63603
--- /dev/null
+++ b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Assertion_Saml.php
@@ -0,0 +1,272 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Saml.php 9094 2008-03-30 18:36:55Z thomas $
+ */
+
+/**
+ * A Xml Assertion Document in SAML Token format
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_InfoCard_Xml_Assertion_Saml extends SimpleXMLElement
+{
+
+    /**
+     * Audience Restriction Condition
+     */
+    const CONDITION_AUDIENCE = 'AudienceRestrictionCondition';
+
+    /**
+     * The URI for a 'bearer' confirmation
+     */
+    const CONFIRMATION_BEARER = 'urn:oasis:names:tc:SAML:1.0:cm:bearer';
+
+    /**
+     * The amount of time in seconds to buffer when checking conditions to ensure
+     * that differences between client/server clocks don't interfer too much
+     */
+    const CONDITION_TIME_ADJ = 3600; // +- 5 minutes
+
+    protected function _getServerName() {
+        return $_SERVER['SERVER_NAME'];
+    }
+
+    protected function _getServerPort() {
+        return $_SERVER['SERVER_PORT'];
+    }
+
+    /**
+     * Validate the conditions array returned from the getConditions() call
+     *
+     * @param array $conditions An array of condtions for the assertion taken from getConditions()
+     * @return mixed Boolean true on success, an array of condition, error message on failure
+     */
+    public function validateConditions(Array $conditions)
+    {
+
+        $currentTime = time();
+
+        if(!empty($conditions)) {
+
+            foreach($conditions as $condition => $conditionValue) {
+                switch(strtolower($condition)) {
+                    case 'audiencerestrictioncondition':
+
+                        $serverName = $this->_getServerName();
+                        $serverPort = $this->_getServerPort();
+
+                        $self_aliases[] = $serverName;
+                        $self_aliases[] = "{{$serverName}:{$serverPort}";
+
+                        $found = false;
+                        if(is_array($conditionValue)) {
+                            foreach($conditionValue as $audience) {
+
+                                list(,,$audience) = explode('/', $audience);
+                                if(in_array($audience, $self_aliases)) {
+                                    $found = true;
+                                    break;
+                                }
+                            }
+                        }
+
+                        if(!$found) {
+                            return array($condition, 'Could not find self in allowed audience list');
+                        }
+
+                        break;
+                    case 'notbefore':
+                        $notbeforetime = strtotime($conditionValue);
+
+                        if($currentTime < $notbeforetime) {
+                            if($currentTime + self::CONDITION_TIME_ADJ < $notbeforetime) {
+                                return array($condition, 'Current time is before specified window');
+                            }
+                        }
+
+                        break;
+                    case 'notonorafter':
+                        $notonoraftertime = strtotime($conditionValue);
+
+                        if($currentTime >= $notonoraftertime) {
+                            if($currentTime - self::CONDITION_TIME_ADJ >= $notonoraftertime) {
+                                return array($condition, 'Current time is after specified window');
+                            }
+                        }
+
+                        break;
+
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Get the Assertion URI for this type of Assertion
+     *
+     * @return string the Assertion URI
+     */
+    public function getAssertionURI()
+    {
+        return Zend_InfoCard_Xml_Assertion::TYPE_SAML;
+    }
+
+    /**
+     * Get the Major Version of the SAML Assertion
+     *
+     * @return integer The major version number
+     */
+    public function getMajorVersion()
+    {
+        return (int)(string)$this['MajorVersion'];
+    }
+
+    /**
+     * The Minor Version of the SAML Assertion
+     *
+     * @return integer The minor version number
+     */
+    public function getMinorVersion()
+    {
+        return (int)(string)$this['MinorVersion'];
+    }
+
+    /**
+     * Get the Assertion ID of the assertion
+     *
+     * @return string The Assertion ID
+     */
+    public function getAssertionID()
+    {
+        return (string)$this['AssertionID'];
+    }
+
+    /**
+     * Get the Issuer URI of the assertion
+     *
+     * @return string the URI of the assertion Issuer
+     */
+    public function getIssuer()
+    {
+        return (string)$this['Issuer'];
+    }
+
+    /**
+     * Get the Timestamp of when the assertion was issued
+     *
+     * @return integer a UNIX timestamp representing when the assertion was issued
+     */
+    public function getIssuedTimestamp()
+    {
+        return strtotime((string)$this['IssueInstant']);
+    }
+
+    /**
+     * Return an array of conditions which the assertions are predicated on
+     *
+     * @throws Exception
+     * @return array an array of conditions
+     */
+    public function getConditions()
+    {
+
+        list($conditions) = $this->xpath("//saml:Conditions");
+
+        if(!($conditions instanceof SimpleXMLElement)) {
+            throw new Exception("Unable to find the saml:Conditions block");
+        }
+
+        $retval = array();
+
+        foreach($conditions->children('urn:oasis:names:tc:SAML:1.0:assertion') as $key => $value) {
+            switch($key) {
+                case self::CONDITION_AUDIENCE:
+                    foreach($value->children('urn:oasis:names:tc:SAML:1.0:assertion') as $audience_key => $audience_value) {
+                        if($audience_key == 'Audience') {
+                            $retval[$key][] = (string)$audience_value;
+                        }
+                    }
+                    break;
+            }
+        }
+
+        $retval['NotBefore'] = (string)$conditions['NotBefore'];
+        $retval['NotOnOrAfter'] = (string)$conditions['NotOnOrAfter'];
+
+        return $retval;
+    }
+
+    /**
+     * Get they KeyInfo element for the Subject KeyInfo block
+     *
+     * @todo Not Yet Implemented
+     * @ignore
+     */
+    public function getSubjectKeyInfo()
+    {
+        /**
+         * @todo Not sure if this is part of the scope for now..
+         */
+
+        if($this->getConfirmationMethod() == self::CONFIRMATION_BEARER) {
+            throw new Exception("Cannot get Subject Key Info when Confirmation Method was Bearer");
+        }
+    }
+
+    /**
+     * Return the Confirmation Method URI used in the Assertion
+     *
+     * @return string The confirmation method URI
+     */
+    public function getConfirmationMethod()
+    {
+        list($confirmation) = $this->xPath("//saml:ConfirmationMethod");
+        return (string)$confirmation;
+    }
+
+    /**
+     * Return an array of attributes (claims) contained within the assertion
+     *
+     * @return array An array of attributes / claims within the assertion
+     */
+    public function getAttributes()
+    {
+        $attributes = $this->xPath('//saml:Attribute');
+
+        $retval = array();
+        foreach($attributes as $key => $value) {
+
+            $retkey = (string)$value['AttributeNamespace'].'/'.(string)$value['AttributeName'];
+
+            $retval[$retkey]['name'] = (string)$value['AttributeName'];
+            $retval[$retkey]['namespace'] = (string)$value['AttributeNamespace'];
+
+            list($aValue) = $value->children('urn:oasis:names:tc:SAML:1.0:assertion');
+            $retval[$retkey]['value'] = (string)$aValue;
+        }
+
+        return $retval;
+    }
+}
diff --git a/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security.php b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security.php
new file mode 100644
index 000000000..da4ef9f79
--- /dev/null
+++ b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security.php
@@ -0,0 +1,302 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml_Security
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Security.php 9094 2008-03-30 18:36:55Z thomas $
+ */
+
+/**
+ * Zend_InfoCard_Xml_Security_Transform
+ */
+require_once 'Zend_InfoCard_Xml_Security_Transform.php';
+
+/**
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml_Security
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_InfoCard_Xml_Security
+{
+    /**
+     * ASN.1 type INTEGER class
+     */
+    const ASN_TYPE_INTEGER = 0x02;
+
+    /**
+     * ASN.1 type BIT STRING class
+     */
+    const ASN_TYPE_BITSTRING = 0x03;
+
+    /**
+     * ASN.1 type SEQUENCE class
+     */
+    const ASN_TYPE_SEQUENCE = 0x30;
+
+    /**
+     * The URI for Canonical Method C14N Exclusive
+     */
+    const CANONICAL_METHOD_C14N_EXC = 'http://www.w3.org/2001/10/xml-exc-c14n#';
+
+    /**
+     * The URI for Signature Method SHA1
+     */
+    const SIGNATURE_METHOD_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
+
+    /**
+     * The URI for Digest Method SHA1
+     */
+    const DIGEST_METHOD_SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1';
+
+    /**
+     * The Identifier for RSA Keys
+     */
+    const RSA_KEY_IDENTIFIER = '300D06092A864886F70D0101010500';
+
+    /**
+     * Constructor  (disabled)
+     *
+     * @return void
+     */
+    private function __construct()
+    {
+    }
+
+    /**
+     * Validates the signature of a provided XML block
+     *
+     * @param  string $strXMLInput An XML block containing a Signature
+     * @return bool True if the signature validated, false otherwise
+     * @throws Exception
+     */
+    static public function validateXMLSignature($strXMLInput)
+    {
+        if(!extension_loaded('openssl')) {
+            SimpleSAML_Logger::debug("You must have the openssl extension installed to use this class");
+        }
+
+        $sxe = simplexml_load_string($strXMLInput);
+
+	$sxe->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
+
+        list($canonMethod) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:CanonicalizationMethod");
+        switch((string)$canonMethod['Algorithm']) {
+            case self::CANONICAL_METHOD_C14N_EXC:
+                $cMethod = (string)$canonMethod['Algorithm'];
+                break;
+            default:
+                SimpleSAML_Logger::debug("Unknown or unsupported CanonicalizationMethod Requested");
+        }
+
+        list($signatureMethod) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:SignatureMethod");
+        switch((string)$signatureMethod['Algorithm']) {
+            case self::SIGNATURE_METHOD_SHA1:
+                $sMethod = (string)$signatureMethod['Algorithm'];
+                break;
+            default:
+                SimpleSAML_Logger::debug("Unknown or unsupported SignatureMethod Requested");
+        }
+
+        list($digestMethod) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference/ds:DigestMethod");
+        switch((string)$digestMethod['Algorithm']) {
+            case self::DIGEST_METHOD_SHA1:
+                $dMethod = (string)$digestMethod['Algorithm'];
+                break;
+            default:
+                SimpleSAML_Logger::debug("Unknown or unsupported DigestMethod Requested");
+        }
+
+        $base64DecodeSupportsStrictParam = version_compare(PHP_VERSION, '5.2.0', '>=');
+
+        list($digestValue) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference/ds:DigestValue");
+        if ($base64DecodeSupportsStrictParam) {
+            $dValue = base64_decode((string)$digestValue, true);
+        } else {
+            $dValue = base64_decode((string)$digestValue);
+        }
+
+        list($signatureValueElem) = $sxe->xpath("//ds:Signature/ds:SignatureValue");
+        if ($base64DecodeSupportsStrictParam) {
+            $signatureValue = base64_decode((string)$signatureValueElem, true);
+        } else {
+            $signatureValue = base64_decode((string)$signatureValueElem);
+        }
+
+        $transformer = new Zend_InfoCard_Xml_Security_Transform();
+
+	//need to fix this later
+        $transforms = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference/ds:Transforms/ds:Transform");
+        while(list( , $transform) = each($transforms)) {
+          $transformer->addTransform((string)$transform['Algorithm']);
+        }
+
+        $transformed_xml = $transformer->applyTransforms($strXMLInput);
+
+        //$transformed_xml_binhash = pack("H*", sha1($transformed_xml));
+        $transformed_xml_binhash = pack("H*", sha1($transformed_xml));
+
+        if($transformed_xml_binhash != $dValue) {
+            SimpleSAML_Logger::debug("Locally Transformed XML (".$transformed_xml_binhash.") does not match XML Document  (".$dValue."). Cannot Verify Signature");
+        }
+
+        $public_key = null;
+
+
+	$sxe->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
+	list($keyValue) = $sxe->xpath("//ds:Signature/ds:KeyInfo");
+
+	$keyValue->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
+
+        list($x509cert) = $keyValue->xpath("ds:X509Data/ds:X509Certificate");
+        list($rsaKeyValue) = $keyValue->xpath("ds:KeyValue/ds:RSAKeyValue");
+
+        switch(true) {
+            case isset($x509cert):
+
+                $certificate = (string)$x509cert;
+
+
+                $pem = "-----BEGIN CERTIFICATE-----\n" .
+                       wordwrap($certificate, 64, "\n", true) .
+                       "\n-----END CERTIFICATE-----";
+
+                $public_key = openssl_pkey_get_public($pem);
+
+                if(!$public_key) {
+                    SimpleSAML_Logger::debug("Unable to extract and prcoess X509 Certificate from KeyValue");
+                }
+
+                break;
+            case isset($rsaKeyValue):
+
+	        $rsaKeyValue->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
+                list($modulus) = $rsaKeyValue->xpath("ds:Modulus");
+                list($exponent) = $rsaKeyValue->xpath("ds:Exponent");
+                if(!isset($modulus) ||
+                   !isset($exponent)) {
+                    SimpleSAML_Logger::debug("RSA Key Value not in Modulus/Exponent form");
+                }
+
+                $modulus = base64_decode((string)$modulus);
+                $exponent = base64_decode((string)$exponent);
+
+                $pem_public_key = self::_getPublicKeyFromModExp($modulus, $exponent);
+
+                $public_key = openssl_pkey_get_public ($pem_public_key);
+
+                break;
+            default:
+                SimpleSAML_Logger::debug("Unable to determine or unsupported representation of the KeyValue block");
+        }
+
+        $transformer = new Zend_InfoCard_Xml_Security_Transform();
+        $transformer->addTransform((string)$canonMethod['Algorithm']);
+
+        list($signedInfo) = $sxe->xpath("//ds:Signature/ds:SignedInfo");
+	$signedInfoXML = self::addNamespace($signedInfo, "http://www.w3.org/2000/09/xmldsig#"); 
+
+        $canonical_signedinfo = $transformer->applyTransforms($signedInfoXML);
+
+        if(openssl_verify($canonical_signedinfo, $signatureValue, $public_key)) {
+	    list($reference) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference");
+            return (string)$reference['URI'];
+        }
+
+        return false;
+    }
+
+    private function addNamespace($xmlElem, $ns) {
+        $xmlElem->addAttribute('DS_NS', $ns);
+        $xml = $xmlElem->asXML();
+        if(preg_match("/<(\w+)\:\w+/", $xml, $matches)) {
+          $prefix = $matches[1];
+          $xml = str_replace("DS_NS", "xmlns:" . $prefix, $xml);
+        }
+        else {
+          $xml = str_replace("DS_NS", "xmlns", $xml);
+        }
+
+        return $xml;
+    }
+
+    /**
+     * Transform an RSA Key in Modulus/Exponent format into a PEM encoding and
+     * return an openssl resource for it
+     *
+     * @param string $modulus The RSA Modulus in binary format
+     * @param string $exponent The RSA exponent in binary format
+     * @return string The PEM encoded version of the key
+     */
+    static protected function _getPublicKeyFromModExp($modulus, $exponent)
+    {
+        $modulusInteger  = self::_encodeValue($modulus, self::ASN_TYPE_INTEGER);
+        $exponentInteger = self::_encodeValue($exponent, self::ASN_TYPE_INTEGER);
+        $modExpSequence  = self::_encodeValue($modulusInteger . $exponentInteger, self::ASN_TYPE_SEQUENCE);
+        $modExpBitString = self::_encodeValue($modExpSequence, self::ASN_TYPE_BITSTRING);
+
+        $binRsaKeyIdentifier = pack( "H*", self::RSA_KEY_IDENTIFIER );
+
+        $publicKeySequence = self::_encodeValue($binRsaKeyIdentifier . $modExpBitString, self::ASN_TYPE_SEQUENCE);
+
+        $publicKeyInfoBase64 = base64_encode( $publicKeySequence );
+
+        $publicKeyString = "-----BEGIN PUBLIC KEY-----\n";
+        $publicKeyString .= wordwrap($publicKeyInfoBase64, 64, "\n", true);
+        $publicKeyString .= "\n-----END PUBLIC KEY-----\n";
+
+        return $publicKeyString;
+    }
+
+    /**
+     * Encode a limited set of data types into ASN.1 encoding format
+     * which is used in X.509 certificates
+     *
+     * @param string $data The data to encode
+     * @param const $type The encoding format constant
+     * @return string The encoded value
+     * @throws Exception
+     */
+    static protected function _encodeValue($data, $type)
+    {
+        // Null pad some data when we get it (integer values > 128 and bitstrings)
+        if( (($type == self::ASN_TYPE_INTEGER) && (ord($data) > 0x7f)) ||
+            ($type == self::ASN_TYPE_BITSTRING)) {
+                $data = "\0$data";
+        }
+
+        $len = strlen($data);
+
+        // encode the value based on length of the string
+        // I'm fairly confident that this is by no means a complete implementation
+        // but it is enough for our purposes
+        switch(true) {
+            case ($len < 128):
+                return sprintf("%c%c%s", $type, $len, $data);
+            case ($len < 0x0100):
+                return sprintf("%c%c%c%s", $type, 0x81, $len, $data);
+            case ($len < 0x010000):
+                return sprintf("%c%c%c%c%s", $type, 0x82, $len / 0x0100, $len % 0x0100, $data);
+            default:
+                SimpleSAML_Logger::debug("Could not encode value");
+        }
+
+        SimpleSAML_Logger::debug("Invalid code path");
+    }
+}
diff --git a/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform.php b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform.php
new file mode 100644
index 000000000..d96bd216d
--- /dev/null
+++ b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml_Security
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Transform.php 9094 2008-03-30 18:36:55Z thomas $
+ */
+
+require_once 'Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature.php';
+require_once 'Zend_InfoCard_Xml_Security_Transform_XmlExcC14N.php';
+
+/**
+ * A class to create a transform rule set based on XML URIs and then apply those rules
+ * in the correct order to a given XML input
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml_Security
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_InfoCard_Xml_Security_Transform
+{
+    /**
+     * A list of transforms to apply
+     *
+     * @var array
+     */
+    protected $_transformList = array();
+
+    /**
+     * Returns the name of the transform class based on a given URI
+     *
+     * @throws Exception
+     * @param string $uri The transform URI
+     * @return string The transform implementation class name
+     */
+    protected function _findClassbyURI($uri)
+    {
+        switch($uri) {
+            case 'http://www.w3.org/2000/09/xmldsig#enveloped-signature':
+                return 'Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature';
+            case 'http://www.w3.org/2001/10/xml-exc-c14n#':
+                return 'Zend_InfoCard_Xml_Security_Transform_XmlExcC14N';
+            default:
+                SimpleSAML_Logger::debug("Unknown or Unsupported Transformation Requested");
+        }
+    }
+
+    /**
+     * Add a Transform URI to the list of transforms to perform
+     *
+     * @param string $uri The Transform URI
+     * @return Zend_InfoCard_Xml_Security_Transform
+     */
+    public function addTransform($uri)
+    {
+        $class = $this->_findClassbyURI($uri);
+
+        $this->_transformList[] = array('uri' => $uri,
+                                        'class' => $class);
+        return $this;
+    }
+
+    /**
+     * Return the list of transforms to perform
+     *
+     * @return array The list of transforms
+     */
+    public function getTransformList()
+    {
+        return $this->_transformList;
+    }
+
+    /**
+     * Apply the transforms in the transform list to the input XML document
+     *
+     * @param string $strXmlDocument The input XML
+     * @return string The XML after the transformations have been applied
+     */
+    public function applyTransforms($strXmlDocument)
+    {
+        $transformer = null;
+        foreach($this->_transformList as $transform) {
+            switch($transform['class']) {
+              case 'Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature':
+                  $transformer = new Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature();
+                  break;
+              case 'Zend_InfoCard_Xml_Security_Transform_XmlExcC14N':
+                  $transformer = new Zend_InfoCard_Xml_Security_Transform_XmlExcC14N();
+                  break;
+            }
+
+            $strXmlDocument = $transformer->transform($strXmlDocument);
+        }
+
+        return $strXmlDocument;
+    }
+}
diff --git a/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature.php b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature.php
new file mode 100644
index 000000000..42d2f126b
--- /dev/null
+++ b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml_Security
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: EnvelopedSignature.php 9094 2008-03-30 18:36:55Z thomas $
+ */
+
+/**
+ * A object implementing the EnvelopedSignature XML Transform
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml_Security
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_InfoCard_Xml_Security_Transform_EnvelopedSignature
+{
+    /**
+     * Transforms the XML Document according to the EnvelopedSignature Transform
+     *
+     * @throws Exception
+     * @param string $strXMLData The input XML data
+     * @return string the transformed XML data
+     */
+    public function transform($strXMLData)
+    {
+        $sxe = simplexml_load_string($strXMLData);
+	$sxe->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
+
+	list($signature) = $sxe->xpath("//ds:Signature");
+        if(!isset($signature)) {
+            SimpleSAML_Logger::debug("Unable to locate Signature Block for EnvelopedSignature Transform");
+        }
+
+        $transformed_xml = str_replace($signature->asXML(), "", $sxe->asXML());
+
+        return $transformed_xml;
+    }
+}
diff --git a/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform_XmlExcC14N.php b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform_XmlExcC14N.php
new file mode 100644
index 000000000..c680dd8b7
--- /dev/null
+++ b/modules/InfoCard/lib/RP/Zend_InfoCard_Xml_Security_Transform_XmlExcC14N.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml_Security
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: XmlExcC14N.php 9094 2008-03-30 18:36:55Z thomas $
+ */
+
+/**
+ * A Transform to perform C14n XML Exclusive Canonicalization
+ *
+ * @category   Zend
+ * @package    Zend_InfoCard
+ * @subpackage Zend_InfoCard_Xml_Security
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_InfoCard_Xml_Security_Transform_XmlExcC14N
+{
+    /**
+     * Transform the input XML based on C14n XML Exclusive Canonicalization rules
+     *
+     * @throws Exception
+     * @param string $strXMLData The input XML
+     * @return string The output XML
+     */
+    public function transform($strXMLData)
+    {
+        $dom = new DOMDocument();
+        $dom->loadXML($strXMLData);
+
+        if(method_exists($dom, 'C14N')) {
+            return $dom->C14N(true, false);
+        }
+
+        SimpleSAML_Logger::debug("This transform requires the C14N() method to exist in the DOM extension");
+    }
+}
diff --git a/modules/InfoCard/templates/default/login-infocard.php b/modules/InfoCard/templates/default/login-infocard.php
new file mode 100644
index 000000000..1b439071a
--- /dev/null
+++ b/modules/InfoCard/templates/default/login-infocard.php
@@ -0,0 +1,58 @@
+<?php
+/*
+* AUTHOR: Samuel Muñoz Hidalgo
+* EMAIL: samuel.mh@gmail.com
+* LAST REVISION: 1-DEC-08
+* DESCRIPTION: 'login-infocard' module template.
+*/
+	$this->includeAtTemplateBase('includes/header.php'); 
+	if (!array_key_exists('icon', $this->data)) $this->data['icon'] = 'lock.png';
+	if (isset($this->data['error'])) { ?>
+		<div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
+		<img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/bomb.png" style="float: left; margin: 15px " />
+		<h2><?php echo $this->t('error_header'); ?></h2>
+		
+		<p><?php echo $this->t($this->data['error']); ?> </p>
+		</div>
+	<?php } ?>
+
+	<h2 style="break: both"><?php echo $this->t('user_IC_header'); ?></h2>
+	
+	<p><?php echo $this->t('user_IC_text'); ?></p>
+	
+	<form name="ctl00" id="ctl00" method="post" action="?">
+		<?php foreach ($this->data['stateparams'] as $name => $value) {
+		echo('<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '" />');
+		}?>
+		<ic:informationCard xmlns:ic="<?php echo $this->data['InfoCard']['schema'] ?>" name='xmlToken' 
+			issuer="<?php echo $this->data['InfoCard']['issuer']; ?>"
+			issuerPolicy="<?php echo $this->data['InfoCard']['issuerPolicy']; ?>"
+			tokenType="<?php echo $this->data['InfoCard']['tokenType']; ?>"			
+			privacyUrl="<?php echo $this->data['InfoCard']['privacyURL']; ?>"
+			privacyVersion="<?php echo $this->data['InfoCard']['privacyVersion']; ?>">
+			<?php
+				$schema = $this->data['InfoCard']['schema']."/claims/";
+				foreach ($this->data['InfoCard']['requiredClaims'] as $claim=>$data) {
+					echo "<ic:add claimType = \"$schema".$claim."\" optional=\"false\" />\n";
+				}
+				foreach ($this->data['InfoCard']['optionalClaims'] as $claim=>$data) {
+					echo "<ic:add claimType = \"$schema".$claim."\" optional=\"true\" />\n";
+				}
+				unset($value);?>
+		</ic:informationCard>
+		<input type='image' src="<?php echo $this->data['IClogo']; ?>" align='center'  style='cursor:pointer' />
+	</form>
+	
+	<?php if (strcmp($this->data['CardGenerator'],'')>0) {
+	echo '<h2>Or get one</h2>';
+	echo '<table border="0">';
+	echo "<form action=\"". $this->data['CardGenerator'] ."\" method='post'>";
+		echo "<tr><td>Username: </td><td><input type='text' name='username' value='usuario' /></tr></td>";
+		echo "<tr><td>Password: </td><td><input type='password' name='password' value='clave' /></tr></td>";
+		echo "<tr><td></td><td><input type='submit' name='Get_card' value='Get InfoCard' /></tr></td>";
+	echo '</form>';
+	echo '</table>';
+	 } ?>
+	<h2><?php echo $this->t('help_header'); ?></h2>	
+	<p><?php echo $this->t('help_text'); ?></p>
+<?php $this->includeAtTemplateBase('includes/footer.php'); ?>
\ No newline at end of file
diff --git a/modules/InfoCard/www/login-infocard.php b/modules/InfoCard/www/login-infocard.php
new file mode 100644
index 000000000..577c533cf
--- /dev/null
+++ b/modules/InfoCard/www/login-infocard.php
@@ -0,0 +1,54 @@
+<?php
+
+/*
+* AUTHOR: Samuel Muñoz Hidalgo
+* EMAIL: samuel.mh@gmail.com
+* LAST REVISION: 1-DEC-08
+* DESCRIPTION:
+*  'login-infocard' module.
+*  Allows an user to authenticate to the system with an Information Card.
+*  Infocard's claims are extracted passed as attributes.
+*/
+
+
+/* Load the configuration. */
+$config = SimpleSAML_Configuration::getInstance();
+$autoconfig = $config->copyFromBase('logininfocard', 'config-login-infocard.php');
+
+$server_key = $autoconfig->getValue('server_key');
+$server_crt = $autoconfig->getValue('server_crt');
+$IClogo = $autoconfig->getValue('IClogo');
+$Infocard =   $autoconfig->getValue('InfoCard');
+$cardGenerator =   $autoconfig->getValue('CardGenerator');
+
+
+/* Load the session of the current user. */
+$session = SimpleSAML_Session::getInstance();
+if($session == NULL) {
+	SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOSESSION');
+}
+
+
+if (!array_key_exists('AuthState', $_REQUEST)) {
+	throw new SimpleSAML_Error_BadRequest('Missing AuthState parameter.');
+}
+$authStateId = $_REQUEST['AuthState'];
+
+
+if(array_key_exists('xmlToken', $_POST) && ($_POST['xmlToken']!=NULL)  ) {
+	$error = sspmod_InfoCard_Auth_Source_ICAuth::handleLogin($authStateId, $_POST['xmlToken']);
+}else {
+	$error = NULL;
+}
+
+//Login Page
+$t = new SimpleSAML_XHTML_Template($config, 'InfoCard:login-infocard.php', 'logininfocard'); //(configuracion, template, diccionario)
+$t->data['header'] = 'simpleSAMLphp: Infocard login';
+$t->data['stateparams'] = array('AuthState' => $authStateId);
+$t->data['IClogo'] = $IClogo;
+$t->data['InfoCard'] = $Infocard;
+$t->data['CardGenerator'] = $cardGenerator;
+$t->data['error'] = $error;
+$t->show();
+exit();
+?>
diff --git a/modules/InfoCard/www/resources/infocard_114x80.png b/modules/InfoCard/www/resources/infocard_114x80.png
new file mode 100644
index 0000000000000000000000000000000000000000..6dba25fbd5b54d68bdf1be245e5c8807bfd06e69
GIT binary patch
literal 3821
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

literal 0
HcmV?d00001

-- 
GitLab