Skip to content
Snippets Groups Projects
Commit 88a223eb authored by Jaime Perez Crespo's avatar Jaime Perez Crespo
Browse files

Extract the InfoCard module out to its own repository.

parent 1194ce95
No related branches found
No related tags found
No related merge requests found
Showing
with 1 addition and 2946 deletions
......@@ -46,7 +46,6 @@ Documentation on specific simpleSAMLphp modules:
* [Installing and configuring the consentAdmin module](./consentAdmin:consentAdmin)
* [OpenId Provider Module](./openidProvider:provider)
* [Authorization](./authorize:authorize)
* [InfoCard Module](./InfoCard:usage)
* [autotest Module](./autotest:test)
* [Statistics](./statistics:statistics)
* [Aggregator](./aggregator:aggregator)
......
......@@ -55,7 +55,7 @@ The next step is to configure the way users authenticate on your IdP. Various mo
[`radius:Radius`](./radius:radius)
: Authenticates an user to a Radius server.
[`InfoCard:ICAuth`](./InfoCard:usage)
[`InfoCard:ICAuth`](https://github.com/simplesamlphp/simplesamlphp-module-infocard/blob/master/README.md)
: Authenticate with an InfoCard.
[`multiauth:MultiAuth`](./multiauth:multiauth)
......
<?php
/*
* AUTHOR: Samuel Muñoz Hidalgo
* EMAIL: samuel.mh@gmail.com
* LAST REVISION: 13-FEB-09
* DESCRIPTION: 'InfoCard' module configuration for simpleSAMLphp.
Some definitions were taken from:
A Guide to Using the Identity Selector
Interoperability Profile V1.5 within Web
Applications and Browsers.
Copyright Microsoft
*/
$config = array (
//------------- TEMPLATE OPTIONS ---------------
'IClogo' => 'resources/infocard_114x80.png', //Infocard logo button
'help_desk_email_URL' => 'mailto:asd@asd.com', //Help desk e-mail
'contact_info_URL' => 'http://google.es', //Contact information
//------------- CERTIFICATE OPTIONS ---------------
/*
* USED IN: Relying Party
* DESCRIPTION: Key of the certificate used in the https connection with the idp, it'll be used
* for decrypting the received XML token,
*/
'idp_key' => '/etc/apache2/ssl/idp.key',
/*
* USED IN: Relying Party
* DESCRIPTION: Only accept tokens signed with this certificate,
* if no certificate is set, it'll be assumed to accept
* a self isued token and accept any token.
*/
'sts_crt' => '/etc/apache2/ssl/sts.crt',
/*
* USED IN: Infocard Generator, STS
* DESCRIPTION: STS certificate for signing Infocards and tokens.
*/
'sts_key' => '/etc/apache2/ssl/sts.key',
/*
* USED IN:
* DESCRIPTION: Array of certificates forming a trust chain. The local signing
* certificate is [0], the one that signed that is [1], etc, chaining to a
* trust anchor.
* HINT: The first one, [0], should be the same as the sts_crt.
*/
'certificates' => array(
0 => '/etc/apache2/ssl/sts.crt',
1 => '/etc/apache2/ssl/CA.crt'
),
//------------- DATA (InfoCard) OPTIONS ---------------
/*
* USED IN: InfoCard Generator, Relying Party and STS
* DESCRIPTION: Infocard information
*/
'InfoCard' => array(
/*
* -issuer (optional, taken from the sts_crt common name value, if no set, self issuer is assumed )
* 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
*/
/*
* Root of the current InfoCard schema
*/
'schema' => 'http://schemas.xmlsoap.org/ws/2005/05/identity',
/*
* -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.
*/
'issuerPolicy' => '',
/*
* -privacyUrl (optional)
* This parameter specifies the URL of the human-readable Privacy Policy of the site, if
* provided.
*/
'privacyURL' => '',
/*
* -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.
*/
'tokenType' => 'urn:oasis:names:tc:SAML:1.0:assertion',
/*-Claims supported by the current schema
givenname
surname
emailaddress
streetaddress
locality
stateorprovince
postalcode
country
primaryphone
dateofbirth
privatepersonalid
gender
webpage
*/
/*
* -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.
*/
'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 (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
*/
'optionalClaims' => array(
'country' => array('displayTag'=>"country", 'description'=>"País"),
'webpage' => array('displayTag'=>"webpage", 'description'=>"Página web")
),
),
//------------- WEB PAGES ---------------
/*
* USED IN: InfoCard Generator, Relying Party (optional form)
* DESCRIPTION: Infocard generator URL, if set it'll appear a form with username-password authentication in the template
*/
'CardGenerator' => 'https://sts.aut.uah.es/simplesaml/module.php/InfoCard/getcardform.php',
/*
* USED IN: InfoCard Generator, Relying Party (issuer), STS (Metadata-Exchange)
* DESCRIPTION: Token generator URL
*/
'tokenserviceurl' => 'https://sts.aut.uah.es/simplesaml/module.php/InfoCard/tokenservice.php',
/*
* USED IN: InfoCard Generator
* DESCRIPTION: Metadata Exchange URL
*/
'mexurl' => 'https://sts.aut.uah.es/simplesaml/module.php/InfoCard/mex.php',
//------------- CREDENTIALS ---------------
/*
* USED IN: InfoCard Generator, Relying Party (optional form)
* TYPES: UsernamePasswordCredential, KerberosV5Credential, X509V3Credential, SelfIssuedCredential
* DESCRIPTION: How the user will be authenticated
* IMPLEMENTED & TESTED: UsernamePasswordCredential, SelfIssuedCredential
*/
'UserCredential' => 'SelfIssuedCredential',
//------------- DEBUG ---------------
/*
* USED IN: tokenservice
* DESCRIPTION: directory where RSTs and RSTRs will be logged EJ: /tmp.
* If null, logging will be dissabled.
* The directory MUST exists and be accessible to the program, otherwise NO log will be written
* Log files have the form urn:uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.log where X is an hexadecimal digit [0-9|a-f]
*/
'debugDir' => '/tmp',
);
This file indicates that the default state of this module
is disabled. To enable, create a file named enable in the
same directory as this file.
{
"wrong_IC": {
"en": "Invalid InfoCard"
},
"get_IC": {
"en": "Get your InfoCard"
},
"get_IC_link": {
"en": "Click here to get your InfoCard"
},
"form_username": {
"en": "Username"
},
"form_password": {
"en": "Password"
},
"error_header": {
"en": "Error"
},
"user_IC_header": {
"en": "Select an InfoCard"
},
"user_IC_text": {
"en": "A service has requested you to authenticate yourself. Please click on the image below to start a session with an InfoCard."
},
"login_button": {
"en": " "
},
"get_button": {
"en": "Get my Infocard"
},
"help_header": {
"en": "HELP! What is an InfoCard?"
},
"help_text": {
"en": "Information Cards (aka InfoCard) is a web authentication technology. Contact with your services provider in order to configure your computer and give you and Information Card (identification virtual card)."
},
"help_desk_link": {
"en": "Help desk homepage"
},
"help_desk_email": {
"en": "Send e-mail to help desk"
},
"contact_info": {
"en": "Contact information"
},
"getcardform_title": {
"en": "Authentication form"
},
"getcardform_self_title": {
"en": "Self-Issued Card form"
},
"getcardform_self_text": {
"en": "Please, enter a self issued InfoCard in order to link it with the managed one we are generating."
},
"getcardform_finished_title": {
"en": "Congratulations, your Infocard was succesfully generated"
},
"getcardform_finished_text": {
"en": "Please follow the next link to get to the login page."
},
"NO_password": {
"en": "Please fill in your password"
},
"NO_user": {
"en": "Please fill in your username"
},
"Wrong_user_pass": {
"en": "Wrong username or password"
},
"": {
"en": ""
}
}
\ No newline at end of file
<?php
/*
* AUTHOR: Samuel Muñoz Hidalgo
* EMAIL: samuel.mh@gmail.com
* LAST REVISION: 16-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' => '',
),
'get_IC' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Get your InfoCard',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Consiga su InfoCard',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'get_IC_link' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Click here to get your InfoCard',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Pinche aquí para conseguir su InfoCard',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'form_username' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Username',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Usuario',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'form_password' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Password',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Contraseña',
'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' => '',
),
'get_button' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Get my Infocard',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Conseguir mi Infocard',
'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 give 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',
),
'getcardform_title' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Authentication form',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Formulario de autenticación',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'getcardform_self_title' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Self-Issued Card form',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Formulario de tarjeta autogestionada',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'getcardform_self_text' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Please, enter a self issued InfoCard in order to link it with the managed one we are generating.',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Por favor, introduzca una InfoCard autogestionada para ligarla a la que vamos a generarle.',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'getcardform_finished_title' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Congratulations, your Infocard was succesfully generated',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Enhorabuena, generó su Infocard con éxito',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'getcardform_finished_text' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Please follow the next link to get to the login page.',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Siga el siguiente enlace para ir a la página de login',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'NO_password' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Please fill in your password',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Introduce una contraseña',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'NO_user' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Please fill in your username',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Introduce tu nombre de usuario',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'Wrong_user_pass' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => 'Wrong username or password',
'de' => '',
'sv' => '',
'fi' => '',
'es' => 'Usuario o contraseña inválidos ',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => '',
'de' => '',
'sv' => '',
'fi' => '',
'es' => '',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
'' => array (
'no' => '',
'nn' => '',
'da' => '',
'en' => '',
'de' => '',
'sv' => '',
'fi' => '',
'es' => '',
'fr' => '',
'nl' => '',
'lb' => '',
'sl' => '',
'hr' => '',
'hu' => '',
'pt' => '',
'pt-br' => '',
),
);
We are glad to announce a new release of the InfoCard
module implementation for simpleSAMLphp.
Sorry for being a bit late but I've just finished my degree exams.
Here are the major changes:
-In addition to user-password authentication, STS is also accepting Self-issued cards.
-Fully compatible with MS Cardspace. Really! (Tested with Digitalme
and Cardspaces)
-mex.php has been fully rewritten, now it's short and understable. :)
-I've added a link in the module main page so it's possible to get a
managed card once you get authenticated by means of a simple user-password form. Because of this getinfocard.php is replaced by getcardform.php
-A new classs called STS has been added to handle the STS messages
(issuing InfoCards, Request Service Token Response, Error Response).
-tokenservice.php make use of STS class. This has allowed us to shorten it quite a log.
-Commented and more elegant code.
-Logging support:It's possible to log the RST (from the identity selector) and the RSTR (from the STS) messages in a configurable directory.
-We carry on using transport binding for the communications.
This work is being supported by RedIRIS (the spanish NREN, www.rediris.es) and CS Department of the University of Alcala (Spain).
This modules has been developed by Samuel Muñoz Hidalgo.
Contact: Enrique de la Hoz: enrique.delahoz@uah.es.
Information cards module for simpleSAMLphp
==========================================
<!--
This file is written in Markdown syntax.
For more information about how to use the Markdown syntax, read here:
http://daringfireball.net/projects/markdown/syntax
-->
AUTHOR: Samuel Muñoz Hidalgo
EMAIL: samuel.mh@gmail.com
LAST REVISION: 13-FEB-09
DESCRIPTION: What you should read before starting doing things.
Introduction
-------------
WARNING: **THIS IS NOT** mature software, it's released with testing, educational, developing purposes. It's on a very early version, so don't rely the life of anybody on it.
This is a simpleSAMLphp module that works with Information Cards techcnologies and provides two basic functionalities:
RP
: Acting as a Relying Party, you can accept user authentication through InfoCards comsumming tokens sent by aSTS.
STS
: Acting as a Secure Token Service you can provide information to a RP generating tokens. Currently, only user password and self issued credentials are supported.
InfoCard Generator
: Your users could request their InfoCard filling a form with their username and password.
Very important
--------------
This document is not a strict guide, I mean it might have some errors or missed information. I've tried to comment almost every trick i've used to make the system work and make your life easier. So, if at any point of the installation you feel lost, breathe twice, think for ten minutes in what you are trying to do, read again the documentation and use your common sense. It'll be usefull when you'll face again the configuration file.
Basic installation
------------------
1. Copy the InfoCard folder in your modules directoy in your SimpleSAMLphp installation directory.
2. Copy (or move) the file `modules/InfoCard/extra/config-login-infocard.php` to the config directory in your SimpleSAMLphp installation directory.
3. Edit the `config/config-login-infocard.php` file, you should configure some values like: `help_desk_email_URL`, `contact_info_URL`, `server_key`, `server_crt`, `sts_crt`, `requiredClaims` and `optionalClaims` to fit your needs.
4. Edit the config/authsources.php file, add this text before the last );
'InfoCard' => array(
'InfoCard:ICAuth',
),
5. That's all.
Adding an Infocard Generator
----------------------------
1. Go into the `modules/InfoCard` folder.
2. Copy `extra/getinfocard.php` to `www/getinfocard.php`
3. Edit the `config/config-login-infocard.php` file and uncomment this line
// 'CardGenerator' => 'getinfocard.php', (delete the two //).
4. Following the previous example, uncomment this `values:certificates`, `sts_key`, `tokenserviceurl` and `mexurl`.
6. Check the previous values andm modify them if you need.
5. Read the USER FUNCTIONS section.
Adding the STS functionality
----------------------------
1. Go into the `modules/InfoCard` folder.
2. Copy `extra/mex.php` and `extra/tokenservice.php` to the www folder.
3. Edit the `config/config-login-infocard.php` file and uncomment the values: `certificates` and `sts_key`.
4. Read the USER FUNCTIONS section.
User functions
--------------
Because there are many authentication issues I cannot guess for you, you'll have to code a little bit to fit this module to your authentication system.
We we'll work with the file `UserFunctions.php` located in `modules/InfoCard/lib/`
`validateUser`, it receives two strings, username and password, you do the validation (against your database?) and return true if you want to validate the user or false instead.
`fillClaims`, it's used by the tokenservice to give information about the user to the relying party. It receives the username, the configured required and optional claims and the claims requested by the RP.
It works filling the claimValues array and your job is the ensure the 'value' variable (`$claimValues[$claim]['value']=` ) of the array gets the value you want. Understand that requested values and your configured ones could not match.
`fillICdata`, it's used by the card generator to retrieve needed information. It receives an authenticated username and returns an array containing information such as the card name, the card image, the expiring time, etc.
Certificates and hosts
----------------------
The architecture is composed by three independent elements:
- User: Identity Selector
- IDP: Relying Party
- STS: IC and token generation.
That's because you should configure two hosts (with two x509 certificates) if you want two have the IDP and STS functionalities in the same machine.
\ No newline at end of file
<?php
/*
* AUTHOR: Samuel Muñoz Hidalgo
* EMAIL: samuel.mh@gmail.com
* LAST REVISION: 22-DEC-08
* DESCRIPTION:
* Authentication module.
* Handles the login information
* Infocard's claims are extracted passed as attributes.
*/
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::redirectTrustedURL($url, array('AuthState' => $id));
}
public static function handleLogin($authStateId, $xmlToken) {
assert('is_string($authStateId)');
$config = SimpleSAML_Configuration::getInstance();
$autoconfig = $config->copyFromBase('logininfocard', 'config-login-infocard.php');
$idp_key = $autoconfig->getValue('idp_key');
$idp_pass = $autoconfig->getValue('idp_key_pass', NULL);
$sts_crt = $autoconfig->getValue('sts_crt');
$Infocard = $autoconfig->getValue('InfoCard');
$infocard = new sspmod_InfoCard_RP_InfoCard();
$infocard->addIDPKey($idp_key, $idp_pass);
$infocard->addSTSCertificate($sts_crt);
if (!$xmlToken)
SimpleSAML_Logger::debug("XMLtoken: ".$xmlToken);
else
SimpleSAML_Logger::debug("NOXMLtoken: ".$xmlToken);
$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);
}
// sanitize the input
$sid = SimpleSAML_Utilities::parseStateID($authStateId);
if (!is_null($sid['url'])) {
SimpleSAML_Utilities::checkURLAllowed($sid['url']);
}
/* 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]);
}
$state['Attributes'] = $attributes;
unset($infocard);
unset($claims);
SimpleSAML_Auth_Source::completeAuth($state);
} else {
unset($infocard);
unset($claims);
return 'wrong_IC';
}
}
}
<?php
/*
* COAUTHOR: Samuel Muñoz Hidalgo
* EMAIL: samuel.mh@gmail.com
* LAST REVISION: 22-DEC-08
* DESCRIPTION: Zend Infocard libraries added sts certificate check
*/
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;
protected $_sts_crt;
public function __construct() {
if(!extension_loaded('mcrypt')) {
throw new Exception("Use of the InfoCard component requires the mcrypt extension to be enabled in PHP");
}
if(!extension_loaded('openssl')) {
throw new Exception("Use of the InfoCard component requires the openssl extension to be enabled in PHP");
}
}
public function addSTSCertificate($sts_crt){
$this->_sts_crt = $sts_crt;
if(($sts_crt==NULL) || (strcmp($sts_crt,'')==0)) {
SimpleSAML_Logger::debug('WARNING: No STS certificate is set, ALL TOKENS WILL BE ACCEPTED');
}else if( (!file_exists($sts_crt)) || (!is_readable($sts_crt))) {
throw new Exception("STS certificate is not readable");
}
}
public function addIDPKey($private_key_file, $password = NULL){
$this->_private_key_file = $private_key_file;
$this->_password = $password;
if(!file_exists($this->_private_key_file)) {
throw new Exception("Private key file does not exists");
}
if(!is_readable($this->_private_key_file)) {
throw new Exception("Private key file is not readable");
}
}
/*Function not used $public_key_file is not used*/
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)) {
throw new Exception("Private key file does not exists");
}
if(!is_readable($this->_private_key_file)) {
throw new Exception("Private key file is not readable");
}
if(!file_exists($this->_public_key_file)) {
throw new Exception("Public key file does not exists");
}
if(!is_readable($this->_public_key_file)) {
throw new Exception("Public key file is not readable");
}
}
public function process($xmlToken) {
if(strpos($xmlToken, "EncryptedData") === false ) {
SimpleSAML_Logger::debug('IC: UNsecureToken');
return self::processUnSecureToken($xmlToken);
}
else {
SimpleSAML_Logger::debug('IC: secureToken');
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) {
SimpleSAML_Logger::debug('ProcSecToken '.$e);
$retval->setError('Failed to extract assertion document');
throw new Exception('Failed to extract assertion document: ' . $e->getMessage());
$retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);
return $retval;
}
try {
$assertions = self::getAssertions($decryptedToken);
}
catch(Exception $e) {
$retval->setError('Failure processing assertion document');
throw new Exception('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');
throw new Exception('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(), $this->_sts_crt);
if(!$reference_id) {
throw new Exception("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 {
throw new Exception("Reference of document signature does not reference the local document");
}
if($reference_id != $assertions->getAssertionID()) {
throw new Exception("Reference of document signature does not reference the local document");
}
$conditions = $assertions->getConditions();
if(is_array($condition_error = $assertions->validateConditions($conditions))) {
throw new Exception("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);
}
}
throw new Exception("Unable to determine Assertion type by Namespace");
}
private function decryptToken($xmlToken) {
if($this->_sxml['Type'] != self::XENC_ELEMENT_TYPE) {
throw new Exception("Unknown EncryptedData type found");
}
$this->_sxml->registerXPathNamespace('enc', self::XENC_NS);
list($encryptionMethod) = $this->_sxml->xpath("//enc:EncryptionMethod");
if(!$encryptionMethod instanceof SimpleXMLElement) {
throw new Exception("EncryptionMethod node not found");
}
$encMethodDom = dom_import_simplexml($encryptionMethod);
if(!$encMethodDom instanceof DOMElement) {
throw new Exception("Failed to create DOM from EncryptionMethod node");
}
if(!$encMethodDom->hasAttribute("Algorithm")) {
throw new Exception("Unable to determine the encryption algorithm in the Symmetric enc:EncryptionMethod XML block");
}
$algo = $encMethodDom->getAttribute("Algorithm");
if($algo != self::XENC_ENC_ALGO) {
throw new Exception("Unsupported encryption algorithm");
}
$this->_sxml->registerXPathNamespace('ds', self::DSIG_NS);
list($keyInfo) = $this->_sxml->xpath("ds:KeyInfo");
if(!$keyInfo instanceof SimpleXMLElement) {
throw new Exception("KeyInfo node not found");
}
$keyInfo->registerXPathNamespace('enc', self::XENC_NS);
list($encryptedKey) = $keyInfo->xpath("enc:EncryptedKey");
if(!$encryptedKey instanceof SimpleXMLElement) {
throw new Exception("EncryptedKey element not found in KeyInfo");
}
$encryptedKey->registerXPathNamespace('enc', self::XENC_NS);
list($keyInfoEncryptionMethod) = $encryptedKey->xpath("enc:EncryptionMethod");
if(!$keyInfoEncryptionMethod instanceof SimpleXMLElement) {
throw new Exception("EncryptionMethod element not found in EncryptedKey");
}
$keyInfoEncMethodDom = dom_import_simplexml($keyInfoEncryptionMethod);
if(!$keyInfoEncMethodDom instanceof DOMElement) {
throw new Exception("Failed to create DOM from EncryptionMethod node");
}
if(!$keyInfoEncMethodDom->hasAttribute("Algorithm")) {
throw new Exception("Unable to determine the encryption algorithm in the Symmetric enc:EncryptionMethod XML block");
}
$keyInfoEncMethodAlgo = $keyInfoEncMethodDom->getAttribute("Algorithm");
if($keyInfoEncMethodAlgo != self::XENC_KEYINFO_ENC_ALGO) {
throw new Exception("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) {
throw new Exception("KeyInfo/SecurityTokenReference/KeyIdentifier node not found in KeyInfo");
}
$keyIdDom = dom_import_simplexml($keyIdentifier);
if(!$keyIdDom instanceof DOMElement) {
throw new Exception("Failed to create DOM from KeyIdentifier node");
}
if(!$keyIdDom->hasAttribute("ValueType")) {
throw new Exception("Unable to determine ValueType of KeyIdentifier");
}
$valueType = $keyIdDom->getAttribute("ValueType");
if($valueType != self::WSSE_KEYID_VALUE_TYPE) {
throw new Exception("Unsupported KeyIdentifier ValueType");
}
list($cipherValue) = $encryptedKey->xpath("enc:CipherData/enc:CipherValue");
if(!$cipherValue instanceof SimpleXMLElement) {
throw new Exception("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) {
throw new Exception("Unable to load private key");
}
$result = openssl_private_decrypt($keyCipherValueBase64Decoded, $symmetricKey, $private_key, OPENSSL_PKCS1_OAEP_PADDING);
openssl_free_key($private_key);
if(!$result) {
throw new Exception("Unable to decrypt symmetric key");
}
list($cipherValue) = $this->_sxml->xpath("enc:CipherData/enc:CipherValue");
if(!$cipherValue instanceof SimpleXMLElement) {
throw new Exception("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) {
throw new Exception("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;
}
}
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.
<?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");
}
}
<?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;
}
}
<?php
/*
* COAUTHOR: Samuel Muñoz Hidalgo
* EMAIL: samuel.mh@gmail.com
* LAST REVISION: 22-DEC-08
* DESCRIPTION: modified validatexmlsignature
*/
/**
* 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
*/
/*
* ÚLTIMA REVISIÓN: 4-DEC-2008
*/
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, $sts_crt=NULL){
if(!extension_loaded('openssl')) {
throw new Exception("You must have the openssl extension installed to use this class");
}
$sxe = simplexml_load_string($strXMLInput);
if ($sts_crt != 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");
//Extract the XMLToken issuer public key
switch(true) {
case isset($x509cert):
SimpleSAML_Logger::debug("Public Key: x509cert");
$certificate = (string)$x509cert;
$cert_issuer = "-----BEGIN CERTIFICATE-----\n".wordwrap($certificate, 64, "\n", true)."\n-----END CERTIFICATE-----";
if (!$t_key = openssl_pkey_get_public($cert_issuer)) {
throw new Exception("Wrong token certificate");
}
$t_det = openssl_pkey_get_details($t_key);
$pem_issuer = $t_det['key'];
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)) {
throw new Exception("RSA Key Value not in Modulus/Exponent form");
}
$modulus = base64_decode((string)$modulus);
$exponent = base64_decode((string)$exponent);
$pem_issuer = self::_getPublicKeyFromModExp($modulus, $exponent);
break;
default:
SimpleSAML_Logger::debug("Public Key: Unknown");
throw new Exception("Unable to determine or unsupported representation of the KeyValue block");
}
//Check isuer public key against configured one
$checkcert = file_get_contents($sts_crt);
$check_key = openssl_pkey_get_public($checkcert);
$checkData = openssl_pkey_get_details($check_key);
$pem_local = $checkData['key'];
if ( strcmp($pem_issuer,$pem_local)!=0 ) {
SimpleSAML_Logger::debug("Configured STS cert and received STS cert mismatch");
openssl_free_key($check_key);
throw new Exception("Configured STS cert and received STS cert mismatch");
}
//Validate XML signature
$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:
throw new Exception("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:
throw new Exception("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:
throw new Exception("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();
$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));
if($transformed_xml_binhash != $dValue) {
throw new Exception("Locally Transformed XML (".$transformed_xml_binhash.") does not match XML Document (".$dValue."). Cannot Verify Signature");
}
$transformer = new Zend_InfoCard_Xml_Security_Transform();
$transformer->addTransform((string)$canonMethod['Algorithm']);
list($signedInfo) = $sxe->xpath("//ds:Signature/ds:SignedInfo");
//SimpleSAML_Logger::debug
//print ("signedinfo ".$sxe->saveXML());
$signedInfoXML = self::addNamespace($signedInfo, "http://www.w3.org/2000/09/xmldsig#");
SimpleSAML_Logger::debug("canonicalizo ".$signedInfoXML);
$canonical_signedinfo = $transformer->applyTransforms($signedInfoXML);
if (openssl_verify($canonical_signedinfo,$signatureValue,$check_key)) {
list($reference) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference");
openssl_free_key($check_key);
return (string)$reference['URI'];
} else {
openssl_free_key($check_key);
throw new Exception("Could not validate the XML signature");
}
} else {
$sxe->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
list($reference) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference");
return (string)$reference['URI'];
}
return false;
}
private function addNamespace($xmlElem, $ns) {
$schema = '.*<[^<]*SignedInfo[^>]*'.$ns.'.*>.*';
$pattern='/\//';
$replacement='\/';
$nspattern= '/'.preg_replace($pattern,$replacement,$schema).'/';
if (preg_match($nspattern,$xmlElem->asXML())>0){ //M$ Cardspaces
$xml = $xmlElem->asXML();
}
else { //Digitalme
$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:
throw new Exception("Could not encode value");
}
throw new Exception("Invalid code path");
}
}
<?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;
}
}
<?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;
}
}
<?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 ($strXMLData==NULL) SimpleSAML_Logger::debug("NOXML: ".$dom->saveXML());
else SimpleSAML_Logger::debug("XMLcan: ".$dom->saveXML());
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");
throw new Exception('This transform requires the C14N() method to exist in the DOM extension');
}
}
<?php
/*
* COAUTHOR: Samuel Muñoz Hidalgo
* EMAIL: samuel.mh@gmail.com
* LAST REVISION: 13-FEB-09
* DESCRIPTION: Things the STS can do
* - InfoCard issue
* - Error response (if the user send us wrong credentials)
* - Request Security Token Response
*/
class sspmod_InfoCard_STS {
/*
* USED IN: www/getcardform.php
* INPUT: data and configuration
* OUTPUT; a custom error message for the identity selector
*/
static public function createCard($ICdata,$ICconfig) {
$infocardbuf = '<Object Id="IC01" xmlns="http://www.w3.org/2000/09/xmldsig#">';
$infocardbuf .= '<InformationCard xml:lang="en-us" xmlns="http://schemas.xmlsoap.org/ws/2005/05/identity" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex">';
//cardId
$infocardbuf .= '<InformationCardReference>';
$infocardbuf .= '<CardId>'.$ICdata['CardId'].'</CardId>'; //xs:anyURI cardId (="$cardurl/$ppid"; $ppid = "$uname-" . time();)
$infocardbuf .= '<CardVersion>1</CardVersion>'; //xs:unsignedInt
$infocardbuf .= '</InformationCardReference>';
//cardName
$infocardbuf .= '<CardName>'.$ICdata['CardName'].'</CardName>';
//image
$infocardbuf .= '<CardImage MimeType="'.mime_content_type($ICdata['CardImage']).'">';
$infocardbuf .= base64_encode(file_get_contents($ICdata['CardImage']));
$infocardbuf .= '</CardImage>';
//issuer - times
$infocardbuf .= '<Issuer>'.$ICconfig['InfoCard']['issuer'].'</Issuer>';
$infocardbuf .= '<TimeIssued>'.gmdate('Y-m-d').'T'.gmdate('H:i:s').'Z'.'</TimeIssued>';
$infocardbuf .= '<TimeExpires>'.$ICdata['TimeExpires'].'</TimeExpires>';
//Token Service List
$infocardbuf .= '<TokenServiceList>';
$infocardbuf .= '<TokenService>';
$infocardbuf .= '<wsa:EndpointReference>';
$infocardbuf .= '<wsa:Address>'.$ICconfig['tokenserviceurl'].'</wsa:Address>';
$infocardbuf .= '<wsa:Metadata>';
$infocardbuf .= '<wsx:Metadata>';
$infocardbuf .= '<wsx:MetadataSection>';
$infocardbuf .= '<wsx:MetadataReference>';
$infocardbuf .= '<wsa:Address>'.$ICconfig['mexurl'].'</wsa:Address>';
$infocardbuf .= '</wsx:MetadataReference>';
$infocardbuf .= '</wsx:MetadataSection>';
$infocardbuf .= '</wsx:Metadata>';
$infocardbuf .= '</wsa:Metadata>';
$infocardbuf .= '</wsa:EndpointReference>';
/*Types of User Credentials
* Supported: UsernamePasswordCredential, SelfIssuedCredential
* Unsupported: KerberosV5Credential, X509V3Credential
*/
$infocardbuf .= '<UserCredential>';
$infocardbuf .= '<DisplayCredentialHint>'.$ICdata['DisplayCredentialHint'].'</DisplayCredentialHint>';
switch($ICconfig['UserCredential']){
case 'UsernamePasswordCredential':
$infocardbuf .= '<UsernamePasswordCredential>';
$infocardbuf .= '<Username>'.$ICdata['UserName'].'</Username>';
$infocardbuf .= '</UsernamePasswordCredential>';
break;
case 'KerberosV5Credential':
$infocardbuf .= '<KerberosV5Credential/>';
break;
case 'X509V3Credential':
$infocardbuf .= '<X509V3Credential>';
$infocardbuf .= '<ds:X509Data>';
$infocardbuf .= '<wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/2004/xx/oasis-2004xx-wss-soap-message-security-1.1#ThumbprintSHA1" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis200401-wss-soap-message-security-1.0#Base64Binary">';
/*This element provides a key identifier for the X.509 certificate based on the SHA1 hash
of the entire certificate content expressed as a “thumbprint.” Note that the extensibility
point in the ds:X509Data element is used to add wsse:KeyIdentifier as a child
element.*/
$infocardbuf .= $ICdata['KeyIdentifier']; //xs:base64binary;
$infocardbuf .= '</wsse:KeyIdentifier>';
$infocardbuf .= '</ds:X509Data>';
$infocardbuf .= '</X509V3Credential>';
break;
case 'SelfIssuedCredential':
$infocardbuf .= '<SelfIssuedCredential>';
$infocardbuf .= '<PrivatePersonalIdentifier>';
$infocardbuf .= $ICdata['PPID']; //xs:base64binary;
$infocardbuf .= '</PrivatePersonalIdentifier>';
$infocardbuf .= '</SelfIssuedCredential> ';
break;
default:
break;
}
$infocardbuf .= '</UserCredential>';
$infocardbuf .= '</TokenService>';
$infocardbuf .= '</TokenServiceList>';
//Tokentype
$infocardbuf .= '<SupportedTokenTypeList>';
$infocardbuf .= '<wst:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</wst:TokenType>';
$infocardbuf .= '</SupportedTokenTypeList>';
//Claims
$infocardbuf .= '<SupportedClaimTypeList>';
$url = $ICconfig['InfoCard']['schema'].'/claims/';
foreach ($ICconfig['InfoCard']['requiredClaims'] as $claim=>$data) {
$infocardbuf .= '<SupportedClaimType Uri="'.$url.$claim.'">';
$infocardbuf .= '<DisplayTag>'.$data['displayTag'].'</DisplayTag>';
$infocardbuf .= '<Description>'.$data['description'].'</Description>';
$infocardbuf .= '</SupportedClaimType>';
}
foreach ($ICconfig['InfoCard']['optionalClaims'] as $claim=>$data) {
$infocardbuf .= '<SupportedClaimType Uri="'.$url.$claim.'">';
$infocardbuf .= '<DisplayTag>'.$data['displayTag'].'</DisplayTag>';
$infocardbuf .= '<Description>'.$data['description'].'</Description>';
$infocardbuf .= '</SupportedClaimType>';
}
$infocardbuf .= '</SupportedClaimTypeList>';
//Privacy URL
$infocardbuf .= '<PrivacyNotice>'.$ICconfig['InfoCard']['privacyURL'].'</PrivacyNotice>';
$infocardbuf .= '</InformationCard>';
$infocardbuf .= '</Object>';
$canonicalbuf = sspmod_InfoCard_Utils::canonicalize($infocardbuf);
//construct a SignedInfo block
$signedinfo = '<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">';
$signedinfo .= '<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>';
$signedinfo .= '<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>';
$signedinfo .= '<Reference URI="#IC01">';
$signedinfo .= '<Transforms>';
$signedinfo .= '<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>';
$signedinfo .= '</Transforms>';
$signedinfo .= '<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>';
$signedinfo .= '<DigestValue>'.base64_encode(sha1($canonicalbuf, TRUE)).'</DigestValue>';
$signedinfo .= '</Reference>';
$signedinfo .= '</SignedInfo>';
$canonicalbuf = sspmod_InfoCard_Utils::canonicalize($signedinfo);
$signature = '';
$privkey = openssl_pkey_get_private(file_get_contents($ICconfig['sts_key']));
openssl_sign($canonicalbuf, $signature, $privkey);
openssl_free_key($privkey);
$infocard_signature = base64_encode($signature);
//Envelope
$buf = '<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">';
$buf .= $signedinfo;
$buf .= '<SignatureValue>'.$infocard_signature.'</SignatureValue>';
$buf .= '<KeyInfo>';
$buf .= '<X509Data>';
// signing certificate(s)
foreach ($ICconfig['certificates'] as $idx=>$cert)
$buf .= '<X509Certificate>'.sspmod_InfoCard_Utils::takeCert($cert).'</X509Certificate>';
$buf .= '</X509Data>';
$buf .= '</KeyInfo>';
$buf .= $infocardbuf;
$buf .= '</Signature>';
return $buf;
}
/*
* USED IN: www/tokenservice.php
* INPUT: error message, uuid of the RST
* OUTPUT; a custom error message for the identity selector
*/
static public function errorMessage($msg,$relatesto){
$buf = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">';
$buf .= '<s:Header>';
$buf .= '<a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>';
$buf .= '<a:RelatesTo>'.$relatesto.'</a:RelatesTo>';
$buf .= '</s:Header>';
$buf .= '<s:Body>';
$buf .= '<s:Fault>';
$buf .= '<s:Code>';
$buf .= '<s:Value xmlns:a="http://www.w3.org/2003/05/soap-envelope">';
$buf .= 'a:Sender';
$buf .= '</s:Value>';
$buf .= '<s:Subcode>';
$buf .= '<s:Value xmlns:a="http://schemas.xmlsoap.org/ws/2005/05/identity">';
$buf .= 'a:MissingAppliesTo';
$buf .= '</s:Value>';
$buf .= '</s:Subcode>';
$buf .= '</s:Code>';
$buf .= '<s:Reason>';
$buf .= '<s:Text xml:lang="en">';
$buf .= $msg;
$buf .= '</s:Text>';
$buf .= '</s:Reason>';
$buf .= '</s:Fault>';
$buf .= '</s:Body>';
$buf .= '</s:Envelope>';
return $buf;
}
/*
* USED IN: www/tokenservice.php
* INPUT: claims value, configuration, uuid of the RST
* OUTPUT; a security token for the identity selector
*/
static public function createToken($claimValues,$config,$relatesto){
$assertionid = uniqid('uuid-');
$created = gmdate('Y-m-d').'T'.gmdate('H:i:s').'Z';
$expires = gmdate('Y-m-d', time()+3600).'T'.gmdate('H:i:s', time()+3600).'Z';
//SOAP ENVELOPE
$env = '<?xml version="1.0"?>';
$env .= '<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ic="http://schemas.xmlsoap.org/ws/2005/05/identity" xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:xenc="http://www.w3.org/2001/04/xmlenc" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">';
$env .= '<S:Header>';
$env .= '<wsa:Action wsu:Id="_1">';
$env .= 'http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue';
$env .= '</wsa:Action>';
$env .= '<wsa:RelatesTo wsu:Id="_2">';
$env .= $relatesto;
$env .= '</wsa:RelatesTo>';
$env .= '<wsa:To wsu:id="_3">';
$env .= 'http://www.w3.org/2005/08/addressing/anonymous';
$env .= '</wsa:To>';
$env .= '<wsse:Security S:mustUnderstand="1">';
$env .= '<wsu:Timestamp wsu:Id="_6">';
$env .= '<wsu:Created>'.$created.'</wsu:Created>';
$env .= '<wsu:Expires>'.$expires.'</wsu:Expires>';
$env .= '</wsu:Timestamp>';
$env .= '</wsse:Security>';
$env .= '</S:Header>';
$env .= '<S:Body wsu:Id="_10">';
//RequestSecurityTokenResponse
$env .= sspmod_InfoCard_STS::RequestSecurityTokenResponse($claimValues,$config,$assertionid,$created,$expires);
$env .= '</S:Body>';
$env .= '</S:Envelope>';
return $env;
}
/*
* USED IN: createToken
* INPUT: claims value, configuration, uuid, times
* OUTPUT; returns the <wst:RequestSecurityTokenResponse>' of the RSTR
*/
static private function RequestSecurityTokenResponse ($claimValues,$config,$assertionid,$created,$expires){
$tr = '<wst:RequestSecurityTokenResponse>';
$tr .= '<wst:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</wst:TokenType>';
$tr .= '<wst:LifeTime>';
$tr .= '<wsu:Created>'.$created.'</wsu:Created>';
$tr .= '<wsu:Expires>'.$expires.'</wsu:Expires>';
$tr .= '</wst:LifeTime>';
//Encrypted token: SAML assertion
$tr .= '<wst:RequestedSecurityToken>';
$tr .= sspmod_InfoCard_STS::saml_assertion($claimValues,$config,$assertionid,$created,$expires);
$tr .= '</wst:RequestedSecurityToken>';
//RequestedAattachedReference
$tr .= '<wst:RequestedAttachedReference>';
$tr .= '<wsse:SecurityTokenReference>';
$tr .= '<wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">';
$tr .= $assertionid;
$tr .= '</wsse:KeyIdentifier>';
$tr .= '</wsse:SecurityTokenReference>';
$tr .= '</wst:RequestedAttachedReference>';
//RequestedUnattachedReference
$tr .= '<wst:RequestedUnattachedReference>';
$tr .= '<wsse:SecurityTokenReference>';
$tr .= '<wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">';
$tr .= $assertionid;
$tr .= '</wsse:KeyIdentifier>';
$tr .= '</wsse:SecurityTokenReference>';
$tr .= '</wst:RequestedUnattachedReference>';
//RequestedDisplayToken
$tr .= '<ic:RequestedDisplayToken>';
$tr .= '<ic:DisplayToken xml:lang="en-us">';
foreach ($claimValues as $claim=>$data) {
$tr .= '<ic:DisplayClaim Uri="'.$config['InfoCard']['schema'].'/claims/'.$claim.'">';
$tr .= '<ic:DisplayTag>'.$data['displayTag'].'</ic:DisplayTag>';
$tr .= '<ic:DisplayValue>'.$data['value'].'</ic:DisplayValue>';
$tr .= "</ic:DisplayClaim>";
}
$tr .= '</ic:DisplayToken>';
$tr .= '</ic:RequestedDisplayToken>';
$tr .= '</wst:RequestSecurityTokenResponse>';
return $tr;
}
/*
* USED IN: RequestSecurityTokenResponse
* INPUT: claims value, configuration, uuid, times
* OUTPUT; STS Signed SAML assertion
*/
static private function saml_assertion($claimValues,$config,$assertionid,$created,$expires){
$saml = '<saml:Assertion MajorVersion="1" MinorVersion="0" AssertionID="'.$assertionid.'" Issuer="'.$config['issuer'].'" IssueInstant="'.$created.'" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">';
$saml .= '<saml:Conditions NotBefore="'.$created.'" NotOnOrAfter="'.$expires.'" />';
$saml .= '<saml:AttributeStatement>';
$saml .= '<saml:Subject>';
$saml .= '<saml:SubjectConfirmation>';
$saml .= '<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:holder-of-key</saml:ConfirmationMethod>';
// proof key
$saml .= '<dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">';
$saml .= '<dsig:X509Data>';
$saml .= '<dsig:X509Certificate>'.sspmod_InfoCard_Utils::takeCert($config['sts_crt']).'</dsig:X509Certificate>';
$saml .= '</dsig:X509Data>';
$saml .= '</dsig:KeyInfo>';
$saml .= '</saml:SubjectConfirmation>';
$saml .= '</saml:Subject>';
foreach ($claimValues as $claim=>$data) {
$saml .= '<saml:Attribute AttributeName="'.$claim.'" AttributeNamespace="'.$config['InfoCard']['schema'].'/claims">';
$saml .= '<saml:AttributeValue>'.$data['value'].'</saml:AttributeValue>';
$saml .= '</saml:Attribute>';
}
$saml .= '</saml:AttributeStatement>';
//Pure SAML Assertion digest
$canonicalbuf = sspmod_InfoCard_Utils::canonicalize($saml.'</saml:Assertion>');
$myhash = sha1($canonicalbuf,TRUE);
$samldigest = base64_encode($myhash);
//Digest block
$signedinfo = '<dsig:SignedInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" >';
$signedinfo .= '<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />';
$signedinfo .= '<dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />';
$signedinfo .= '<dsig:Reference URI="#'.$assertionid.'">';
$signedinfo .= '<dsig:Transforms>';
$signedinfo .= '<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />';
$signedinfo .= '<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />';
$signedinfo .= '</dsig:Transforms>';
$signedinfo .= '<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />';
$signedinfo .= '<dsig:DigestValue>'.$samldigest.'</dsig:DigestValue>';
$signedinfo .= '</dsig:Reference>';
$signedinfo .= '</dsig:SignedInfo>';
//Signature of the digest
$canonicalbuf = sspmod_InfoCard_Utils::canonicalize($signedinfo);
$privkey = openssl_pkey_get_private(file_get_contents($config['sts_key']));
$signature = '';
openssl_sign($canonicalbuf, $signature, $privkey);
openssl_free_key($privkey);
$samlsignature = base64_encode($signature);
//Signature block
$saml .= '<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">';
$saml .= $signedinfo;
$saml .= '<dsig:SignatureValue>'.$samlsignature.'</dsig:SignatureValue>';
$saml .= '<dsig:KeyInfo>';
$saml .= '<dsig:X509Data>';
$saml .= '<dsig:X509Certificate>'.sspmod_InfoCard_Utils::takeCert($config['sts_crt']).'</dsig:X509Certificate>';
$saml .= '</dsig:X509Data>';
$saml .= '</dsig:KeyInfo>';
$saml .= '</dsig:Signature>';
$saml .= '</saml:Assertion>';
return $saml;
}
}
<?php
/*
* AUTHOR: Samuel Muñoz Hidalgo
* EMAIL: samuel.mh@gmail.com
* LAST REVISION: 13-FEB-09
* DESCRIPTION: Functions for interconecting the system with your data model.
* Edit this functions to fit your needs
*/
class sspmod_InfoCard_UserFunctions {
/* Called by www/getinfocard.php and tokenservice.php
* INPUT: credencial data (array), and type of credential
* OUTPUT: true if the data is correct or false in other case
*/
static public function validateUser($credential,$type){
$status=false;
switch($type){
case 'UsernamePasswordCredential':
if( (strcmp($credential['username'],'usuario')==0) && (strcmp($credential['password'],'clave')==0) )
$status=true;
break;
case 'KerberosV5Credential':
break;
case 'X509V3Credential':
break;
case 'SelfIssuedCredential':
//$credential['PPID']
$status = true;
break;
default:
break;
}
if (!$pass==NULL){ //Username/Password credentials
}else { //PPID credential
}
return $status;
}
/* Called by www/tokenservice.php
* INPUT: username, configured required claims, configured optional claims and requested claims
* OUTPUT: array of claims wiht value and display tag.
*/
static public function fillClaims($user, $configuredRequiredClaims, $configuredOptionalClaims, $requiredClaims){
$claimValues = array();
foreach ($requiredClaims as $claim){
if (array_key_exists($claim,$configuredRequiredClaims) ){
//The claim exists
$claimValues[$claim]['value']="value-".$claim;
$claimValues[$claim]['displayTag']=$configuredRequiredClaims[$claim]['displayTag'];
}else if (array_key_exists($claim,$configuredOptionalClaims) ){
//The claim exists
$claimValues[$claim]['value']="value-".$claim;
$claimValues[$claim]['displayTag']=$configuredOptionalClaims[$claim]['displayTag'];
}else{
//The claim DOES NOT exist
$claimValues[$claim]['value']="unknown-value";
$claimValues[$claim]['displayTag']=$claim;
}
}
return $claimValues;
}
/*
* INPUT: Unified way to create a single card identificator for a user
* OUTPUT: User's card Identificator
*/
static public function generate_card_ID($user) {
return 'urn:self-sts.uah.es:'.$user;
}
/* Called by www/getinfocard.php
* INPUT: valid username
* OUTPUT: array containing user data to create its InfoCard
*/
static public function fillICdata($user,$UserCredential,$ppid=NULL) {
$ICdata = array();
$ICdata['CardId'] = sspmod_InfoCard_UserFunctions::generate_card_ID($user);
$ICdata['CardName'] = $user."-SELFCREDENTIAL-IC";
$ICdata['CardImage'] = '/var/simplesaml/modules/InfoCard/www/resources/demoimage.png';
$ICdata['TimeExpires'] = "9999-12-31T23:59:59Z";
//Credentials
$ICdata['DisplayCredentialHint'] = 'Enter your password';
switch($UserCredential){
case 'UsernamePasswordCredential':
$ICdata['UserName'] = $user;
break;
case 'KerberosV5Credential':
break;
case 'X509V3Credential':
$ICdata['KeyIdentifier'] = NULL; //X509V3Credential
break;
case 'SelfIssuedCredential':
$ICdata['PPID'] = $ppid;
break;
default:
break;
}
return $ICdata;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment