From 1fed9ea77ad8942041a87c62c7a601dd51463dde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20=C3=85kre=20Solberg?= <andreas.solberg@uninett.no>
Date: Fri, 14 Sep 2007 11:20:59 +0000
Subject: [PATCH] Initial commit of version 0.4 of simplesamlphp

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2 44740490-163a-0410-bde0-09ae8108e29a
---
 COPYING                                       |   22 +
 cert/server.crt                               |   16 +
 cert/server.pem                               |   15 +
 config/config-template.php                    |   48 +
 docs/README                                   |   29 +
 docs/simplesamlphp-install.html               |  182 +++
 docs/simplesamlphp-install.pdf                |  Bin 0 -> 43359 bytes
 docs/source/simplesamlphp-install.xml         |  588 +++++++
 lib/SimpleSAML/Bindings/SAML20/HTTPPost.php   |  213 +++
 .../Bindings/SAML20/HTTPRedirect.php          |  125 ++
 lib/SimpleSAML/Bindings/Shib13/HTTPPost.php   |  198 +++
 lib/SimpleSAML/Configuration.php              |   53 +
 lib/SimpleSAML/Session.php                    |  223 +++
 lib/SimpleSAML/Utilities.php                  |   92 ++
 lib/SimpleSAML/XHTML/Template.php             |   45 +
 lib/SimpleSAML/XML/AuthnResponse.php          |  115 ++
 lib/SimpleSAML/XML/MetaDataStore.php          |  105 ++
 lib/SimpleSAML/XML/SAML20/AuthnRequest.php    |  195 +++
 lib/SimpleSAML/XML/SAML20/AuthnResponse.php   |  528 +++++++
 lib/SimpleSAML/XML/SAML20/LogoutRequest.php   |  182 +++
 lib/SimpleSAML/XML/SAML20/LogoutResponse.php  |  152 ++
 lib/SimpleSAML/XML/Shib13/AuthnRequest.php    |  114 ++
 lib/SimpleSAML/XML/Shib13/AuthnResponse.php   |  398 +++++
 lib/xmlseclibs.php                            | 1387 +++++++++++++++++
 metadata-templates/saml20-idp-hosted.php      |   37 +
 metadata-templates/saml20-idp-remote.php      |   41 +
 metadata-templates/saml20-sp-hosted.php       |   37 +
 metadata-templates/saml20-sp-remote.php       |   84 +
 metadata-templates/shib13-idp-hosted.php      |   16 +
 metadata-templates/shib13-idp-remote.php      |   29 +
 metadata-templates/shib13-sp-hosted.php       |   35 +
 metadata-templates/shib13-sp-remote.php       |   32 +
 templates/error.php                           |   97 ++
 templates/login.php                           |  124 ++
 templates/post-debug.php                      |   91 ++
 templates/post.php                            |   24 +
 templates/status.php                          |  111 ++
 www/_include.php                              |   18 +
 www/auth/login-auto.php                       |   95 ++
 www/auth/login-radius.php                     |   95 ++
 www/auth/login.php                            |   98 ++
 www/example-simple/saml2-example.php          |   52 +
 www/example-simple/shib13-example.php         |   35 +
 www/index.html                                |   88 ++
 www/resources/icons/bino.png                  |  Bin 0 -> 15118 bytes
 www/resources/icons/bomb.png                  |  Bin 0 -> 3439 bytes
 www/resources/icons/bomb_l.png                |  Bin 0 -> 8960 bytes
 www/resources/icons/compass_l.png             |  Bin 0 -> 17694 bytes
 www/resources/icons/debug.png                 |  Bin 0 -> 10724 bytes
 www/resources/icons/lock.png                  |  Bin 0 -> 14639 bytes
 www/resources/icons/pencil.png                |  Bin 0 -> 3004 bytes
 www/resources/sprites.gif                     |  Bin 0 -> 12536 bytes
 www/saml2/idp/SSOService.php                  |  140 ++
 www/saml2/idp/SingleLogoutService.php         |  146 ++
 www/saml2/sp/AssertionConsumerService.php     |   52 +
 www/saml2/sp/SingleLogoutService.php          |   78 +
 www/saml2/sp/initSLO.php                      |   66 +
 www/saml2/sp/initSSO.php                      |   97 ++
 www/shib13/sp/AssertionConsumerService.php    |   69 +
 www/shib13/sp/initSSO.php                     |   99 ++
 60 files changed, 7011 insertions(+)
 create mode 100644 COPYING
 create mode 100755 cert/server.crt
 create mode 100755 cert/server.pem
 create mode 100644 config/config-template.php
 create mode 100644 docs/README
 create mode 100644 docs/simplesamlphp-install.html
 create mode 100644 docs/simplesamlphp-install.pdf
 create mode 100644 docs/source/simplesamlphp-install.xml
 create mode 100644 lib/SimpleSAML/Bindings/SAML20/HTTPPost.php
 create mode 100644 lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php
 create mode 100644 lib/SimpleSAML/Bindings/Shib13/HTTPPost.php
 create mode 100644 lib/SimpleSAML/Configuration.php
 create mode 100644 lib/SimpleSAML/Session.php
 create mode 100644 lib/SimpleSAML/Utilities.php
 create mode 100644 lib/SimpleSAML/XHTML/Template.php
 create mode 100644 lib/SimpleSAML/XML/AuthnResponse.php
 create mode 100644 lib/SimpleSAML/XML/MetaDataStore.php
 create mode 100644 lib/SimpleSAML/XML/SAML20/AuthnRequest.php
 create mode 100644 lib/SimpleSAML/XML/SAML20/AuthnResponse.php
 create mode 100644 lib/SimpleSAML/XML/SAML20/LogoutRequest.php
 create mode 100644 lib/SimpleSAML/XML/SAML20/LogoutResponse.php
 create mode 100644 lib/SimpleSAML/XML/Shib13/AuthnRequest.php
 create mode 100644 lib/SimpleSAML/XML/Shib13/AuthnResponse.php
 create mode 100644 lib/xmlseclibs.php
 create mode 100644 metadata-templates/saml20-idp-hosted.php
 create mode 100644 metadata-templates/saml20-idp-remote.php
 create mode 100644 metadata-templates/saml20-sp-hosted.php
 create mode 100644 metadata-templates/saml20-sp-remote.php
 create mode 100644 metadata-templates/shib13-idp-hosted.php
 create mode 100644 metadata-templates/shib13-idp-remote.php
 create mode 100644 metadata-templates/shib13-sp-hosted.php
 create mode 100644 metadata-templates/shib13-sp-remote.php
 create mode 100644 templates/error.php
 create mode 100644 templates/login.php
 create mode 100644 templates/post-debug.php
 create mode 100644 templates/post.php
 create mode 100644 templates/status.php
 create mode 100644 www/_include.php
 create mode 100644 www/auth/login-auto.php
 create mode 100644 www/auth/login-radius.php
 create mode 100644 www/auth/login.php
 create mode 100644 www/example-simple/saml2-example.php
 create mode 100644 www/example-simple/shib13-example.php
 create mode 100644 www/index.html
 create mode 100644 www/resources/icons/bino.png
 create mode 100644 www/resources/icons/bomb.png
 create mode 100644 www/resources/icons/bomb_l.png
 create mode 100644 www/resources/icons/compass_l.png
 create mode 100644 www/resources/icons/debug.png
 create mode 100644 www/resources/icons/lock.png
 create mode 100644 www/resources/icons/pencil.png
 create mode 100644 www/resources/sprites.gif
 create mode 100644 www/saml2/idp/SSOService.php
 create mode 100644 www/saml2/idp/SingleLogoutService.php
 create mode 100644 www/saml2/sp/AssertionConsumerService.php
 create mode 100644 www/saml2/sp/SingleLogoutService.php
 create mode 100644 www/saml2/sp/initSLO.php
 create mode 100644 www/saml2/sp/initSSO.php
 create mode 100644 www/shib13/sp/AssertionConsumerService.php
 create mode 100644 www/shib13/sp/initSSO.php

diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000..7cd1553ad
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+simpleSAMLphp is based on code from Sun OpenSSO Extensions (formerly known as Lightbulb).
+The initial versions of the SAML 2.0 part was written by Pat Patterson, Sun.
+
+The functionality have been extended and Andreas Ă…kre Solberg, UNINETT, has rewritten the
+library and added support for Shibboleth IdP/SP, and SAML 2.0 IdP. The product is used to 
+bridge AAI protocols in the GÉANT project, http://geant2.net
+
+----
+simpleSAMLphp is subject to the terms
+of the Common Development and Distribution License
+(the License). You may not use this file except in
+compliance with the License.
+
+You can obtain a copy of the License at
+https://opensso.dev.java.net/public/CDDLv1.0.html or
+opensso/legal/CDDLv1.0.txt
+See the License for the specific language governing
+permission and limitations under the License.
+
+When distributing Covered Code, include this CDDL
+Header Notice in each file and include the License file
+at opensso/legal/CDDLv1.0.txt.
diff --git a/cert/server.crt b/cert/server.crt
new file mode 100755
index 000000000..b4147e516
--- /dev/null
+++ b/cert/server.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMC
+Tk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYD
+VQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG
+9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4
+MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xi
+ZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2Zl
+aWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5v
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LO
+NoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHIS
+KOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d
+1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8
+BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7n
+bK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2Qar
+Q4/67OZfHd7R+POBXhophSMv1ZOo
+-----END CERTIFICATE-----
diff --git a/cert/server.pem b/cert/server.pem
new file mode 100755
index 000000000..673196b17
--- /dev/null
+++ b/cert/server.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9
+IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+
+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQAB
+AoGAD4/Z4LWVWV6D1qMIp1Gzr0ZmdWTE1SPdZ7Ej8glGnCzPdguCPuzbhGXmIg0V
+J5D+02wsqws1zd48JSMXXM8zkYZVwQYIPUsNn5FetQpwxDIMPmhHg+QNBgwOnk8J
+K2sIjjLPL7qY7Itv7LT7Gvm5qSOkZ33RCgXcgz+okEIQMYkCQQDzbTOyDL0c5WQV
+6A2k06T/azdhUdGXF9C0+WkWSfNaovmTgRXh1G+jMlr82Snz4p4/STt7P/XtyWzF
+3pkVgZr3AkEA7nPjXwHlttNEMo6AtxHd47nizK2NUN803ElIUT8P9KSCoERmSXq6
+6PDekGNic4ldpsSvOeYCk8MAYoDBy9kvVwJBAMLgX4xg6lzhv7hR5+pWjTb1rIY6
+rCHbrPfU264+UZXz9v2BT/VUznLF81WMvStD9xAPHpFS6R0OLghSZhdzhI0CQQDL
+8Duvfxzrn4b9QlmduV8wLERoT6rEVxKLsPVz316TGrxJvBZLk/cV0SRZE1cZf4uk
+XSWMfEcJ/0Zt+LdG1CqjAkEAqwLSglJ9Dy3HpgMz4vAAyZWzAxvyA1zW0no9GOLc
+PQnYaNUN/Fy2SYtETXTb0CQ9X1rt8ffkFP7ya+5TC83aMg==
+-----END RSA PRIVATE KEY-----
diff --git a/config/config-template.php b/config/config-template.php
new file mode 100644
index 000000000..49833941a
--- /dev/null
+++ b/config/config-template.php
@@ -0,0 +1,48 @@
+<?php
+/* 
+ * The configuration of simpleSAMLphp
+ * 
+ * 
+ */
+
+$config = array (
+
+	/*
+	 * Setup the following parameters to match the directory of your installation.
+	 * See the user manual for more details.
+	 */
+	'basedir' 				=> '/var/www/simplesamlphp/',
+	'baseurlpath'			=> 'simplesamlphp/',
+	'templatedir'			=> '/var/www/simplesamlphp/templates',
+	'metadatadir'			=> '/var/www/simplesamlphp/metadata',
+	
+	/*
+	 * If you set the debug parameter to true, all SAML messages will be visible in the
+	 * browser, and require the user to click the submit button. If debug is set to false,
+	 * Browser/POST SAML messages will be automaticly submitted.
+	 */
+	'debug'					=>	false,
+	
+	/* 
+	 * This value is the duration of the session in seconds. Make sure that the time duration of
+	 * cookies both at the SP and the IdP exceeds this duration.
+	 */
+	'session.duration'		=>  8 * (60*60), // 8 hours.
+	
+	/*
+	 * Default IdPs. If you do not enter an idpentityid in the SSO initialization endpoints,
+	 * the default IdP configured here will be used.
+	 */
+	'default-saml20-idp'	=> 'sam.feide.no',
+	'default-shib13-idp'	=> 'urn:mace:switch.ch:aaitest:dukono.switch.ch',
+	
+	/*
+	 * LDAP configuration. This is only relevant if you use the LDAP authentication plugin.
+	 */
+	'auth.ldap.dnpattern'	=> 'uid=%username%,dc=feide,dc=no,ou=feide,dc=uninett,dc=no',
+	'auth.ldap.hostname'	=> 'ldap.uninett.no',
+	'auth.ldap.attributes'	=> 'objectclass=*'
+);
+
+
+?>
\ No newline at end of file
diff --git a/docs/README b/docs/README
new file mode 100644
index 000000000..5c9503318
--- /dev/null
+++ b/docs/README
@@ -0,0 +1,29 @@
+README
+
+
+Installation instructions:
+==========================
+
+Store the simplesamlphp directory somewhere...
+
+In there there is a www directory, it have to be accessible from web, on the root of a vhost. The www can be moved outside the simplesamlphp folder. You can in example drop the content of the www folder into your existing web site folder.
+
+IF you decide to move the www folder out of the simplesamlphp folder, then you need to update the www/_include.php file properly.
+
+Next, configure config.php:
+- set the path and hostnames.
+- Use sam.feide.no as default idp.
+- Set the default duration of a session to be in example 3 hours.
+
+
+Then, configure saml20-sp-hosted to match your SP metadata. Change dev.andreas.feide.no to your hostname. Contact feide to ensure that your meta data is added to the Feide IdP.
+
+Then configure the saml20-idp-remote to match Feide. If there exists an entry for sam.feide.no it is probably already there.
+
+Then test the /example-simple/saml2-example.php log in with the feide test user, and look at the attributes. then test sp initated logout.
+
+Look at the example code of how to integrate with a service.
+
+Contact Andreas for questions:
+andreas@uninett.no
+
diff --git a/docs/simplesamlphp-install.html b/docs/simplesamlphp-install.html
new file mode 100644
index 000000000..3c13eb2c8
--- /dev/null
+++ b/docs/simplesamlphp-install.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>simpleSAMLphp Installation and Configuration</title><link rel="stylesheet" href="html.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.69.1" /></head><body><div class="article" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="id721994"></a>simpleSAMLphp Installation and Configuration</h2></div><div><div class="author"><h3 class="author"><span class="firstname">Andreas Ă…kre</span> <span class="surname">Solberg</span></h3><code class="email">&lt;<a href="mailto:andreas.solberg@uninett.no">andreas.solberg@uninett.no</a>&gt;</code></div></div><div><p class="pubdate">Fri Sep 14 10:49:49 2007</p></div></div><hr /></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id856632">The history of simpleSAMLphp</a></span></dt><dt><span class="section"><a href="#id856682">Changelog</a></span></dt><dd><dl><dt><span class="section"><a href="#id856693">Version 0.4</a></span></dt></dl></dd><dt><span class="section"><a href="#id856807">Download and get simpleSAMLphp</a></span></dt><dd><dl><dt><span class="section"><a href="#id856826">Getting a working copy of simpleSAMLphp from subversion</a></span></dt></dl></dd><dt><span class="section"><a href="#id856866">Installing simpleSAMLphp</a></span></dt><dd><dl><dt><span class="section"><a href="#id856941">The simpleSAMLphp installation webpage</a></span></dt></dl></dd><dt><span class="section"><a href="#id856967">Making configuration and metadata files</a></span></dt><dt><span class="section"><a href="#sect.config">Configuring simpleSAMLphp</a></span></dt><dd><dl><dt><span class="section"><a href="#id857037">Configuration for LDAP authentication plugin</a></span></dt></dl></dd><dt><span class="section"><a href="#id857095">Setting up a SAML 2.0 SP</a></span></dt><dd><dl><dt><span class="section"><a href="#id857107">Configuring metadata for a SAML 2.0 SP</a></span></dt><dt><span class="section"><a href="#id857190">Test the SAML 2.0 SP example</a></span></dt></dl></dd><dt><span class="section"><a href="#id857224">Setting up a Shibboleth 1.3 SP</a></span></dt><dd><dl><dt><span class="section"><a href="#id857235">Configuring metadata for Shibboleth 1.3 SP</a></span></dt><dt><span class="section"><a href="#id857296">Test the Shibboleth 1.3 SP example</a></span></dt></dl></dd><dt><span class="section"><a href="#id857331">Setting up a SAML 2.0 IdP</a></span></dt><dd><dl><dt><span class="section"><a href="#id857342">Configuring the SAML 2.0 IdP</a></span></dt><dt><span class="section"><a href="#id857376">Adding a SAML IdP signing certificate</a></span></dt><dt><span class="section"><a href="#id857440">Test SAML 2.0 IdP</a></span></dt></dl></dd><dt><span class="section"><a href="#id857453">Using the built-in SP WAYF functionality</a></span></dt><dt><span class="section"><a href="#id857466">Setting up WebSSO bridges</a></span></dt><dd><dl><dt><span class="section"><a href="#id857477">Bridging SAML 2.0 &lt;-&gt; SAML 2.0</a></span></dt><dt><span class="section"><a href="#id857522">Bridging Shibboleth 1.3 &lt;-&gt; Shibboleth 1.3</a></span></dt><dt><span class="section"><a href="#id857533">Bridging Shibboleth 1.3 &lt;-&gt; SAML 2.0</a></span></dt><dt><span class="section"><a href="#id857544">Bridging SAML 2.0 &lt;-&gt; Shibboleth 1.3</a></span></dt><dt><span class="section"><a href="#id857554">Bridging SAML 2.0 &lt;-&gt; OpenID</a></span></dt><dt><span class="section"><a href="#id857564">Bridging Shibboelth 1.3 &lt;-&gt; OpenID</a></span></dt></dl></dd><dt><span class="section"><a href="#id857576">Authentication API</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id856632"></a>The history of simpleSAMLphp</h2></div></div></div><p>simpleSAMLphp is based on code from <a href="https://opensso.dev.java.net/public/extensions/" target="_top">Sun OpenSSO
+    Extensions</a> (formerly known as Lightbulb).</p><p>The initial versions of the SAML 2.0 SP part was written by <a href="http://blogs.sun.com/superpat/" target="_top">Pat Patterson, Sun</a>.</p><p>The functionality has been extended and <a href="http://claimid.com/erlang" target="_top">Andreas Ă…kre Solberg</a>, <a href="http://uninett.no" target="_top">UNINETT</a>, has rewritten the library and
+    added support for Shibboleth. The product is used to bridge AAI protocols
+    in the GÉANT project, <a href="http://geant2.net" target="_top">http://geant2.net</a>.</p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id856682"></a>Changelog</h2></div></div></div><p>Here is changes between simpleSAML versions. Look here if you are
+    upgrading, to see if there are any changes to the config format.</p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id856693"></a>Version 0.4</h3></div></div></div><p>Released 2007-09-14. Revision X.</p><div class="itemizedlist"><ul type="disc"><li><p>Improved documentation</p></li><li><p>Authentication plugin API. Only LDAP authenticaiton plugin is
+          included, but it is now easier to implement your own plugin.</p></li><li><p>Added support for SAML 2.0 IdP to work with Google Apps for
+          Education. Tested.</p></li><li><p>Initial implementation of SAML 2.0 Single Log-Out
+          functionality both for SP and IdP. Seems to work, but not yet
+          well-tested.</p></li><li><p>Added support for bridging SAML 2.0 to SAML 2.0.</p></li><li><p>Added some time skew offset to the NotBefore timestamp on the
+          assertion, to allow some time skew between the SP and IdP.</p></li><li><p>Fixed Browser/POST page to automaticly submit, and have fall
+          back functionality for user agents with no javascript
+          support.</p></li><li><p>Fixed some bug with warning traversing Shibboleth 1.3
+          Assertions.</p></li><li><p>Fixed tabindex on the login page of the LDAP authentication
+          module to allow you to tab from username, to password and then to
+          submit.</p></li><li><p>Fixed bug on autodiscovering hostname in multihost
+          environments.</p></li><li><p>Cleaned out some debug messages, and added a debug option in
+          the configuration file. This debug option let's you turn on the
+          possibility of showing all SAML messages to users in the web
+          browser, and manually submit them.</p></li><li><p>Several minor bugfixes.</p></li></ul></div></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id856807"></a>Download and get simpleSAMLphp</h2></div></div></div><p>You can go to <a href="http://rnd.feide.no/category/simplesamlphp/" target="_top">http://rnd.feide.no/category/simplesamlphp/</a>
+    to find the most recent release of simpleSAMLphp. Download the zipped
+    file, and unzip it on your webserver. However I hightly reccomend running
+    from a subversion checkout instead.</p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id856826"></a>Getting a working copy of simpleSAMLphp from subversion</h3></div></div></div><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Warning</h3><p>Right now the subversion repository is requiring a username /
+        password. I'll update the access control, so that everyone can get
+        read access without authentication. I'll announce it on the rnd blog
+        when it is ready.</p></div><p>If you want a working copy from subversion enter:</p><pre class="screen">svn co https://svn.uninett.no/svn/feidernd/simplesamlphp</pre><p>If you know subversion you know how to view logs and review
+      changes to the files. To update the version you have checked out,
+      enter:</p><pre class="screen">cd simplesamlphp
+svn up</pre></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id856866"></a>Installing simpleSAMLphp</h2></div></div></div><p>First find an appropriate place for the <code class="filename">simplesamlphp
+    </code>folder. In example
+    <code class="filename">/var/simplesamlphp</code>.</p><p>Of the folders inside simplesamlphp, only the www folder needs to be
+    accessible from the web. There are several ways of putting the
+    simpleSAMLphp depending on the way web sites are structured on your apache
+    web server. Here is what I believe is the best configuration.</p><p>Find the apache configuration file for the virtual hosts that you
+    want to run simpleSAML on. The configuration may look like this:</p><pre class="programlisting">&lt;VirtualHost  *&gt;
+        ServerName service.example.com
+        DocumentRoot /var/www/service.example.com
+
+        Alias /simplesamlphp /var/simplesamlphp/www
+&lt;/VirtualHost&gt;
+</pre><p>What is special is tha Alias directive. That directive will give
+    control to simplesamlphp to all urls that matches
+    <code class="literal">http(s)://service.example.com/simplesamlphp/*</code>.
+    SimpleSAML will need to have several SAML interfaces available on the web,
+    and all these interfaces are included in the www subdirectory of your
+    simplesamlphp installation. You can set the alias to whatever you want,
+    but this alias must be set in the config.php file of simpleSAML as
+    described in <a href="#sect.config" title="Configuring simpleSAMLphp">the section called “Configuring simpleSAMLphp”</a>. Here is an example of how
+    this configuration may look like in config.php:</p><pre class="programlisting">$config = array (
+	'basedir' 				=&gt; '/var/simplesamlphp/',
+	'baseurl'				=&gt; 'http://service.example.com',
+	'baseurlpath'			=&gt; 'simplesamlphp/',</pre><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id856941"></a>The simpleSAMLphp installation webpage</h3></div></div></div><p>When you have installed simpleSAMLphp, you can access the homepage
+      of your installation, which contains some information and a few links to
+      the test services. The url of an installation can be in example:</p><div class="literallayout"><p>https://service.example.com/simplesamlphp/</p></div><p>But it depends on how you set it up with apache.</p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id856967"></a>Making configuration and metadata files</h2></div></div></div><p>Configuration and metadata files are stored in a template format,
+    you need to copy them to have your local copies. The reason why it is done
+    this way, is that when you upgrade you can do svn up in subversion or just
+    copy the whole directory over your installation, without replacing your
+    existing configuration. When you are updating, you should investigate
+    whether the config format is changed, this should be documented in the
+    changelog.</p><p>Here are the steps you need to do to create local configuration
+    files:</p><pre class="screen">cd /var/simplesamlphp
+cp config/config-template.php config/config.php
+cp -r metadata-templates/*.php metadata/
+</pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="sect.config"></a>Configuring simpleSAMLphp</h2></div></div></div><p>First configure all the paths in the beginning of the config file,
+    to correspond to your organization of the apache web server, and where you
+    place simpleSAMLphp.</p><p>You will need to set the entityid of a default IdP in
+    <code class="literal">default-saml20-idp</code> or
+    <code class="literal">default-shib13-idp</code> depending on whether you use
+    shibboleth or SAML 2.0.</p><p>There is one parameter debug that may be set to true or false. If
+    you set it to true, then all Browser/POST SAML messages will be printed to
+    the web browser, and the user will have to manually submit it. </p><p>The session.duration parameter says how many seconds that a session
+    should be valid. After this amont of time, the session is not valid
+    anymore.</p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857037"></a>Configuration for LDAP authentication plugin</h3></div></div></div><p>If you want to perform local authentication on this server, and
+      you want to use the LDAP authenticaiton plugin, then you need to
+      configure the following parameters:</p><div class="itemizedlist"><ul type="disc"><li><p><code class="literal">auth.ldap.dnpattern</code>: What DN should you
+          bind to? Replacing %username% with the username the user types
+          in.</p></li><li><p><code class="literal">auth.ldap.hostname</code>: The hostname of the
+          LDAP server</p></li><li><p><code class="literal">auth.ldap.attributes</code>: Search parameter to
+          LDAP. What attributes should be extracted?
+          <code class="literal">objectclass=*</code> gives you all.</p></li></ul></div></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id857095"></a>Setting up a SAML 2.0 SP</h2></div></div></div><p>This functionality is relevant if you want to integrate SAML 2.0
+    authentication on a service of yours, and you know one or more IdPs that
+    you can connect to. You would need metadata for those IdPs.</p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857107"></a>Configuring metadata for a SAML 2.0 SP</h3></div></div></div><p>To configure a SAML 2.0 SP, you first need to configure the SP
+      data for all your vhosts. If you run only one host, you need only one
+      entry. This metadata is stored in the
+      <code class="filename">metadata/saml20-sp-hosted.php</code> file. Here is an
+      example of a metadata:</p><pre class="programlisting">	"dev.andreas.feide.no" =&gt; array(
+		'host'							=&gt;	'dev.andreas.feide.no',
+ 		"assertionConsumerServiceURL"	=&gt;	"http://dev.andreas.feide.no/saml2/sp/AssertionConsumerService.php", 
+		"issuer"						=&gt;	"dev.andreas.feide.no",
+		"spNameQualifier" 				=&gt;	"dev.andreas.feide.no",
+		"ForceAuthn"					=&gt;	"false",
+		"NameIDFormat"					=&gt;	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+	),</pre><p>Note that you should fill in the host field matching the hostname
+      of your vhost. That way simpleSAMLphp can automatically detect what SP
+      metadata to use based on the <code class="literal">Host:</code> header sent by the
+      HTTP user agent.</p><p>You also need to configure the metadata for the IdP that you want
+      to use. Here is a metadata example for the Feide IdP:</p><pre class="programlisting">	"sam.feide.no" =&gt;  array( 
+			"SingleSignOnUrl"	=&gt;	"https://sam.feide.no/amserver/SSORedirect/metaAlias/idp",
+		 	"SingleLogOutUrl"	=&gt;	"https://sam.feide.no/amserver/IDPSloRedirect/metaAlias/idp",
+		 	"certFingerprint"	=&gt;	"3a:e7:d3:d3:06:ba:57:fd:7f:62:6a:4b:a8:64:b3:4a:53:d9:5d:d0",
+		 	"base64attributes"	=&gt;	true),</pre><p>The IdP metadata is stored in the
+      <code class="filename">metadata/saml20-idp-remote.php</code> file. Configure the
+      correct URLs of the endpoints, the hash of the certificate, and whether
+      the IdP is base64 encoding attributes or not. Most IdPs don't use
+      base64, so if you do not connect to Feide you should turn this parameter
+      to <code class="literal">false</code>. Notice that the key of the array is the
+      entity id of the IdP, in this example:
+      <code class="literal">sam.feide.no</code>.</p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857190"></a>Test the SAML 2.0 SP example</h3></div></div></div><p>Go to the URL of the test page, similar to:</p><div class="literallayout"><p>http://service.example.com/simplesamlphp/example-simple/saml2-example.php</p></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The simpleSAMLphp installation homepage will link you to this
+        example, so you do not need to type in the full url.</p></div><p>You should be redirected to the IdP. Login, and you should be sent
+      back and shown all the attributes sent form the IdP.</p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id857224"></a>Setting up a Shibboleth 1.3 SP</h2></div></div></div><p>If you want to configure a service with authentication towards an
+    external Shibboleth 1.3 IdP, this section describes you how to proceed.
+    </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857235"></a>Configuring metadata for Shibboleth 1.3 SP</h3></div></div></div><p>Configure Shibboleth 1.3 SP metadata for all your vhosts. If you
+      run only one host, you need only one entry. This metadata is stored in
+      the <code class="filename">metadata/shib13-sp-hosted.php</code> file. Here is an
+      example:</p><pre class="programlisting">	'http://dev.andreas.feide.no'	=&gt; array(
+		'AssertionConsumerService'	=&gt;	'http://dev.andreas.feide.no/shib13/sp/AssertionConsumerService.php',
+		'host'						=&gt;	'dev.andreas.feide.no'
+	),</pre><p>Note that you should fill in the host field matching the hostname
+      of your vhost. That way simpleSAMLphp can automatically detect what SP
+      metadata to use based on the <code class="literal">Host:</code> header sent by the
+      HTTP user agent.</p><p>You also need to configure the metadata for the Shibboleth 1.3
+      IdPs that you want to connect to. Here is an example:</p><pre class="programlisting">	'urn:mace:switch.ch:aaitest:dukono.switch.ch'	=&gt; array(
+		'SingleSignOnUrl'		=&gt;	'https://dukono.switch.ch/shibboleth-idp/SSO',
+		'certFingerprint'		=&gt;	'c7279a9f28f11380509e075441e3dc55fb9ab864' 
+	),</pre><p>Notice that the key of the array is the entity ID.</p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857296"></a>Test the Shibboleth 1.3 SP example</h3></div></div></div><p>Go to the URL of the shibboleth test page, similar to:</p><div class="literallayout"><p>http://service.example.com/example-simple/shib13-example.php</p></div><p>You should be redirected to the IdP. Login, and you should be sent
+      back and shown all the attributes sent form the IdP.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>simpleSAMLphp does not support the attribute profile that
+        Shibboleth is using by default. To make attributes work, you need to
+        configure the IdP to perform attribute push.</p></div></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id857331"></a>Setting up a SAML 2.0 IdP</h2></div></div></div><p>If you have a user database and want to offer a SAML 2.0 IdP
+    functinoality towards external services, here is how you set it up.</p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857342"></a>Configuring the SAML 2.0 IdP</h3></div></div></div><p>Setup idp metadata in saml20-idp-hosted. Then for all the SP the
+      IdP shold trust in saml20-sp-remote. Then configure in config.php, ldap
+      DN patterns, ldap host etc. Next add a certificate with openssl.</p><p>Example config.php:</p><pre class="programlisting">	'auth.ldap.dnpattern'	=&gt; 'uid=%username%,dc=feide,dc=no,ou=feide,dc=uninett,dc=no',
+	'auth.ldap.hostname'	=&gt; 'ldap.uninett.no',
+	'auth.ldap.attributes'	=&gt; 'objectclass=*'</pre><p>Example IdP Metadata saml20-idp-hosted:</p><pre class="programlisting">	'dev2.andreas.feide.no' =&gt; array(
+		'host'				=&gt;	'dev2.andreas.feide.no',
+		'SingleSignOnUrl'	=&gt;	"http://dev2.andreas.feide.no/saml2/idp/SSOService.php",
+		'SingleLogOutUrl'	=&gt;	"http://dev2.andreas.feide.no/saml2/idp/LogoutService.php",
+		'privatekey'		=&gt;	'server.pem',
+		'certificate'		=&gt;	'server.crt',
+		'base64attributes'	=&gt;	true,
+		'auth'				=&gt;	'auth/login.php'
+	)</pre><p>The server.pem and server.crt is an example certificate shipped
+      with the package, and be used for demo purposes, but you must generate
+      your own to use in production services.</p><p>You also need to configure metadata for trusted SPs, here is an
+      example:</p><pre class="programlisting">_	"dev.andreas.feide.no" =&gt; array(
+		'host'							=&gt;	'dev.andreas.feide.no',
+ 		"assertionConsumerServiceURL"	=&gt;	"http://dev.andreas.feide.no/saml2/sp/AssertionConsumerService.php", 
+		"issuer"						=&gt;	"dev.andreas.feide.no",
+		"spNameQualifier" 				=&gt;	"dev.andreas.feide.no",
+		"ForceAuthn"					=&gt;	"false",
+		"NameIDFormat"					=&gt;	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+	),</pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857376"></a>Adding a SAML IdP signing certificate</h3></div></div></div><p>You should generate a new certificate for your IdP.</p><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Warning</h3><p>There is a certificate that follows this package that you can
+        use for test purposes, but off course NEVER use this in production as
+        the private key is also included in the package and can be downloaded
+        by anyone.</p></div><p>Here is an examples of openssl commands to generate a new key and
+      a selfsigned certificate to use for signing SAML messages:</p><pre class="screen">openssl genrsa -des3 -out server2.key 1024 
+openssl rsa -in server2.key -out server2.pem
+openssl req -new -key server.key -out server2.csr
+openssl x509 -req -days 60 -in server2.csr -signkey server2.key -out server2.crt</pre><p>The certificate above will be valid for 60 days.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>simpleSAMLphp will only work with RSA and not DSA
+        certificates.</p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857440"></a>Test SAML 2.0 IdP</h3></div></div></div><p>To test the SAML 2.0 IdP, it is best to configure two hosts with
+      simpleSAMLphp, and use the SAML 2.0 SP demo example to test the
+      IdP.</p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id857453"></a>Using the built-in SP WAYF functionality</h2></div></div></div><p>The WAYF is not yet a part of the simpleSAMLphp release. This
+    functionality will be added soon.</p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id857466"></a>Setting up WebSSO bridges</h2></div></div></div><p>simpleSAMLphp can be used to bridge between two WebSSO protocols.
+    Here is some short descriptions of how to setup the different bridge
+    configurations.</p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857477"></a>Bridging SAML 2.0 &lt;-&gt; SAML 2.0</h3></div></div></div><p>In this setup you can bridge between two federations using SAML
+      2.0.</p><p>To approach this, you must configure both saml 2.0 IdP and SP
+      hosted metadata, and in the IdP hosted metadata configure the auth
+      parameter to be the SP initialization endpoint, like this:</p><pre class="screen">		'auth'				=&gt;	'saml2/sp/initSSO.php?idpentityid=sam.feide.no'</pre><p>As you can see you specify the IdP in the remote federation as a
+      parameter to the initalization endpoint.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>This section of the documentation is only a placeholder. There
+        will be more detailed information added later. For now, ask the author
+        if you want more details of such a setup.</p><p>Briding SAML 2.0 SLO is not implemented. Will be improved
+        soon.</p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857522"></a>Bridging Shibboleth 1.3 &lt;-&gt; Shibboleth 1.3</h3></div></div></div><p>Will be supported soon.</p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857533"></a>Bridging Shibboleth 1.3 &lt;-&gt; SAML 2.0</h3></div></div></div><p>Will be supported soon.</p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857544"></a>Bridging SAML 2.0 &lt;-&gt; Shibboleth 1.3</h3></div></div></div><p>Will be supported soon.</p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857554"></a>Bridging SAML 2.0 &lt;-&gt; OpenID</h3></div></div></div><p>Will be supported soon.</p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id857564"></a>Bridging Shibboelth 1.3 &lt;-&gt; OpenID</h3></div></div></div><p>Will be supported soon.</p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id857576"></a>Authentication API</h2></div></div></div><p>The authentication plugin should be placed in the auth directory.
+    </p><p>The following parameters must be accepted in the incomming
+    URL:</p><div class="itemizedlist"><ul type="disc"><li><p><code class="literal">RelayState</code>: This is the URL that the user
+        should be sent back to after authentication within the plugin.</p></li><li><p><code class="literal">RequestID</code>: This is the ID of an incomming
+        request.</p></li></ul></div><p>The initSSO.php takes in addition the following parameters:</p><div class="itemizedlist"><ul type="disc"><li><p><code class="literal">idpentityid</code>: This is the entityid of the IdP
+        to authenticate with. This parameter is optional, if not set the
+        default for this host will be used.</p></li><li><p><code class="literal">spentityid</code>: This is which SP config to use.
+        This parameter is optional, if not set the default for this host will
+        be used.</p></li></ul></div><p>In hosted IdP metadata there is a config parameter auth that will
+    tell simpleSAML which authentication plugin that can be used.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Tip</h3><p>The authentication API is pretty basic. The easiest way to
+      understand how it works is to look at one of the existing plugins that
+      is located in the auth directory of your installation.</p></div></div></div></body></html>
diff --git a/docs/simplesamlphp-install.pdf b/docs/simplesamlphp-install.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..aecd7d045e1c15b4f8840ed6fb1ff8a9fc2d4b30
GIT binary patch
literal 43359
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
Bn05dF

literal 0
HcmV?d00001

diff --git a/docs/source/simplesamlphp-install.xml b/docs/source/simplesamlphp-install.xml
new file mode 100644
index 000000000..69e644b30
--- /dev/null
+++ b/docs/source/simplesamlphp-install.xml
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<article>
+  <title>simpleSAMLphp Installation and Configuration</title>
+
+  <articleinfo>
+    <date>2007-08-30</date>
+
+    <pubdate>Fri Sep 14 10:49:49 2007</pubdate>
+
+    <author>
+      <firstname>Andreas Ă…kre</firstname>
+
+      <surname>Solberg</surname>
+
+      <email>andreas.solberg@uninett.no</email>
+    </author>
+  </articleinfo>
+
+  <section>
+    <title>The history of simpleSAMLphp</title>
+
+    <para>simpleSAMLphp is based on code from <ulink
+    url="https://opensso.dev.java.net/public/extensions/">Sun OpenSSO
+    Extensions</ulink> (formerly known as Lightbulb).</para>
+
+    <para>The initial versions of the SAML 2.0 SP part was written by <ulink
+    url="http://blogs.sun.com/superpat/">Pat Patterson, Sun</ulink>.</para>
+
+    <para>The functionality has been extended and <ulink
+    url="http://claimid.com/erlang">Andreas Ă…kre Solberg</ulink>, <ulink
+    url="http://uninett.no">UNINETT</ulink>, has rewritten the library and
+    added support for Shibboleth. The product is used to bridge AAI protocols
+    in the GÉANT project, <ulink
+    url="http://geant2.net">http://geant2.net</ulink>.</para>
+  </section>
+
+  <section>
+    <title>Changelog</title>
+
+    <para>Here is changes between simpleSAML versions. Look here if you are
+    upgrading, to see if there are any changes to the config format.</para>
+
+    <section>
+      <title>Version 0.4</title>
+
+      <para>Released 2007-09-14. Revision X.</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>Improved documentation</para>
+        </listitem>
+
+        <listitem>
+          <para>Authentication plugin API. Only LDAP authenticaiton plugin is
+          included, but it is now easier to implement your own plugin.</para>
+        </listitem>
+
+        <listitem>
+          <para>Added support for SAML 2.0 IdP to work with Google Apps for
+          Education. Tested.</para>
+        </listitem>
+
+        <listitem>
+          <para>Initial implementation of SAML 2.0 Single Log-Out
+          functionality both for SP and IdP. Seems to work, but not yet
+          well-tested.</para>
+        </listitem>
+
+        <listitem>
+          <para>Added support for bridging SAML 2.0 to SAML 2.0.</para>
+        </listitem>
+
+        <listitem>
+          <para>Added some time skew offset to the NotBefore timestamp on the
+          assertion, to allow some time skew between the SP and IdP.</para>
+        </listitem>
+
+        <listitem>
+          <para>Fixed Browser/POST page to automaticly submit, and have fall
+          back functionality for user agents with no javascript
+          support.</para>
+        </listitem>
+
+        <listitem>
+          <para>Fixed some bug with warning traversing Shibboleth 1.3
+          Assertions.</para>
+        </listitem>
+
+        <listitem>
+          <para>Fixed tabindex on the login page of the LDAP authentication
+          module to allow you to tab from username, to password and then to
+          submit.</para>
+        </listitem>
+
+        <listitem>
+          <para>Fixed bug on autodiscovering hostname in multihost
+          environments.</para>
+        </listitem>
+
+        <listitem>
+          <para>Cleaned out some debug messages, and added a debug option in
+          the configuration file. This debug option let's you turn on the
+          possibility of showing all SAML messages to users in the web
+          browser, and manually submit them.</para>
+        </listitem>
+
+        <listitem>
+          <para>Several minor bugfixes.</para>
+        </listitem>
+      </itemizedlist>
+    </section>
+  </section>
+
+  <section>
+    <title>Download and get simpleSAMLphp</title>
+
+    <para>You can go to <ulink
+    url="http://rnd.feide.no/category/simplesamlphp/">http://rnd.feide.no/category/simplesamlphp/</ulink>
+    to find the most recent release of simpleSAMLphp. Download the zipped
+    file, and unzip it on your webserver. However I hightly reccomend running
+    from a subversion checkout instead.</para>
+
+    <section>
+      <title>Getting a working copy of simpleSAMLphp from subversion</title>
+
+      <warning>
+        <para>Right now the subversion repository is requiring a username /
+        password. I'll update the access control, so that everyone can get
+        read access without authentication. I'll announce it on the rnd blog
+        when it is ready.</para>
+      </warning>
+
+      <para>If you want a working copy from subversion enter:</para>
+
+      <screen>svn co https://svn.uninett.no/svn/feidernd/simplesamlphp</screen>
+
+      <para>If you know subversion you know how to view logs and review
+      changes to the files. To update the version you have checked out,
+      enter:</para>
+
+      <screen>cd simplesamlphp
+svn up</screen>
+    </section>
+  </section>
+
+  <section>
+    <title>Installing simpleSAMLphp</title>
+
+    <para>First find an appropriate place for the <filename>simplesamlphp
+    </filename>folder. In example
+    <filename>/var/simplesamlphp</filename>.</para>
+
+    <para>Of the folders inside simplesamlphp, only the www folder needs to be
+    accessible from the web. There are several ways of putting the
+    simpleSAMLphp depending on the way web sites are structured on your apache
+    web server. Here is what I believe is the best configuration.</para>
+
+    <para>Find the apache configuration file for the virtual hosts that you
+    want to run simpleSAML on. The configuration may look like this:</para>
+
+    <programlisting>&lt;VirtualHost  *&gt;
+        ServerName service.example.com
+        DocumentRoot /var/www/service.example.com
+
+        Alias /simplesamlphp /var/simplesamlphp/www
+&lt;/VirtualHost&gt;
+</programlisting>
+
+    <para>What is special is tha Alias directive. That directive will give
+    control to simplesamlphp to all urls that matches
+    <literal>http(s)://service.example.com/simplesamlphp/*</literal>.
+    SimpleSAML will need to have several SAML interfaces available on the web,
+    and all these interfaces are included in the www subdirectory of your
+    simplesamlphp installation. You can set the alias to whatever you want,
+    but this alias must be set in the config.php file of simpleSAML as
+    described in <xref linkend="sect.config" />. Here is an example of how
+    this configuration may look like in config.php:</para>
+
+    <programlisting>$config = array (
+	'basedir' 				=&gt; '/var/simplesamlphp/',
+	'baseurl'				=&gt; 'http://service.example.com',
+	'baseurlpath'			=&gt; 'simplesamlphp/',</programlisting>
+
+    <section>
+      <title>The simpleSAMLphp installation webpage</title>
+
+      <para>When you have installed simpleSAMLphp, you can access the homepage
+      of your installation, which contains some information and a few links to
+      the test services. The url of an installation can be in example:</para>
+
+      <literallayout>https://service.example.com/simplesamlphp/</literallayout>
+
+      <para>But it depends on how you set it up with apache.</para>
+    </section>
+  </section>
+
+  <section>
+    <title>Making configuration and metadata files</title>
+
+    <para>Configuration and metadata files are stored in a template format,
+    you need to copy them to have your local copies. The reason why it is done
+    this way, is that when you upgrade you can do svn up in subversion or just
+    copy the whole directory over your installation, without replacing your
+    existing configuration. When you are updating, you should investigate
+    whether the config format is changed, this should be documented in the
+    changelog.</para>
+
+    <para>Here are the steps you need to do to create local configuration
+    files:</para>
+
+    <screen>cd /var/simplesamlphp
+cp config/config-template.php config/config.php
+cp -r metadata-templates/*.php metadata/
+</screen>
+  </section>
+
+  <section id="sect.config">
+    <title>Configuring simpleSAMLphp</title>
+
+    <para>First configure all the paths in the beginning of the config file,
+    to correspond to your organization of the apache web server, and where you
+    place simpleSAMLphp.</para>
+
+    <para>You will need to set the entityid of a default IdP in
+    <literal>default-saml20-idp</literal> or
+    <literal>default-shib13-idp</literal> depending on whether you use
+    shibboleth or SAML 2.0.</para>
+
+    <para>There is one parameter debug that may be set to true or false. If
+    you set it to true, then all Browser/POST SAML messages will be printed to
+    the web browser, and the user will have to manually submit it. </para>
+
+    <para>The session.duration parameter says how many seconds that a session
+    should be valid. After this amont of time, the session is not valid
+    anymore.</para>
+
+    <section>
+      <title>Configuration for LDAP authentication plugin</title>
+
+      <para>If you want to perform local authentication on this server, and
+      you want to use the LDAP authenticaiton plugin, then you need to
+      configure the following parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><literal>auth.ldap.dnpattern</literal>: What DN should you
+          bind to? Replacing %username% with the username the user types
+          in.</para>
+        </listitem>
+
+        <listitem>
+          <para><literal>auth.ldap.hostname</literal>: The hostname of the
+          LDAP server</para>
+        </listitem>
+
+        <listitem>
+          <para><literal>auth.ldap.attributes</literal>: Search parameter to
+          LDAP. What attributes should be extracted?
+          <literal>objectclass=*</literal> gives you all.</para>
+        </listitem>
+      </itemizedlist>
+    </section>
+  </section>
+
+  <section>
+    <title>Setting up a SAML 2.0 SP</title>
+
+    <para>This functionality is relevant if you want to integrate SAML 2.0
+    authentication on a service of yours, and you know one or more IdPs that
+    you can connect to. You would need metadata for those IdPs.</para>
+
+    <section>
+      <title>Configuring metadata for a SAML 2.0 SP</title>
+
+      <para>To configure a SAML 2.0 SP, you first need to configure the SP
+      data for all your vhosts. If you run only one host, you need only one
+      entry. This metadata is stored in the
+      <filename>metadata/saml20-sp-hosted.php</filename> file. Here is an
+      example of a metadata:</para>
+
+      <programlisting>	"dev.andreas.feide.no" =&gt; array(
+		'host'							=&gt;	'dev.andreas.feide.no',
+ 		"assertionConsumerServiceURL"	=&gt;	"http://dev.andreas.feide.no/saml2/sp/AssertionConsumerService.php", 
+		"issuer"						=&gt;	"dev.andreas.feide.no",
+		"spNameQualifier" 				=&gt;	"dev.andreas.feide.no",
+		"ForceAuthn"					=&gt;	"false",
+		"NameIDFormat"					=&gt;	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+	),</programlisting>
+
+      <para>Note that you should fill in the host field matching the hostname
+      of your vhost. That way simpleSAMLphp can automatically detect what SP
+      metadata to use based on the <literal>Host:</literal> header sent by the
+      HTTP user agent.</para>
+
+      <para>You also need to configure the metadata for the IdP that you want
+      to use. Here is a metadata example for the Feide IdP:</para>
+
+      <programlisting>	"sam.feide.no" =&gt;  array( 
+			"SingleSignOnUrl"	=&gt;	"https://sam.feide.no/amserver/SSORedirect/metaAlias/idp",
+		 	"SingleLogOutUrl"	=&gt;	"https://sam.feide.no/amserver/IDPSloRedirect/metaAlias/idp",
+		 	"certFingerprint"	=&gt;	"3a:e7:d3:d3:06:ba:57:fd:7f:62:6a:4b:a8:64:b3:4a:53:d9:5d:d0",
+		 	"base64attributes"	=&gt;	true),</programlisting>
+
+      <para>The IdP metadata is stored in the
+      <filename>metadata/saml20-idp-remote.php</filename> file. Configure the
+      correct URLs of the endpoints, the hash of the certificate, and whether
+      the IdP is base64 encoding attributes or not. Most IdPs don't use
+      base64, so if you do not connect to Feide you should turn this parameter
+      to <literal>false</literal>. Notice that the key of the array is the
+      entity id of the IdP, in this example:
+      <literal>sam.feide.no</literal>.</para>
+    </section>
+
+    <section>
+      <title>Test the SAML 2.0 SP example</title>
+
+      <para>Go to the URL of the test page, similar to:</para>
+
+      <literallayout>http://service.example.com/simplesamlphp/example-simple/saml2-example.php</literallayout>
+
+      <note>
+        <para>The simpleSAMLphp installation homepage will link you to this
+        example, so you do not need to type in the full url.</para>
+      </note>
+
+      <para>You should be redirected to the IdP. Login, and you should be sent
+      back and shown all the attributes sent form the IdP.</para>
+    </section>
+  </section>
+
+  <section>
+    <title>Setting up a Shibboleth 1.3 SP</title>
+
+    <para>If you want to configure a service with authentication towards an
+    external Shibboleth 1.3 IdP, this section describes you how to proceed.
+    </para>
+
+    <section>
+      <title>Configuring metadata for Shibboleth 1.3 SP</title>
+
+      <para>Configure Shibboleth 1.3 SP metadata for all your vhosts. If you
+      run only one host, you need only one entry. This metadata is stored in
+      the <filename>metadata/shib13-sp-hosted.php</filename> file. Here is an
+      example:</para>
+
+      <programlisting>	'http://dev.andreas.feide.no'	=&gt; array(
+		'AssertionConsumerService'	=&gt;	'http://dev.andreas.feide.no/shib13/sp/AssertionConsumerService.php',
+		'host'						=&gt;	'dev.andreas.feide.no'
+	),</programlisting>
+
+      <para>Note that you should fill in the host field matching the hostname
+      of your vhost. That way simpleSAMLphp can automatically detect what SP
+      metadata to use based on the <literal>Host:</literal> header sent by the
+      HTTP user agent.</para>
+
+      <para>You also need to configure the metadata for the Shibboleth 1.3
+      IdPs that you want to connect to. Here is an example:</para>
+
+      <programlisting>	'urn:mace:switch.ch:aaitest:dukono.switch.ch'	=&gt; array(
+		'SingleSignOnUrl'		=&gt;	'https://dukono.switch.ch/shibboleth-idp/SSO',
+		'certFingerprint'		=&gt;	'c7279a9f28f11380509e075441e3dc55fb9ab864' 
+	),</programlisting>
+
+      <para>Notice that the key of the array is the entity ID.</para>
+    </section>
+
+    <section>
+      <title>Test the Shibboleth 1.3 SP example</title>
+
+      <para>Go to the URL of the shibboleth test page, similar to:</para>
+
+      <literallayout>http://service.example.com/example-simple/shib13-example.php</literallayout>
+
+      <para>You should be redirected to the IdP. Login, and you should be sent
+      back and shown all the attributes sent form the IdP.</para>
+
+      <note>
+        <para>simpleSAMLphp does not support the attribute profile that
+        Shibboleth is using by default. To make attributes work, you need to
+        configure the IdP to perform attribute push.</para>
+      </note>
+    </section>
+  </section>
+
+  <section>
+    <title>Setting up a SAML 2.0 IdP</title>
+
+    <para>If you have a user database and want to offer a SAML 2.0 IdP
+    functinoality towards external services, here is how you set it up.</para>
+
+    <section>
+      <title>Configuring the SAML 2.0 IdP</title>
+
+      <para>Setup idp metadata in saml20-idp-hosted. Then for all the SP the
+      IdP shold trust in saml20-sp-remote. Then configure in config.php, ldap
+      DN patterns, ldap host etc. Next add a certificate with openssl.</para>
+
+      <para>Example config.php:</para>
+
+      <programlisting>	'auth.ldap.dnpattern'	=&gt; 'uid=%username%,dc=feide,dc=no,ou=feide,dc=uninett,dc=no',
+	'auth.ldap.hostname'	=&gt; 'ldap.uninett.no',
+	'auth.ldap.attributes'	=&gt; 'objectclass=*'</programlisting>
+
+      <para>Example IdP Metadata saml20-idp-hosted:</para>
+
+      <programlisting>	'dev2.andreas.feide.no' =&gt; array(
+		'host'				=&gt;	'dev2.andreas.feide.no',
+		'SingleSignOnUrl'	=&gt;	"http://dev2.andreas.feide.no/saml2/idp/SSOService.php",
+		'SingleLogOutUrl'	=&gt;	"http://dev2.andreas.feide.no/saml2/idp/LogoutService.php",
+		'privatekey'		=&gt;	'server.pem',
+		'certificate'		=&gt;	'server.crt',
+		'base64attributes'	=&gt;	true,
+		'auth'				=&gt;	'auth/login.php'
+	)</programlisting>
+
+      <para>The server.pem and server.crt is an example certificate shipped
+      with the package, and be used for demo purposes, but you must generate
+      your own to use in production services.</para>
+
+      <para>You also need to configure metadata for trusted SPs, here is an
+      example:</para>
+
+      <programlisting>_	"dev.andreas.feide.no" =&gt; array(
+		'host'							=&gt;	'dev.andreas.feide.no',
+ 		"assertionConsumerServiceURL"	=&gt;	"http://dev.andreas.feide.no/saml2/sp/AssertionConsumerService.php", 
+		"issuer"						=&gt;	"dev.andreas.feide.no",
+		"spNameQualifier" 				=&gt;	"dev.andreas.feide.no",
+		"ForceAuthn"					=&gt;	"false",
+		"NameIDFormat"					=&gt;	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+	),</programlisting>
+    </section>
+
+    <section>
+      <title>Adding a SAML IdP signing certificate</title>
+
+      <para>You should generate a new certificate for your IdP.</para>
+
+      <warning>
+        <para>There is a certificate that follows this package that you can
+        use for test purposes, but off course NEVER use this in production as
+        the private key is also included in the package and can be downloaded
+        by anyone.</para>
+      </warning>
+
+      <para>Here is an examples of openssl commands to generate a new key and
+      a selfsigned certificate to use for signing SAML messages:</para>
+
+      <screen>openssl genrsa -des3 -out server2.key 1024 
+openssl rsa -in server2.key -out server2.pem
+openssl req -new -key server.key -out server2.csr
+openssl x509 -req -days 60 -in server2.csr -signkey server2.key -out server2.crt</screen>
+
+      <para>The certificate above will be valid for 60 days.</para>
+
+      <note>
+        <para>simpleSAMLphp will only work with RSA and not DSA
+        certificates.</para>
+      </note>
+    </section>
+
+    <section>
+      <title>Test SAML 2.0 IdP</title>
+
+      <para>To test the SAML 2.0 IdP, it is best to configure two hosts with
+      simpleSAMLphp, and use the SAML 2.0 SP demo example to test the
+      IdP.</para>
+    </section>
+  </section>
+
+  <section>
+    <title>Using the built-in SP WAYF functionality</title>
+
+    <para>The WAYF is not yet a part of the simpleSAMLphp release. This
+    functionality will be added soon.</para>
+  </section>
+
+  <section>
+    <title>Setting up WebSSO bridges</title>
+
+    <para>simpleSAMLphp can be used to bridge between two WebSSO protocols.
+    Here is some short descriptions of how to setup the different bridge
+    configurations.</para>
+
+    <section>
+      <title>Bridging SAML 2.0 &lt;-&gt; SAML 2.0</title>
+
+      <para>In this setup you can bridge between two federations using SAML
+      2.0.</para>
+
+      <para>To approach this, you must configure both saml 2.0 IdP and SP
+      hosted metadata, and in the IdP hosted metadata configure the auth
+      parameter to be the SP initialization endpoint, like this:</para>
+
+      <screen>		'auth'				=&gt;	'saml2/sp/initSSO.php?idpentityid=sam.feide.no'</screen>
+
+      <para>As you can see you specify the IdP in the remote federation as a
+      parameter to the initalization endpoint.</para>
+
+      <note>
+        <para>This section of the documentation is only a placeholder. There
+        will be more detailed information added later. For now, ask the author
+        if you want more details of such a setup.</para>
+
+        <para>Briding SAML 2.0 SLO is not implemented. Will be improved
+        soon.</para>
+      </note>
+    </section>
+
+    <section>
+      <title>Bridging Shibboleth 1.3 &lt;-&gt; Shibboleth 1.3</title>
+
+      <para>Will be supported soon.</para>
+    </section>
+
+    <section>
+      <title>Bridging Shibboleth 1.3 &lt;-&gt; SAML 2.0</title>
+
+      <para>Will be supported soon.</para>
+    </section>
+
+    <section>
+      <title>Bridging SAML 2.0 &lt;-&gt; Shibboleth 1.3</title>
+
+      <para>Will be supported soon.</para>
+    </section>
+
+    <section>
+      <title>Bridging SAML 2.0 &lt;-&gt; OpenID</title>
+
+      <para>Will be supported soon.</para>
+    </section>
+
+    <section>
+      <title>Bridging Shibboelth 1.3 &lt;-&gt; OpenID</title>
+
+      <para>Will be supported soon.</para>
+    </section>
+  </section>
+
+  <section>
+    <title>Authentication API</title>
+
+    <para>The authentication plugin should be placed in the auth directory.
+    </para>
+
+    <para>The following parameters must be accepted in the incomming
+    URL:</para>
+
+    <itemizedlist>
+      <listitem>
+        <para><literal>RelayState</literal>: This is the URL that the user
+        should be sent back to after authentication within the plugin.</para>
+      </listitem>
+
+      <listitem>
+        <para><literal>RequestID</literal>: This is the ID of an incomming
+        request.</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>The initSSO.php takes in addition the following parameters:</para>
+
+    <itemizedlist>
+      <listitem>
+        <para><literal>idpentityid</literal>: This is the entityid of the IdP
+        to authenticate with. This parameter is optional, if not set the
+        default for this host will be used.</para>
+      </listitem>
+
+      <listitem>
+        <para><literal>spentityid</literal>: This is which SP config to use.
+        This parameter is optional, if not set the default for this host will
+        be used.</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>In hosted IdP metadata there is a config parameter auth that will
+    tell simpleSAML which authentication plugin that can be used.</para>
+
+    <tip>
+      <para>The authentication API is pretty basic. The easiest way to
+      understand how it works is to look at one of the existing plugins that
+      is located in the auth directory of your installation.</para>
+    </tip>
+  </section>
+</article>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php b/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php
new file mode 100644
index 000000000..8d68c99f7
--- /dev/null
+++ b/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php
@@ -0,0 +1,213 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnResponse.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_Bindings_SAML20_HTTPPost {
+
+	private $configuration = null;
+	private $metadata = null;
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	
+	public function sendResponseUnsigned($response, $idpentityid, $spentityid, $relayState = null, $endpoint = 'assertionConsumerServiceURL') {
+
+		$idpmd = $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted');
+		$spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote');
+		
+		$destination = $spmd[$endpoint];
+		
+		echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+				"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+		<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+		<head>
+			<meta http-equiv="content-type" content="text/html; charset=utf-8">
+			<title>Send SAML 2.0 Authentication Response</title>
+		</head>
+		<body>
+		<h1>Send SAML 2.0 Authentication Response</h1>
+		 
+		 <form style="border: 1px solid #777; margin: 2em; padding: 2em" method="post" action="' . $destination . '">
+			<input type="hidden" name="SAMLResponse" value="' . base64_encode($response) . '" />
+			<input type="hidden" name="RelayState" value="' . $relayState. '">
+			<input type="submit" value="Submit the SAML 1.1 Response" />
+		 </form>
+		 
+		<ul>
+			<li>From IdP: <tt>' . $idpentityid . '</tt></li>
+			<li>To SP: <tt>' . $spentityid . '</tt></li>
+			<li>SP Assertion Consumer Service URL: <tt>' . $destination . '</tt></li>
+			<li>RelayState: <tt>' . $relayState . '</tt></li>
+		</ul>
+		
+		<p>SAML Message: <pre>' .  htmlentities($response) . '</pre>
+		
+		
+		</body>
+		</html>';
+	}
+	
+	public function sendResponse($response, $idpentityid, $spentityid, $relayState = null) {
+
+		$idpmd = $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted');
+		$spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote');
+		
+		$destination = $spmd['assertionConsumerServiceURL'];
+	
+		/*
+		$privatekey = "/home/as/erlang/feide2/cert/edugain/server1Key.pem";
+		$publiccert = "/home/as/erlang/feide2/cert/edugain/server2chain.pem";
+		*/
+
+		$privatekey = "/home/as/erlang/feide2/cert/server.pem";
+		$publiccert = "/home/as/erlang/feide2/cert/server.crt";
+		
+		$privatekey = $this->configuration->getValue('basedir') . '/cert/' . $idpmd['privatekey'];
+		$publiccert = $this->configuration->getValue('basedir') . '/cert/' . $idpmd['certificate'];
+
+		if (!file_exists($privatekey))
+			throw new Exception('Could not find private key file [' . $privatekey . '] which is needed to sign the authentication response');
+
+		if (!file_exists($publiccert)) 
+			throw new Exception('Could not find certificate [' . $publiccert . '] to attach to the authentication resposne');
+
+		
+		/*
+		 * XMLDSig. Sign the complete request with the key stored in cert/server.pem
+		 */
+		$objXMLSecDSig = new XMLSecurityDSig();
+		//$objXMLSecDSig->idKeys[] = 'ResponseID';
+		#$objXMLSecDSig->idKeys = array('ResponseID');
+		
+		$objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
+	
+	
+		try {
+			$responsedom = new DOMDocument();
+			$responsedom->loadXML(str_replace("\n", "", str_replace ("\r", "", $response)));
+		} catch (Exception $e) {
+			throw new Exception("foo");
+		}
+		$responseroot = $responsedom->getElementsByTagName('Response')->item(0);
+		
+		//$assertionroot = $responsedom->getElementsByTagName('Assertion')->item(1);
+		$firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0);
+		
+		//$objXMLSecDSig->addReferenceList(array($responseroot), XMLSecurityDSig::SHA1, //array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'));
+		
+		$objXMLSecDSig->addReferenceList(array($firstassertionroot), XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature',
+			'http://www.w3.org/2001/10/xml-exc-c14n#'));
+		
+		#$objXMLSecDSig->addRefInternal($responseroot, $responseroot, XMLSecurityDSig::SHA1);
+		
+		/* create new XMLSecKey using RSA-SHA-1 and type is private key */
+		$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
+		
+		/* load the private key from file - last arg is bool if key in file (TRUE) or is string (FALSE) */
+		$objKey->loadKey($privatekey,TRUE);
+		
+		
+		
+		
+		
+		$objXMLSecDSig->sign($objKey);
+		
+		$public_cert = file_get_contents($publiccert);
+		$objXMLSecDSig->add509Cert($public_cert, true);
+		/*
+		$public_cert = file_get_contents("cert/edugain/public2.pem");
+		$objXMLSecDSig->add509Cert($public_cert, true);
+		
+		$public_cert = file_get_contents("cert/edugain/public3.pem");
+		$objXMLSecDSig->add509Cert($public_cert, true);
+		*/
+		
+		
+		$objXMLSecDSig->appendSignature($firstassertionroot, true, true);
+		//$objXMLSecDSig->appendSignature($responseroot, true, false);
+		
+		$response = $responsedom->saveXML();
+		
+		
+		# openssl genrsa -des3 -out server.key 1024 
+		# openssl rsa -in server.key -out server.pem
+		# openssl req -new -key server.key -out server.csr
+		# openssl x509 -req -days 60 -in server.csr -signkey server.key -out server.crt
+		
+		if ($this->configuration->getValue('debug')) {
+	
+			$p = new SimpleSAML_XHTML_Template($this->configuration, 'post-debug.php');
+			
+			$p->data['header'] = 'SAML Response Debug-mode';
+			$p->data['RelayStateName'] = 'RelayState';
+			$p->data['RelayState'] = $relayState;
+			$p->data['destination'] = $destination;
+			$p->data['response'] = str_replace("\n", "", base64_encode($response));
+			$p->data['responseHTML'] = htmlentities($responsedom->saveHTML());
+			
+			$p->show();
+
+		
+		} else {
+
+			$p = new SimpleSAML_XHTML_Template($this->configuration, 'post.php');
+	
+			$p->data['RelayStateName'] = 'RelayState';
+			$p->data['RelayState'] = $relayState;
+			$p->data['destination'] = $destination;
+			$p->data['response'] = base64_encode($response);
+			
+			$p->show();
+
+		
+		}
+		
+		
+	}
+	
+	public function decodeResponse($post) {
+		$rawResponse = 	$post["SAMLResponse"];
+		$relaystate = 	$post["RelayState"];
+		
+		$samlResponseXML = base64_decode( $rawResponse );
+		
+		//error_log("Response is: " . $samlResponseXML);
+        
+		$samlResponse = new SimpleSAML_XML_SAML20_AuthnResponse($this->configuration, $this->metadata);
+	
+		$samlResponse->setXML($samlResponseXML);
+		
+		if (isset($relaystate)) {
+			$samlResponse->setRelayState($relaystate);
+		}
+	
+        #echo("Authn response = " . $samlResponse );
+
+        return $samlResponse;
+        
+	}
+
+
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php
new file mode 100644
index 000000000..cf12376a5
--- /dev/null
+++ b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php
@@ -0,0 +1,125 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_Bindings_SAML20_HTTPRedirect {
+
+	private $configuration = null;
+	private $metadata = null;
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	public function sendMessage($request, $remoteentityid, $relayState = null, $endpoint = 'SingleSignOnUrl', $direction = 'SAMLRequest', $mode = 'SP') {
+		if (!in_array($mode, array('SP', 'IdP'))) {
+			throw new Exception('mode parameter of sendMessage() must be either SP or IdP');
+		}
+		$metadataset = 'saml20-idp-remote';
+		if ($mode == 'IdP') {
+			$metadataset = 'saml20-sp-remote';
+		}
+
+		$md = $this->metadata->getMetaData($remoteentityid, $metadataset);
+		$idpTargetUrl = $md[$endpoint];
+	
+		$encodedRequest = urlencode( base64_encode( gzdeflate( $request ) ));
+		
+		$redirectURL = $idpTargetUrl . "?" . $direction . "=" . $encodedRequest;
+		if (isset($relayState)) {
+			$redirectURL .= "&RelayState=" . urlencode($relayState);
+		}
+		
+
+		header("Location: " . $redirectURL);
+		
+	}
+
+
+
+	public function decodeRequest($get) {
+		if (!isset($get['SAMLRequest'])) {
+			throw new Exception('SAMLRequest parameter not set in paramter (on SAML 2.0 HTTP Redirect binding endpoint)');
+		}
+		$rawRequest = 	$get["SAMLRequest"];
+		$relaystate = isset($get["RelayState"]) ? $get["RelayState"] : null;
+		
+		$samlRequestXML = gzinflate(base64_decode( $rawRequest ));
+         
+		$samlRequest = new SimpleSAML_XML_SAML20_AuthnRequest($this->configuration, $this->metadata);
+	
+		$samlRequest->setXML($samlRequestXML);
+		
+		if (isset($relaystate)) {
+			$samlRequest->setRelayState($relaystate);
+		}
+	
+        #echo("Authn response = " . $samlResponse );
+
+        return $samlRequest;
+        
+	}
+	
+	public function decodeLogoutRequest($get) {
+		if (!isset($get['SAMLRequest'])) {
+			throw new Exception('SAMLRequest parameter not set in paramter (on SAML 2.0 HTTP Redirect binding endpoint)');
+		}
+		$rawRequest = 	$get["SAMLRequest"];
+		$relaystate = isset($get["RelayState"]) ? $get["RelayState"] : null;
+		
+		$samlRequestXML = gzinflate(base64_decode( $rawRequest ));
+         
+		$samlRequest = new SimpleSAML_XML_SAML20_LogoutRequest($this->configuration, $this->metadata);
+	
+		$samlRequest->setXML($samlRequestXML);
+		
+		if (isset($relaystate)) {
+			$samlRequest->setRelayState($relaystate);
+		}
+	
+        #echo("Authn response = " . $samlResponse );
+
+        return $samlRequest;
+	}
+	
+	public function decodeLogoutResponse($get) {
+		if (!isset($get['SAMLResponse'])) {
+			throw new Exception('SAMLResponse parameter not set in paramter (on SAML 2.0 HTTP Redirect binding endpoint)');
+		}
+		$rawRequest = 	$get["SAMLResponse"];
+		$relaystate = isset($get["RelayState"]) ? $get["RelayState"] : null;
+		
+		$samlRequestXML = gzinflate(base64_decode( $rawRequest ));
+         
+		$samlRequest = new SimpleSAML_XML_SAML20_LogoutResponse($this->configuration, $this->metadata);
+	
+		$samlRequest->setXML($samlRequestXML);
+		
+		if (isset($relaystate)) {
+			$samlRequest->setRelayState($relaystate);
+		}
+	
+        #echo("Authn response = " . $samlResponse );
+
+        return $samlRequest;
+	}
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php
new file mode 100644
index 000000000..cbe2a19a3
--- /dev/null
+++ b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php
@@ -0,0 +1,198 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/Shib13/AuthnResponse.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_Bindings_Shib13_HTTPPost {
+
+	private $configuration = null;
+	private $metadata = null;
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	
+	public function sendResponseUnsigned($response, $idpentityid, $spentityid, $relayState = null, $endpoint = 'assertionConsumerServiceURL') {
+
+		$idpmd = $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted');
+		$spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote');
+		
+		$destination = $spmd[$endpoint];
+		
+		echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+				"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+		<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+		<head>
+			<meta http-equiv="content-type" content="text/html; charset=utf-8">
+			<title>Send SAML 2.0 Authentication Response</title>
+		</head>
+		<body>
+		<h1>Send SAML 2.0 Authentication Response</h1>
+		 
+		 <form style="border: 1px solid #777; margin: 2em; padding: 2em" method="post" action="' . $destination . '">
+			<input type="hidden" name="SAMLResponse" value="' . base64_encode($response) . '" />
+			<input type="hidden" name="TARGET" value="' . $relayState. '">
+			<input type="submit" value="Submit the SAML 1.1 Response" />
+		 </form>
+		 
+		<ul>
+			<li>From IdP: <tt>' . $idpentityid . '</tt></li>
+			<li>To SP: <tt>' . $spentityid . '</tt></li>
+			<li>SP Assertion Consumer Service URL: <tt>' . $destination . '</tt></li>
+			<li>RelayState: <tt>' . $relayState . '</tt></li>
+		</ul>
+		
+		<p>SAML Message: <pre>' .  htmlentities($response) . '</pre>
+		
+		
+		</body>
+		</html>';
+	}
+	
+	public function sendResponse($response, $idpentityid, $spentityid, $relayState = null) {
+
+		$idpmd = $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted');
+		$spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote');
+		
+		$destination = $spmd['assertionConsumerServiceURL'];
+	
+		/*
+		$privatekey = "/home/as/erlang/feide2/cert/edugain/server1Key.pem";
+		$publiccert = "/home/as/erlang/feide2/cert/edugain/server2chain.pem";
+		*/
+
+		$privatekey = "/home/as/erlang/feide2/cert/server.pem";
+		$publiccert = "/home/as/erlang/feide2/cert/server.crt";
+
+		
+		/*
+		 * XMLDSig. Sign the complete request with the key stored in cert/server.pem
+		 */
+		$objXMLSecDSig = new XMLSecurityDSig();
+		//$objXMLSecDSig->idKeys[] = 'ResponseID';
+		#$objXMLSecDSig->idKeys = array('ResponseID');
+		
+		$objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
+		
+		$responsedom = new DOMDocument();
+		$responsedom->loadXML(str_replace ("\r", "", $response));
+		
+		$responseroot = $responsedom->getElementsByTagName('Response')->item(0);
+		
+		//$assertionroot = $responsedom->getElementsByTagName('Assertion')->item(1);
+		$firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0);
+		
+		#$objXMLSecDSig->addReferenceList(array($responseroot), XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'));
+		$objXMLSecDSig->addReferenceList(array($firstassertionroot), XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature',
+			'http://www.w3.org/2001/10/xml-exc-c14n#'));
+		
+		#$objXMLSecDSig->addRefInternal($responseroot, $responseroot, XMLSecurityDSig::SHA1);
+		
+		/* create new XMLSecKey using RSA-SHA-1 and type is private key */
+		$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
+		
+		/* load the private key from file - last arg is bool if key in file (TRUE) or is string (FALSE) */
+		$objKey->loadKey($privatekey,TRUE);
+		
+		
+		
+		
+		
+		$objXMLSecDSig->sign($objKey);
+		
+		$public_cert = file_get_contents($publiccert);
+		$objXMLSecDSig->add509Cert($public_cert, true);
+		/*
+		$public_cert = file_get_contents("cert/edugain/public2.pem");
+		$objXMLSecDSig->add509Cert($public_cert, true);
+		
+		$public_cert = file_get_contents("cert/edugain/public3.pem");
+		$objXMLSecDSig->add509Cert($public_cert, true);
+		*/
+		
+		
+		$objXMLSecDSig->appendSignature($firstassertionroot, true);
+		
+		$response = $responsedom->saveXML();
+		
+		
+		# openssl genrsa -des3 -out server.key 1024 
+		# openssl rsa -in server.key -out server.pem
+		# openssl req -new -key server.key -out server.csr
+		# openssl x509 -req -days 60 -in server.csr -signkey server.key -out server.crt
+		
+		
+		
+		echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+				"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+		<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+		<head>
+			<meta http-equiv="content-type" content="text/html; charset=utf-8">
+			<title>Send SAML 2.0 Authentication Response</title>
+		</head>
+		<body>
+		<h1>Send SAML 2.0 Authentication Response</h1>
+		 
+		 <form style="border: 1px solid #777; margin: 2em; padding: 2em" method="post" action="' . $destination . '">
+			<input type="hidden" name="SAMLResponse" value="' . base64_encode($response) . '" />
+			<input type="hidden" name="TARGET" value="' . $relayState. '">
+			<input type="submit" value="Submit the SAML 1.1 Response" />
+		 </form>
+		 
+		<ul>
+			<li>From IdP: <tt>' . $idpentityid . '</tt></li>
+			<li>To SP: <tt>' . $spentityid . '</tt></li>
+			<li>SP Assertion Consumer Service URL: <tt>' . $destination . '</tt></li>
+			<li>RelayState: <tt>' . $relayState . '</tt></li>
+		</ul>
+		
+		<p>SAML Message: <pre>' .  htmlentities($responsedom->saveHTML()) . '</pre>
+		
+		
+		</body>
+		</html>';
+		
+	}
+	
+	public function decodeResponse($post) {
+		$rawResponse = 	$post["SAMLResponse"];
+		$relaystate = 	$post["TARGET"];
+		
+		$samlResponseXML = base64_decode( $rawResponse );
+        
+		$samlResponse = new SimpleSAML_XML_Shib13_AuthnResponse($this->configuration, $this->metadata);
+	
+		$samlResponse->setXML($samlResponseXML);
+		
+		if (isset($relaystate)) {
+			$samlResponse->setRelayState($relaystate);
+		}
+	
+        #echo("Authn response = " . $samlResponse );
+
+        return $samlResponse;
+        
+	}
+
+
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Configuration.php b/lib/SimpleSAML/Configuration.php
new file mode 100644
index 000000000..116c018a8
--- /dev/null
+++ b/lib/SimpleSAML/Configuration.php
@@ -0,0 +1,53 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_Configuration {
+
+	private static $instance = null;
+
+	private $configpath = null;	
+	private $configuration = null;
+
+	// private constructor restricts instantiaton to getInstance()
+	private function __construct($configpath) {
+
+		$this->configpath = $configpath;
+
+	}
+	
+	public function getInstance() {
+		return self::$instance;
+	}
+	
+	public static function init($path) {
+		self::$instance = new SimpleSAML_Configuration($path);
+	}
+
+	private function loadConfig() {
+		require_once($this->configpath . '/config.php');
+		$this->configuration = $config;
+	}
+
+	public function getValue($name) {
+		if (!isset($this->configuration)) {
+			$this->loadConfig();
+		}
+		return $this->configuration[$name];
+	}
+
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php
new file mode 100644
index 000000000..03befb7c6
--- /dev/null
+++ b/lib/SimpleSAML/Session.php
@@ -0,0 +1,223 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+
+
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnRequest.php');
+require_once('SimpleSAML/XML/AuthnResponse.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+
+/**
+ * A class representing a session.
+ */
+class SimpleSAML_Session {
+
+	const STATE_ONLINE = 1;
+	const STATE_LOGOUTINPROGRESS = 2;
+	const STATE_LOGGEDOUT = 3;
+
+	private static $instance = null;
+
+	private $configuration = null;
+	
+	private $authnrequests = array();
+	private $authnresponse = null;
+	
+	private $logoutrequest = null;
+	
+	private $authenticated = null;
+	private $protocol = null;
+	private $attributes = null;
+	
+	
+	private $sessionindex = null;
+	private $nameid = null;
+	private $nameidformat = null;
+	
+	private $sp_at_idpsessions = array();
+	
+	// Session duration parameters
+	private $sessionstarted = null;
+	private $sessionduration = null;
+
+	// private constructor restricts instantiaton to getInstance()
+	private function __construct($protocol, SimpleSAML_XML_AuthnResponse $message = null, $authenticated = true) {
+
+		$this->configuration = SimpleSAML_Configuration::getInstance();
+
+		$this->protocol = $protocol;
+		$this->authnresponse = $message;
+		
+		$this->authenticated = $authenticated;
+		if ($authenticated) {
+			$this->sessionstarted = time();
+		}
+		
+		$this->sessionduration = $this->configuration->getValue('session.duration');
+	}
+	
+	public function add_sp_session($entityid) {
+		$this->sp_at_idpsessions[$entityid] = self::STATE_ONLINE;
+	}
+	
+	public function get_next_sp_logout() {
+		
+		if (!$this->sp_at_idpsessions) return null;
+		
+		foreach ($this->sp_at_idpsessions AS $entityid => $sp) {
+			if ($sp == self::STATE_ONLINE) {
+				$this->sp_at_idpsessions[$entityid] = self::STATE_LOGOUTINPROGRESS;
+				return $entityid;
+			}
+		}
+		return null;
+	}
+	
+	public function set_sp_logout_completed($entityid) {
+		$this->sp_at_idpsessions[$entityid] = self::STATE_LOGGEDOUT;
+	}
+	
+	
+	public function dump_sp_sessions() {
+		foreach ($this->sp_at_idpsessions AS $entityid => $sp) {
+			error_log('Dump sp sessions: ' . $entityid . ' status: ' . $sp);
+		}
+	}
+	
+	public function getInstance() {
+		if (isset(self::$instance)) {
+			return self::$instance;
+		} elseif(isset($_SESSION['SimpleSAMLphp_SESSION'])) {
+			self::$instance = $_SESSION['SimpleSAMLphp_SESSION'];
+			return self::$instance;
+		}
+		return null;
+	}
+	
+	public static function init($protocol, $message = null, $authenticated = true) {
+		
+		$preinstance = self::getInstance();
+		
+		if (isset($preinstance)) {
+			if (isset($message)) $preinstance->authnresponse = $message;
+			if (isset($authenticated)) $preinstance->setAuthenticated($authenticated);
+		} else {	
+			self::$instance = new SimpleSAML_Session($protocol, $message, $authenticated);
+			$_SESSION['SimpleSAMLphp_SESSION'] = self::$instance;
+		}
+	}
+
+	public function setAuthnRequest($requestid, SimpleSAML_XML_SAML20_AuthnRequest $xml) {	
+		$this->authnrequests[$requestid] = $xml;
+	}
+	
+	public function getAuthnRequest($requestid) {
+		return $this->authnrequests[$requestid];
+	}
+	
+	public function setAuthnResponse(SimpleSAML_XML_AuthnResponse $xml) {
+		$this->authnresponse = $xml;
+	}
+	
+	public function getAuthnResposne() {
+		return $this->authnresponse;
+	}
+	
+	public function setLogoutRequest(SimpleSAML_XML_SAML20_LogoutRequest $lr) {
+		$this->logoutrequest = $lr;
+	}
+	
+	public function getLogoutRequest() {
+		return $this->logoutrequest;
+	}
+
+	public function setSessionIndex($sessionindex) {
+		$this->sessionindex = $sessionindex;
+	}
+	public function getSessionIndex() {
+		return $this->sessionindex;
+	}
+	public function setNameID($nameid) {
+		$this->nameid = $nameid;
+	}
+	public function getNameID() {
+		return $this->nameid;
+	}
+	public function setNameIDformat($nameidformat) {
+		$this->nameidformat = $nameidformat;
+	}
+	public function getNameIDformat() {
+		return $this->nameidformat;
+	}
+
+	public function setAuthenticated($auth) {
+		$this->authenticated = $auth;
+		if ($auth) {
+			$this->sessionstarted = time();
+		}
+	}
+	
+	public function setSessionDuration($duration) {
+		$this->sessionduration = $duration;
+	}
+	
+	
+	/*
+	 * Is the session representing an authenticated user, and is the session still alive.
+	 * This function will return false after the user has timed out.
+	 */
+
+	public function isValid() {
+		if (!$this->isAuthenticated()) return false;
+		return $this->remainingTime() > 0;
+	}
+	
+	/*
+	 * If the user is authenticated, how much time is left of the session.
+	 */
+	public function remainingTime() {
+		return $this->sessionduration - (time() - $this->sessionstarted);
+	}
+
+	/* 
+	 * Is the user authenticated. This function does not check the session duration.
+	 */
+	public function isAuthenticated() {
+		return $this->authenticated;
+	}
+	
+	
+	
+	
+	public function getProtocol() {
+		return $this->protocol;
+	}
+	
+	public function getAttributes() {
+		return $this->attributes;
+	}
+
+	public function getAttribute($name) {
+		return $this->attributes[$name];
+	}
+
+	public function setAttributes($attributes) {
+		$this->attributes = $attributes;
+	}
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php
new file mode 100644
index 000000000..6b6af783e
--- /dev/null
+++ b/lib/SimpleSAML/Utilities.php
@@ -0,0 +1,92 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_Utilities {
+
+
+	public static function selfURLNoQuery() {
+	
+		$s = empty($_SERVER["HTTPS"]) ? ''
+			: ($_SERVER["HTTPS"] == "on") ? "s"
+			: "";
+		$protocol = self::strleft(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s;
+		$port = ($_SERVER["SERVER_PORT"] == "80") ? ""
+			: (":".$_SERVER["SERVER_PORT"]);
+		$querystring = '';
+		return $protocol."://".$_SERVER['HTTP_HOST'].$port . $_SERVER['SCRIPT_NAME'];
+	
+	}
+
+	public static function selfURL() {
+	
+		$s = empty($_SERVER["HTTPS"]) ? ''
+			: ($_SERVER["HTTPS"] == "on") ? "s"
+			: "";
+		$protocol = self::strleft(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s;
+		$port = ($_SERVER["SERVER_PORT"] == "80") ? ""
+			: (":".$_SERVER["SERVER_PORT"]);
+		$querystring = '';
+		return $protocol."://".$_SERVER['HTTP_HOST'].$port.$_SERVER['REQUEST_URI'];
+	
+	}
+	
+	public static function addURLparameter($url, $parameter) {
+		if (strstr($url, '?')) {
+			return $url . '&' . $parameter;
+		} else {
+			return $url . '?' . $parameter;
+		}
+	}
+	
+	public static function strleft($s1, $s2) {
+		return substr($s1, 0, strpos($s1, $s2));
+	}
+	
+	public static function checkDateConditions($start=NULL, $end=NULL) {
+		$currentTime = time();
+	
+		if (! empty($start)) {
+			$startTime = strtotime($start);
+			/* Allow for a 10 minute difference in Time */
+			if (($startTime < 0) || (($startTime - 600) > $currentTime)) {
+				return FALSE;
+			}
+		}
+		if (! empty($end)) {
+			$endTime = strtotime($end);
+			if (($endTime < 0) || ($endTime <= $currentTime)) {
+				return FALSE;
+			}
+		}
+		return TRUE;
+	}
+	
+	public static function generateID() {
+	
+		$length = 42;
+		$key = "_";
+		for ( $i=0; $i < $length; $i++ )
+		{
+			 $key .= dechex( rand(0,15) );
+		}
+		return $key;
+	}
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XHTML/Template.php b/lib/SimpleSAML/XHTML/Template.php
new file mode 100644
index 000000000..11e845ee4
--- /dev/null
+++ b/lib/SimpleSAML/XHTML/Template.php
@@ -0,0 +1,45 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_XHTML_Template {
+
+	private $configuration = null;
+	private $template = 'default.php';
+	
+	public $data = null;
+
+	function __construct(SimpleSAML_Configuration $configuration, $template) {
+		$this->configuration = $configuration;
+		$this->template = $template;
+		
+		$this->data['baseurlpath'] = $this->configuration->getValue('baseurlpath');
+	}
+	
+	public function show() {
+		$data = $this->data;
+		$filename = $this->configuration->getValue('templatedir') . '/' . $this->template;
+		if (!file_exists($filename)) {
+			throw new Exception('Could not find template file [' . $this->template . '] at [' . $filename . ']');
+		}
+		require_once($filename);
+	}
+	
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XML/AuthnResponse.php b/lib/SimpleSAML/XML/AuthnResponse.php
new file mode 100644
index 000000000..c2cd28d46
--- /dev/null
+++ b/lib/SimpleSAML/XML/AuthnResponse.php
@@ -0,0 +1,115 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+
+require_once('xmlseclibs.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+abstract class SimpleSAML_XML_AuthnResponse {
+
+	private $configuration = null;
+	private $metadata = 'default.php';
+	
+	private $message = null;
+	private $dom;
+	private $relayState = null;
+	
+	private $validIDs = null;
+	
+	const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0';
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	
+	abstract public function validate();
+
+	abstract public function createSession();
+
+	
+	
+	abstract public function getAttributes();
+
+	
+	abstract public function getIssuer();
+	
+	abstract public function getNameID();
+	
+	
+	public function setXML($xml) {
+		$this->message = $xml;
+	}
+	
+	public function getXML() {
+		return $this->message;
+	}
+	
+	public function setRelayState($relayState) {
+		$this->relayState = $relayState;
+	}
+	
+	public function getRelayState() {
+		return $this->relayState;
+	}
+	
+	public function getDOM() {
+		if (isset($this->message) ) {
+			
+			/*
+			if (isset($this->dom)) {
+				return $this->dom;
+			}
+			*/
+		
+			$token = new DOMDocument();
+			$token->loadXML(str_replace ("\r", "", $this->message));
+			if (empty($token)) {
+				throw new Exception("Unable to load token");
+			}
+			$this->dom = $token;
+			return $this->dom;
+		
+		} 
+		
+		return null;
+	}
+	
+
+
+	
+	public static function generateID() {
+	
+		$length = 42;
+		$key = "_";
+		for ( $i=0; $i < $length; $i++ )
+		{
+			 $key .= dechex( rand(0,15) );
+		}
+		return $key;
+	}
+	
+	public static function generateIssueInstant($offset = 0) {
+		return gmdate("Y-m-d\TH:i:s\Z", time() + $offset);
+	}
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XML/MetaDataStore.php b/lib/SimpleSAML/XML/MetaDataStore.php
new file mode 100644
index 000000000..8d15a3ed8
--- /dev/null
+++ b/lib/SimpleSAML/XML/MetaDataStore.php
@@ -0,0 +1,105 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+
+require_once('SimpleSAML/Configuration.php');
+
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_XML_MetaDataStore {
+
+	private $configuration = null;
+	private $metadata = null;
+	private $hostmap = null;
+
+	function __construct(SimpleSAML_Configuration $configuration) {
+		$this->configuration = $configuration;
+	}
+
+	public function load($set) {
+		$metadata = null;
+		if (!in_array($set, array(
+			'saml20-sp-hosted', 'saml20-sp-remote','saml20-idp-hosted', 'saml20-idp-remote',
+			'shib13-sp-hosted', 'shib13-sp-remote', 'shib13-idp-hosted', 'shib13-idp-remote'))) {
+				throw new Exception('Trying to load illegal set of Meta data [' . $set . ']');
+		}
+		
+		$metadatasetfile = $this->configuration->getValue('metadatadir') . '/' . $set . '.php';
+		
+		if (!file_exists($metadatasetfile)) {
+			throw new Exception('Could not open file: ' . $metadatasetfile);
+		}
+		include($metadatasetfile);
+		
+		if (!is_array($metadata)) {
+			throw new Exception('Could not load metadata set [' . $set . '] from file: ' . $metadatasetfile);
+		}
+		foreach ($metadata AS $key => $entry) { 
+			$this->metadata[$set][$key] = $entry;
+			$this->metadata[$set][$key]['entityid'] = $key;
+			
+			if (isset($entry['host'])) {
+				$this->hostmap[$set][$entry['host']] = $key;
+			}
+			
+		}
+		/*
+		echo '<pre>';
+		print_r();
+		echo '</pre>';
+		*/
+	}
+
+	public function getMetaDataCurrentEntityID($set = 'saml20-sp-hosted') {
+	
+		if (!isset($this->metadata[$set])) {
+			$this->load($set);
+		}
+		$currenthost = $_SERVER['HTTP_HOST'];
+		if (!isset($this->hostmap[$set])) {
+			throw new Exception('No default entities defined for metadata set [' . $set . ']');
+		}
+		if (!isset($currenthost)) {
+			throw new Exception('Could not get HTTP_HOST, in order to resolve default entity ID');
+		}
+		if (!isset($this->hostmap[$set][$currenthost])) {
+			throw new Exception('Could not find any default metadata entities in set [' . $set . '] for host [' . $currenthost . ']');
+		}
+		if (!$this->hostmap[$set][$currenthost]) throw new Exception('Could not find default metadata for current host');
+		return $this->hostmap[$set][$currenthost];
+	}
+
+	public function getMetaDataCurrent($set = 'saml20-sp-hosted') {
+		return $this->getMetaData($this->getMetaDataCurrentEntityID($set), $set);
+	}
+	
+	public function getMetaData($entityid = null, $set = 'saml20-sp-hosted') {
+		if (!isset($entityid)) {
+			return $this->getMetaDataCurrent($set);
+		}
+		
+		//echo 'find metadata for entityid [' . $entityid . '] in metadata set [' . $set . ']';
+		
+		if (!isset($this->metadata[$set])) {
+			$this->load($set);
+		}
+		if (!isset($this->metadata[$set][$entityid]) ) {
+			throw new Exception('Could not find metadata for entityid [' . $entityid . '] in metadata set [' . $set . ']');
+		}
+		return $this->metadata[$set][$entityid];
+	}
+	
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XML/SAML20/AuthnRequest.php b/lib/SimpleSAML/XML/SAML20/AuthnRequest.php
new file mode 100644
index 000000000..83986d75b
--- /dev/null
+++ b/lib/SimpleSAML/XML/SAML20/AuthnRequest.php
@@ -0,0 +1,195 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_XML_SAML20_AuthnRequest {
+
+	private $configuration = null;
+	private $metadata = 'default.php';
+	
+	private $message = null;
+	private $dom;
+	private $relayState = null;
+	
+	
+	const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0';
+
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	public function setXML($xml) {
+		$this->message = $xml;
+	}
+	
+	public function getXML() {
+		return $this->message;
+	}
+	
+	public function setRelayState($relayState) {
+		$this->relayState = $relayState;
+	}
+	
+	public function getRelayState() {
+		return $this->relayState;
+	}
+	
+	public function getDOM() {
+		if (isset($this->message) ) {
+		
+			/* if (isset($this->dom) && $this->dom != null ) {
+				return $this->dom;
+			} */
+		
+			$token = new DOMDocument();
+			$token->loadXML(str_replace ("\r", "", $this->message));
+			if (empty($token)) {
+				throw new Exception("Unable to load token");
+			}
+			$this->dom = $token;
+			return $this->dom;
+		
+		} 
+		
+		return null;
+	}
+	
+	
+	public function getIssuer() {
+		$dom = $this->getDOM();
+		$issuer = null;
+		
+		if (!$dom instanceof DOMDocument) {
+			throw new Exception("Could not get message DOM in AuthnRequest object");
+		}
+		
+		//print_r($dom->saveXML());
+		
+		if ($issuerNodes = $dom->getElementsByTagName('Issuer')) {
+			if ($issuerNodes->length > 0) {
+				$issuer = $issuerNodes->item(0)->textContent;
+			}
+		}
+		return $issuer;
+	}
+	
+	public function getRequestID() {
+		$dom = $this->getDOM();
+		$requestid = null;
+		
+		if (empty($dom)) {
+			throw new Exception("Could not get message DOM in AuthnRequest object");
+		}
+		
+		$requestelement = $dom->getElementsByTagName('AuthnRequest')->item(0);
+		$requestid = $requestelement->getAttribute('ID');
+		return $requestid;
+		/*
+		if ($issuerNodes = $dom->getElementsByTagName('Issuer')) {
+			if ($issuerNodes->length > 0) {
+				$requestid = $issuerNodes->item(0)->textContent;
+			}
+		}
+		return $requestid;	
+		*/
+	}
+	
+	public function createSession() {
+	
+		
+		$session = SimpleSAML_Session::getInstance();
+		
+		if (!isset($session)) {
+			SimpleSAML_Session::init(self::PROTOCOL, null, false);
+			$session = SimpleSAML_Session::getInstance();
+		}
+
+		$session->setAuthnRequest($this->getRequestID(), $this);
+		
+		/*
+		if (isset($this->relayState)) {
+			$session->setRelayState($this->relayState);
+		}
+		*/
+		return $session;
+	}
+	
+
+	public function generate($spentityid) {
+		$md = $this->metadata->getMetaData($spentityid);
+		
+		$id = self::generateID();
+		$issueInstant = self::generateIssueInstant();
+
+		$assertionConsumerServiceURL = $md['assertionConsumerServiceURL'];
+		$spNameQualifier = $md['spNameQualifier'];
+		$nameidformat = isset($md['NameIDformat']) ? 
+			$md['NameIDformat'] : 
+			'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent';
+		
+		$authnRequest = "<samlp:AuthnRequest  " .
+		  "xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"\n" .
+		  "ID=\"" . $id . "\" " .
+		  "Version=\"2.0\" " .
+		  "IssueInstant=\"" . $issueInstant . "\" " .
+		  "ForceAuthn=\"false\" " .
+		  "IsPassive=\"false\" " .
+		  "ProtocolBinding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" " .
+		  "AssertionConsumerServiceURL=\"" . $assertionConsumerServiceURL . "\">\n" .
+			"<saml:Issuer " .
+			"xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" .
+			  $spentityid .
+			"</saml:Issuer>\n" .
+			"<samlp:NameIDPolicy  " .
+			"xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" " .
+			"Format=\"" . $nameidformat. "\" " .
+			"SPNameQualifier=\"" . $spNameQualifier . "\" " .
+			"AllowCreate=\"true\" />\n" . 
+			"<samlp:RequestedAuthnContext " .
+			"xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" " .
+			"Comparison=\"exact\">" .
+			  "<saml:AuthnContextClassRef " .
+			  "xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" .
+				"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" .
+			  "</saml:AuthnContextClassRef>" .
+			"</samlp:RequestedAuthnContext>\n" .
+		  "</samlp:AuthnRequest>";
+		  
+		return $authnRequest;
+	}
+	
+	public static function generateID() {
+	
+		$length = 42;
+		$key = "_";
+		for ( $i=0; $i < $length; $i++ )
+		{
+			 $key .= dechex( rand(0,15) );
+		}
+		return $key;
+	}
+	
+	public static function generateIssueInstant() {
+		return gmdate("Y-m-d\TH:i:s\Z");
+	}
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XML/SAML20/AuthnResponse.php b/lib/SimpleSAML/XML/SAML20/AuthnResponse.php
new file mode 100644
index 000000000..1e7b18920
--- /dev/null
+++ b/lib/SimpleSAML/XML/SAML20/AuthnResponse.php
@@ -0,0 +1,528 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ă…kre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/AuthnResponse.php');
+
+require_once('xmlseclibs.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse {
+
+	private $configuration = null;
+	private $metadata = 'default.php';
+	
+	private $message = null;
+	private $dom;
+	private $relayState = null;
+	
+	private $validIDs = null;
+	
+	const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0';
+	
+	const TRANSIENT 	= 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
+	const EMAIL 		= 'urn:oasis:names:tc:SAML:2.0:nameid-format:email';
+	
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+
+	
+	public function validate() {
+	
+		$dom = $this->getDOM();
+		
+		/* Create an XML security object, and register ID as the id attribute for sig references. */
+		$objXMLSecDSig = new XMLSecurityDSig();
+		$objXMLSecDSig->idKeys[] = 'ID';
+		
+		/* Locate the signature element to be used. */
+		$objDSig = $objXMLSecDSig->locateSignature($dom);
+		
+
+		/* If no signature element was found, throw an error */
+		if (!$objDSig) {
+			throw new Exception("Could not locate XML Signature element in Authentication Response");
+		}
+		
+		
+		/* Must check certificate fingerprint now - validateReference removes it */        
+		// TODO FIX"!!!
+		if ( ! $this->validateCertFingerprint($objDSig) ) {
+			throw new Exception("Fingerprint Validation Failed");
+		}
+
+		/* Get information about canoncalization in to the xmlsec library. Read from the siginfo part. */
+		$objXMLSecDSig->canonicalizeSignedInfo();
+		
+		$refids = $objXMLSecDSig->getRefIDs();
+		
+		
+		
+		/* Validate refrences */
+		$retVal = $objXMLSecDSig->validateReference();
+		if (! $retVal) {
+			throw new Exception("XMLsec: digest validation failed");
+		}
+
+		$key = NULL;
+		$objKey = $objXMLSecDSig->locateKey();
+	
+		if ($objKey) {
+			if ($objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig)) {
+				/* Handle any additional key processing such as encrypted keys here */
+			}
+		}
+	
+		if (empty($objKey)) {
+			throw new Exception("Error loading key to handle Signature");
+		}
+
+		if (! $objXMLSecDSig->verify($objKey)) {
+			throw new Exception("Unable to validate Signature");
+		}
+		
+		$this->validIDs = $refids;
+		return true;
+	}
+	
+	
+	
+	
+	function validateCertFingerprint($dom) {
+//		$dom = $this->getDOM();
+		$fingerprint = "";
+		
+		
+		// Find the certificate in the document.
+		if ($x509certNodes = $dom->getElementsByTagName('X509Certificate')) {
+			if ($x509certNodes->length > 0) {
+				$x509cert = $x509certNodes->item(0)->textContent;
+				$x509data = base64_decode( $x509cert );
+				$fingerprint = strtolower( sha1( $x509data ) );
+			}
+		}
+	
+		// Get the issuer of the assertion.
+		$issuer = $this->getIssuer();
+		$md = $this->metadata->getMetaData($issuer, 'saml20-idp-remote');
+		
+		/*
+		 * Get fingerprint from saml20-idp-remote metadata...
+		 * 
+		 * Accept fingerprints with or without colons, case insensitive
+		 */
+		$issuerFingerprint = strtolower( str_replace(":", "", $md['certFingerprint']) );
+	
+
+		
+		if (empty($issuerFingerprint)) {
+			throw new Exception("Certificate finger print for entity ID [" . $issuer . "] in metadata was empty.");
+		}
+		if (empty($fingerprint)) {
+			throw new Exception("Certificate finger print in message was empty.");
+		}
+
+		if ($fingerprint != $issuerFingerprint) {
+			echo "Expecting fingerprint $issuerFingerprint but got fingerprint $fingerprint .st";
+		}
+	
+		return ($fingerprint == $issuerFingerprint);
+	}
+	
+	
+	public function createSession() {
+	
+	//($protocol, $message = null, $authenticated = true) {
+		SimpleSAML_Session::init(self::PROTOCOL, $this, true);
+		$session = SimpleSAML_Session::getInstance();
+		$session->setAttributes($this->getAttributes());
+		
+		
+		$nameid = $this->getNameID();
+		
+		$session->setNameID($nameid['NameID']);
+		$session->setNameIDFormat($nameid['Format']);
+		$session->setSessionIndex($this->getSessionIndex());
+		/*
+		$nameID["NameID"] = $node->nodeValue;
+		
+				$nameID["NameQualifier"] = $node->getAttribute('NameQualifier');
+				$nameID["SPNameQualifier"] = $node->getAttribute('SPNameQualifier');
+		*/
+		return $session;
+	}
+	
+	//TODO
+	function getSessionIndex() {
+		$token = $this->getDOM();
+		if ($token instanceof DOMDocument) {
+			$xPath = new DOMXpath($token);
+			$xPath->registerNamespace('mysaml', SAML2_ASSERT_NS);
+			$xPath->registerNamespace('mysamlp', SAML2_PROTOCOL_NS);
+	
+			$query = '/mysamlp:Response/mysaml:Assertion/mysaml:AuthnStatement';
+			$nodelist = $xPath->query($query);
+			if ($node = $nodelist->item(0)) {
+				return $node->getAttribute('SessionIndex');
+			}
+		}
+		return NULL;
+	}
+
+	
+	public function getAttributes() {
+
+
+		$md = $this->metadata->getMetadata($this->getIssuer(), 'saml20-idp-remote');
+		
+		$base64 = isset($md['base64attributes']) ? $md['base64attributes'] : false;
+		
+		define('SAML2_ASSERT_NS', 'urn:oasis:names:tc:SAML:2.0:assertion');
+		define('SAML2_PROTOCOL_NS', 'urn:oasis:names:tc:SAML:2.0:protocol');
+		
+		define('SAML2_BINDINGS_POST', 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST');
+		
+		define('SAML2_STATUS_SUCCESS', 'urn:oasis:names:tc:SAML:2.0:status:Success');
+		
+		/*
+		echo 'Validids<pre>';
+		print_r($this->validIDs);
+		echo '</pre>';
+		*/
+
+		$attributes = array();
+		$token = $this->getDOM();
+		
+		
+		//echo '<pre>' . $this->getXML() . '</pre>';
+		
+		
+		if ($token instanceof DOMDocument) {
+		
+			/*
+			echo "<PRE>token:";
+			echo htmlentities($token->saveXML());
+			echo ":</PRE>";
+			*/
+			
+			$xPath = new DOMXpath($token);
+			$xPath->registerNamespace("mysaml", SAML2_ASSERT_NS);
+			$xPath->registerNamespace("mysamlp", SAML2_PROTOCOL_NS);
+			$query = "/mysamlp:Response/mysaml:Assertion/mysaml:Conditions";
+			$nodelist = $xPath->query($query);
+		
+			if ($node = $nodelist->item(0)) {
+		
+				$start = $node->getAttribute("NotBefore");
+				$end = $node->getAttribute("NotOnOrAfter");
+	
+				if (! SimpleSAML_Utilities::checkDateConditions($start, $end)) {
+					error_log( " Date check failed ... (from $start to $end)");
+		
+					return $attributes;
+				}
+			}
+	
+			$valididqueries = array();
+			foreach ($this->validIDs AS $vid) {
+				$valididqueries[] = "@ID='" . $vid . "'";
+			}
+			$valididquery = join(' or ', $valididqueries);
+			
+	
+			foreach (
+				array(
+					"/mysamlp:Response[" . $valididquery . "]/mysaml:Assertion/mysaml:AttributeStatement/mysaml:Attribute",
+					"/mysamlp:Response/mysaml:Assertion[" . $valididquery . "]/mysaml:AttributeStatement/mysaml:Attribute") AS $query) {
+		
+//				echo 'performing query : ' . $query;
+		
+//				$query = "/mysamlp:Response[" . $valididquery . "]/mysaml:Assertion/mysaml:AttributeStatement/mysaml:Attribute";
+				$nodelist = $xPath->query($query);
+				
+
+				
+//				if (is_array($nodelist)) {
+					
+
+					foreach ($nodelist AS $node) {
+
+						if ($name = $node->getAttribute("Name")) {
+//							echo "Name ";
+							$value = array();
+							foreach ($node->childNodes AS $child) {
+								if ($child->localName == "AttributeValue") {
+									$newvalue = $child->textContent;
+									if ($base64) {
+										$values = explode('_', $newvalue);
+										foreach($values AS $v) {
+											$value[] = base64_decode($v);
+										}
+									} else {
+		
+										$value[] = $newvalue;
+									}
+								}
+							}
+							$attributes[$name] = $value;
+						}
+					}
+					
+//				}
+				
+			}
+			
+			
+			
+		}
+/*
+		echo '<p>Attributes<pre>';
+		print_r($attributes);
+		echo '</pre>';
+*/
+		return $attributes;
+	}
+
+	
+	public function getIssuer() {
+		$dom = $this->getDOM();
+		$issuer = null;
+		if ($issuerNodes = $dom->getElementsByTagName('Issuer')) {
+			if ($issuerNodes->length > 0) {
+				$issuer = $issuerNodes->item(0)->textContent;
+			}
+		}
+		return $issuer;
+	}
+	
+	public function getNameID() {
+		
+		$dom = $this->getDOM();
+		$nameID = array();
+		
+		if ($dom instanceof DOMDocument) {
+			$xPath = new DOMXpath($dom);
+			$xPath->registerNamespace('mysaml', SAML2_ASSERT_NS);
+			$xPath->registerNamespace('mysamlp', SAML2_PROTOCOL_NS);
+	
+			$query = '/mysamlp:Response/mysaml:Assertion/mysaml:Subject/mysaml:NameID';
+			$nodelist = $xPath->query($query);
+			if ($node = $nodelist->item(0)) {
+
+				$nameID["NameID"] = $node->nodeValue;
+				$nameID["NameQualifier"] = $node->getAttribute('NameQualifier');
+				$nameID["SPNameQualifier"] = $node->getAttribute('SPNameQualifier');
+				$nameID["Format"] = $node->getAttribute('Format');
+			}
+		}
+		//echo '<pre>'; print_r($nameID); echo '</pre>';
+		return $nameID;
+	}
+	
+
+	// Not updated for response. from request.
+	public function generate($idpentityid, $spentityid, $inresponseto, $nameid, $attributes) {
+	
+		//echo 'idp:' . $idpentityid . ' sp:' . $spentityid .' inresponseto:' .  $inresponseto . ' namid:' . $nameid;
+	
+		$idpmd 	= $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted');
+		$spmd 	= $this->metadata->getMetaData($spentityid, 'saml20-sp-remote');
+		
+		$id = self::generateID();
+		$issueInstant = self::generateIssueInstant();
+		$assertionExpire = self::generateIssueInstant(60 * 5); # 5 minutes
+		$notBefore = self::generateIssueInstant(-30);
+		
+		$assertionid = self::generateID();
+		$sessionindex = self::generateID();
+		
+
+		$issuer = $idpentityid;
+
+		$assertionConsumerServiceURL = $spmd['assertionConsumerServiceURL'];
+		$spNameQualifier = $spmd['spNameQualifier'];
+		
+		$destination = $spmd['assertionConsumerServiceURL'];
+		
+		$base64 = isset($idpmd['base64attributes']) ? $idpmd['base64attributes'] : false;
+		
+		$encodedattributes = '';
+		foreach ($attributes AS $name => $value) {
+			$encodedattributes .= $this->enc_attribute($name, $value[0], $base64);
+		}
+		$attributestatement = '<saml:AttributeStatement>' . $encodedattributes . '</saml:AttributeStatement>';
+		
+		if (!$spmd['simplesaml.attributes']) 
+			$attributestatement = '';
+		
+		$namid = null;
+		if ($spmd['NameIDFormat'] == self::EMAIL) {
+			$nameid = $this->generateNameID($spmd['NameIDFormat'], $attributes[$spmd['simplesaml.nameidattribute']][0]);
+		} else {
+			$nameid = $this->generateNameID($spmd['NameIDFormat'], self::generateID(), $issuer, $spNameQualifier);
+		}
+		
+		/*
+		$authnResponse = '<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+    ID="' . $id . '"
+    InResponseTo="' . $inresponseto. '" Version="2.0"
+    IssueInstant="' . $issueInstant . '"
+    Destination="' . $destination . '">
+    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . $issuer . '</saml:Issuer>
+    <samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
+        <samlp:StatusCode xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+            Value="urn:oasis:names:tc:SAML:2.0:status:Success"> </samlp:StatusCode>
+    </samlp:Status>
+    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0"
+        ID="' . $assertionid . '" IssueInstant="' . $issueInstant . '">
+        <saml:Issuer>' . $issuer . '</saml:Issuer>
+        <saml:Subject>
+            <saml:NameID NameQualifier="' . $issuer . '" SPNameQualifier="'. $spentityid. '"
+                Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+                >' . $nameid. '</saml:NameID>
+            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+                <saml:SubjectConfirmationData NotOnOrAfter="' . $assertionExpire . '"
+                    InResponseTo="' . $inresponseto. '"
+                    Recipient="' . $destination . '"/>
+            </saml:SubjectConfirmation>
+        </saml:Subject>
+        <saml:Conditions NotBefore="' . $issueInstant. '" NotOnOrAfter="' . $assertionExpire. '">
+            <saml:AudienceRestriction>
+                <saml:Audience>' . $spentityid . '</saml:Audience>
+            </saml:AudienceRestriction>
+        </saml:Conditions>
+        <saml:AuthnStatement AuthnInstant="' . $issueInstant . '"
+            SessionIndex="' . $sessionindex . '">
+            <saml:AuthnContext>
+                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
+            </saml:AuthnContext>
+        </saml:AuthnStatement>
+        <saml:AttributeStatement>
+            ' . $encodedattributes . '
+        </saml:AttributeStatement>
+    </saml:Assertion>
+</samlp:Response>
+';
+
+		
+		$authnResponse = '<samlp:Response 
+    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" 
+    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" 
+    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" 
+    ID="' . $id . '" 
+    IssueInstant="' . $issueInstant . '" 
+Version="2.0"> 
+
+    <samlp:Status>
+       <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /> 
+    </samlp:Status> 
+    <saml:Assertion ID="' . $assertionid . '" 
+       IssueInstant="' . $issueInstant . '" 
+       Version="2.0"> 
+        <saml:Issuer>' . $issuer . '</saml:Issuer>
+       <saml:Subject> 
+          <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">test</saml:NameID> 
+          <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer" /> 
+       </saml:Subject> 
+       <saml:Conditions NotBefore="' . $notBefore. '" NotOnOrAfter="' . $assertionExpire. '"></saml:Conditions> 
+       <saml:AuthnStatement AuthnInstant="' . $issueInstant. '"> 
+          <saml:AuthnContext> 
+             <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> 
+          </saml:AuthnContext> 
+       </saml:AuthnStatement>
+    </saml:Assertion>
+</samlp:Response> 
+';
+*/
+		$authnResponse = '<samlp:Response 
+			xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" 
+			xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" 
+			ID="' . $id . '"
+			InResponseTo="' . $inresponseto. '" Version="2.0"
+			IssueInstant="' . $issueInstant . '"
+			Destination="' . $destination . '">
+	<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . $issuer . '</saml:Issuer>
+	<samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
+		<samlp:StatusCode xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+			Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
+	</samlp:Status>
+	<saml:Assertion Version="2.0"
+		ID="' . $assertionid . '" IssueInstant="' . $issueInstant . '">
+		<saml:Issuer>' . $issuer . '</saml:Issuer>
+		<saml:Subject>
+			' . $nameid . ' 
+			<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+				<saml:SubjectConfirmationData NotOnOrAfter="' . $assertionExpire . '"
+					InResponseTo="' . $inresponseto. '"
+					Recipient="' . $destination . '"/>
+			</saml:SubjectConfirmation>
+		</saml:Subject>
+		<saml:Conditions NotBefore="' . $notBefore. '" NotOnOrAfter="' . $assertionExpire. '">
+            <saml:AudienceRestriction>
+                <saml:Audience>' . $spentityid . '</saml:Audience>
+            </saml:AudienceRestriction>
+		</saml:Conditions> 
+		<saml:AuthnStatement AuthnInstant="' . $issueInstant . '"
+			SessionIndex="' . $sessionindex . '">
+			<saml:AuthnContext>
+				<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
+			</saml:AuthnContext>
+        </saml:AuthnStatement>
+        ' . $attributestatement. '
+    </saml:Assertion>
+</samlp:Response>
+';
+
+
+//echo $authnResponse;
+
+
+		//  echo $authnResponse; exit(0);
+		return $authnResponse;
+	}
+
+
+	private function generateNameID($type = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient', 
+			$value = 'anonymous', $namequalifier = null, $spnamequalifier = null) {
+			
+		if ($type == self::EMAIL) {
+			return '<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">' . $value . '</saml:NameID>';
+
+		} else {
+			return '<saml:NameID NameQualifier="' . $namequalifier . '" SPNameQualifier="'. $spnamequalifier. '"
+                Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+                >' . $value. '</saml:NameID>';
+		}
+		
+	}
+
+	
+	private function enc_attribute($name,$value, $base64 = false) {
+		return '<saml:Attribute Name="' . $name. '">
+                <saml:AttributeValue xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+                >' . ($base64 ? base64_encode($value) : htmlspecialchars($value) ) . '</saml:AttributeValue>
+            </saml:Attribute>';
+	}
+	
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XML/SAML20/LogoutRequest.php b/lib/SimpleSAML/XML/SAML20/LogoutRequest.php
new file mode 100644
index 000000000..8dfb35d6a
--- /dev/null
+++ b/lib/SimpleSAML/XML/SAML20/LogoutRequest.php
@@ -0,0 +1,182 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_XML_SAML20_LogoutRequest {
+
+	private $configuration = null;
+	private $metadata = null;
+	
+	private $message = null;
+	private $dom;
+	private $relayState = null;
+	
+	
+	const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0';
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	public function setXML($xml) {
+		$this->message = $xml;
+	}
+	
+	public function getXML() {
+		return $this->message;
+	}
+	
+	public function setRelayState($relayState) {
+		$this->relayState = $relayState;
+	}
+	
+	public function getRelayState() {
+		return $this->relayState;
+	}
+	
+	public function getDOM() {
+		if (isset($this->message) ) {
+		
+			/* if (isset($this->dom) && $this->dom != null ) {
+				return $this->dom;
+			} */
+		
+			$token = new DOMDocument();
+			$token->loadXML(str_replace ("\r", "", $this->message));
+			if (empty($token)) {
+				throw new Exception("Unable to load token");
+			}
+			$this->dom = $token;
+			return $this->dom;
+		
+		} 
+		
+		return null;
+	}
+	
+	
+	public function getIssuer() {
+		$dom = $this->getDOM();
+		$issuer = null;
+		
+		if (!$dom instanceof DOMDocument) {
+			throw new Exception("Could not get message DOM in AuthnRequest object");
+		}
+		
+		//print_r($dom->saveXML());
+		
+		if ($issuerNodes = $dom->getElementsByTagName('Issuer')) {
+			if ($issuerNodes->length > 0) {
+				$issuer = $issuerNodes->item(0)->textContent;
+			}
+		}
+		return $issuer;
+	}
+	
+	public function getRequestID() {
+		$dom = $this->getDOM();
+		$requestid = null;
+		
+		if (empty($dom)) {
+			throw new Exception("Could not get message DOM in AuthnRequest object");
+		}
+		
+		$requestelement = $dom->getElementsByTagName('LogoutRequest')->item(0);
+		$requestid = $requestelement->getAttribute('ID');
+		return $requestid;
+		/*
+		if ($issuerNodes = $dom->getElementsByTagName('Issuer')) {
+			if ($issuerNodes->length > 0) {
+				$requestid = $issuerNodes->item(0)->textContent;
+			}
+		}
+		return $requestid;	
+		*/
+	}
+	
+
+
+	public function generate($issuer, $receiver, $nameid, $nameidformat, $sessionindex, $mode) {
+	
+		if (!in_array($mode, array('SP', 'IdP'))) {
+			throw new Exception('mode parameter of generate() must be either SP or IdP');
+		}
+		if ($mode == 'IdP') {
+			$issuerset = 'saml20-idp-hosted';
+			$receiverset = 'saml20-sp-remote';
+		} else {
+			$issuerset = 'saml20-sp-hosted';
+			$receiverset = 'saml20-idp-remote';
+		}
+	
+		$issuermd 	= $this->metadata->getMetaData($issuer, $issuerset);
+		$receivermd = $this->metadata->getMetaData($receiver, $receiverset);
+		
+		$id = self::generateID();
+		$issueInstant = self::generateIssueInstant();
+
+		$destination = $receivermd['SingleLogOutUrl'];
+
+/*
+		$spNameQualifier = $md['spNameQualifier'];
+		$nameidformat = isset($md['NameIDformat']) ? 
+			$md['NameIDformat'] : 
+			'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent';
+	*/	
+		$logoutRequest = "<samlp:LogoutRequest " .
+      "xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" " . 
+      "ID=\"" . $id . "\" " .
+      "Version=\"2.0\" " .
+      "IssueInstant=\"" . $issueInstant . "\"> " .
+        "<saml:Issuer " . 
+        "xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" .
+          $issuer .
+        "</saml:Issuer>" .
+        "<saml:NameID " . 
+        "xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" " . 
+//        "NameQualifier=\"" . $nameId["NameQualifier"] . "\" " . 
+//        "SPNameQualifier=\"" . $nameId["SPNameQualifier"] . "\" " . 
+        "Format=\"" .  $nameidformat. "\">" . 
+          $nameid . 
+        "</saml:NameID>" . 
+        "<samlp:SessionIndex " .
+        "xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">" . 
+          $sessionindex .
+        "</samlp:SessionIndex>" .
+      "</samlp:LogoutRequest>";
+		  
+		return $logoutRequest;
+	}
+	
+	public static function generateID() {
+	
+		$length = 42;
+		$key = "_";
+		for ( $i=0; $i < $length; $i++ )
+		{
+			 $key .= dechex( rand(0,15) );
+		}
+		return $key;
+	}
+	
+	public static function generateIssueInstant() {
+		return gmdate("Y-m-d\TH:i:s\Z");
+	}
+
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XML/SAML20/LogoutResponse.php b/lib/SimpleSAML/XML/SAML20/LogoutResponse.php
new file mode 100644
index 000000000..c83cde719
--- /dev/null
+++ b/lib/SimpleSAML/XML/SAML20/LogoutResponse.php
@@ -0,0 +1,152 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+
+require_once('xmlseclibs.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_XML_SAML20_LogoutResponse {
+
+	private $configuration = null;
+	private $metadata = null;
+	
+	private $message = null;
+	private $dom;
+	private $relayState = null;
+	
+	const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0';
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	public function setXML($xml) {
+		$this->message = $xml;
+	}
+	
+	public function getXML() {
+		return $this->message;
+	}
+	
+	public function setRelayState($relayState) {
+		$this->relayState = $relayState;
+	}
+	
+	public function getRelayState() {
+		return $this->relayState;
+	}
+	
+	public function getDOM() {
+		if (isset($this->message) ) {
+			
+			/*
+			if (isset($this->dom)) {
+				return $this->dom;
+			}
+			*/
+		
+			$token = new DOMDocument();
+			$token->loadXML(str_replace ("\r", "", $this->message));
+			if (empty($token)) {
+				throw new Exception("Unable to load token");
+			}
+			$this->dom = $token;
+			return $this->dom;
+		
+		} 
+		
+		return null;
+	}
+	
+
+	
+	public function getIssuer() {
+		$dom = $this->getDOM();
+		$issuer = null;
+		if ($issuerNodes = $dom->getElementsByTagName('Issuer')) {
+			if ($issuerNodes->length > 0) {
+				$issuer = $issuerNodes->item(0)->textContent;
+			}
+		}
+		return $issuer;
+	}
+
+
+	// Not updated for response. from request.
+	public function generate($issuer, $receiver, $inresponseto, $mode ) {
+		if (!in_array($mode, array('SP', 'IdP'))) {
+			throw new Exception('mode parameter of generate() must be either SP or IdP');
+		}
+		if ($mode == 'IdP') {
+			$issuerset = 'saml20-idp-hosted';
+			$receiverset = 'saml20-sp-remote';
+		} else {
+			$issuerset = 'saml20-sp-hosted';
+			$receiverset = 'saml20-idp-remote';
+		}
+		
+	
+		//echo 'idp:' . $idpentityid . ' sp:' . $spentityid .' inresponseto:' .  $inresponseto . ' namid:' . $nameid;
+	
+		$issuermd 	= $this->metadata->getMetaData($issuer, $issuerset);
+		$receivermd = $this->metadata->getMetaData($receiver, $receiverset);
+		
+		$id = self::generateID();
+		$issueInstant = self::generateIssueInstant();
+
+		$destination = $receivermd['SingleLogOutUrl'];
+		
+		$samlResponse = '<samlp:LogoutResponse  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+ID="_' . $id . '" Version="2.0" IssueInstant="' . $issueInstant . '" Destination="'. $destination. '" InResponseTo="' . $inresponseto . '">
+<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . $issuer . '</saml:Issuer>
+<samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
+<samlp:StatusCode  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+Value="urn:oasis:names:tc:SAML:2.0:status:Success">
+</samlp:StatusCode>
+<samlp:StatusMessage xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
+Successfully logged out from service ' . $issuer . '
+</samlp:StatusMessage>
+</samlp:Status>
+</samlp:LogoutResponse>';
+
+		return $samlResponse;
+	}
+
+
+	
+	
+	public static function generateID() {
+	
+		$length = 42;
+		$key = "_";
+		for ( $i=0; $i < $length; $i++ )
+		{
+			 $key .= dechex( rand(0,15) );
+		}
+		return $key;
+	}
+	
+	public static function generateIssueInstant($offset = 0) {
+		return gmdate("Y-m-d\TH:i:s\Z", time() + $offset);
+	}
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XML/Shib13/AuthnRequest.php b/lib/SimpleSAML/XML/Shib13/AuthnRequest.php
new file mode 100644
index 000000000..ef7c0c9aa
--- /dev/null
+++ b/lib/SimpleSAML/XML/Shib13/AuthnRequest.php
@@ -0,0 +1,114 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_XML_Shib13_AuthnRequest {
+
+	private $configuration = null;
+	private $metadata = null;
+	
+	private $issuer = null;
+	private $relayState = null;
+	
+	private $requestid = null;
+	
+	
+	const PROTOCOL = 'shibboleth';
+
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	public function setRelayState($relayState) {
+		$this->relayState = $relayState;
+	}
+	
+	public function getRelayState() {
+		return $this->relayState;
+	}
+	
+	public function setIssuer($issuer) {
+		$this->issuer = $issuer;
+	}
+	public function getIssuer() {
+		return $this->issuer;
+	}
+	
+
+
+	public function parseGet($get) {
+		return null;
+	}
+	
+	public function setNewRequestID() {	
+		$this->requestid = $this->generateID();
+	}
+	
+	public function getRequestID() {
+		return $this->requestid;
+	}
+	
+	public function createSession() {
+		
+		$session = SimpleSAML_Session::getInstance();
+		
+		if (!isset($session)) {
+			SimpleSAML_Session::init(self::PROTOCOL);
+			$session = SimpleSAML_Session::getInstance();
+		}
+
+		$session->setAuthnRequest($this->getRequestID(), $this);
+		
+		/*
+		if (isset($this->relayState)) {
+			$session->setRelayState($this->relayState);
+		}
+		*/
+		return $session;
+	}
+	
+	public function createRedirect($destination) {
+		$idpmetadata = $this->metadata->getMetaData($destination, 'shib13-idp-remote');
+		$spmetadata = $this->metadata->getMetaData($this->getIssuer(), 'shib13-sp-hosted');
+	
+		$desturl = $idpmetadata['SingleSignOnUrl'];
+		$shire = $spmetadata['AssertionConsumerService'];
+		$target = $this->getRelayState();
+		
+		$url = $desturl . '?' .
+	    	'providerId=' . urlencode($this->getIssuer()) .
+		    '&shire=' . urlencode($shire) .
+		    (isset($target) ? '&target=' . urlencode($target) : '');
+		return $url;
+	}
+	
+	public static function generateID() {
+		$length = 42;
+		$key = "_";
+		for ( $i=0; $i < $length; $i++ ) {
+			 $key .= dechex( rand(0,15) );
+		}
+		return $key;
+	}
+	
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/XML/Shib13/AuthnResponse.php b/lib/SimpleSAML/XML/Shib13/AuthnResponse.php
new file mode 100644
index 000000000..22412500c
--- /dev/null
+++ b/lib/SimpleSAML/XML/Shib13/AuthnResponse.php
@@ -0,0 +1,398 @@
+<?php
+
+
+/**
+ * SimpleSAMLphp
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
+ */
+ 
+require_once('SimpleSAML/Configuration.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/AuthnResponse.php');
+
+require_once('xmlseclibs.php');
+ 
+/**
+ * Configuration of SimpleSAMLphp
+ */
+class SimpleSAML_XML_Shib13_AuthnResponse extends SimpleSAML_XML_AuthnResponse {
+
+	private $configuration = null;
+	private $metadata = 'default.php';
+	
+	private $message = null;
+	private $dom;
+	private $relayState = null;
+	
+	private $validIDs = null;
+	
+	const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0';
+	const SHIB_PROTOCOL_NS = 'urn:oasis:names:tc:SAML:1.0:protocol';
+	const SHIB_ASSERT_NS = 'urn:oasis:names:tc:SAML:1.0:assertion';
+
+	function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_XML_MetaDataStore $metadatastore) {
+		$this->configuration = $configuration;
+		$this->metadata = $metadatastore;
+	}
+	
+	// Inhereted public function setXML($xml) {
+	// Inhereted public function getXML() {
+	// Inhereted public function setRelayState($relayState) {
+	// Inhereted public function getRelayState() {
+
+	
+	public function validate() {
+	
+		$dom = $this->getDOM();
+		
+		/* Create an XML security object, and register ID as the id attribute for sig references. */
+		$objXMLSecDSig = new XMLSecurityDSig();
+		$objXMLSecDSig->idKeys[] = 'ResponseID';
+		
+		/* Locate the signature element to be used. */
+		$objDSig = $objXMLSecDSig->locateSignature($dom);
+		
+
+		/* If no signature element was found, throw an error */
+		if (!$objDSig) {
+			throw new Exception("Could not locate XML Signature element in Authentication Response");
+		}
+		
+		
+		/* Must check certificate fingerprint now - validateReference removes it */        
+		// TODO FIX"!!!
+		if ( ! $this->validateCertFingerprint($objDSig) ) {
+			throw new Exception("Fingerprint Validation Failed");
+		}
+
+		/* Get information about canoncalization in to the xmlsec library. Read from the siginfo part. */
+		$objXMLSecDSig->canonicalizeSignedInfo();
+		
+		$refids = $objXMLSecDSig->getRefIDs();
+		
+		
+		
+		/* Validate refrences */
+		$retVal = $objXMLSecDSig->validateReference();
+		if (! $retVal) {
+			throw new Exception("XMLsec: digest validation failed");
+		}
+
+		$key = NULL;
+		$objKey = $objXMLSecDSig->locateKey();
+	
+		if ($objKey) {
+			if ($objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig)) {
+				/* Handle any additional key processing such as encrypted keys here */
+			}
+		}
+	
+		if (empty($objKey)) {
+			throw new Exception("Error loading key to handle Signature");
+		}
+
+		if (! $objXMLSecDSig->verify($objKey)) {
+			throw new Exception("Unable to validate Signature");
+		}
+		
+		$this->validIDs = $refids;
+		return true;
+	}
+	
+	
+	
+	
+	function validateCertFingerprint($dom) {
+//		$dom = $this->getDOM();
+		$fingerprint = "";
+		
+		
+		// Find the certificate in the document.
+		if ($x509certNodes = $dom->getElementsByTagName('X509Certificate')) {
+			if ($x509certNodes->length > 0) {
+				$x509cert = $x509certNodes->item(0)->textContent;
+				$x509data = base64_decode( $x509cert );
+				$fingerprint = strtolower( sha1( $x509data ) );
+			}
+		}
+	
+		// Get the issuer of the assertion.
+		$issuer = $this->getIssuer();
+		
+		//echo 'found issuer: ' . $this->getIssuer();
+		$md = $this->metadata->getMetaData($issuer, 'shib13-idp-remote');
+		
+		/*
+		 * Get fingerprint from saml20-idp-remote metadata...
+		 * 
+		 * Accept fingerprints with or without colons, case insensitive
+		 */
+		$issuerFingerprint = strtolower( str_replace(":", "", $md['certFingerprint']) );
+	
+		//echo 'issuer fingerprint: ' . $issuerFingerprint;
+		
+		if (empty($issuerFingerprint)) {
+			throw new Exception("Certificate finger print for entity ID [" . $issuer . "] in metadata was empty.");
+		}
+		if (empty($fingerprint)) {
+			throw new Exception("Certificate finger print in message was empty.");
+		}
+
+		if ($fingerprint != $issuerFingerprint) {
+			throw new Exception("Expecting certificate fingerprint [$issuerFingerprint] but got [$fingerprint]");
+		}
+	
+		return ($fingerprint == $issuerFingerprint);
+	}
+	
+	
+	public function createSession() {
+	
+		SimpleSAML_Session::init(self::PROTOCOL, $this, true);
+		$session = SimpleSAML_Session::getInstance();
+		$session->setAttributes($this->getAttributes());
+		
+		$nameid = $this->getNameID();
+		
+		$session->setNameID($nameid['NameID']);
+		$session->setNameIDFormat($nameid['Format']);
+		$session->setSessionIndex($this->getSessionIndex());
+		/*
+		$nameID["NameID"] = $node->nodeValue;
+		
+				$nameID["NameQualifier"] = $node->getAttribute('NameQualifier');
+				$nameID["SPNameQualifier"] = $node->getAttribute('SPNameQualifier');
+		*/
+		return $session;
+	}
+	
+	//TODO
+	function getSessionIndex() {
+		$token = $this->getDOM();
+		if ($token instanceof DOMDocument) {
+			$xPath = new DOMXpath($token);
+			$xPath->registerNamespace('mysamlp', self::SHIB_PROTOCOL_NS);
+			$xPath->registerNamespace('mysaml', self::SHIB_ASSERT_NS);
+			
+			$query = '/mysamlp:Response/mysaml:Assertion/mysaml:AuthnStatement';
+			$nodelist = $xPath->query($query);
+			if ($node = $nodelist->item(0)) {
+				return $node->getAttribute('SessionIndex');
+			}
+		}
+		return NULL;
+	}
+
+	
+	public function getAttributes() {
+
+
+		$md = $this->metadata->getMetadata($this->getIssuer(), 'shib13-idp-remote');
+		
+		//$base64 = isset($md['base64attributes']) ? $md['base64attributes'] : false;
+		
+		/*
+		define('SAML2_BINDINGS_POST', 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST');
+		define('SAML2_STATUS_SUCCESS', 'urn:oasis:names:tc:SAML:2.0:status:Success');
+		*/
+		
+		/*
+		echo 'Validids<pre>';
+		print_r($this->validIDs);
+		echo '</pre>';
+		*/
+
+		$attributes = array();
+		$token = $this->getDOM();
+			
+		
+		//echo $this->getXML();
+		
+		$attributes = array();
+		
+		if ($token instanceof DOMDocument) {
+		
+			$sxml = simplexml_import_dom($token);
+			
+			$sxml->registerXPathNamespace('samlp', self::SHIB_PROTOCOL_NS);
+			$sxml->registerXPathNamespace('saml', self::SHIB_ASSERT_NS);
+			
+
+			
+			$assertions = $sxml->xpath('/samlp:Response[@ResponseID="' . $this->validIDs[0] . '"]/saml:Assertion');
+
+			foreach ($assertions AS $assertion) {				
+
+				if ($assertion->Conditions) {
+
+					if (($start = (string)$assertion->Conditions['NotBefore']) &&
+						($end = (string)$assertion->Conditions['NotOnOrAfter'])) {
+	
+						if (! SimpleSAML_Utilities::checkDateConditions($start, $end)) {
+							error_log( " Date check failed ... (from $start to $end)");
+							next;
+						} 
+
+					}
+
+				}
+				
+				if (isset($assertion->AttributeStatement->Attribute)) {
+					foreach ($assertion->AttributeStatement->Attribute AS $attribute) {
+						$values = array();
+						foreach ($attribute->AttributeValue AS $val) {
+							$values[] = (string) $val;
+						}
+						
+						$attributes[(string)$attribute['AttributeName']] = $values;
+					}
+				}
+				
+			}
+		
+		
+			/*
+			echo "<PRE>token:";
+			echo htmlentities($token->saveXML());
+			echo ":</PRE>";
+			*/
+			/*
+			echo '<pre>Attributes: ';
+			print_r($attributes);
+			echo '</pre>';
+	*/
+		}
+		return $attributes;
+		
+		
+	}
+
+	
+	public function getIssuer() {
+	
+		$token = $this->getDOM();
+		$xPath = new DOMXpath($token);
+		$xPath->registerNamespace('mysamlp', self::SHIB_PROTOCOL_NS);
+		$xPath->registerNamespace('mysaml', self::SHIB_ASSERT_NS);
+
+		$query = '/mysamlp:Response/mysaml:Assertion/@Issuer';
+		$nodelist = $xPath->query($query);
+
+		if ($attr = $nodelist->item(0)) {
+			return $attr->value;
+		} else {
+			throw Exception('Could not find Issuer field in Authentication response');
+		}
+
+	}
+	
+	public function getNameID() {
+		
+		
+		$token = $this->getDOM();
+		$nameID = array();
+		if ($token instanceof DOMDocument) {
+			$xPath = new DOMXpath($token);
+			$xPath->registerNamespace('mysamlp', self::SHIB_PROTOCOL_NS);
+			$xPath->registerNamespace('mysaml', self::SHIB_ASSERT_NS);
+	
+			$query = '/mysamlp:Response/mysaml:Assertion/mysaml:AuthenticationStatement/mysaml:Subject/mysaml:NameIdentifier';
+			$nodelist = $xPath->query($query);
+			if ($node = $nodelist->item(0)) {
+				$nameID["NameID"] = $node->nodeValue;
+				$nameID["Format"] = $node->getAttribute('Format');
+				$nameID["NameQualifier"] = $node->getAttribute('NameQualifier');
+			}
+		}
+		return $nameID;
+
+	}
+	
+
+	// Not updated for response. from request.
+	public function generate($idpentityid, $spentityid, $inresponseto, $nameid, $attributes) {
+	
+		//echo 'idp:' . $idpentityid . ' sp:' . $spentityid .' inresponseto:' .  $inresponseto . ' namid:' . $nameid;
+	
+		$idpmd 	= $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted');
+		$spmd 	= $this->metadata->getMetaData($spentityid, 'saml20-sp-remote');
+		
+		$id = self::generateID();
+		$issueInstant = self::generateIssueInstant();
+		$assertionExpire = self::generateIssueInstant(60 * 5); # 5 minutes
+		
+		$assertionid = self::generateID();
+		$sessionindex = self::generateID();
+		
+		if (is_null($nameid)) {
+			$nameid = self::generateID();
+		}
+
+		$issuer = $idpentityid;
+
+		$assertionConsumerServiceURL = $spmd['assertionConsumerServiceURL'];
+		$spNameQualifier = $spmd['spNameQualifier'];
+		
+		$destination = $spmd['assertionConsumerServiceURL'];
+		
+		$encodedattributes = '';
+		foreach ($attributes AS $name => $value) {
+			$encodedattributes .= $this->enc_attribute($name, $value[0], true);
+		}
+		
+		$authnResponse = '<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+    ID="' . $id . '"
+    InResponseTo="' . $inresponseto. '" Version="2.0"
+    IssueInstant="' . $issueInstant . '"
+    Destination="' . $destination . '">
+    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . $issuer . '</saml:Issuer>
+    <samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
+        <samlp:StatusCode xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+            Value="urn:oasis:names:tc:SAML:2.0:status:Success"> </samlp:StatusCode>
+    </samlp:Status>
+    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0"
+        ID="' . $assertionid . '" IssueInstant="' . $issueInstant . '">
+        <saml:Issuer>' . $issuer . '</saml:Issuer>
+        <saml:Subject>
+            <saml:NameID NameQualifier="' . $issuer . '" SPNameQualifier="'. $spentityid. '"
+                Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+                >' . $nameid. '</saml:NameID>
+            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+                <saml:SubjectConfirmationData NotOnOrAfter="' . $assertionExpire . '"
+                    InResponseTo="' . $inresponseto. '"
+                    Recipient="' . $destination . '"/>
+            </saml:SubjectConfirmation>
+        </saml:Subject>
+        <saml:Conditions NotBefore="' . $issueInstant. '" NotOnOrAfter="' . $assertionExpire. '">
+            <saml:AudienceRestriction>
+                <saml:Audience>' . $spentityid . '</saml:Audience>
+            </saml:AudienceRestriction>
+        </saml:Conditions>
+        <saml:AuthnStatement AuthnInstant="' . $issueInstant . '"
+            SessionIndex="' . $sessionindex . '">
+            <saml:AuthnContext>
+                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
+            </saml:AuthnContext>
+        </saml:AuthnStatement>
+        <saml:AttributeStatement>
+            ' . $encodedattributes . '
+        </saml:AttributeStatement>
+    </saml:Assertion>
+</samlp:Response>
+';
+		  
+		return $authnResponse;
+	}
+
+
+	
+
+	
+}
+
+?>
\ No newline at end of file
diff --git a/lib/xmlseclibs.php b/lib/xmlseclibs.php
new file mode 100644
index 000000000..f441eafd9
--- /dev/null
+++ b/lib/xmlseclibs.php
@@ -0,0 +1,1387 @@
+<?php 
+/**
+ * xmlseclibs.php
+ *
+ * Copyright (c) 2007, Robert Richards <rrichards@ctindustries.net>.
+ * 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 Robert Richards nor the names of his
+ *     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.
+ *
+ * @author     Robert Richards <rrichards@ctindustries.net>
+ * @copyright  2007 Robert Richards <rrichards@ctindustries.net>
+ * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
+ * @version    1.0.0
+ */
+ 
+/*
+Functions to generate simple cases of Exclusive Canonical XML - Callable function is C14NGeneral() 
+i.e.: $canonical = C14NGeneral($domelement, TRUE);
+*/
+
+/* helper function */
+function sortAndAddAttrs($element, $arAtts) {
+   $newAtts = array();
+   foreach ($arAtts AS $attnode) {
+      $newAtts[$attnode->nodeName] = $attnode;
+   }
+   ksort($newAtts);
+   foreach ($newAtts as $attnode) {
+      $element->setAttribute($attnode->nodeName, $attnode->nodeValue);
+   }
+}
+
+/* helper function */
+function canonical($tree, $element, $withcomments) {
+	if ($tree->nodeType != XML_DOCUMENT_NODE) {
+		$dom = $tree->ownerDocument;
+	} else {
+		$dom = $tree;
+	}
+	if ($element->nodeType != XML_ELEMENT_NODE) {
+		if ($element->nodeType == XML_COMMENT_NODE && ! $withcomments) {
+			return;
+		}
+		$tree->appendChild($dom->importNode($element, TRUE));
+		return;
+	}
+	$arNS = array();
+	if ($element->namespaceURI != "") {
+		if ($element->prefix == "") {
+			$elCopy = $dom->createElementNS($element->namespaceURI, $element->nodeName);
+		} else {
+			$prefix = $tree->lookupPrefix($element->namespaceURI);
+			if ($prefix == $element->prefix) {
+				$elCopy = $dom->createElementNS($element->namespaceURI, $element->nodeName);
+			} else {
+				$elCopy = $dom->createElement($element->nodeName);
+				$arNS[$element->namespaceURI] = $element->prefix;
+			}
+		}
+	} else {
+		$elCopy = $dom->createElement($element->nodeName);
+	}
+	$tree->appendChild($elCopy);
+
+	/* Create DOMXPath based on original document */
+	$xPath = new DOMXPath($element->ownerDocument);
+
+	/* Get namespaced attributes */
+	$arAtts = $xPath->query('attribute::*[namespace-uri(.) != ""]', $element);
+
+	/* Create an array with namespace URIs as keys, and sort them */
+	foreach ($arAtts AS $attnode) {
+		if (array_key_exists($attnode->namespaceURI, $arNS) && 
+			($arNS[$attnode->namespaceURI] == $attnode->prefix)) {
+			continue;
+		}
+		$prefix = $tree->lookupPrefix($attnode->namespaceURI);
+		if ($prefix != $attnode->prefix) {
+		   $arNS[$attnode->namespaceURI] = $attnode->prefix;
+		} else {
+			$arNS[$attnode->namespaceURI] = NULL;
+		}
+	}
+	if (count($arNS) > 0) {
+		asort($arNS);
+	}
+
+	/* Add namespace nodes */
+	foreach ($arNS AS $namespaceURI=>$prefix) {
+		if ($prefix != NULL) {
+	      	$elCopy->setAttributeNS("http://www.w3.org/2000/xmlns/",
+                               "xmlns:".$prefix, $namespaceURI);
+		}
+	}
+	if (count($arNS) > 0) {
+		ksort($arNS);
+	}
+
+	/* Get attributes not in a namespace, and then sort and add them */
+	$arAtts = $xPath->query('attribute::*[namespace-uri(.) = ""]', $element);
+	sortAndAddAttrs($elCopy, $arAtts);
+
+	/* Loop through the URIs, and then sort and add attributes within that namespace */
+	foreach ($arNS as $nsURI=>$prefix) {
+	   $arAtts = $xPath->query('attribute::*[namespace-uri(.) = "'.$nsURI.'"]', $element);
+	   sortAndAddAttrs($elCopy, $arAtts);
+	}
+
+	foreach ($element->childNodes AS $node) {
+		canonical($elCopy, $node, $withcomments);
+	}
+}
+
+/*
+$element - DOMElement for which to produce the canonical version of
+$exclusive - boolean to indicate exclusive canonicalization (must pass TRUE)
+$withcomments - boolean indicating wether or not to include comments in canonicalized form
+*/
+function C14NGeneral($element, $exclusive=FALSE, $withcomments=FALSE) {
+	/* IF PHP 5.2+ then use built in canonical functionality */
+	$php_version = explode('.', PHP_VERSION);
+	if (($php_version[0] > 5) || ($php_version[0] == 5 && $php_version[1] >= 2) ) {
+		return $element->C14N($exclusive, $withcomments);
+	}
+
+	/* Must be element */
+	if (! $element instanceof DOMElement) {
+		return NULL;
+	}
+	/* Currently only exclusive XML is supported */
+	if ($exclusive == FALSE) {
+		throw new Exception("Only exclusive canonicalization is supported in this version of PHP");
+	}
+	
+	$copyDoc = new DOMDocument();
+	canonical($copyDoc, $element, $withcomments);
+	return $copyDoc->saveXML($copyDoc->documentElement, LIBXML_NOEMPTYTAG);
+}
+
+class XMLSecurityKey {
+	const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
+	const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
+	const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
+	const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
+	const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
+	const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
+	const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
+	const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1';
+
+	private $cryptParams = array();
+	public $type = 0;
+	public $key = NULL;
+	public $passphrase = "";
+	public $iv = NULL;
+	public $name = NULL;
+	public $keyChain = NULL;
+	public $isEncrypted = FALSE;
+	public $encryptedCtx = NULL;
+	public $guid = NULL;
+
+	public function __construct($type, $params=NULL) {
+		switch ($type) {
+			case (XMLSecurityKey::TRIPLEDES_CBC):
+				$this->cryptParams['library'] = 'mcrypt';
+				$this->cryptParams['cipher'] = MCRYPT_TRIPLEDES;
+				$this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+				$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
+				break;
+			case (XMLSecurityKey::AES128_CBC):
+				$this->cryptParams['library'] = 'mcrypt';
+				$this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
+				$this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+				$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
+				break;
+			case (XMLSecurityKey::AES192_CBC):
+				$this->cryptParams['library'] = 'mcrypt';
+				$this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
+				$this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+				$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
+				break;
+			case (XMLSecurityKey::AES256_CBC):
+				$this->cryptParams['library'] = 'mcrypt';
+				$this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128;
+				$this->cryptParams['mode'] = MCRYPT_MODE_CBC;
+				$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
+				break;
+			case (XMLSecurityKey::RSA_1_5):
+				$this->cryptParams['library'] = 'openssl';
+				$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
+				$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
+				if (is_array($params) && ! empty($params['type'])) {
+					if ($params['type'] == 'public' || $params['type'] == 'private') {
+						$this->cryptParams['type'] = $params['type'];
+						break;
+					}
+				}
+				throw new Exception('Certificate "type" (private/public) must be passed via parameters');
+				return;
+			case (XMLSecurityKey::RSA_OAEP_MGF1P):
+				$this->cryptParams['library'] = 'openssl';
+				$this->cryptParams['padding'] = OPENSSL_PKCS1_OAEP_PADDING;
+				$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
+				$this->cryptParams['hash'] = NULL;
+				if (is_array($params) && ! empty($params['type'])) {
+					if ($params['type'] == 'public' || $params['type'] == 'private') {
+						$this->cryptParams['type'] = $params['type'];
+						break;
+					}
+				}
+				throw new Exception('Certificate "type" (private/public) must be passed via parameters');
+				return;
+			case (XMLSecurityKey::RSA_SHA1):
+				$this->cryptParams['library'] = 'openssl';
+				$this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
+				if (is_array($params) && ! empty($params['type'])) {
+					if ($params['type'] == 'public' || $params['type'] == 'private') {
+						$this->cryptParams['type'] = $params['type'];
+						break;
+					}
+				}
+				throw new Exception('Certificate "type" (private/public) must be passed via parameters');
+				break;
+			default:
+				throw new Exception('Invalid Key Type');
+				return;
+		}
+		$this->type = $type;
+	}
+
+	public function generateSessionKey() {
+		$key = '';
+		if (! empty($this->cryptParams['cipher']) && ! empty($this->cryptParams['mode'])) {
+			$keysize = mcrypt_module_get_algo_key_size($this->cryptParams['cipher']);
+			/* Generating random key using iv generation routines */
+			if (($keysize > 0) && ($td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '',$this->cryptParams['mode'], ''))) {
+				if ($this->cryptParams['cipher'] == MCRYPT_RIJNDAEL_128) {
+					$keysize = 16;
+					if ($this->type == XMLSecurityKey::AES256_CBC) {
+						$keysize = 32;
+					} elseif ($this->type == XMLSecurityKey::AES192_CBC) {
+						$keysize = 24;
+					}
+				}
+				while (strlen($key) < $keysize) {
+					$key .= mcrypt_create_iv(mcrypt_enc_get_iv_size ($td),MCRYPT_RAND);
+				}
+				mcrypt_module_close($td);
+				$key = substr($key, 0, $keysize);
+				$this->key = $key;
+			}
+		}
+		return $key;
+	}
+
+	public function loadKey($key, $isFile=FALSE, $isCert = FALSE) {
+		if ($isFile) {
+			$this->key = file_get_contents($key);
+		} else {
+			$this->key = $key;
+		}
+		if ($isCert) {
+			$this->key = openssl_x509_read($this->key);
+			openssl_x509_export($this->key, $str_cert);
+			$this->key = $str_cert;
+		}
+		if ($this->cryptParams['library'] == 'openssl') {
+			if ($this->cryptParams['type'] == 'public') {
+				$this->key = openssl_get_publickey($this->key);
+			} else {
+				$this->key = openssl_get_privatekey($this->key, $this->passphrase);
+			}
+		} else if ($this->cryptParams['cipher'] == MCRYPT_RIJNDAEL_128) {
+			/* Check key length */
+			switch ($this->type) {
+				case (XMLSecurityKey::AES256_CBC):
+					if (strlen($this->key) < 25) {
+						throw new Exception('Key must contain at least 25 characters for this cipher');
+					}
+					break;
+				case (XMLSecurityKey::AES192_CBC):
+					if (strlen($this->key) < 17) {
+						throw new Exception('Key must contain at least 17 characters for this cipher');
+					}
+					break;
+			}
+		}
+	}
+
+	private function encryptMcrypt($data) {
+    	$td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], '');
+	    $this->iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
+	    mcrypt_generic_init($td, $this->key, $this->iv);
+    	$encrypted_data = $this->iv.mcrypt_generic($td, $data);
+	    mcrypt_generic_deinit($td);
+    	mcrypt_module_close($td);
+		return $encrypted_data;
+	}
+
+	private function decryptMcrypt($data) {
+    	$td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], '');
+		$iv_length = mcrypt_enc_get_iv_size($td);
+
+		$this->iv = substr($data, 0, $iv_length);
+		$data = substr($data, $iv_length);
+
+	    mcrypt_generic_init($td, $this->key, $this->iv);
+    	$decrypted_data = mdecrypt_generic($td, $data);
+	    mcrypt_generic_deinit($td);
+    	mcrypt_module_close($td);
+		if ($this->cryptParams['mode'] == MCRYPT_MODE_CBC) {
+	        $dataLen = strlen($decrypted_data);
+			$paddingLength = substr($decrypted_data, $dataLen - 1, 1);
+        	$decrypted_data = substr($decrypted_data, 0, $dataLen - ord($paddingLength));
+		}
+		return $decrypted_data;
+	}
+
+	private function encryptOpenSSL($data) {
+		if ($this->cryptParams['type'] == 'public') {
+			if (! openssl_public_encrypt($data, $encrypted_data, $this->key, $this->cryptParams['padding'])) {
+				throw new Exception('Failure encrypting Data');
+				return;
+			}
+		} else {
+			if (! openssl_private_encrypt($data, $encrypted_data, $this->key, $this->cryptParams['padding'])) {
+				throw new Exception('Failure encrypting Data');
+				return;
+			}
+		}
+		return $encrypted_data;
+	}
+
+	private function decryptOpenSSL($data) {
+		if ($this->cryptParams['type'] == 'public') {
+			if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
+				throw new Exception('Failure decrypting Data');
+				return;
+			}
+		} else {
+			if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
+				throw new Exception('Failure decrypting Data');
+				return;
+			}
+		}
+		return $decrypted;
+	}
+
+	private function signOpenSSL($data) {
+		if (! openssl_sign ($data, $signature, $this->key)) {
+			throw new Exception('Failure Signing Data');
+			return;
+		}
+		return $signature;
+	}
+
+	private function verifyOpenSSL($data, $signature) {
+		return openssl_verify ($data, $signature, $this->key);
+	}
+
+	public function encryptData($data) {
+		switch ($this->cryptParams['library']) {
+			case 'mcrypt':
+				return $this->encryptMcrypt($data);
+				break;
+			case 'openssl':
+				return $this->encryptOpenSSL($data);
+				break;
+		}
+	}
+
+	public function decryptData($data) {
+		switch ($this->cryptParams['library']) {
+			case 'mcrypt':
+				return $this->decryptMcrypt($data);
+				break;
+			case 'openssl':
+				return $this->decryptOpenSSL($data);
+				break;
+		}
+	}
+
+	public function signData($data) {
+		switch ($this->cryptParams['library']) {
+			case 'openssl':
+				return $this->signOpenSSL($data);
+				break;
+		}
+	}
+
+	public function verifySignature($data, $signature) {
+		switch ($this->cryptParams['library']) {
+			case 'openssl':
+				return $this->verifyOpenSSL($data, $signature);
+				break;
+		}
+	}
+
+	public function getAlgorith() {
+		return $this->cryptParams['method'];
+	}
+
+	static function makeAsnSegment($type, $string) {
+		switch ($type){
+			case 0x02:
+				if (ord($string) > 0x7f)
+					$string = chr(0).$string;
+				break;
+			case 0x03:
+				$string = chr(0).$string;
+				break;
+		}
+	
+		$length = strlen($string);
+	
+		if ($length < 128){
+		   $output = sprintf("%c%c%s", $type, $length, $string);
+		} else if ($length < 0x0100){
+		   $output = sprintf("%c%c%c%s", $type, 0x81, $length, $string);
+		} else if ($length < 0x010000) {
+		   $output = sprintf("%c%c%c%c%s", $type, 0x82, $length/0x0100, $length%0x0100, $string);
+		} else {
+			$output = NULL;
+		}
+		return($output);
+	}
+
+	/* Modulus and Exponent must already be base64 decoded */
+	static function convertRSA($modulus, $exponent) {
+		/* make an ASN publicKeyInfo */
+		$exponentEncoding = XMLSecurityKey::makeAsnSegment(0x02, $exponent);    
+		$modulusEncoding = XMLSecurityKey::makeAsnSegment(0x02, $modulus);    
+		$sequenceEncoding = XMLSecurityKey:: makeAsnSegment(0x30, $modulusEncoding.$exponentEncoding);
+		$bitstringEncoding = XMLSecurityKey::makeAsnSegment(0x03, $sequenceEncoding);
+		$rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500"); 
+		$publicKeyInfo = XMLSecurityKey::makeAsnSegment (0x30, $rsaAlgorithmIdentifier.$bitstringEncoding);
+
+		/* encode the publicKeyInfo in base64 and add PEM brackets */
+		$publicKeyInfoBase64 = base64_encode($publicKeyInfo);    
+		$encoding = "-----BEGIN PUBLIC KEY-----\n";
+		$offset = 0;
+		while ($segment=substr($publicKeyInfoBase64, $offset, 64)){
+		   $encoding = $encoding.$segment."\n";
+		   $offset += 64;
+		}
+		return $encoding."-----END PUBLIC KEY-----\n";
+	}
+	
+	public function serializeKey($parent) {
+		
+	}
+}
+
+class XMLSecurityDSig {
+	const XMLDSIGNS = 'http://www.w3.org/2000/09/xmldsig#';
+	const SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1';
+	const SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256';
+	const SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512';
+	const RIPEMD160 = 'http://www.w3.org/2001/04/xmlenc#ripemd160';
+
+	const C14N = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
+	const C14N_COMMENTS = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments';
+	const EXC_C14N = 'http://www.w3.org/2001/10/xml-exc-c14n#';
+	const EXC_C14N_COMMENTS = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments';
+
+	const template = '<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+  <ds:SignedInfo>
+    <ds:SignatureMethod />
+  </ds:SignedInfo>
+</ds:Signature>';
+	
+	public $sigNode = NULL;
+	public $idKeys = array();
+	public $idNS = array();
+	private $signedInfo = NULL;
+	private $xPathCtx = NULL;
+	private $canonicalMethod = NULL;
+	private $prefix = 'ds';
+	private $searchpfx = 'secdsig';
+
+	public function __construct() {
+		$sigdoc = new DOMDocument();
+		$sigdoc->loadXML(XMLSecurityDSig::template);
+		$this->sigNode = $sigdoc->documentElement;
+	}
+
+	private function getXPathObj() {
+		if (empty($this->xPathCtx) && ! empty($this->sigNode)) {
+			$xpath = new DOMXPath($this->sigNode->ownerDocument);
+			$xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+
+			$this->xPathCtx = $xpath;
+		}
+		return $this->xPathCtx;
+	}
+
+	static function generate_GUID($prefix='_pfx') {
+		$uuid = md5(uniqid(rand(), true));
+		$guid =  $prefix.substr($uuid,0,8)."-".
+				substr($uuid,8,4)."-".
+				substr($uuid,12,4)."-".
+				substr($uuid,16,4)."-".
+				substr($uuid,20,12);
+		return $guid;
+	}
+
+	public function locateSignature($objDoc) {
+		if ($objDoc instanceof DOMDocument) {
+			$doc = $objDoc;
+		} else {
+			$doc = $objDoc->ownerDocument;
+		}
+		if ($doc) {
+			$xpath = new DOMXPath($doc);
+			$xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+			$query = ".//secdsig:Signature";
+			$nodeset = $xpath->query($query, $objDoc);
+			
+
+			$this->sigNode = $nodeset->item(0);
+			return $this->sigNode;
+		}
+		return NULL;
+	}
+
+	public function createNewSignNode($name, $value=NULL) {
+		$doc = $this->sigNode->ownerDocument;
+		if (! is_null($value)) {
+			$node = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, $this->prefix.':'.$name, $value);
+		} else {
+			$node = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, $this->prefix.':'.$name);
+		}
+		return $node;
+	}
+
+	public function setCanonicalMethod($method) {
+		switch ($method) {
+			case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315':
+			case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments':
+			case 'http://www.w3.org/2001/10/xml-exc-c14n#':
+			case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments':
+				$this->canonicalMethod = $method;
+				break;
+			default:
+				throw new Exception('Invalid Canonical Method');
+		}
+		if ($xpath = $this->getXPathObj()) {
+			$query = './'.$this->searchpfx.':SignedInfo';
+			$nodeset = $xpath->query($query, $this->sigNode);
+			if ($sinfo = $nodeset->item(0)) {
+				$query = './'.$this->searchpfx.'CanonicalizationMethod';
+				$nodeset = $xpath->query($query, $sinfo);
+				if (! ($canonNode = $nodeset->item(0))) {
+					$canonNode = $this->createNewSignNode('CanonicalizationMethod');
+					$sinfo->insertBefore($canonNode, $sinfo->firstChild);
+				}
+				$canonNode->setAttribute('Algorithm', $this->canonicalMethod);
+			}
+		}
+	}
+
+	private function canonicalizeData($node, $canonicalmethod, $arXPath=NULL, $prefixList=NULL) {
+		$exclusive = FALSE;
+		$withComments = FALSE;
+		switch ($canonicalmethod) {
+			case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315':
+				$exclusive = FALSE;
+				$withComments = FALSE;
+				break;
+			case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments':
+				$withComments = TRUE;
+				break;
+			case 'http://www.w3.org/2001/10/xml-exc-c14n#':
+				$exclusive = TRUE;
+				break;
+			case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments':
+				$exclusive = TRUE;
+				$withComments = TRUE;
+				break;
+		}
+/* Support PHP versions < 5.2 not containing C14N methods in DOM extension */
+		$php_version = explode('.', PHP_VERSION);
+		if (($php_version[0] < 5) || ($php_version[0] == 5 && $php_version[1] < 2) ) {
+			if (! is_null($arXPath)) {
+				throw new Exception("PHP 5.2.0 or higher is required to perform XPath Transformations");
+			}
+			return C14NGeneral($node, $exclusive, $withComments);
+		}
+		return $node->C14N($exclusive, $withComments, $arXPath, $prefixList);
+	}
+
+	public function canonicalizeSignedInfo() {
+
+		$doc = $this->sigNode->ownerDocument;
+		$canonicalmethod = NULL;
+		if ($doc) {
+			$xpath = $this->getXPathObj();
+			$query = "./secdsig:SignedInfo";
+			$nodeset = $xpath->query($query, $this->sigNode);
+			if ($signInfoNode = $nodeset->item(0)) {
+				$query = "./secdsig:CanonicalizationMethod";
+				$nodeset = $xpath->query($query, $signInfoNode);
+				if ($canonNode = $nodeset->item(0)) {
+					$canonicalmethod = $canonNode->getAttribute('Algorithm');
+				}
+				$this->signedInfo = $this->canonicalizeData($signInfoNode, $canonicalmethod);
+				return $this->signedInfo;
+			}
+		}
+		return NULL;
+	}
+
+	public function calculateDigest ($digestAlgorithm, $data) {
+		switch ($digestAlgorithm) {
+			case XMLSecurityDSig::SHA1:
+				$alg = 'sha1';
+				break;
+			case XMLSecurityDSig::SHA256:
+				$alg = 'sha256';
+				break;
+			case XMLSecurityDSig::SHA512:
+				$alg = 'sha512';
+				break;
+			case XMLSecurityDSig::RIPEMD160:
+				$alg = 'ripemd160';
+				break;
+			default:
+				throw new Exception("Cannot validate digest: Unsupported Algorith <$digestAlgorithm>");
+		}
+		return base64_encode(hash($alg, $data, TRUE));
+	}
+
+	public function validateDigest($refNode, $data) {
+		$xpath = new DOMXPath($refNode->ownerDocument);
+		$xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+		$query = 'string(./secdsig:DigestMethod/@Algorithm)';
+		$digestAlgorithm = $xpath->evaluate($query, $refNode);
+		$digValue = $this->calculateDigest($digestAlgorithm, $data);
+		$query = 'string(./secdsig:DigestValue)';
+		$digestValue = $xpath->evaluate($query, $refNode);
+		return ($digValue == $digestValue);
+	}
+
+	public function processTransforms($refNode, $objData) {
+		$data = $objData;
+		$xpath = new DOMXPath($refNode->ownerDocument);
+		$xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+		$query = './secdsig:Transforms/secdsig:Transform';
+		$nodelist = $xpath->query($query, $refNode);
+		$canonicalMethod = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
+		$arXPath = NULL;
+		$prefixList = NULL;
+		foreach ($nodelist AS $transform) {
+			$algorithm = $transform->getAttribute("Algorithm");
+			switch ($algorithm) {
+				case 'http://www.w3.org/2001/10/xml-exc-c14n#':
+				case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments':
+					$node = $transform->firstChild;
+					while ($node) {
+						if ($node->localName == 'InclusiveNamespaces') {
+							if ($pfx = $node->getAttribute('PrefixList')) {
+								$arpfx = array();
+								$pfxlist = split(" ", $pfx);
+								foreach ($pfxlist AS $pfx) {
+									$val = trim($pfx);
+									if (! empty($val)) {
+										$arpfx[] = $val;
+									}
+								}
+								if (count($arpfx) > 0) {
+									$prefixList = $arpfx;
+								}
+							}
+							break;
+						}
+						$node = $node->nextSibling;
+					}
+				case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315':
+				case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments':
+					$canonicalMethod = $algorithm;
+					break;
+				case 'http://www.w3.org/TR/1999/REC-xpath-19991116':
+					$node = $transform->firstChild;
+					while ($node) {
+						if ($node->localName == 'XPath') {
+							$arXPath = array();
+							$arXPath['query'] = '(.//. | .//@* | .//namespace::*)['.$node->nodeValue.']';
+							$arXpath['namespaces'] = array();
+							$nslist = $xpath->query('./namespace::*', $node);
+							foreach ($nslist AS $nsnode) {
+								if ($nsnode->localName != "xml") {
+									$arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
+								}
+							}
+							break;
+						}
+						$node = $node->nextSibling;
+					}
+					break;
+			}
+		}
+		if ($data instanceof DOMNode) {
+			$data = $this->canonicalizeData($objData, $canonicalMethod, $arXPath, $prefixList);
+		}
+		return $data;
+	}
+
+	public function processRefNode($refNode) {
+		$dataObject = NULL;
+		if ($uri = $refNode->getAttribute("URI")) {
+			$arUrl = parse_url($uri);
+			if (empty($arUrl['path'])) {
+				if ($identifier = $arUrl['fragment']) {
+					$xPath = new DOMXPath($refNode->ownerDocument);
+					if ($this->idNS && is_array($this->idNS)) {
+						foreach ($this->idNS AS $nspf=>$ns) {
+							$xPath->registerNamespace($nspf, $ns);
+						}
+					}
+					$iDlist = '@Id="'.$identifier.'"';
+					if (is_array($this->idKeys)) {
+						foreach ($this->idKeys AS $idKey) {
+							$iDlist .= " or @$idKey='$identifier'";
+						}
+					}
+					$query = '//*['.$iDlist.']';
+					$dataObject = $xPath->query($query)->item(0);
+				} else {
+					$dataObject = $refNode->ownerDocument;
+				}
+			} else {
+				$dataObject = file_get_contents($arUrl);
+			}
+		} else {
+			$dataObject = $refNode->ownerDocument;
+		}
+		$data = $this->processTransforms($refNode, $dataObject);
+		return $this->validateDigest($refNode, $data);
+	}
+	
+	public function getRefNodeID($refNode) {
+		if ($uri = $refNode->getAttribute("URI")) {
+			$arUrl = parse_url($uri);
+			if (empty($arUrl['path'])) {
+				if ($identifier = $arUrl['fragment']) {
+					return $identifier;
+				}
+			}
+		}
+		return null;
+	}
+	
+	public function getRefIDs() {
+		$refids = array();
+		$doc = $this->sigNode->ownerDocument;
+
+		$xpath = $this->getXPathObj();
+		$query = "./secdsig:SignedInfo/secdsig:Reference";
+		$nodeset = $xpath->query($query, $this->sigNode);
+		if ($nodeset->length == 0) {
+			throw new Exception("Reference nodes not found");
+		}
+		foreach ($nodeset AS $refNode) {
+			$refids[] = $this->getRefNodeID($refNode);
+		}
+		return $refids;
+	}
+
+	public function validateReference() {
+		$doc = $this->sigNode->ownerDocument;
+		if (! $doc->isSameNode($this->sigNode)) {
+			$this->sigNode->parentNode->removeChild($this->sigNode);
+		}
+		$xpath = $this->getXPathObj();
+		$query = "./secdsig:SignedInfo/secdsig:Reference";
+		$nodeset = $xpath->query($query, $this->sigNode);
+		if ($nodeset->length == 0) {
+			throw new Exception("Reference nodes not found");
+		}
+		foreach ($nodeset AS $refNode) {
+			if (! $this->processRefNode($refNode)) {
+				throw new Exception("Reference validation failed");
+			}
+		}
+		return TRUE;
+	}
+
+	private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=NULL, $options=NULL) {
+		$prefix = NULL;
+		$prefix_ns = NULL;
+		$id_name = 'ID';
+
+		if (is_array($options)) {
+			$prefix = empty($options['prefix'])?NULL:$options['prefix'];
+			$prefix_ns = empty($options['prefix_ns'])?NULL:$options['prefix_ns'];
+			$id_name = empty($options['id_name'])?'Id':$options['id_name'];
+		}
+
+		$refNode = $this->createNewSignNode('Reference');
+		$sinfoNode->appendChild($refNode);
+
+		if ($node instanceof DOMDocument) {
+			$uri = NULL;
+		} else {
+/* Do wer really need to set a prefix? */
+			$uri = XMLSecurityDSig::generate_GUID();
+			$refNode->setAttribute("URI", '#'.$uri);
+			//$refNode->setAttribute("URI", '');
+		}
+
+		$transNodes = $this->createNewSignNode('Transforms');
+		$refNode->appendChild($transNodes);
+
+		if (is_array($arTransforms)) {
+			foreach ($arTransforms AS $transform) {
+				$transNode = $this->createNewSignNode('Transform');
+				$transNodes->appendChild($transNode);
+				$transNode->setAttribute('Algorithm', $transform);
+			}
+		} elseif (! empty($this->canonicalMethod)) {
+			$transNode = $this->createNewSignNode('Transform');
+			$transNodes->appendChild($transNode);
+			$transNode->setAttribute('Algorithm', $this->canonicalMethod);
+		}
+		
+		if (! empty($uri)) {
+			$attname = $id_name;
+			if (! empty($prefix)) {
+				$attname = $prefix.':'.$attname;
+			}
+			$node->setAttributeNS($prefix_ns, $attname, $uri);
+		}
+		
+		$canonicalData = $this->processTransforms($refNode, $node);
+		$digValue = $this->calculateDigest($algorithm, $canonicalData);
+		
+		$digestMethod = $this->createNewSignNode('DigestMethod');
+		$refNode->appendChild($digestMethod);
+		$digestMethod->setAttribute('Algorithm', $algorithm);
+
+		$digestValue = $this->createNewSignNode('DigestValue', $digValue);
+		$refNode->appendChild($digestValue);
+	}
+
+	public function addReference($node, $algorithm, $arTransforms=NULL, $options=NULL) {
+		if ($xpath = $this->getXPathObj()) {
+			$query = "./secdsig:SignedInfo";
+			$nodeset = $xpath->query($query, $this->sigNode);
+			if ($sInfo = $nodeset->item(0)) {
+				$this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options);
+			}
+		}
+	}
+
+	public function addReferenceList($arNodes, $algorithm, $arTransforms=NULL, $options=NULL) {
+		if ($xpath = $this->getXPathObj()) {
+			$query = "./secdsig:SignedInfo";
+			$nodeset = $xpath->query($query, $this->sigNode);
+			if ($sInfo = $nodeset->item(0)) {
+				foreach ($arNodes AS $node) {
+					$this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options);
+				}
+			}
+		}
+	}
+
+   public function addObject($data, $mimetype=NULL, $encoding=NULL) {
+      $objNode = $this->createNewSignNode('Object');
+      $this->sigNode->appendChild($objNode);
+      if (! empty($mimetype)) {
+         $objNode->setAtribute('MimeType', $mimetype);
+      }
+      if (! empty($encoding)) {
+         $objNode->setAttribute('Encoding', $encoding);
+      }
+      
+      if ($data instanceof DOMElement) {
+         $newData = $this->sigNode->ownerDocument->importNode($data, TRUE);
+      } else {
+         $newData = $this->sigNode->ownerDocument->createTextNode($data);
+      }
+      $objNode->appendChild($newData);
+
+      return $objNode;
+   }
+
+	public function locateKey($node=NULL) {
+		if (empty($node)) {
+			$node = $this->sigNode;
+		}
+		if (! $node instanceof DOMNode) {
+			return NULL;
+		}
+		if ($doc = $node->ownerDocument) {
+			$xpath = new DOMXPath($doc);
+			$xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+			$query = "string(./secdsig:SignedInfo/secdsig:SignatureMethod/@Algorithm)";
+			$algorithm = $xpath->evaluate($query, $node);
+			if ($algorithm) {
+				try {
+					$objKey = new XMLSecurityKey($algorithm, array('type'=>'public'));
+				} catch (Exception $e) {
+					return NULL;
+				}
+				return $objKey;
+			}
+		}
+		return NULL;
+	}
+	
+	public function verify($objKey) {
+		$doc = $this->sigNode->ownerDocument;
+		$xpath = new DOMXPath($doc);
+		$xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+		$query = "string(./secdsig:SignatureValue)";
+		$sigValue = $xpath->evaluate($query, $this->sigNode);
+		if (empty($sigValue)) {
+			throw new Exception("Unable to locate SignatureValue");
+		}
+		return $objKey->verifySignature($this->signedInfo, base64_decode($sigValue));
+	}
+	
+	public function signData($objKey, $data) {
+		return $objKey->signData($data);
+	}
+	
+	public function sign($objKey) {
+		if ($xpath = $this->getXPathObj()) {
+			$query = "./secdsig:SignedInfo";
+			$nodeset = $xpath->query($query, $this->sigNode);
+			if ($sInfo = $nodeset->item(0)) {
+				$query = "./secdsig:SignatureMethod";
+				$nodeset = $xpath->query($query, $sInfo);
+				$sMethod = $nodeset->item(0);
+				$sMethod->setAttribute('Algorithm', $objKey->type);
+				$data = $this->canonicalizeData($sInfo, $this->canonicalMethod);
+				$sigValue = base64_encode($this->signData($objKey, $data));
+				$sigValueNode = $this->createNewSignNode('SignatureValue', $sigValue);
+				if ($infoSibling = $sInfo->nextSibling) {
+					$infoSibling->parentNode->insertBefore($sigValueNode, $infoSibling);
+				} else {
+					$this->sigNode->appendChild($sigValueNode);
+				}
+			}
+		}
+	}
+
+	public function appendCert() {
+		
+	}
+
+	public function appendKey($objKey, $parent=NULL) {
+		$objKey->serializeKey($parent);
+	}
+
+	public function appendSignature($parentNode, $insertBefore = FALSE, $assertion = false) {
+		$baseDoc = ($parentNode instanceof DOMDocument)?$parentNode:$parentNode->ownerDocument;
+		$newSig = $baseDoc->importNode($this->sigNode, TRUE);
+
+	
+	
+		$xnode = null;
+		
+		$xpath = new DOMXPath($baseDoc);
+		$xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+		$xpath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:2.0:protocol');
+		$xpath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:2.0:assertion');
+
+
+		if ($insertBefore && !$assertion) {
+
+			$query = "//samlp:Status";
+			$nodeset = $xpath->query($query, $parentNode);
+
+			$xnode = $nodeset->item(0);
+			if (!$xnode)
+				throw new Exception("Could not find node to sign before (Root signing mode)");
+		
+			$parentNode->insertBefore($newSig, $xnode);
+			
+		} elseif ($insertBefore) {
+			
+			$query = "//saml:Assertion/saml:Subject";
+			$nodeset = $xpath->query($query, $parentNode);
+
+			$xnode = $nodeset->item(0);
+			if (!$xnode)
+				throw new Exception("Could not find node to sign before (Assertion signing mode)");
+
+			$parentNode->insertBefore($newSig, $xnode);
+		} else {
+			$parentNode->appendChild($newSig);
+		}
+	}
+	
+	static function get509XCert($cert, $isPEMFormat=TRUE) {
+		if ($isPEMFormat) {
+			$data = '';
+			$arCert = explode("\n", $cert);
+			$inData = FALSE;
+			foreach ($arCert AS $curData) {
+				if (! $inData) {
+					if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) {
+						$inData = TRUE;
+					}
+				} else {
+					if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) {
+						break;
+					}
+					$data .= trim($curData);
+				}
+			}
+		} else {
+			$data = $cert;
+		}
+		return $data;
+	}
+	
+	static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=TRUE, $isURL=False, $xpath=NULL) {
+          if ($isURL) {
+            $cert = file_get_contents($cert);
+          }
+          if (! $parentRef instanceof DOMElement) {
+            throw new Exception('Invalid parent Node parameter');
+          }
+          $baseDoc = $parentRef->ownerDocument;
+
+          if (empty($xpath)) {
+              $xpath = new DOMXPath($parentRef->ownerDocument);
+              $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS);
+          }
+          $data = XMLSecurityDSig::get509XCert($cert, $isPEMFormat);
+
+         $query = "./secdsig:KeyInfo";
+         $nodeset = $xpath->query($query, $parentRef);
+         $keyInfo = $nodeset->item(0);
+         if (! $keyInfo) {
+              $inserted = FALSE;
+              $keyInfo = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:KeyInfo');
+
+               $query = "./secdsig:Object";
+               $nodeset = $xpath->query($query, $parentRef);
+               if ($sObject = $nodeset->item(0)) {
+                    $sObject->parentNode->insertBefore($keyInfo, $sObject);
+                    $inserted = TRUE;
+               }
+
+              if (! $inserted) {
+                   $parentRef->appendChild($keyInfo);
+              }
+         }
+         $x509DataNode = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509Data');
+         $keyInfo->appendChild($x509DataNode);
+         $x509CertNode = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509Certificate', $data);
+         $x509DataNode->appendChild($x509CertNode);
+
+     }
+
+	public function add509Cert($cert, $isPEMFormat=TRUE, $isURL=False) {
+         if ($xpath = $this->getXPathObj()) {
+            self::staticAdd509Cert($this->sigNode, $cert, $isPEMFormat, $isURL, $xpath);
+         }
+	}
+}
+
+class XMLSecEnc {
+	const template = "<xenc:EncryptedData xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'>
+   <xenc:CipherData>
+      <xenc:CipherValue></xenc:CipherValue>
+   </xenc:CipherData>
+</xenc:EncryptedData>";
+
+	const Element = 'http://www.w3.org/2001/04/xmlenc#Element';
+	const Content = 'http://www.w3.org/2001/04/xmlenc#Content';
+	const URI = 3;
+	const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#';
+
+	private $encdoc = NULL;
+	private $rawNode = NULL;
+	public $type = NULL;
+	public $encKey = NULL;
+	
+	public function __construct() {
+		$this->encdoc = new DOMDocument();
+		$this->encdoc->loadXML(XMLSecEnc::template);
+	}
+	
+	public function setNode($node) {
+		$this->rawNode = $node;
+	}
+
+	public function encryptNode($objKey, $replace=TRUE) {
+		$data = '';
+		if (empty($this->rawNode)) {
+			throw new Exception('Node to encrypt has not been set');
+		}
+		if (! $objKey instanceof XMLSecurityKey) {
+			throw new Exception('Invalid Key');
+		}
+		$doc = $this->rawNode->ownerDocument;
+		$xPath = new DOMXPath($this->encdoc);
+		$objList = $xPath->query('/xenc:EncryptedData/xenc:CipherData/xenc:CipherValue');
+		$cipherValue = $objList->item(0);
+		if ($cipherValue == NULL) {
+			throw new Exception('Error locating CipherValue element within template');
+		}
+		switch ($this->type) {
+			case (XMLSecEnc::Element):
+				$data = $doc->saveXML($this->rawNode);
+				$this->encdoc->documentElement->setAttribute('Type', XMLSecEnc::Element);
+				break;
+			case (XMLSecEnc::Content):
+				$children = $this->rawNode->childNodes;
+				foreach ($children AS $child) {
+					$data .= $doc->saveXML($child);
+				}
+				$this->encdoc->documentElement->setAttribute('Type', XMLSecEnc::Content);
+				break;
+			default:
+				throw new Exception('Type is currently not supported');
+				return;
+		}
+		
+		$encMethod = $this->encdoc->documentElement->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptionMethod'));
+		$encMethod->setAttribute('Algorithm', $objKey->getAlgorith());
+		$cipherValue->parentNode->parentNode->insertBefore($encMethod, $cipherValue->parentNode);
+		
+		$strEncrypt = base64_encode($objKey->encryptData($data));
+		$value = $this->encdoc->createTextNode($strEncrypt);
+		$cipherValue->appendChild($value);
+
+		if ($replace) {
+			switch ($this->type) {
+				case (XMLSecEnc::Element):
+					if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
+						return $this->encdoc;
+					}
+					$importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, TRUE);
+					$this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode);
+					return $importEnc;
+					break;
+				case (XMLSecEnc::Content):
+					$importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, TRUE);
+					while($this->rawNode->firstChild) {
+						$this->rawNode->removeChild($this->rawNode->firstChild);
+					}
+					$this->rawNode->appendChild($importEnc);
+					return $importEnc;
+					break;
+			}
+		}
+	}
+
+	public function decryptNode($objKey, $replace=TRUE) {
+		$data = '';
+		if (empty($this->rawNode)) {
+			throw new Exception('Node to decrypt has not been set');
+		}
+		if (! $objKey instanceof XMLSecurityKey) {
+			throw new Exception('Invalid Key');
+		}
+		$doc = $this->rawNode->ownerDocument;
+		$xPath = new DOMXPath($doc);
+		$xPath->registerNamespace('xmlencr', XMLSecEnc::XMLENCNS);
+		/* Only handles embedded content right now and not a reference */
+		$query = "./xmlencr:CipherData/xmlencr:CipherValue";
+		$nodeset = $xPath->query($query, $this->rawNode);
+
+		if ($node = $nodeset->item(0)) {
+			$encryptedData = base64_decode($node->nodeValue);
+			$decrypted = $objKey->decryptData($encryptedData);
+			if ($replace) {
+				switch ($this->type) {
+					case (XMLSecEnc::Element):
+						$newdoc = new DOMDocument();
+						$newdoc->loadXML($decrypted);
+						if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
+							return $newdoc;
+						}
+						$importEnc = $this->rawNode->ownerDocument->importNode($newdoc->documentElement, TRUE);
+						$this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode);
+						return $importEnc;
+						break;
+					case (XMLSecEnc::Content):
+						if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
+							$doc = $this->rawNode;
+						} else {
+							$doc = $this->rawNode->ownerDocument;
+						}
+						$newFrag = $doc->createDOMDocumentFragment();
+						$newFrag->appendXML($decrypted);
+						$this->rawNode->parentNode->replaceChild($newFrag, $this->rawNode);
+						return $this->rawNode->parentNode;
+						break;
+					default:
+						return $decrypted;
+				}
+			} else {
+				return $decrypted;
+			}
+		} else {
+			throw new Exception("Cannot locate encrypted data");
+		}
+	}
+
+	public function encryptKey($srcKey, $rawKey, $append=TRUE) {
+		if ((! $srcKey instanceof XMLSecurityKey) || (! $rawKey instanceof XMLSecurityKey)) {
+			throw new Exception('Invalid Key');
+		}
+		$strEncKey = base64_encode($srcKey->encryptData($rawKey->key));
+		$root = $this->encdoc->documentElement;
+		$encKey = $this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptedKey');
+		if ($append) {
+			$keyInfo = $root->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'));
+			$keyInfo->appendChild($encKey);
+		} else {
+			$this->encKey = $encKey;
+		}
+		$encMethod = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptionMethod'));
+		$encMethod->setAttribute('Algorithm', $srcKey->getAlgorith());
+		if (! empty($srcKey->name)) {
+			$keyInfo = $encKey->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'));
+			$keyInfo->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyName', $srcKey->name));
+		}
+		$cipherData = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:CipherData'));
+		$cipherData->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:CipherValue', $strEncKey));
+		return;
+	}
+	
+	public function decryptKey($encKey) {
+		if (! $encKey->isEncrypted) {
+			throw new Exception("Key is not Encrypted");
+		}
+		if (empty($encKey->key)) {
+			throw new Exception("Key is missing data to perform the decryption");
+		}
+		return $this->decryptNode($encKey, FALSE);
+	}
+	
+	public function locateEncryptedData($element) {
+		if ($element instanceof DOMDocument) {
+			$doc = $element;
+		} else {
+			$doc = $element->ownerDocument;
+		}
+		if ($doc) {
+			$xpath = new DOMXPath($doc);
+			$query = "//*[local-name()='EncryptedData' and namespace-uri()='".XMLSecEnc::XMLENCNS."']";
+			$nodeset = $xpath->query($query);
+			return $nodeset->item(0);
+		}
+		return NULL;
+	}
+	
+	public function locateKey($node=NULL) {
+		if (empty($node)) {
+			$node = $this->rawNode;
+		}
+		if (! $node instanceof DOMNode) {
+			return NULL;
+		}
+		if ($doc = $node->ownerDocument) {
+			$xpath = new DOMXPath($doc);
+			$xpath->registerNamespace('xmlsecenc', XMLSecEnc::XMLENCNS);
+			$query = ".//xmlsecenc:EncryptionMethod";
+			$nodeset = $xpath->query($query, $node);
+			if ($encmeth = $nodeset->item(0)) {
+   				$attrAlgorithm = $encmeth->getAttribute("Algorithm");
+				try {
+					$objKey = new XMLSecurityKey($attrAlgorithm, array('type'=>'private'));
+				} catch (Exception $e) {
+					return NULL;
+				}
+				return $objKey;
+			}
+		}
+		return NULL;
+	}
+	
+	static function staticLocateKeyInfo($objBaseKey=NULL, $node=NULL) {
+		if (empty($node) || (! $node instanceof DOMNode)) {
+			return NULL;
+		}
+		if ($doc = $node->ownerDocument) {
+			$xpath = new DOMXPath($doc);
+			$xpath->registerNamespace('xmlsecenc', XMLSecEnc::XMLENCNS);
+			$xpath->registerNamespace('xmlsecdsig', XMLSecurityDSig::XMLDSIGNS);
+			$query = "./xmlsecdsig:KeyInfo";
+			$nodeset = $xpath->query($query, $node);
+			if ($encmeth = $nodeset->item(0)) {
+				foreach ($encmeth->childNodes AS $child) {
+					switch ($child->localName) {
+						case 'KeyName':
+							if (! empty($objBaseKey)) {
+								$objBaseKey->name = $child->nodeValue;
+							}
+							break;
+						case 'KeyValue':
+							foreach ($child->childNodes AS $keyval) {
+								switch ($keyval->localName) {
+									case 'DSAKeyValue':
+										throw new Exception("DSAKeyValue currently not supported");
+										break;
+									case 'RSAKeyValue':
+										$modulus = NULL;
+										$exponent = NULL;
+										if ($modulusNode = $keyval->getElementsByTagName('Modulus')->item(0)) {
+											$modulus = base64_decode($modulusNode->nodeValue);
+										}
+										if ($exponentNode = $keyval->getElementsByTagName('Exponent')->item(0)) {
+											$exponent = base64_decode($exponentNode->nodeValue);
+										}
+										if (empty($modulus) || empty($exponent)) {
+											throw new Exception("Missing Modulus or Exponent");
+										}
+										$publicKey = XMLSecurityKey::convertRSA($modulus, $exponent);
+										$objBaseKey->loadKey($publicKey);
+										break;
+								}
+							}
+							break;
+						case 'RetrievalMethod':
+							/* Not currently supported */
+							break;
+						case 'EncryptedKey':
+							$objenc = new XMLSecEnc();
+							$objenc->setNode($child);
+							if (! $objKey = $objenc->locateKey()) {
+								throw new Exception("Unable to locate algorithm for this Encrypted Key");
+							}
+							$objKey->isEncrypted = TRUE;
+							$objKey->encryptedCtx = $objenc;
+							XMLSecEnc::staticLocateKeyInfo($objKey, $child);
+							return $objKey;
+							break;
+						case 'X509Data':
+							if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) {
+								if ($x509certNodes->length > 0) {
+									$x509cert = $x509certNodes->item(0)->textContent;
+									$x509cert = str_replace(array("\r", "\n"), "", $x509cert);
+									$x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n";
+									$objBaseKey->loadKey($x509cert);
+								}
+							}
+							break;
+					}
+				}
+			}
+			return $objBaseKey;
+		}
+		return NULL;
+	}
+	
+	public function locateKeyInfo($objBaseKey=NULL, $node=NULL) {
+		if (empty($node)) {
+			$node = $this->rawNode;
+		}
+		return XMLSecEnc::staticLocateKeyInfo($objBaseKey, $node);
+	}
+}
+?>
\ No newline at end of file
diff --git a/metadata-templates/saml20-idp-hosted.php b/metadata-templates/saml20-idp-hosted.php
new file mode 100644
index 000000000..b1eab5941
--- /dev/null
+++ b/metadata-templates/saml20-idp-hosted.php
@@ -0,0 +1,37 @@
+<?php
+/* 
+ * SAML 2.0 Meta data for simpleSAMLphp
+ *
+ * The SAML 2.0 IdP Hosted config is used by the SAML 2.0 IdP to identify itself.
+ *
+ */
+
+
+$metadata = array( 
+
+	// The SAML entity ID is the index of this config.
+	'dev2.andreas.feide.no' => array(
+	
+		// The hostname of the server (VHOST) that this SAML entity will use.
+		'host'				=>	'dev2.andreas.feide.no',
+		
+		// SAML endpoints.
+		'SingleSignOnUrl'	=>	"http://dev2.andreas.feide.no/saml2/idp/SSOService.php",
+		'SingleLogOutUrl'	=>	"http://dev2.andreas.feide.no/saml2/idp/LogoutService.php",
+		
+		// X.509 key and certificate. Relative to the cert directory.
+		'privatekey'		=>	'server.pem',
+		'certificate'		=>	'server.crt',
+		
+		/* If base64attributes is set to true, then all attributes will be base64 encoded. Make sure
+		 * that you set the SP to have the same value for this.
+		 */
+		'base64attributes'	=>	false,
+		
+		// Authentication plugin to use. login.php is the default one that uses LDAP.
+		'auth'				=>	'auth/login.php'
+	)
+
+);
+
+?>
diff --git a/metadata-templates/saml20-idp-remote.php b/metadata-templates/saml20-idp-remote.php
new file mode 100644
index 000000000..3f0afacb3
--- /dev/null
+++ b/metadata-templates/saml20-idp-remote.php
@@ -0,0 +1,41 @@
+<?php
+/* 
+ * SAML 2.0 Meta data for simpleSAMLphp
+ *
+ * The SAML 2.0 IdP Remote config is used by the SAML 2.0 SP to identify trusted SAML 2.0 IdPs.
+ *
+ */
+
+
+
+$metadata = array( 
+	"feide2.erlang.no-saml2" => 
+		array(
+			"SingleSignOnUrl"	=>	"https://feide2.erlang.no/saml2/idp/SSOService.php",
+		 	"SingleLogOutUrl"	=>	"https://feide2.erlang.no/saml2/idp/LogoutService.php",
+		 	"certFingerprint"	=>	"afe71c28ef740bc87425be13a2263d37971da1f9",
+		 	"base64attributes"	=>	true),
+
+	'dev2.andreas.feide.no' => 
+		array(
+			"SingleSignOnUrl"	=>	"http://dev2.andreas.feide.no/saml2/idp/SSOService.php",
+		 	"SingleLogOutUrl"	=>	"http://dev2.andreas.feide.no/saml2/idp/LogoutService.php",
+		 	"certFingerprint"	=>	"afe71c28ef740bc87425be13a2263d37971da1f9",
+		 	"base64attributes"	=>	false),
+		 	
+	"sam.feide.no" => 
+		array( 
+			"SingleSignOnUrl"	=>	"https://sam.feide.no/amserver/SSORedirect/metaAlias/idp",
+		 	"SingleLogOutUrl"	=>	"https://sam.feide.no/amserver/IDPSloRedirect/metaAlias/idp",
+		 	"certFingerprint"	=>	"3a:e7:d3:d3:06:ba:57:fd:7f:62:6a:4b:a8:64:b3:4a:53:d9:5d:d0",
+		 	"base64attributes"	=>	true),
+		 	
+	"max.feide.no" => 
+		array(
+			"SingleSignOnUrl"	=>	"https://max.feide.no/amserver/SSORedirect/metaAlias/idp",
+		 	"SingleLogOutUrl"	=>	"https://max.feide.no/amserver/IDPSloRedirect/metaAlias/idp",
+		 	"certFingerprint"	=>	"d79b0e23c0833d2f5b8d94abd54ae693708b1eef",
+		 	"base64attributes"	=>	false )
+
+    );
+?>
diff --git a/metadata-templates/saml20-sp-hosted.php b/metadata-templates/saml20-sp-hosted.php
new file mode 100644
index 000000000..d6357b0aa
--- /dev/null
+++ b/metadata-templates/saml20-sp-hosted.php
@@ -0,0 +1,37 @@
+<?php
+/* 
+ * SAML 2.0 Meta data for simpleSAMLphp
+ *
+ * The SAML 2.0 IdP Remote config is used by the SAML 2.0 SP to identify itself.
+ *
+ */
+ 
+$metadata = array( 
+	"dev.andreas.feide.no" => array(
+		'host'							=>	'dev.andreas.feide.no',
+ 		"assertionConsumerServiceURL"	=>	"http://dev.andreas.feide.no/saml2/sp/AssertionConsumerService.php", 
+		"issuer"						=>	"dev.andreas.feide.no",
+		"spNameQualifier" 				=>	"dev.andreas.feide.no",
+		"ForceAuthn"					=>	"false",
+		"NameIDFormat"					=>	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+	),
+	"feide2.erlang.no" => array(
+		'host'							=>	'feide2.erlang.no',
+ 		"assertionConsumerServiceURL"	=>	"https://feide2.erlang.no/saml2/sp/AssertionConsumerService.php", 
+		"issuer"						=>	"feide2.erlang.no",
+		"spNameQualifier" 				=>	"feide2.erlang.no",
+		"ForceAuthn"					=>	"false",
+		"NameIDFormat"					=>	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+	),
+	"feide3.erlang.no" => array(
+		'host'							=>	'feide3.erlang.no',
+ 		"assertionConsumerServiceURL"	=>	"https://feide3.erlang.no/saml2/sp/AssertionConsumerService.php", //
+		"issuer"						=>	"feide3.erlang.no",
+		"spNameQualifier" 				=>	"feide3.erlang.no",
+		"ForceAuthn"					=>	"false",
+		"NameIDFormat"					=>	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+	)
+);
+
+
+?>
diff --git a/metadata-templates/saml20-sp-remote.php b/metadata-templates/saml20-sp-remote.php
new file mode 100644
index 000000000..78fc98b30
--- /dev/null
+++ b/metadata-templates/saml20-sp-remote.php
@@ -0,0 +1,84 @@
+<?php
+/* 
+ * SAML 2.0 Meta data for simpleSAMLphp
+ *
+ * The SAML 2.0 SP Remote config is used by the SAML 2.0 IdP to identify trusted SAML 2.0 SPs.
+ *
+ *	Required parameters:
+ * 
+ *		assertionConsumerServiceURL
+ *		spNameQualifier
+ *		NameIDFormat
+ *		simplesaml.attributes (Will you send an attributestatement [true/false])
+ *
+ *	Optional parameters:
+ *
+ *		ForceAuthn (default: "false")
+ *		simplesaml.nameidattribute (only needed when you are using NameID format email.
+ *
+ */
+
+$metadata = array( 
+
+	'dev.andreas.feide.no' => array(
+ 		'assertionConsumerServiceURL'	=>	'http://dev.andreas.feide.no/saml2/sp/AssertionConsumerService.php', 
+		'spNameQualifier' 				=>	'dev.andreas.feide.no',
+		'ForceAuthn'					=>	'false',
+		'NameIDFormat'					=>	'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
+		'simplesaml.attributes'			=>	true
+	),
+	
+	/*
+	 * This example shows an example config that works with Google Apps for education.
+	 * What is important is that you have an attribute in your IdP that maps to the local part of the email address
+	 * at Google Apps. In example, if your google account is foo.com, and you have a user that has an email john@foo.com, then you
+	 * must set the simplesaml.nameidattribute to be the name of an attribute that for this user has the value of 'john'.
+	 */
+	'google.com' => array(
+ 		'assertionConsumerServiceURL'	=>	'https://www.google.com/a/foo.com/acs', 
+		'spNameQualifier' 				=>	'google.com',
+		'ForceAuthn'					=>	'false',
+		'NameIDFormat'					=>	'urn:oasis:names:tc:SAML:2.0:nameid-format:email',
+		'simplesaml.nameidattribute'	=>	'uid',
+		'simplesaml.attributes'			=>	false
+	),
+	
+	"feide2.erlang.no" => array(
+ 		"assertionConsumerServiceURL"	=>	"https://feide2.erlang.no/saml2/sp/AssertionConsumerService.php", 
+		"spNameQualifier" 				=>	"feide2.erlang.no",
+		"ForceAuthn"					=>	"false",
+		"NameIDFormat"					=>	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
+		'simplesaml.nameidattribute'	=>	'uid',
+		'simplesaml.attributes'			=>	true
+	),
+		
+	"feide3.erlang.no" => array(
+ 		"assertionConsumerServiceURL"	=>	"https://feide3.erlang.no/saml2/sp/AssertionConsumerService.php", //
+		"spNameQualifier" 				=>	"feide3.erlang.no",
+		"ForceAuthn"					=>	"false",
+		"NameIDFormat"					=>	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
+		'simplesaml.attributes'			=>	true
+	),
+	
+	"skjak.uninett.no" => array(
+ 		"assertionConsumerServiceURL"	=>	"https://skjak.uninett.no/Shibboleth.sso/SAML2/POST", //
+		"spNameQualifier" 				=>	"skjak.uninett.no",
+		"ForceAuthn"					=>	"false",
+		"NameIDFormat"					=>	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
+		'simplesaml.attributes'			=>	true
+		),
+	"skjak.uninett.no" => array(
+// 		"assertionConsumerServiceURL"	=>	"https://skjak2.uninett.no:443/fam/Consumer/metaAlias/sp_meta_alias", //
+ 		"assertionConsumerServiceURL"	=>	"https://skjak.uninett.no/Shibboleth.sso/SAML2/POST", //
+		"spNameQualifier" 				=>	"skjak.uninett.no",
+		"ForceAuthn"					=>	"false",
+		"NameIDFormat"					=>	"urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
+		'simplesaml.attributes'			=>	true
+		)
+		
+		
+
+);
+
+
+?>
diff --git a/metadata-templates/shib13-idp-hosted.php b/metadata-templates/shib13-idp-hosted.php
new file mode 100644
index 000000000..ce175ddb8
--- /dev/null
+++ b/metadata-templates/shib13-idp-hosted.php
@@ -0,0 +1,16 @@
+<?php
+/* 
+ * SAML 2.0 Meta data for simpleSAMLphp
+ *
+ */
+
+
+$metadata = array(
+	'feide.erlang.no-shib13'	=> array(
+		'issuer'						=>	'feide.erlang.no',
+		'assertionDurationMinutes'		=>	10,
+		'audience'						=> 'urn:mace:feide:shiblab'
+	)
+);
+
+?>
\ No newline at end of file
diff --git a/metadata-templates/shib13-idp-remote.php b/metadata-templates/shib13-idp-remote.php
new file mode 100644
index 000000000..aba114a16
--- /dev/null
+++ b/metadata-templates/shib13-idp-remote.php
@@ -0,0 +1,29 @@
+<?php
+/* 
+ * SAML 2.0 Meta data for simpleSAMLphp
+ *
+ */
+
+
+$metadata = array(
+
+	'urn:mace:switch.ch:aaitest:dukono.switch.ch'	=> array(
+		'SingleSignOnUrl'		=>	'https://dukono.switch.ch/shibboleth-idp/SSO',
+		'certFingerprint'		=>	'c7279a9f28f11380509e075441e3dc55fb9ab864' 
+//		'certFingerprint'		=>	'4e730f327ce8d9fe6269298d8f777a4bd0937ba5'
+//		c7279a9f28f11380509e075441e3dc55fb9ab864
+		// "SingleLogOutUrl" => "https://mars.feide.no/amserver/IDPSloRedirect/metaAlias/idp",
+	),
+	
+	'feide.erlang.no-shib13'	=> array(
+		'issuer'						=>	'feide.erlang.no',
+		'assertionDurationMinutes'		=>	10,
+		'audience'						=> 'urn:mace:feide:shiblab'
+	),
+	
+	'urn:mace:dfnwayf'	=> array(
+		'SingleSignOnUrl'		=>	'https://dfn.wayf.com/WAYF'
+	)
+);
+
+?>
\ No newline at end of file
diff --git a/metadata-templates/shib13-sp-hosted.php b/metadata-templates/shib13-sp-hosted.php
new file mode 100644
index 000000000..70c78d235
--- /dev/null
+++ b/metadata-templates/shib13-sp-hosted.php
@@ -0,0 +1,35 @@
+<?php
+/* 
+ * SAML 2.0 Meta data for simpleSAMLphp
+ *
+ */
+
+$metadata = array(
+	'http://dev.andreas.feide.no'	=> array(
+		'AssertionConsumerService'	=>	'http://dev.andreas.feide.no/shib13/sp/AssertionConsumerService.php',
+		'host'						=>	'dev.andreas.feide.no'
+	),
+	'https://sp.shiblab.feide.no'	=> array(
+		'shire'				=>	'http://sp.shiblab.feide.no/Shibboleth.sso/SAML/POST',
+		'spnamequalifier'	=>	'urn:feide.no',
+		'audience'			=>	'urn:mace:feide:shiblab'
+	),
+	'urn:geant:edugain:component:be:switchaai-test:central' => array(
+		'shire'				=>	'https://edugain-login.switch.ch/ShiBE-R/WebSSOResponseListener',
+		'spnamequalifier'	=>	'urn:geant:edugain:component:be:rediris:rediris.es',
+		'audience'			=>	'urn:geant:edugain:component:be:switchaai-test:central'
+	),
+	'urn:geant:edugain:component:be:rediris:rediris.es' => array(
+		'shire'				=>	'http://serrano.rediris.es:8080/PAPIWebSSOResponseListener/request',
+		'spnamequalifier'	=>	'urn:geant:edugain:component:be:rediris:rediris.es',
+		'audience'			=>	'urn:geant:edugain:component:be:rediris:rediris.es'
+	),
+	'https://skjak.uninett.no/shibboleth/target' => array(
+		'shire'				=>	'https://skjak.uninett.no/Shibboleth.shire',
+		'spnamequalifier'	=>	'https://skjak.uninett.no/shibboleth/target',
+		'audience'			=>	'https://skjak.uninett.no/shibboleth/target'
+	)
+
+);
+
+?>
\ No newline at end of file
diff --git a/metadata-templates/shib13-sp-remote.php b/metadata-templates/shib13-sp-remote.php
new file mode 100644
index 000000000..f79d904bf
--- /dev/null
+++ b/metadata-templates/shib13-sp-remote.php
@@ -0,0 +1,32 @@
+<?php
+/* 
+ * SAML 2.0 Meta data for simpleSAMLphp
+ *
+ */
+
+
+$metadata = array(
+	'https://sp.shiblab.feide.no'	=> array(
+		'shire'				=>	'http://sp.shiblab.feide.no/Shibboleth.sso/SAML/POST',
+		'spnamequalifier'	=>	'urn:feide.no',
+		'audience'			=>	'urn:mace:feide:shiblab'
+	),
+	'urn:geant:edugain:component:be:switchaai-test:central' => array(
+		'shire'				=>	'https://edugain-login.switch.ch/ShiBE-R/WebSSOResponseListener',
+		'spnamequalifier'	=>	'urn:geant:edugain:component:be:rediris:rediris.es',
+		'audience'			=>	'urn:geant:edugain:component:be:switchaai-test:central'
+	),
+	'urn:geant:edugain:component:be:rediris:rediris.es' => array(
+		'shire'				=>	'http://serrano.rediris.es:8080/PAPIWebSSOResponseListener/request',
+		'spnamequalifier'	=>	'urn:geant:edugain:component:be:rediris:rediris.es',
+		'audience'			=>	'urn:geant:edugain:component:be:rediris:rediris.es'
+	),
+	'https://skjak.uninett.no/shibboleth/target' => array(
+		'shire'				=>	'https://skjak.uninett.no/Shibboleth.shire',
+		'spnamequalifier'	=>	'https://skjak.uninett.no/shibboleth/target',
+		'audience'			=>	'https://skjak.uninett.no/shibboleth/target'
+	)
+
+);
+
+?>
\ No newline at end of file
diff --git a/templates/error.php b/templates/error.php
new file mode 100644
index 000000000..8d4600144
--- /dev/null
+++ b/templates/error.php
@@ -0,0 +1,97 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title><?php echo $data['header']; ?></title>
+
+<style type="text/css">
+
+/* these styles are in the head of this page because this is a unique page */
+
+/* THE BIG GUYS */
+* {margin:0;padding:0}
+body {text-align:center;padding: 20px 0;background: #222;color:#333;font:83%/1.5 arial,tahoma,verdana,sans-serif}
+img {border:none;display:block}
+hr {margin: 1em 0;background:#eee;height:1px;color:#eee;border:none;clear:both}
+
+/* LINKS */
+a,a:link,a:link,a:link,a:hover {font-weight:bold;background:transparent;text-decoration:underline;cursor:pointer} 
+a:link {color:#c00} 
+a:visited {color:#999} 
+a:hover,a:active {color:#069} 
+
+/* LISTS */
+ul {margin: .3em 0 1.5em 2em}
+	ul.related {margin-top:-1em}
+li {margin-left:2em}
+dt {font-weight:bold}
+#wrap {border: 1px solid #fff;position:relative;background:#fff;width:600px;margin: 0 auto;text-align:left}
+#header {background: #666 url("/<?php echo $data['baseurlpath']; ?>resources/sprites.gif") repeat-x 0 100%;margin: 0 0 25px;padding: 0 0 8px}
+#header h1 {color:#fff;font-size: 145%;padding:20px 20px 12px}
+#poweredby {width:96px;height:63px;position:absolute;top:0;right:0}
+#content {padding: 0 20px}
+
+/* TYPOGRAPHY */
+p, ul, ol {margin: 0 0 1.5em}
+h1, h2, h3, h4, h5, h6 {letter-spacing: -1px;font-family: arial,verdana,sans-serif;margin: 1.2em 0 .3em;color:#000;border-bottom: 1px solid #eee;padding-bottom: .1em}
+h1 {font-size: 196%;margin-top:0;border:none}
+h2 {font-size: 136%}
+h3 {font-size: 126%}
+h4 {font-size: 116%}
+h5 {font-size: 106%}
+h6 {font-size: 96%}
+
+.old {text-decoration:line-through}
+</style>
+</head>
+<body>
+
+<div id="wrap">
+
+	<div id="header">
+		<h1>simpleSAMLphp error page</h1>
+		<div id="poweredby"><img src="/<?php echo $data['baseurlpath']; ?>resources/icons/bomb_l.png" alt="Login screen" /></div>
+	</div>
+	
+	<div id="content">
+	
+
+
+
+		<h2><?php if (isset($data['header'])) { echo $data['header']; } else { echo "Some error occured"; } ?></h2>
+		
+		<p>
+			
+			<?php echo $data['message']; ?>
+
+		</p>
+
+		
+		<p>The debug information below may be interesting for the administrator / help desk:</p>
+		
+		<div style="border: 1px solid #eee; padding: 1em; font-size: x-small">
+			<p style="margin: 1px"><?php echo htmlentities($data['e']->getMessage()); ?></p>
+			<div style=" padding: 1em; font-family: monospace; ">
+				<?php echo htmlentities($data['e']->getTraceAsString()); ?>
+			</div>
+		</div>
+		
+		<h2 style="clear: both">How to get help</h2>
+		
+		
+		<p>This error probably is due to some unexpected behaviour or to misconfiguration of simpleSAMLphp. Contact the administrator of this login service, and send them the error message above.</p>
+		
+
+
+		<hr />
+		
+		Copyright &copy; 2007 <a href="http://rnd.feide.no/">Feide RnD</a>
+		
+		<hr />
+	
+	</div>
+
+</div>
+
+</body>
+</html>
diff --git a/templates/login.php b/templates/login.php
new file mode 100644
index 000000000..756e37f62
--- /dev/null
+++ b/templates/login.php
@@ -0,0 +1,124 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title><?php echo $data['header']; ?></title>
+<script>
+<!--
+function sf(){document.f.username.focus();}
+// -->
+</script>
+<style type="text/css">
+
+/* these styles are in the head of this page because this is a unique page */
+
+/* THE BIG GUYS */
+* {margin:0;padding:0}
+body {text-align:center;padding: 20px 0;background: #222;color:#333;font:83%/1.5 arial,tahoma,verdana,sans-serif}
+img {border:none;display:block}
+hr {margin: 1em 0;background:#eee;height:1px;color:#eee;border:none;clear:both}
+
+/* LINKS */
+a,a:link,a:link,a:link,a:hover {font-weight:bold;background:transparent;text-decoration:underline;cursor:pointer} 
+a:link {color:#c00} 
+a:visited {color:#999} 
+a:hover,a:active {color:#069} 
+
+/* LISTS */
+ul {margin: .3em 0 1.5em 2em}
+	ul.related {margin-top:-1em}
+li {margin-left:2em}
+dt {font-weight:bold}
+#wrap {border: 1px solid #fff;position:relative;background:#fff;width:600px;margin: 0 auto;text-align:left}
+#header {background: #666 url("/<?php echo $data['baseurlpath']; ?>resources/sprites.gif") repeat-x 0 100%;margin: 0 0 25px;padding: 0 0 8px}
+#header h1 {color:#fff;font-size: 145%;padding:20px 20px 12px}
+#poweredby {width:96px;height:63px;position:absolute;top:0;right:0}
+#content {padding: 0 20px}
+
+/* TYPOGRAPHY */
+p, ul, ol {margin: 0 0 1.5em}
+h1, h2, h3, h4, h5, h6 {letter-spacing: -1px;font-family: arial,verdana,sans-serif;margin: 1.2em 0 .3em;color:#000;border-bottom: 1px solid #eee;padding-bottom: .1em}
+h1 {font-size: 196%;margin-top:0;border:none}
+h2 {font-size: 136%}
+h3 {font-size: 126%}
+h4 {font-size: 116%}
+h5 {font-size: 106%}
+h6 {font-size: 96%}
+
+.old {text-decoration:line-through}
+</style>
+</head>
+<body onload="sf();">
+
+<div id="wrap">
+
+	<div id="header">
+		<h1>simpleSAMLphp authentication</h1>
+		<div id="poweredby"><img src="/<?php echo $data['baseurlpath']; ?>resources/icons/lock.png" alt="Login screen" /></div>
+	</div>
+	
+	<div id="content">
+	
+		<?php if (isset($data['error'])) { ?>
+		<div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5"
+		<img src="/<?php echo $data['baseurlpath']; ?>resources/icons/bomb.png" style="float: left; margin: 15px " />
+		<h2>What you entered was not accepted!</h2>
+		
+		<p><?php echo $data['error']; ?> </p>
+		</div>
+		<?php } ?>
+	
+		<h2 style="break: both">Enter your username and password</h2>
+		
+		<p>
+			A service has requested you to authenticate your self. That means you need to enter your username and password in the form below.
+		</p>
+		
+		<form action="?" method="post" name="f">
+
+		<table>
+			<tr>
+				<td rowspan="2"><img src="/<?php echo $data['baseurlpath']; ?>resources/icons/pencil.png" /></td>
+				<td style="padding: .3em;">Username</td>
+				<td><input type="text" tabindex="1" name="username" 
+					<?php if (isset($data['username'])) {
+						echo 'value="' . $data['username'] . '"';
+					} ?> /></td>
+				<td style="padding: .4em; rowspan="2">
+					<input type="submit" tabindex="3" value="Login" />
+					<input type="hidden" name="RelayState" value="<?php echo $data['relaystate']; ?>" />
+				</td>
+			</tr>
+			<tr>
+				<td style="padding: .3em;">Password</td>
+				<td><input type="password" tabindex="2" name="password" /></td>
+			</tr>
+		</table>
+		
+		
+		</form>
+		
+		
+		<h2>Help! I don't remember my password.</h2>
+		
+		
+		<p>Too bad! - Without your username and password you cannot authenticate your self and access the service.
+		There may be someone that can help you. Contact the help desk at your university!</p>
+		
+		<h2>About simpleSAMLphp</h2>
+		<p>Hey! This simpleSAMLphp thing is pretty cool, where can I read more about it?
+		You can find more information about simpleSAMLphp at <a href="http://rnd.feide.no">the Feide RnD blog</a> over at <a href="http://uninett.no">UNINETT</a>.</p>
+		
+
+		<hr />
+		
+		Copyright &copy; 2007 <a href="http://rnd.feide.no/">Feide RnD</a>
+		
+		<hr />
+	
+	</div>
+
+</div>
+
+</body>
+</html>
diff --git a/templates/post-debug.php b/templates/post-debug.php
new file mode 100644
index 000000000..b3dfebf11
--- /dev/null
+++ b/templates/post-debug.php
@@ -0,0 +1,91 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title><?php echo $data['header']; ?></title>
+<script>
+<!--
+function sf(){document.f.username.focus();}
+// -->
+</script>
+<style type="text/css">
+
+/* these styles are in the head of this page because this is a unique page */
+
+/* THE BIG GUYS */
+* {margin:0;padding:0}
+body {text-align:center;padding: 20px 0;background: #222;color:#333;font:83%/1.5 arial,tahoma,verdana,sans-serif}
+img {border:none;display:block}
+hr {margin: 1em 0;background:#eee;height:1px;color:#eee;border:none;clear:both}
+
+/* LINKS */
+a,a:link,a:link,a:link,a:hover {font-weight:bold;background:transparent;text-decoration:underline;cursor:pointer} 
+a:link {color:#c00} 
+a:visited {color:#999} 
+a:hover,a:active {color:#069} 
+
+/* LISTS */
+ul {margin: .3em 0 1.5em 2em}
+	ul.related {margin-top:-1em}
+li {margin-left:2em}
+dt {font-weight:bold}
+#wrap {border: 1px solid #fff;position:relative;background:#fff;width:600px;margin: 0 auto;text-align:left}
+#header {background: #666 url("/<?php echo $data['baseurlpath']; ?>resources/sprites.gif") repeat-x 0 100%;margin: 0 0 25px;padding: 0 0 8px}
+#header h1 {color:#fff;font-size: 145%;padding:20px 20px 12px}
+#poweredby {width:96px;height:63px;position:absolute;top:0;right:0}
+#content {padding: 0 20px}
+
+/* TYPOGRAPHY */
+p, ul, ol {margin: 0 0 1.5em}
+h1, h2, h3, h4, h5, h6 {letter-spacing: -1px;font-family: arial,verdana,sans-serif;margin: 1.2em 0 .3em;color:#000;border-bottom: 1px solid #eee;padding-bottom: .1em}
+h1 {font-size: 196%;margin-top:0;border:none}
+h2 {font-size: 136%}
+h3 {font-size: 126%}
+h4 {font-size: 116%}
+h5 {font-size: 106%}
+h6 {font-size: 96%}
+
+.old {text-decoration:line-through}
+</style>
+</head>
+<body onload="sf();">
+
+<div id="wrap">
+
+	<div id="header">
+		<h1>simpleSAMLphp authentication</h1>
+		<div id="poweredby"><img src="/<?php echo $data['baseurlpath']; ?>resources/icons/debug.png" alt="Debug" /></div>
+	</div>
+	
+	<div id="content">
+	
+
+
+		<h2>Sending a SAML response to the service</h2>
+	
+		<p>You are about to send a SAML response back to the service. Hit the send response button to continue.</p>
+		
+		<form method="post" action="<?php echo $data['destination']; ?>">
+			<input type="hidden" name="SAMLResponse" value="<?php echo $data['response']; ?>" />
+			<input type="hidden" name="<?php echo $data['RelayStateName']; ?>" value="<?php echo $data['RelayState']; ?>">
+			<input type="submit" value="Submit the response to the service" />
+		</form>
+
+		<h2>Debug mode</h2>
+		
+		<p>As you are in debug mode you are lucky to see the content of the response you are sending:</p>
+		
+		<pre style="overflow: scroll; border: 1px solid #eee"><?php echo $data['responseHTML']; ?></pre>
+
+		<hr />
+		
+		Copyright &copy; 2007 <a href="http://rnd.feide.no/">Feide RnD</a>
+		
+		<hr />
+	
+	</div>
+
+</div>
+
+</body>
+</html>
diff --git a/templates/post.php b/templates/post.php
new file mode 100644
index 000000000..2329cdbca
--- /dev/null
+++ b/templates/post.php
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+	<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+	<title>SAML 2.0 POST</title>
+</head>
+<body onload="document.forms[0].submit()">
+
+	<noscript>
+		<p><strong>Note:</strong> Since your browser does not support JavaScript, you must press the button below once to proceed.</p> 
+	</noscript> 
+	
+	<form method="post" action="<?php echo $data['destination']; ?>">
+		<input type="hidden" name="SAMLResponse" value="<?php echo $data['response']; ?>" />
+		<input type="hidden" name="<?php echo $data['RelayStateName']; ?>" value="<?php echo $data['RelayState']; ?>">
+		
+		<noscript>
+			<input type="submit" value="Submit the response to the service" />
+		</noscript>
+	</form>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/templates/status.php b/templates/status.php
new file mode 100644
index 000000000..609c04361
--- /dev/null
+++ b/templates/status.php
@@ -0,0 +1,111 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title><?php echo $data['header']; ?></title>
+
+<style type="text/css">
+
+/* these styles are in the head of this page because this is a unique page */
+
+/* THE BIG GUYS */
+* {margin:0;padding:0}
+body {text-align:center;padding: 20px 0;background: #222;color:#333;font:83%/1.5 arial,tahoma,verdana,sans-serif}
+img {border:none;display:block}
+hr {margin: 1em 0;background:#eee;height:1px;color:#eee;border:none;clear:both}
+
+/* LINKS */
+a,a:link,a:link,a:link,a:hover {font-weight:bold;background:transparent;text-decoration:underline;cursor:pointer} 
+a:link {color:#c00} 
+a:visited {color:#999} 
+a:hover,a:active {color:#069} 
+
+/* LISTS */
+ul {margin: .3em 0 1.5em 2em}
+	ul.related {margin-top:-1em}
+li {margin-left:2em}
+dt {font-weight:bold}
+#wrap {border: 1px solid #fff;position:relative;background:#fff;width:600px;margin: 0 auto;text-align:left}
+#header {background: #666 url("/<?php echo $data['baseurlpath']; ?>resources/sprites.gif") repeat-x 0 100%;margin: 0 0 25px;padding: 0 0 8px}
+#header h1 {color:#fff;font-size: 145%;padding:20px 20px 12px}
+#poweredby {width:96px;height:63px;position:absolute;top:0;right:0}
+#content {padding: 0 20px}
+
+/* TYPOGRAPHY */
+p, ul, ol {margin: 0 0 1.5em}
+h1, h2, h3, h4, h5, h6 {letter-spacing: -1px;font-family: arial,verdana,sans-serif;margin: 1.2em 0 .3em;color:#000;border-bottom: 1px solid #eee;padding-bottom: .1em}
+h1 {font-size: 196%;margin-top:0;border:none}
+h2 {font-size: 136%}
+h3 {font-size: 126%}
+h4 {font-size: 116%}
+h5 {font-size: 106%}
+h6 {font-size: 96%}
+
+.old {text-decoration:line-through}
+</style>
+</head>
+<body>
+
+<div id="wrap">
+
+	<div id="header">
+		<h1>simpleSAMLphp status page</h1>
+		<div id="poweredby"><img src="/<?php echo $data['baseurlpath']; ?>resources/icons/bino.png" alt="Bino" /></div>
+	</div>
+	
+	<div id="content">
+
+		<h2><?php if (isset($data['header'])) { echo $data['header']; } else { echo "Some error occured"; } ?></h2>
+		
+		<p>Hi, this is the status page of simpleSAMLphp. Here you can see if your session is timed out, how long it lasts until it times out and all the attributes that is attached to your session.</p>
+		
+		<p><?php echo $data['valid']; ?>. Your session is valid for <?php echo $data['remaining']; ?> seconds from now.</p>
+		
+		<h2>Your attributes</h2>
+		
+
+			<table>
+			<?php
+			
+			$attributes = $data['attributes'];
+			foreach ($attributes AS $name => $value) {
+				if (sizeof($value) > 1) {
+					echo '<tr><td>' . $name . '</td><td><ul>';
+					foreach ($value AS $v) {
+						echo '<li>' . $v . '</li>';
+					}
+					echo '</ul></td></tr>';
+				} else {
+					echo '<tr><td>' . $name . '</td><td>' . $value[0] . '</td></tr>';
+				}
+			}
+			
+			#echo "\n\n\n" . $session->getMessage() . "\n\n\n";
+			
+			?>
+			</table>
+
+		<h2>Logout</h2>
+
+			<p><?php echo $data['logout']; ?></p>
+		
+		<h2>About simpleSAMLphp</h2>
+		<p>Hey! This simpleSAMLphp thing is pretty cool, where can I read more about it?
+		You can find more information about simpleSAMLphp at <a href="http://rnd.feide.no">the Feide RnD blog</a> over at <a href="http://uninett.no">UNINETT</a>.</p>
+		
+
+		
+
+
+		<hr />
+		
+		Copyright &copy; 2007 <a href="http://rnd.feide.no/">Feide RnD</a>
+		
+		<hr />
+	
+	</div>
+
+</div>
+
+</body>
+</html>
diff --git a/www/_include.php b/www/_include.php
new file mode 100644
index 000000000..ab5e7dcab
--- /dev/null
+++ b/www/_include.php
@@ -0,0 +1,18 @@
+<?php
+
+
+
+$path_extra = dirname(dirname(__FILE__)) . '/lib';
+
+$path = ini_get('include_path');
+$path = $path_extra . PATH_SEPARATOR . $path;
+ini_set('include_path', $path);
+
+require_once('SimpleSAML/Configuration.php');
+
+SimpleSAML_Configuration::init(dirname(dirname(__FILE__)) . '/config');
+
+
+
+
+?>
\ No newline at end of file
diff --git a/www/auth/login-auto.php b/www/auth/login-auto.php
new file mode 100644
index 000000000..f06c29baf
--- /dev/null
+++ b/www/auth/login-auto.php
@@ -0,0 +1,95 @@
+<?php
+
+
+require_once('../../www/_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnRequest.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+require_once('SimpleSAML/XHTML/Template.php');
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+	
+$session = SimpleSAML_Session::getInstance();
+
+$error = null;
+$attributes = array();
+	
+if (isset($_POST['username'])) {
+
+
+	$dn = str_replace('%username%', $_POST['username'], $config->getValue('auth.ldap.dnpattern'));
+	$pwd = $_POST['password'];
+
+	$ds = ldap_connect($config->getValue('auth.ldap.hostname'));
+	
+	if ($ds) {
+	
+		if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) {
+			echo "Failed to set LDAP Protocol version to 3";
+			exit;
+		}
+		/*
+		if (!ldap_start_tls($ds)) {
+		echo "Failed to start TLS";
+		exit;
+		}
+		*/
+		if (!ldap_bind($ds, $dn, $pwd)) {
+			$error = "Bind failed, wrong username or password. Tried with DN=[" . $dn . "] DNPattern=[" . $config->getValue('auth.ldap.dnpattern') . "]";
+			
+			
+		} else {
+			$sr = ldap_read($ds, $dn, $config->getValue('auth.ldap.attributes'));
+			$ldapentries = ldap_get_entries($ds, $sr);
+			
+
+			for ($i = 0; $i < $ldapentries[0]['count']; $i++) {
+				$values = array();
+				if ($ldapentries[0][$i] == 'jpegphoto') continue;
+				for ($j = 0; $j < $ldapentries[0][$ldapentries[0][$i]]['count']; $j++) {
+					$values[] = $ldapentries[0][$ldapentries[0][$i]][$j];
+				}
+				
+				$attributes[$ldapentries[0][$i]] = $values;
+			}
+
+			// generelt ldap_next_entry for flere, men bare ett her
+			//print_r($ldapentries);
+			//print_r($attributes);
+			
+			$session->setAuthenticated(true);
+			$session->setAttributes($attributes);
+			$returnto = $_SESSION['webssourl']. '?RequestID=' . $_REQUEST['RequestID'];
+			header("Location: " . $returnto);
+
+		}
+	// ldap_close() om du vil, men frigjoeres naar skriptet slutter
+	}
+	
+
+	
+	
+}
+
+
+$t = new SimpleSAML_XHTML_Template($config, 'login.php');
+
+$t->data['header'] = 'simpleSAMLphp: Enter username and password';	
+$t->data['requestid'] = $_REQUEST['RequestID'];
+$t->data['error'] = $error;
+if (isset($error)) {
+	$t->data['username'] = $_POST['username'];
+}
+
+$t->show();
+
+
+?>
diff --git a/www/auth/login-radius.php b/www/auth/login-radius.php
new file mode 100644
index 000000000..49ceee2e9
--- /dev/null
+++ b/www/auth/login-radius.php
@@ -0,0 +1,95 @@
+<?php
+
+
+require_once('../../www/_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnRequest.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+require_once('SimpleSAML/XHTML/Template.php');
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+	
+$session = SimpleSAML_Session::getInstance();
+
+$error = null;
+$attributes = array();
+	
+if (isset($_POST['username'])) {
+
+
+	$dn = str_replace('%username%', $_POST['username'], $config->getValue('auth.ldap.dnpattern'));
+	$pwd = $_POST['password'];
+
+	$ds = ldap_connect($config->getValue('auth.ldap.hostname'));
+	
+	if ($ds) {
+	
+		if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) {
+			echo "Failed to set LDAP Protocol version to 3";
+			exit;
+		}
+		/*
+		if (!ldap_start_tls($ds)) {
+		echo "Failed to start TLS";
+		exit;
+		}
+		*/
+		if (!ldap_bind($ds, $dn, $pwd)) {
+			$error = "Bind failed, wrong username or password. Tried with DN=[" . $dn . "] DNPattern=[" . $config->getValue('auth.ldap.dnpattern') . "]";
+			
+			
+		} else {
+			$sr = ldap_read($ds, $dn, $config->getValue('auth.ldap.attributes'));
+			$ldapentries = ldap_get_entries($ds, $sr);
+			
+
+			for ($i = 0; $i < $ldapentries[0]['count']; $i++) {
+				$values = array();
+				if ($ldapentries[0][$i] == 'jpegphoto') continue;
+				for ($j = 0; $j < $ldapentries[0][$ldapentries[0][$i]]['count']; $j++) {
+					$values[] = $ldapentries[0][$ldapentries[0][$i]][$j];
+				}
+				
+				$attributes[$ldapentries[0][$i]] = $values;
+			}
+
+			// generelt ldap_next_entry for flere, men bare ett her
+			//print_r($ldapentries);
+			//print_r($attributes);
+			
+			$session->setAuthenticated(true);
+			$session->setAttributes($attributes);
+			$returnto = $_REQUEST['RelayState'];
+			header("Location: " . $returnto);
+
+		}
+	// ldap_close() om du vil, men frigjoeres naar skriptet slutter
+	}
+	
+
+	
+	
+}
+
+
+$t = new SimpleSAML_XHTML_Template($config, 'login.php');
+
+$t->data['header'] = 'simpleSAMLphp: Enter username and password';	
+$t->data['requestid'] = $_REQUEST['RequestID'];
+$t->data['error'] = $error;
+if (isset($error)) {
+	$t->data['username'] = $_POST['username'];
+}
+
+$t->show();
+
+
+?>
diff --git a/www/auth/login.php b/www/auth/login.php
new file mode 100644
index 000000000..31f05dfbd
--- /dev/null
+++ b/www/auth/login.php
@@ -0,0 +1,98 @@
+<?php
+
+
+require_once('../../www/_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnRequest.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+require_once('SimpleSAML/XHTML/Template.php');
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+	
+$session = SimpleSAML_Session::getInstance();
+
+$error = null;
+$attributes = array();
+	
+if (isset($_POST['username'])) {
+
+
+	$dn = str_replace('%username%', $_POST['username'], $config->getValue('auth.ldap.dnpattern'));
+	$pwd = $_POST['password'];
+
+	$ds = ldap_connect($config->getValue('auth.ldap.hostname'));
+	
+	if ($ds) {
+	
+		if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) {
+			echo "Failed to set LDAP Protocol version to 3";
+			exit;
+		}
+		/*
+		if (!ldap_start_tls($ds)) {
+		echo "Failed to start TLS";
+		exit;
+		}
+		*/
+		if (!ldap_bind($ds, $dn, $pwd)) {
+			$error = "Bind failed, wrong username or password. Tried with DN=[" . $dn . "] DNPattern=[" . $config->getValue('auth.ldap.dnpattern') . "]";
+			
+			
+		} else {
+			$sr = ldap_read($ds, $dn, $config->getValue('auth.ldap.attributes'));
+			$ldapentries = ldap_get_entries($ds, $sr);
+			
+
+			for ($i = 0; $i < $ldapentries[0]['count']; $i++) {
+				$values = array();
+				if ($ldapentries[0][$i] == 'jpegphoto') continue;
+				for ($j = 0; $j < $ldapentries[0][$ldapentries[0][$i]]['count']; $j++) {
+					$values[] = $ldapentries[0][$ldapentries[0][$i]][$j];
+				}
+				
+				$attributes[$ldapentries[0][$i]] = $values;
+			}
+
+			// generelt ldap_next_entry for flere, men bare ett her
+			//print_r($ldapentries);
+			//print_r($attributes);
+			
+			$session->setAuthenticated(true);
+			$session->setAttributes($attributes);
+			
+			$session->setNameID(SimpleSAML_Utilities::generateID());
+			$session->setNameIDFormat('urn:oasis:names:tc:SAML:2.0:nameid-format:transient');
+			
+			$returnto = $_REQUEST['RelayState'];
+			header("Location: " . $returnto);
+			exit(0);
+
+		}
+	// ldap_close() om du vil, men frigjoeres naar skriptet slutter
+	}
+
+	
+}
+
+
+$t = new SimpleSAML_XHTML_Template($config, 'login.php');
+
+$t->data['header'] = 'simpleSAMLphp: Enter username and password';	
+$t->data['relaystate'] = $_REQUEST['RelayState'];
+$t->data['error'] = $error;
+if (isset($error)) {
+	$t->data['username'] = $_POST['username'];
+}
+
+$t->show();
+
+
+?>
diff --git a/www/example-simple/saml2-example.php b/www/example-simple/saml2-example.php
new file mode 100644
index 000000000..7da667c98
--- /dev/null
+++ b/www/example-simple/saml2-example.php
@@ -0,0 +1,52 @@
+<?php
+
+require_once('../_include.php');
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnRequest.php');
+require_once('SimpleSAML/XML/SAML20/AuthnResponse.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php');
+require_once('SimpleSAML/XHTML/Template.php');
+
+session_start();
+
+/* Load simpleSAMLphp, configuration and metadata */
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+$session = SimpleSAML_Session::getInstance();
+
+/* Check if valid local session exists.. */
+if (!isset($session) || !$session->isValid() ) {
+	header('Location: /' . $config->getValue('baseurlpath') . 'saml2/sp/initSSO.php?RelayState=' . urlencode(SimpleSAML_Utilities::selfURL()));
+	exit(0);
+}
+
+$attributes = $session->getAttributes();
+
+/*
+ * The attributes variable now contains all the attributes. So this variable is basicly all you need to perform integration in 
+ * your PHP application.
+ * 
+ * To debug the content of the attributes variable, do something like:
+ *
+ * print_r($attributes);
+ *
+ */
+
+
+
+$et = new SimpleSAML_XHTML_Template($config, 'status.php');
+
+$et->data['header'] = 'SAML 2.0 SP Demo Example';
+$et->data['remaining'] = $session->remainingTime();
+$et->data['attributes'] = $attributes;
+$et->data['valid'] = $session->isValid() ? 'Session is valid' : 'Session is invalid';
+$et->data['logout'] = '[ <a href="https://sam.feide.no/amserver/saml2/jsp/idpSingleLogoutInit.jsp?binding=urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect">IdP intiated logout from Feide (only if you are connected to the Feide IdP)</a> ]</p>
+			<p>[ <a href="/' . $config->getValue('baseurlpath') . 'saml2/sp/initSLO.php?RelayState=' .  urlencode(SimpleSAML_Utilities::selfURL()) . '">SP initated logout</a> ]';
+$et->show();
+
+
+?>
\ No newline at end of file
diff --git a/www/example-simple/shib13-example.php b/www/example-simple/shib13-example.php
new file mode 100644
index 000000000..377816a7f
--- /dev/null
+++ b/www/example-simple/shib13-example.php
@@ -0,0 +1,35 @@
+<?php
+
+require_once('../_include.php');
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XHTML/Template.php');
+session_start();
+
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+$session = SimpleSAML_Session::getInstance();
+
+if (!isset($session) || !$session->isValid() ) {
+	
+	header('Location: ' . $config->getValue('baseurlpath') . '/shib13/sp/initSSO.php?RelayState=' . urlencode(SimpleSAML_Utilities::selfURL()));
+		// . '&idpentityid=' . $idpentityid );
+	exit(0);
+}
+
+$et = new SimpleSAML_XHTML_Template($config, 'status.php');
+
+$et->data['header'] = 'Shibboleth demo';
+$et->data['remaining'] = $session->remainingTime();
+$et->data['attributes'] = $session->getAttributes();
+$et->data['valid'] = $session->isValid() ? 'Session is valid' : 'Session is invalid';
+$et->data['logout'] = 'Shibboleth logout not implemented yet.';
+
+$et->show();
+
+
+?>
diff --git a/www/index.html b/www/index.html
new file mode 100644
index 000000000..9940b30d5
--- /dev/null
+++ b/www/index.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>simpleSAMLphp</title>
+
+<style type="text/css">
+
+/* these styles are in the head of this page because this is a unique page */
+
+/* THE BIG GUYS */
+* {margin:0;padding:0}
+body {text-align:center;padding: 20px 0;background: #222;color:#333;font:83%/1.5 arial,tahoma,verdana,sans-serif}
+img {border:none;display:block}
+hr {margin: 1em 0;background:#eee;height:1px;color:#eee;border:none;clear:both}
+
+/* LINKS */
+a,a:link,a:link,a:link,a:hover {font-weight:bold;background:transparent;text-decoration:underline;cursor:pointer} 
+a:link {color:#c00} 
+a:visited {color:#999} 
+a:hover,a:active {color:#069} 
+
+/* LISTS */
+ul {margin: .3em 0 1.5em 2em}
+	ul.related {margin-top:-1em}
+li {margin-left:2em}
+dt {font-weight:bold}
+#wrap {border: 1px solid #fff;position:relative;background:#fff;width:600px;margin: 0 auto;text-align:left}
+#header {background: #666 url("resources/sprites.gif") repeat-x 0 100%;margin: 0 0 25px;padding: 0 0 8px}
+#header h1 {color:#fff;font-size: 145%;padding:20px 20px 12px}
+#poweredby {width:96px;height:63px;position:absolute;top:0;right:0}
+#content {padding: 0 20px}
+
+/* TYPOGRAPHY */
+p, ul, ol {margin: 0 0 1.5em}
+h1, h2, h3, h4, h5, h6 {letter-spacing: -1px;font-family: arial,verdana,sans-serif;margin: 1.2em 0 .3em;color:#000;border-bottom: 1px solid #eee;padding-bottom: .1em}
+h1 {font-size: 196%;margin-top:0;border:none}
+h2 {font-size: 136%}
+h3 {font-size: 126%}
+h4 {font-size: 116%}
+h5 {font-size: 106%}
+h6 {font-size: 96%}
+
+.old {text-decoration:line-through}
+</style>
+</head>
+<body>
+
+<div id="wrap">
+
+	<div id="header">
+		<h1>simpleSAMLphp is installed</h1>
+		<div id="poweredby"><img src="resources/icons/compass_l.png" alt="Bino" /></div>
+	</div>
+	
+	<div id="content">
+
+		<h2>Welcome to simpleSAMlphp</h2>
+		
+		<p>You have installed simpleSAMLphp on this web host.</p>
+		
+		<p>After you have configured it properly as described in the documentation you may want to test one of the two examples:
+			<ul>
+				<li><a href="example-simple/saml2-example.php">SAML 2.0 SP example</a></li>
+				<li><a href="example-simple/shib13-example.php">Shibboleth 1.3 SP example</a></li>
+			</ul>
+		</p>
+
+		<h2>About simpleSAMLphp</h2>
+		<p>Hey! This simpleSAMLphp thing is pretty cool, where can I read more about it?
+		You can find more information about simpleSAMLphp at <a href="http://rnd.feide.no">the Feide RnD blog</a> over at <a href="http://uninett.no">UNINETT</a>.</p>
+		
+
+		
+
+
+		<hr />
+		
+		Copyright &copy; 2007 <a href="http://rnd.feide.no/">Feide RnD</a>
+		
+		<hr />
+	
+	</div>
+
+</div>
+
+</body>
+</html>
diff --git a/www/resources/icons/bino.png b/www/resources/icons/bino.png
new file mode 100644
index 0000000000000000000000000000000000000000..8708a439c91d39ac5a195d1af6d87178663775c8
GIT binary patch
literal 15118
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

literal 0
HcmV?d00001

diff --git a/www/resources/icons/bomb.png b/www/resources/icons/bomb.png
new file mode 100644
index 0000000000000000000000000000000000000000..35811006b5cabde251612955aa1f6385c71829da
GIT binary patch
literal 3439
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
Ro~{4@002ovPDHLkV1nmltq%YI

literal 0
HcmV?d00001

diff --git a/www/resources/icons/bomb_l.png b/www/resources/icons/bomb_l.png
new file mode 100644
index 0000000000000000000000000000000000000000..901409504180b295662068d599aa85e7f5482003
GIT binary patch
literal 8960
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
a$NvM{Nk$_xYo8AQ0000<MNUMnLSTYIlwcJA

literal 0
HcmV?d00001

diff --git a/www/resources/icons/compass_l.png b/www/resources/icons/compass_l.png
new file mode 100644
index 0000000000000000000000000000000000000000..2ad574a7b38e661b462e0ad8d72207234cd8e827
GIT binary patch
literal 17694
zcmW(+bx_>T&;G!{;ZmTuyZ6xI94-ZlTZ_9>tT>04;_mL!;!xa*ySuv;cl&+ccV~9@
zzs+PP$vjD(gefb@V4xDC0sw#^Co8G?-wpe}jST+p>=7{<1^~%jIY}{f_odS|6!)(d
ziS*v`^~vgS@=wN}YEIk@jE674I&zd`0&wD?E({Wu;@jL4=q?|hF^8XpxrbA-jEXFX
z@8w?2PcbKW<p$&fB2W3kF)p&)8}UCZnI$%qsV0`mJFhvPH8pFn^DCX>RE=LHsJoUQ
z&9$w2jQh5qIZwQAt{D7Q`e6fAPq!H!Hk|Pr*x)Q?0sf2}dILF=-a*%}>BEAHi;JqB
zP0Oxhb>>;8Qip5Q-J(WR0P<|UOq1~9zqMujfJOOd^<R=Z^(0PsA8*lg>CK^wfOo0G
zGb+)wIo!nG=-KB#;Wa7b16V_T(aUna9ogO@6m)7#@==j0toZqVwdL2o^OLbnTArj2
z?kw~qKkijdq=PzjeJiRdU<sd7Rb|x5hDr+Z(oj(^$M01Ih;k1YCp)1jnB+pTtHM4`
zD~B!>(bCjd`W#rvNn?nB@|~ebfj+I*Qk@mI#Te;>LCV?iy<-5PFb{rl^~@jFkyDqL
z>C?i=Nfm1mZ<yP^<<D)x!aEo4y40})Y+6vq!-GfwC=!({YR=Zxl9_M6(lz%EEb&lg
zeurDcV#Y;*FtJk`#>mQ=bG^Xm>f$yzm#m*F>}6m=K{d-s9L^S8=~#-i?Nm?;*Qxqo
zxN&KdG$B~oqC%Le#1MQT?*=e3VN>4Z7`A5*F_$qCa(f4J++t+C?wVY$^eMVG#ZokW
zJ?i>HYQ+h3P6qCTXLjr+-A!EX&d2o2apMt<#&}x7r@%Q-4v0YEBKt#`IL$M7*M*hz
zUT9|Kr=?y%5>B?S8L8?+uka$FckMU798@eU7}h*vDArqNKu%36>_F$<*@g@<?`!k-
ziUJ$Winxy<A<~REMEHm7jI2c=X`Gh?iM8CtC545-`hG7w)}o8@#XU56|7>iEr>?Ek
ztmO3qEdyv|qOe1QwnT%(sfdY)Vol!G@5qZ7vy-iuMBVg{#F{b~2>{;nZF7j<#a6G&
zwBpA>F^HdK=lMqBLyQZ=aX5)>W@Uv{Va&OCoX^P0>W3z)fgG2`SdLo%m(u1UX($||
z6Yu%DShP?}-vg0CZ#)`H@Bd#V0c4MCl|T4BO!ca3e37|0fVkcTOI>b`N}NjAH8wO%
z{abCZis_0a4L>uL`5jEeOfJmzamSI5m<U@@q*5?QsFUXtzOwIxEcWK}fASLcD_ig3
zU+&laeijdqD|KvP>kAEmJ0)zdv?_J$e{Mf9)j4j8$4;%S=@SzX$6#?cW)*BYez*xi
zD!sW!0ZUPnMoQ1KY&$ELR8^h-Zf$Lqh5=#J%C4^ULYlw7GNpmqfq`8oQAavCmx}>R
zAjos{YX1W|+t)v^qayX`x<jo&5(cFV?8CE@gPir#6}J9nucrlj8MmmuJmqEP>f1M}
zD}Q%CSL#?Oz6v#Jj5Ly`f`M0?f8>SxwY;Qb>;NV#9rVzJ!LqQNt*a)bHJZf|M$Tvb
zYgA?z)UjM0?smE)<-z{3H!n6xn;W%KIOAsEH`+?Ct{H|miqKCG`^9UQBT!yh868C-
zswDVb>E5@3EvabwkY#K`ic%1mOG-?x)M@@v*zql-#IM8>f*eIo*x>Wz_U+a%9|;Mm
z>lyzlcVwKBm%_$kB&GUs*x;3O)nh+1so-qABfGh!#mb#eymThT8^81M;<K-~kFEWP
zGyACP7>kSVASS@)_pygx?FkF`3-&s^k?6PN!>I*2dHrb0T@axSj|5IlUu_83bnEsU
zL~p+7y7sh4r88onqyNASlhM*jwoJ{-!_E|N?am^AQJi-clIMuJ)c_kep6Qj%)|w`I
zt9WR@%?XmEwA%HOjaRT0Dqy}4IB3e5eELyoXzlG}u{Qmz?N0yVR_ca;V3@yq6LNER
zH@vSMKEPo~gpDINE_B5j8XUbr*U9rDw8o-<`;2|6S0ze(s9<N(X0Av-9!VbB>ZqcU
zdqZyU=1Cqds;yWEAg2PzOaOMCzXzrI1@<Kq5E2?Hnjl}uYmPPZ7v?e7`u0Mh?e%gq
zKh^zkW!aTiUPvo6u`V?^>C$JheZiM0v^Yk2@a`?=SAKN+ZGB~_8ZsM5@m%w#)KV=_
zw4C}@BuAz-`V9eI1eH@;tm3d69fnUHAF2c4y>xvOd*8qc;Jts(^Ep$OLcFG^q9Ve&
ze8}qXQiHn5a3V{uqc#JI3mh{DGL=7(HLf^)!i5Hz#$i&Y{0!B^b2ZFGB=<VukYl2m
zea<}dmKg<*fk37OS%(u`*kp-8&JP}@+Q}AxK479Urwuiy?lAtqbxTwv`uzRkCsL9y
zNlSOj9|6I^bNpXP*$H;`x32`@z;iCg9uaG|X<hI@|B;}zjSY!~qC?Koqcqdn*EUn4
z(G;TynpPK~EYBk*z>p?i*rH_5MSvvrVstnS|4S^w<*O`FPqw3b;HBqnci~77aJqaa
z(Dr!bu-oFZnmIEn0_TK2!A%M4p_RoyLTrM~n{txzptGRD)uIN7l~tDKUn<95vj&Ox
z!XJ6p`b(u`DeaMx&IkdrmZA)w{Qk;np-F`xS<(_)VDQrS*FPX4K<-=DM3F}g9{^jw
zj|s`i>*)Phs%QYEUW;)rsu7-`uQ9y7`=-=Vs~N8P-DB+LCQ|H6ZFWqdv7V1!kDj%B
zj@%`h#Flc|-^OgqL}Q!+G!Zci3j)Ew%*$81##Q<vq_NGtb)io!cjS5GQRqre1C}@d
z5Q)u8)V_oO^A=UcF0i_B<*siIV74y8S;y5#3a&7oHQgDJH?ncbLy&oI#8Q)^i{5j?
z75G37KD<8Ezp#QRO<+Sj0E9Y8L<7*1u;6->VHE(h2%E{D>Y{Je&+D_8eSu(%bb|T?
z1q39~TF<*RJ#QB+1~y%Sx2q34!9V&=$`_5Snc3KiyK>=F!X^N;{qaOq$e8~KHS(gA
zB1185{!E=W9Tf;=spXC*mRVNR8j;ZOo=UHRiqIv`e01HWoByJ-er{fK`dY`Cwd(LJ
zml<U=pOT16qdk3AfH}j%J{wWVMkvE$$Hj{t;7Ho=D!~KO1ohU#;h7Z8<d4G{{^J*h
z3Jd$ptof?ymxBW}8JStlEtVB!qR4%gT_kjXf#KnnruKGUkUCMCNLhLL-#sf8<UmyT
z>70ga?@N@1<>;R#1wOEgYTCm15MhMPl;OjI!cWQXxC3x#ks?IDZ6&B<h~AWbo~+QR
zWfb64c+y{Yz@VS0yhzt`xj&~;X(X#)dVHeQqQqcU(-~IR(3n)<)!^|SHKcEke*5Dq
z>()NbRLMZ|bv$Jh3xMEZcRj-_6XW9IB9!shRe-zOEc3&UBf>!L{QBDLaPBEn(`QR$
zOT>sl?I{R<V4%c0>8HQzW$|A6aFm<af_}%({?KU+E_2x^a@x4w&5hRJR7yVAEk5B6
zBO2k0ziK!gf!y=a{s!C*yzk$K9+=7`qvNL(SmW0R^^E><YVUY^>L@n*L{RNAs~d>g
z4dhJ}@PkswE#KGI5=zqk%Hhx1>N1>VA7ENYjS9jg<hHfM;s=|TsFkUbM%PFdlkJSv
z*4KKFChQLpL~3j3D9oDe;+17E`vwUFqauIhQXufo^tV)n0odDoFsGe?>WFIi!niO<
zx|*b5asfd%Ca~~WUub4lPE}vk`@XPu=lUM;;g3-YJfgoId}m31DCWRM*I>8Bxd&Oo
z+#GMLA)j%Mnx2obNyqiW_=IBP8kK6U-3}kcCBnHN9>RU*X!^%tuiLD@{I$e`r#vSD
zCoN?@F?*!f9h|zU72JKgX!CKrf*F@99y_khoM0;<VQCM2(R9R0pnLaH+1EeY`!!}3
zJCHuPw4TTN?EPhCRy*8-T}vsSYhGl2sa{>SzvE+FE{ClO(g<<JN~Fs>CJ=Dawf<F0
zs}VCWSnPFLv`xa6Lul{uv9w8SV$Hhu_Q#<SOTVgBbuPoQAi9PKxA<q#mx7yo!=2N{
zb)|BxO8nWfeUQI@)m?(Q+$dKT&2><bKUURAnoWU%aGOz?H@PrM%)Q~nfh^|t?1ZoI
zP~2z?Ss5qZ+QiQ5$w@xC`%7VuXJ>K~J|PeC%O@csP~v`&+f|jp#)cQE1&R{nDr3iy
z#E|F{@f!>C5Nk)6gbnKbC8H1_?kI!`yJ&(`kbbj37(G%tgo4-KQAK><#M-c=im&cB
zxB5y@c-uu^y5(S8uhS&7**d`LrUY-Sy1fLaD5nZHgC5upU4Q%Se(iZuoBhK2>0F`V
zu&ui__{u^>%;=D4zXvLOIY2W7foFJ^R$5WfZA=T~|FZ7Kq{vCa2b&6+wN)xa_3D7m
z`JQ|*i5WhuyMJB#zVCqnUQWT1FTkC1_Q>W5?B^H*25>3=s$t6aWBl?r+4j!*2G$np
zy<Ocbj58M1(EK=&aj3=?52s3L`Elm8two9ke#LriL8$&bMG^l}UmJj;&CJZni&D0_
z7krysDy-%d@c$`4R9evb^FO@w^R!`EOsa{Kfs?d|rhiF0Als1Mo}dpZAmX{+7H1w}
z7vdQt99$dbKNV#n`+C=Y2eDf?Z~fYjBziA)K?gn3>+uNG3sw*A0X;v3*v<2;9`g{Q
z_i<%M9AD;@(#cj&26b7=m=ic>^`|Usxhjz&^_X=|O*r8$DimjNhpP*A+TvA(bQ6xH
zxhA^4xJ3eXh>D@1YXoVw>><2-Ai#ZRf4{P{q~s480dk1pIn_&;<P;~0<yF8D+lLSD
zH5dZ_#zm39_66}Na&u!jtZ1frFD$ZsG}mOzu=mwNKY!_oLCxZ|@lQdxhkLsme~b5h
zNgp+4|K0KGSzV1h>Zr$u^-96#*lDRv6sA4W@8z-00d|C@*cI2vW4<Rj9_&?6s&V^K
z6Y1E5-bokFF^Ij@mKOl<>-D)7$Km#H^Wp4TnyHH{i$Y{U#VyY8;?ew<D<P?l_pEQo
z@Brn8?mICkV|Q_j<#?8!<{C(e`FErkkPUc5qv0@_en-&hedks-N6Aq@som<1GMe21
zLq%KRhTz3xQrSHvO)wDURtIqy9`P@u=yOlCA#=SQeGp~+W$qXxM4tRUyc`TiMKCet
z6d`i%kEIO)TY(22y;=_LnR?*J(7#V^I8G%MhLe;n#WT&mFPx1FFDZeHj4+b;Qjok}
ze49q#Q^YlV^c(UPghS51_$CMMk+D}9*}EgeM-iv<BCO{`DiT0O2#5=vCdigB9^{4e
z@z+_3JfZZ`ag&DWjv2Gp8m1vAh8o}j$jA#6+G^^AwyMkA&VAfz<C{5q7l}pyXsLbE
zXy3S9o^NUZn0~VNtK?1^>fBd!UooUklU|N$3~LL)Z8rR;!6|EICbeZtjRMjL^Y1>x
zz^sZNEL-bmUOVFfuMF=;q|>vgqchZs1YUq8p7C*=;h++-NH#c-tVD|P8<f4{Cy~lP
zZ&DuqHuE2Xd{BnZ_2F(mFoT)Quf%b;`y2|02q9c0O*u!XupX-rQ3N}{Py&ci5Exv-
zi^}7l1G+ryk_AZs=mbK!1RY&TnT`}z0q^ngF(UH7qu9?`AyeEF{u9y}QG469Ru7kc
zFNef)9BZXiY!ev_N`byC4rF?Gkea?OH4)#(Ws@LHWTa(XOx-JtSg8@LET&&>eSwFa
zpsJz>q#j{%iZ=!$O4(Fo`CcxyuE(rtD~L$q7NH;QARw0p<e^h$Y$2BfcCF0%EIFbp
z$}iW62lS{Q<HTv7Y1gYhGh>h$k;7ePMa8@PX^QlGdYqxnv3YFe4{ciNt`)=n57&RJ
z-C2vEjfICRI8+Q0;bb()w*@h9+9Utk@X0oG#lWUqVdCWSljRnRdq)yD;Rp|d#R#;U
zKgiQ;L24ah0N4RfLwt`)&zQs!nvedFb4nQLUd{4mF%cJWNllR^A;o9H#vlId=zI}%
zm4l3m_k5WN@ucigkb8Pk%;=R*-I{|+PWP$u{e<_Ja3CNs2G7bOg9Iw}@U)SeKeOa5
zNgY_Lq9cW}e&sqdGegT0Jhm;f>kWxdahRN&V_pKBnLSv?NRa8%i4x!d9|$(_<VjcH
z;@`N{fp<Mb$MBYEYJ;avI)?ttpzWA$AHy5#SjV96DUhXUQOjMTBvu_`4$+jeSjfKz
zjP%3V(@JHBj?L%yHS752{A_)JhWp3F#DBxo`e@{Ep;LRT3f~18LZ}8Ky1%ejeopaa
zM=%7iIof|qx`?A~-2oAHg8GHG+rRdHcrozH1c>R<=KjO@xI#$@Eda9N;_b09X)+^L
z;GkV;!0f{MG6Uc8N~bLVBR=gX#3to!CRs$_7I<jtKgC=W^Y?V8=D?5Y-C{euP6^`l
z@bG{q2l6uPa`3zfxn<8`n{y-EkJgun=%PkFAsE+34vjUD=%3sPm`$0?!D5$P-V4u1
zo<Z8u;&QXCnHSxb<|2gYZ0AuIe35|{<fd@K-2XgH#`euPrnZCpHgdSLS@4OHTM>rV
z@|kD`ozFLX!H>CeVt_N?oYZfQLiy)r?#r)sxfyzF9Gb)kZUN3PQsE%ni-pjs!|OA|
z0OwS4-w^s7E}ozp9WbJ9_YR?;FaNeyLAu&t!Hw`r6@4l`t2V7L@&Gn5=)1BLG6Nqq
zq4BK2yGtE%k(n1lK`U1^3yv$B-pX?i^ks6xEI}2FI=R;2#1_iyCr<s}h(zMcUilo?
zsFdmvU&7dE*49mS$ZEzw7!Wc2=9{E+%h~#m$jHzV7F&;t_e>EtcP^;NAz-AQ|5oF(
z2-(bjGgOkX|7{TJ*l>oTp{`yLQUtwmT%1L-T%*pn8DJzE&u4PI(R_FyIQC`FlvNHZ
zp{p8f1Y(SNC>YTvE6UA3QOnVh?_7PBB;Z5f5zXQ`Sd6&ipMs8(V1j8^w?|xrPJwfQ
z$g5s8D_#txDD}tQ4u8#q6U)LqnqP4qbr!^@l(NozWXO+)!i{T24+xYy=o3O9h}9M&
zPFT+2PSQzx#1#gtmcylHpFf(a3>h4Vqw$}q%l3r19Z;%;*yfmHXS*M1ZQbX#>+8HL
z$PtbAM=ng_{#Edk)4ZKwx^J0i-LvKsX}5=SF_+~OQN;M*^~^!)_X}_*0PK{b!y^L7
z?AR-L|JvCbb~EEh1J#h2L_i3(A`7dr+W?$E%D+F`K6&p{m}Mdh9}cKea{^0HY*<P8
zJri&)+=nM7Ccaqb`;~`Fwo&CflUZCjYJFp*wZWu}gB>CDP_@b8!JPt#*zI=9yq?#S
zGKjnG9e)<GV{3Y$dbKCkX*@kC1}Uc-r6!@wYo)lEGgEVNjVph;2`$pg2!IXm?UPdm
zhLvY$4kQt+A_Ne^0CT`05D;3~f9Rx}W?@*Bt&2&Kzt<3dy-c<oJh(^+!zUyoYa~_X
z{*&{nqN8Kws?x|!fh~%pi)iLV8xayJJy$#EF^y|8J}=;(>+JpkkC|<GW5hWq&ivoo
zzZMZjMN-T8IL+&aTD}N$<Y~X#0W8a>GyQnXw4ov6@CVr<!%l48)$=F~A~*e13a(Er
z{s3tBjOHHprGX-^YzTWaOH+<`t6vS*O-rI}Go>jf*v~0!9E=15_MW_b!!L4#+6k<F
zepB2b0P}ONH2QtCdmP0-I^ey0b+i;qqnX%xKQMmQb`_F-&`08spup%IFc!so%OOq2
zQU5Z#N=kJSCnWZ#<E>(}nE(fHK!}3qj{W=@UUl?CRuo6LvHeLe4ti1B*x^1&%FNDj
zxxN1OdUx2gpB0Zu$qFq@6d<b@nxbZAV=7v#CD3iq?-7uFeeEGLcHp?zza=PA{Iv)7
zNj}xxY}(eydkFm~vq2lnTnui5d;Qb-J|6nLz7R2;fiFjs-8u+(eg(J&dgd+YBU*zi
z9;dnaNb{$ZMM5jc<!LbtN%^Zn8`@e^m-x#LMT9L)!K1|RS>^c3%UFl~q-ZXRRPWb(
zYa&DVh%Ya+mRg<;gOeM=crDLPmiW1`^&j0pFy(LGN)~tBc*?HdZu-xPp927{37J_Q
z49#^abx{CDG8IKa>kXCihffozj}WrQT>OfXw#fG>11hQO21L|Y+u5HMq;f@6otr+v
zOvxsZIsNP<qzQje+6nPn)A`KED8v5h;9QN?@nm@s!SpNFQJ)ZilXU1K)kDmq;e;iD
z=(n=;mw01l)^imXZX>IJZMIO$@u*STKIzi^YsUZTJ`9O+u>YKAEWBG+!ILS5TsnJi
z_4_(o@JCDkTz__!FHK%=DnuV8No1l(Jz({n{KerPPyy_x<b<Suvgv7$b6<YvCk`je
zQh_tMp}gH9iN1WkvM}fi0YYm^9VK%I^-eKt^c^cZd)`uW*sWjv(<?NVHp$bgyUtWB
zkW>Pmi8Br_l1h$TEr4or4cZ9=4tgs$@Wxz$K{()mP2yTKz}xqjH~_Ktd1-hm`nA`$
z-K}E=LfOQlLAq3AJmX|4THkPDwo&+yH9f;X*8hS>4pGqRKGE)Ww=Cx9Gr8&imtSPo
z=kmxnv>FQsC+5N}K5pl&L%(=wVqsuF5huC7gRPGTlstxBS86v0+5d@39d~Q3D@d?D
zw)oOp`10g7{dPasSW^6fmCcB<MD&_0A-U=&4~<}>Nw-dUHh;Jn&d9y6Xu0tRuENtG
zj@^oayci@_>s|P`L6rvz!&6){`oP2BiaaW1!{+{5-OkQ=u+;}M8E%}9;)2P7bZf7c
zL!aEf!vT(|A^~Xtgd(kT_lMe_#z2ASvtp&%>i3k;O1QeNi?L~!%ljNeKoD7(+@Q(n
z{Y!7?zl1GqTBkJXl7Tegh$pOusVkC?;eC8A2RXm1u{~)hzv2OgWB&d79gD|qliBMJ
z4C-A`*(@KT%gT$C$;!W7Px7z&>M(;>MWKSt!J7}CZ7g$?{k3p}DC-lIxOOuP2y;UE
znk)dyF(<UJsD3VqX6U(s71H}Xf+fI)&qZkt{(Nh-p~^l%<y|zxz@`XS`o4@uDo@a|
zH&$9s%XgT-XR>`SLW}pSieDO9S%pJB;g1wdnyv^H=Mwk#tGd*DPl>8`9prGOS2>kr
z{7TH6)3WeQf2B@b_bkQ$h9C2^dF<)d0~YWuP~4-eLV3Yf<oteR41#68)tH;U7R_o+
z3V(k~<<Lf?(mYoCRY4K+I_lsZ+0fpqs84gqWuXarkMLqEzJ>ei3p!BzYYnE~mY1i>
zT$#yUMrx;fpa$WpqP{76d=Ds}QM!V2QO*U4yPK{^M+_w@y1f6cyG@yJy#D4KWUrrq
zH!%S_r$>_--n6FbE-#hTwq;&|e4B6j=w=|j2k7v~Cjf9GX8^6dN9=3D-NJ%?8cX5m
zxkQX1v2<{Fx3~Qo#oIXXf!t5Oz4rT=h$UPkGCLWNp|r1;8yDxwXtw6~!uc5geVtY=
zRk<XHdAQv2He-?cMK<2|^(vb{2CT<bOI-eU`a6WHHC3@W3B}P9W02Is>v$aNlD{0i
z*wHqjr}rD?DZKO#OWqV_N&xReiys8nUT6e+`jDqCkPKK%kSA6cBB3z3u`#C|<)a`5
z&hDx#D2PyNnU3@3OxW-SzN=!NUiOk=RDF&yw~Z)7_llmA`p<#=@v;fJ#Qpe`LUjdt
zxnb0{^2%0H4=*og9TLy<DT8}7NLJ@A1kP~|wn9?l_A3d$5b*$hF~=^rja&D5{P*vF
z`@eMDWnoR_JvcLsVXDh{1iCzwysS6h&^-=my^6Kh=2>BCXc5=LgpxF~8Ll`_MPOtI
z2R)yvkqI~npM&XG4-ZbcQn&?<a-MU#82Q3`85so76(K~(HF88*;W-J$)g|iZx}V+R
zXgE3*Nb!p68DR|&hWGnVf9oQO^G9~Vu2_(bX+q4yYr~)>>R$xsw1RpF;suaPa*fhl
z%#HSV@@V;f$Y7ln;<a~DcA6$IWW6TdlX=~qcywm;3YRkd*#H<>F;5+vzA8#}!9VUW
z{7cpsbeRv5FE8l-eD!Kc(6fcD{C3v-&wA+lXKv%}0wr^J0EQ=M4nd@;(CG$Aa0?|A
z80Lnj9>s|<GnX4#i51&l5RF7f6UQCYdtAazm#aY*QZpU|q-ktJ^EqBeyQaI(X#)kv
z;)MG4dPg@90dT&_Won!<)vRVW5jSjSfNKoP4k8p+l>4JPrD)!kLgIMUDoP)d)IJ`p
zg}o=Fl+B}66X<Fyog=&{RE`h5x#%U(FPg_9Phzs{k&wVzO7Z&!2U~+%@GE&s9445O
zIcp0|wXW0NCD72>q(I)J$mryECN8zwwB=9YJS`yu<lWc|(TxMTg=E93X}Nj{Wko^5
z4sNUjc!+#)B{^kB#ARiS)$Ih)#f*JQWEqXXPX#3q^1%KdyPTMH!tJ|w3F*(KE-BLB
zr+Xt89*HL)NaQmt6{AHY)@&xi#MO%FNrau5ov~p}%?@D0jxW;eLFXd_BjY@;=F2Qw
zt#@t55e7O7`Mr8K9~PxsE!GrL3-w2l7U8mmV!&NQOit41;k>)Py$wlEPgmj0av{n_
zLj~&J%3jy2kF0-k#2cezU*9edx7*DBE+jDUj>R_+PTo_h%yXXtpmDRm!)L$oBI5xj
z+aV~}Or&HqSOSjy+VK7H+)2=p?4q2?PSswsUFnXzWz#zOY*pW?AX06RAtP0hyeG1b
za50|?>p4jrNjQ4#k)lonhU1KiIyT;3cW&Tn6nbRb_;Gb-*j?@t)v70kynvQj0@>h&
zWCBk}7e2&bx~Ju~v05@ap#Xb?o*SqsJx_-4@88U0sZw)N(pUOHl)mUMNj=@lnVj}a
zhV`~Gk{}S^0oHGm@2|i6J;^1(a3+DliyUrA>szer#J9WQyoMyUEGf0(q@hTfOu>;`
ztiyHhhU|e?GaGm!!`m`x?P2KSZc*QK-m5D$5QXGp57s2x)gDNo=IB8o*&uxEoK&mZ
zzrjEJ#)_&TTc}E(9b**8Qie*1tj`kH$;xRaLOMFBJ#x8+wD>8yhQ3OM>|zp6(Sgw<
z)RFo-l?XsAe(x1#D&Af>75%OAMU3d*rglety+nrSwMP406xPJ`;dJje=@*3BJnyvv
zzRssxvSjPcO&Xc*;>f=-N#P&Jfq<?J%sF^P=;8kBt;vo_H0eiFU`9P@@;cSI;@?)K
z&*|}$W}ERhn)g+aeUTp<U8fBHLO{N52sSp%gJ;=)OkrY37Va)VsR{j4xXBMs$}iiP
z6rUK3y+yHzy*BBBcbpXgWK5!S0u!0Ck3!;=|M;cT^;bUCs~sKEP&^>7It{bUDVV$L
z<?tMz`}-u2k{GM0Do}|ueb}h|$)6$%-_eT+pcM$sn0#9aPiB^H#c_j&xD~MwiAV_1
z95ZE@NINY0YLki<gnWy1-XBZkZX9W_7nHQ;^iCUF6I*I^EiU-6h-awCponEa3Y5Hj
z9BNl|d26FEbj>nl7*vccU||5HO+a;~`hkhKq7y4ppg@j>)!rH><dinYF;??`lE&a7
zI1t(m7CbWNk8z$~4XQ$pbhGe|eH%aMrmQ@zmdQP>doa64EK9UTbiujLk4tO9U|cn;
zi%SFdO~fNB(Y`oah1_H-ld-yzJKG})!lGQsuOo5u`*<=FulyKKP{*CF`*TBem;oVc
z0n>Xp8zJm5a@&7JdQWL)Y(e9Go1dmcnb1F45cHam?R?{-Jz9KRZktk?pPY>B{phL^
z84dy}J}Rr~Hp2n;wSw!P8ry9O5drt|6n%3fAP%bCVBy*GS90<tRM+ZhEU+M6<AP#S
z(MRw7tOUt@-Bq9R+aMnfchNQ@mq)z%&{0!S*$+`0f$v%0hM&M)C^l#01^c{bxi2zG
zQ)G?nSsczNdUDE5mP%5k#6c!0^)6-Gd{j-r2i;~Nk;Dz~6&`XDG*GTibxP)mDxTQ1
zlGj03#E7z{c>{%5S<%S9q<yCE+&G7S{*Y%uuO%cWDo8f)jT}GA``~*K?vzO=fe1^3
zoA?LHRMil6J0YBN9kBwl69Qk^?~b;VFC>6YnX@Nn&;H8?Fwo~+ql?6@>jOY;v)>-F
znGVP~H1E!h142R{7w9{DOC)eekg&*dhkkNC2&wj>nSaj5@r@Mmr<DqRpag*0?_vXV
zofi_#+TeNH?WuDdsxP1YGNQ7N@<5?cDh7P=+4skvr&`v1YWa!>I<`A}Zm=_lUe9~5
zra!j7Mn997see^ZQ>l^e5VzBdEC>(_Mx?rgoVyI^RF!Dss9S|*j}|0PnT|+F`XiN*
z)@DHjk!=`D;#=K~K(m@8l#4Bm!BJ#q`5(NEBCk;lN0c%x|0`=pseRTW;h*Y3mnEog
z2tCvqw@V691>*uaZGi;j04om`;^kGfFP6{NHbs%t6@8i8H_oBfl&=9K3X#1BE$a^i
zv<FsW5%QWIN*4rqr0aJX<arn$PWIAm5>et)v|vQ?g}Z$Lxb|98X^oYURBqTgDl<UA
z<_{`V6*m9HR@ufpIFMpe&iM2Gn?mENXZ(VNg7hGk(slEJy`?(<*vwVLx_xIQVu;sX
zP&fKVRpW|0ZyI-`d>?TW1o4-)&=AYt)wPuOLt2uV-f|3@7LpczF<N>(QhEH3%RzTV
zPlp4Uw}w_iITt^e1Cu~mP&%(&w}Ysm4Sv%(00SM|JeX1s%7}Oq{IX4BTmS$=^6t*O
zoUR;-mz`ofvV#H-XX~Jc9Jna>iN~9%hE>~f{rLYZ1BjP*QS|>B{(1PUcDwk~au1Uv
z78!l^fsk~}7?Wf<KYgX4OzmCA8Rp~hte+WO$%#VaGzd!wD*7<^xk6*WC4iOr`_RN@
z>^mFY_hV{b_~Ga!Y)rFi{|q>2Fg|(p<cTS_SZ3%l4YEig9&p>Ap-&GlV@>pn+;Vsv
zP-mntqER6FLf72oM^0-yJc51OHs`sqG5w}p5V)RUXo&x%p0b><NH<){h@UNg5deTk
zV|T9Z12?RpksKQX+fXpf5{~LUQ1w*bb3JnPA*?_A`kRX-6pY2=ft^J%O6W0V|BEX~
zqZwP!WcRl$H@yv^zl#c3?*n#jnRUw3S;zX%>e}Q0I4Yx?)N$WAAg$?=kiPUDUTUhr
zOhM`n6*N2qO5$Z^y!=rrKBG*`35(u)KO^}3Ds;%>c;WM77wXexi^DeZah`R<(ugrF
z=LJc(_gzrsWz)FN7(9?PCs8|K_(uweF*mRoo|`|Y?x!g3^7juVdbZdB{rC0Qa0kz@
z=#}pjzrGqPT!=>q{9}9v9LzYC@YDL=wm!m-ruT}#)*XUnK!N$j@X&g-;>qw2ZH!zI
zCkQCzrk|NC|9v^&DwmO~{keaGL`#>0gS63k*Ugbxh7@wh&5Lb)_FpiMHQRIX;2&A*
zWwsg@y+a2vvSC!zyc&A^_<7l;*)EQzoyXrQomh$SL?=&+9RryMSxknH9bmst+Yr~}
z6oPznNFz~>FA=ZahmxGG&C@r*-uBT9#<YV-hzI^5*)Ds)d>?E37qf|GWTB~kMsPXA
zz=s*62~@qb2okW<<T)JB8Tc~G6+JoYT=o|Z;i|>cq|UBiUvqss?^fjlOgGbGR)bRv
z;p+6;6}z)0qyTOF(@#`JLI@!|1hFQ`3ocg*jZSlicmuaH8hQ}i7rV{y<<PX>D%L(@
zy+NDKgOG<Vmr^5Xeu5hlWK&K*)BFz8la&EK4c(lT6R(ibh6+RLxcpP$8*rAKL=ZnO
z{0_fwB%=cekoY^Pod!peoPpS_fft(gr9~S=nuk>bzP~r{V`c#Q`t!H`Q*M@-IJ_&|
z6?MD>Q=bpWLEhm7U>>mWea&n*;47cHz*3PwOHbXa=xgR4PZhCQQRWGGp2bJo<N_ph
zGIPYnYyqXlwx`Dk&gwGr(KM<kuoVuX3bd5%u9BN`q(L3u7@|6gOh=Xbhu4MtuJ&)1
zt!Nhx|H$U|pFf9C7pYhcBQ;nROLM6u;?O|kD)S<ka&X+)>$Xf1?Ab&Mvy(l<HW759
zpSOHqs$Fn<%OBTBO=A8^+YQfM-fWQGUb(tRA3EBgov!!<h&*WBO}0_+1nDZm-~kk>
zglL1uQ!$;8^$furMQQ?4fJkYhShQMKUGP6k?Uy95Q|AJ{ph>@-ScvAw_^EroDAj$B
z7c`{R-RS-2=ksCJWz~u0bI#H1c3M@mTfm`gby+`Ua#h;x&Th3GFD-_3!!Hx)5t8h5
z^A)IDHrp@n9yBY6Cr9}59lb222^-%D%aMK3DyV{%cb*aRzQS1o?S7F$mVSym=nS*3
zB(i4&-rPkbaLV6}BMKs~9jI~X+GM+F688cJ1J-A!YWGmMiDs78B%ZLoPwDf5WHrV3
z#=x-ke|(anuZ=RM;K^PD=nuFmF*pDN;t(|nXMzL_h#)>EcX-EnE=NyXTWJX0r=Y0G
zR#FH_e`u@Iz>!lcQV*{U+C#Mr6LNl|!XQe-7P!5>Q`J*!Y7J>-D<2^Ef@bKF`l-%;
z(``?zd#VT=(yZ}Qz9c2dQDrT#AxwsDT=Z8%M$zoNcDAd><wC|EBGW+hE%NQGR5A!?
zK&C{l44I0eGq(tY_zMMq8KeI>Sp!`&bjm0Lq-O`_fcNCmtYW<8BCv4h$>MYN_6CQb
z5HCi61f1~w+D>mHx~qPCjh^TZzL`sRgiqwALSTd08&+U>->i75l%^Z3&`?p%h@eVV
zRj#!rKq#2G$GKuzLNiHumTM+rK`}Xx^c_Zz@G%0iw9QTcIC&8_MXB1QFpl%UEo{07
z8(nDN*mcN)y5}1)AyJNF$7U4|TT0(+K<Vt)m_DPU1M=LlthER+F~n*&d0G5)R(8yo
zb(=4hj^6OVWqMe`*LYR(Y{J*Bt|aoom~MlIrTMp(`ht$%m6k{VH%6M&+l|aypNcX!
zsmLl4MvMw^yCE<zKJGU_fxJRjxZ!nH_`M<{6BkIs>a2tC1(cw$rhcKr$aS2mx@8BW
zArw9GD-7?>i1p^zl^1I88N|3nuElu%GF-+8ld-@i{ZP4F*N7QiqAy5QT7V|sJi6tt
zr^kg^nqG+!Ok1J;a|^RM2#K0QU}0sDm%s*L7X|rUPrgEgC17Wil3OrUIg-3y-3BJy
zY7q8lBWG}R!<bs5$-KTi!~D7TeB0Pzw<`g0gXG7<0f;otdlO1E!2ty5fPM7$$cBJi
ze8(Qa%0%;EZq)|T?4?nFRIG$^;mgT~9R;k3k;7R{M&!}(6kW1kwte~HCl+>9|B};7
zo68cCM$&tk{}?a_#`w<c>v<Pj)<A7EtvDK*Z`A1aNSa&GG08736ez?6LlO=Rk+TBj
z^cy97wP17)uXUv1H4+a;?KCsXB<~b~BL6VDTyHD2z`lTZzWNGnPsF%wb1uffzeX(B
zn><0HM$17Y9jhyIpVRgES=IJ5f9Z;03DcH8=)41D;c_U~s-LihFRxq)C;(FU-+Ri+
zd+>&5n|G~G0=Fa6{BQtQ&Z2M->$uPh;cC@L%5|w)HCjOGD*urC`yp(>sA!S;#H{t2
z^!Ce#j=Fjsy1(XL1@xlKiF^Rc4WN!}!;H2dai@*mi1jD4hRESv|B?wQ52^KW-t;Q?
zKsrCa+l5s-Y~PTcITV2UxVC>~8EF5Rk~sl|X9L*s%jdRk%Dn_Ex06<D%&|FPy47`{
zP7xbqT=VZI0?^~R%4FIF!#{8S6`A_%q`-)MPH2SvhRxy2_f{=@J0O?T)}UK>8U49O
z)H@h|yfUZRDPN1CVU_*Ct#sY*Po(etz?Hg&p4^#lzxd-re7e={RFlioFP1}>56g%C
zKQz9C3TP?<0lep_Zhw9j;%qX)3@u(42}MWtrOerJND5cI(t;<4AlE2(hzgYyl{(YV
zn|by3)20Z}5>0Gu0fp0^ey|KR=@ifOcE=L?VxQm3ykGrEhcwUxoKLZ|9LU*Ta&Q;i
zz{0_>^m;OMJr;_W0bxx=@^>1{b}%Sm7jy!VDHo%?YVV4BVO?zgcZyG6SmFaEpHth5
zk>`22XkMWrSL&t&D;Zgh?aSLk|7;QkoF8yY0EP0;+2bd0OZNE9ygOexb0J)!3g04q
z-&uQhgjuWm&-iSOfz9yI06GeVx~ak`>uGeqlL&U9h>qMRzqO5o)m)YYg`ij;6X#&0
zV@)`BEYc63Rerg1K6X9=0wBVy90G=;BrDB6$*ki@xQ;4tozX=#mrjRBFzb%D{5#oC
zDgRYkny2o%A8M`oMw;R-ysimE3pEsLOUg|1+@dE&Fk!dbK2wg>UVbb$9N6vG-|v1%
zTUwnKq_0&6{R~H!&PSe^7tBSO2;%6@fhBa)GD0SFqtxw<+U?nm>Kya^fR5CkQf3!S
ze{ZVJED^{eqGZ|O(C4)~S{#(c|1xP%T~_^aDEakYkCL_xelY>xH9H*xKm%Yg?sr|&
z*VoR=R{d-92esJ`=st&^3~EG*F>~xYd9sKbfU4a>g2Uv`FS<Wf2}pp*;NalnDho)1
zV$)d<MG=1_&kkX<s;!VC7~p0qh$MWwH|UV06Jr?7R%3`#^Q4xrhRYEZV%De*3{AHh
zw+TIb^>WCMek;DK>f!Ah)A`!!POC8yPGI5(<dS%vO_mk1El&kf@N~j%odBbmlP;M`
z3IH6cxYY9CWq7%fbJ5Q0lLsOM7JRCtG~t*~_td8Ibn32;tknBQDoeS6MBe0#QRm1n
z;|w6!{BDuElfsGD@CBTwhXtB&qg8szlfm;A!Q4M)x0~oxaqV2PaJ4}jH|WP_^YV&%
zTVH&moHmAy0C=DY78--r>E9xHO{LppYOe$^BIh7hdHhXiKCE$G$jVH&y1fQlm!P0b
zJNpB^fUS>#J8Ve2m)p#mN$@kNgkYw$ACS><5maKwXU4gkMu$p8%$QFXPK0F$%e892
zf&&+}bx;_>(mtokG02MQwi>GXzAn&PTkyR2e@UKN;lJTF(Zx{w#klJ@K7N;0FsTi%
zB-1BcT;2RfCo`x{LIS`pV>)krxrVgWlqd4GS7qO}-4g44KdtBVQ&rnge#0iz6M}~+
z1BTP6meZ#lK8Y*8g=hm#Jb>m6z|qS`+uE(Zp7QVLS&BA{fAnbfTM<4q?0)IkA;&}p
zb7H>z(UsYVCu$@o4SsZ@R1Hk&zFM`qx901%7g%)}%5O)i3kN-*P#El<I_R1IN11|(
z2-I~#ysi+nX{UDaLqGuJJrKkjVEmm+9TZ)cRd5sCA#3n_y;^6xh|VF_VeZgYyR5yj
z>70EJuw`iVH}G@KQ(75l&Ne9o{ug6&?H{{7=)dE^vODj1oqsE8Icp#OV?O;9-H$Oi
z@qWNWCEtB^T2LWcq*=eYQ~~(fsz9k26cC4|U1#`Pz4CH2>3$G^{nCdZk^6$oQBRke
z6!%cntA(Y8v}*m_fKIFVv9EHyOGy#cAj(tjTD$E&@v$CT<~#`+<N4h8%5{^s9F~cf
zm)?_j6FBVADt}S#u#gE0Ff!23UYA9^)2xdVCf0qPl^)0LvJ2XfbPpvO4L*N=9^`!N
zp7#^KGM}9meSJY<5^~wwQoH!mG*e-Pe{R6jJD?oY{&e=m@;|Dn846)VA@bpT8xrM1
z3SJ&d$??!O<CnmyVWMtp?&d!kQQ=?EIw>#^XWvOmS2cHAuytg~dj0b8<z@}C?s@E-
zfJeGJEBf%3{MK#VkYfIkcu@=ksg?&2a)Z&NKY$rYanxAk;=mVVPsk-y=ur{!oAl(7
zI#<^b@lOS~1im0ncSqFIX`I%nZ(qftg=-_*-)a?4ZV0Bz3b_ua{ciN#o`((-GeZwV
zUq%}bud-V+|216+5EDgNpsTvwzT0U~{Cd9|qIca!;SkdnS0!>K`Z6u5)8vQkiJNDB
z-1M6d^9E}cYpKzJLI&-4$AdNL&z~1y@2zO6rp9$-340C<-5pvZ`49WZ*2Df$!W(RK
zyfivYU3GZI?R`k;Q8G1?=2fPFhfp7U8`gbsd^QB1knp>YGy(YAb_q%(9nso?#GkbJ
z-Pw*zaXW)}0-r@NO|C!*4!_-eQf7Ti{y+&k9(H}Mulw|_hoWe%_s{$oUUsurWjRuR
z{uU0m;9MK?W_at%dO5ATeG?kP++bStz*s(9a~>C-v#8f2`*kGUVe~i7x2|oIu&m^Z
zzPk$VWtwfrJ{muV<Omc(_%*aFhaK(v@~^X+B-4Ic6-P%-HpkJ+_j!A-dk(MC_U@A_
z;BpgW$|?{*+?iOv7!O(4!}_zJqWWrcq!G`?c^-fAnv0n>e@q?y!6s17?c6Xx*-3f|
z?F#9R%r?<}TdJ1DOeY07klF0FMF!`mb_)|<tvkp|^qH{Km&Vh01k4&=+1T<UB(cZX
z+u1!;A=X0+2cjzizt=0*ljyoVC*Xs(S_ukZEaUh~AOHgL^PSI(!;?!1W@mLZU%ymb
zuB=mtuq6;$bnxCL**au55K1rl7*tU@cLcKBl1{M(i7$N>mZyQgLCRnUAv6ISu4bG>
zZj1XC`x6a~Z~}qI504jhLf_N(;cA7WgmldQj=7^j_yJ%~aP-84kF@aSvu!@buXWl6
zuii@=+GC6LTIGEJ=CY3$BkSia*>`<jtx5Ee7Dli3Mt}$$A?2_}gp4fPdwuw&TfH;#
zIXw*um-DVGBDJ=F3BicU9NR==V)xU&vR>rmfj_CgxjkHfkXufxhuq+d4rVUfI2OPt
zf(I-{jB|a5mq-cOZ<bH}N)Sl79`EJjAuFmb{F`BSU`E=FvH&Nw-q%b-ytg=eU1I&E
zasTi>Os$4(JlglZ2ff9?;bm%1EBvA82x)QF?>E9kF8~Xm>_Mkwi?A~^jcSin$2DB1
zeB!N45rmz=43Yegnwe(nOmlNlfPiiw)P{R9HsAHx7I3#6?rssnof0Ji90^BM2DJvq
z2EA{oRKvo4=D`CI{dbw$DRmz70P9|K)O2&dLEhQRlQZ>$A?ZH?FO~(lZQqvp$}$Qx
z`TT$g{vbjIZ+mZVA&dL(DsYBaNK~UKE@3`z6D-l0f<X_D>kYds_DYKWN*IA`lHWjI
z`pP~l_r@7J48jA-Vt9Q^GwtZ^Nk^g<d&@J=rT}GnL#S0sL=2X4-?o7tpZL0$Dc6hp
zD)@q?%57`ihnH*B24<R|n~pUk64YFaoDv;LcQO^N$dl!1A85Iv%^F2#%AiNPl?T8g
zP7mjsgw~`bL5wfm4K!M3u1}->cVSoX*oKGNC$dFeZ@C6Qxsd|LJVKBuWqU9DG#bHI
zsVj^5iILL8sle>Xfv)k>cd(UnT5E&B-<RunSG7zwJnsPUQCJ$QWth*?=ZQwYbJqUH
zmI^Wrk(a~qfx1dtaVPZUJ=mn|<BqY2IknNZAOB6lsohix1IY*gKJtk!Fh*&<Vf;ZK
z4Tw?2s3Ah`MSR#nO)&j06P_L<j($F;(tQ%`VBvB!#MvOI&=yckW9vLQ!Dq4bx2<=u
z@NL*(0oHJ?od1K_Ai9KDzj`Zzmtid4A7$Vxj=PI4B#HzwjaoSt-yct2pYMiW{~C%g
zl9SQfk#~zo=)QoqjoxYr{j30}^tS`5=y{gfV8}0>;f^CUEAE_h{vNyq6dP0{`q%(q
zd6e?Yk5hF>zvJ8pxRg?<5=({XiI8#5(m6QIUhYOI@Af?)uZ_HA%lnpr%#xY%1n^x6
zapQzf=k6&zZZ@;kSsg2-Mj|wOPQpJPX?3J+p8HcS7Aw^a1jG+{uX?Eerup>v(QZwl
z@*ih`C{EacEv4CWuL1247*J({{Q!!fjYWuunzqE4TYV=g{y5xl=D3G$|6;Nzo;Q%D
zlu`FBmg<Ppcz)?0Ax&HVEXm`}zC`nm|94x;Ap$kDXkU8!O8&;rwGM{2gyE9C)EQ0N
zd+uCl{T-gqoQvJ?ueDg0&`HG_lqsDb^KLoP>c?V9tE;cqo^lZIi+Posed~pX1pr_n
z(|LGn)N@f1z-<T&S3rTagNRMF!N0Y2BkCuqIhJ&K#3G@tqA!M_CU4c3U|jZFyw0$K
zFRlFEc)SY@Vyi^i>X*xPrC>p)KoKsPH#6y))^KVc>-l=-M)9t1ySbWw#^67lWf|0Y
z59huujv!eL6jM&VA-^a;^gN6%7&K<KxeWhZ1afqNbm@xOkNE7`hN<vEPH>bY2r+=4
zN|Py?Sju2|7>?;c6(jrz2wV->Fxev*&Ir(P?S+q+ilcn*&Jj71`JcNKqhl+;11-_O
zDJ;Wp{18HBe^@}~rE9gn*7IMF%^aMX{#*YK6dE1c;IeD#>s9XlbZh5Sn_4-A6;Slw
zwCV$Yfv;<1=ch(xQ%r2i59ipI@NR0bUM#d{_AsDM1HB+hi5D4y?T&GXwTEPCF?qCP
zrP+)J3fNW2@_Y5TNZ|-Il~+U=P0^>T^(Z4kuqKb0pSL9?<ykmV7pVP2*zW}2IReJK
z#hQv$YnySZ2-W@EFzugD=2Fv^z9je*bitCOCvoPr{zQw=U~y9;$KZY-GSWBK3QjhQ
z-mHp@HV;H-$n|(UWMCWj<IY;(C$23J-QQA9#sPBZ8@90yPmEH4%&5pFCqRt1w$=x}
zJ`g~w^Z&gUtkE>gY|Tn(Ica)T6v;Wvh;tY}^-Uuzd59&FCoEQTZjd?!7Q3&2M#=4@
zERK*XMWeWX>vlK!FOb3Nn5B}d$BVK1%xVtT1JgFldELiP?#yGHji~9_c1o|;#R*9h
zEo@;AWofvz3@+hBL)5u-Oz!amFTe=})H+A-)L_`i{AXsLk_WQ7QQ^JztJZ`DFyW7-
zNBUG@&`e2_%G@xqet^b!;bK|K^6VI?&>x4FHyjtQ-gOs`z_S$Rihw2DbeF>xlZb+h
zCUp3dUYpU;(Mi!OoJkkTGrqaN_FdQg-Rf(x>co)#SL$>}J;2)Fb7O+*scQD<vu*d-
zp=_+p?S#Vf0zrWL7r0K$fEW~bmTiA)s*|n1N>r((Mv0z+$QeZ#^WOfx<Cq9K-x<SE
z($qw~?;)Vg0^6Agy2T3$^vSl@>x|n(aThMM42pCOYAg=BM~#{Qh8eHh0G#+(`8Iec
zQM6a}dUEE&qWA^H+Xcne*~VQJ^+8NEcLnE5#nGE893==rztS&q{Vb83f%O{pn*b4x
z7S(!vO~f9_zs);CF-h%kBp)iKoRn9c9`Y4|9(GX{5^F<2%H4;F_GPODwXBwn!kIln
z#<o&N*oW~-EDd$M@Znlmp~xqs#~_+tZchD$_*Su5s3Mb{A2{zm#;CY?5}p$JDJE5>
zef4&0iVdbo4zxrP@0<JA9>()F$s1htj#)RgXy3OM-J8V}Dfu5<O8AA_(44!{m%lX^
z^Pm4?&3Ks`vr@<2oRBOK1bRyxBIz*$FwTbDn+K4MkA5`5U&E1#!|4*M2YDR=#$*9?
z%7uIcx>E?)?5#0SY!DOmA+x%qo_@o0=i@w1RUm^`E_0CSkoyxe&7+Rsc9-pwOOx&1
z@!5u8`a*8-G}8Lu-p%s-8$ZK;a^(M$1BKDP+k3Zxkpik{cO7oAFF*{(4>$RdqJ_k^
z%)aCwL&m`fTPZ42XZyyB@$EOQ!slpR5{boV3y^rU1(!ZyY~Ta)%^!O`@ZO{hMZST^
zMZq_U6!>h}y1x;<IT~ABOYQ3ij~{pd=zpy+{VIG73B6IYr47B0zl|Lp1s1=m##7uT
zFfx9ju`EfzKxm1qkH>W4WjqP;@!VM{9sJbRl!DpqN>fqGrJricfaunM9|#tcfz<eT
zAgeIYQdqD5{x>dn!_r0u07DZ9U51Xocw=CYT1z;u1!B4q?h@KI9m-asAw)dEMITHE
zQPBM3%I|vUVs1J4aN)nxcv0oozMt8iBmWE31S|VY^`go1Ei+%P;Q}%At&lxY)R>>2
zzZwfnXi^0xp{lZ4=EYyPVhM#Rr^*L&0m1Glp3@-M7-4^HCp!?bL6D2G9lKnN2dQJ5
z%ZbIkf$2!`0t71gro)$==y}7KKj*!lM+Tk`%GjRX?eX4)MJ5ykAUI#ko35s1tFEWU
z#ztu&*TJ$6y4_jK#ZWtAaygPp_7K!gc5|Yym9n+c*{&m37zyn$*xySVHf^P6p5H)y
zy}cC34@!40O1vEE*`2(%%zU}8^UlKGpE9<nN3y7>xOffH#z|WW6xB3T(H1UTNcB^y
zEw!t~k!)x2Tz~*N8yK=F*Ew@BUIyCsIlE&AvM+aw{{Cafj!1bM(y#BE%^lj;e_og`
z*L8k*cU~!@cEEnY8oOVh?NjgxkanFpbEY_nN_HEZ%VEsLIFQ!a?KD}1QYkwMu^-Q7
zJf^;7=PA^2Jay_6{pzV-(w3KuS-?m<p{^f|MxpYv>-xVp^FeQC0Dv+~0<wm|!h*Z(
zCILV|`!qIs$OQx?yBD5I?c1HlYyg0=L16bYG()M+?UXI;pzPcMn2mHUq#m{&>fTn<
z&))X!yfI&{_rme+yio=SU=rXUa)=gE5P(!8VEtY(4fAJFb!|gN>Nh(?J6je`X|f^=
z=xk<18E<#$Kz6AI<FWe))=5S~i~0kI?Z*;{^=4XE_y5gi`0vep&>sQ-h$cXw&zo2q
z+~xCmZq|~rl4i#=n^@O4!_*3O;xM9j0A!El?OiqYDx6ZTY~9(Mylkfq=Tz0N%eud`
zb+hb&fI^TmK1<!_l6s;yk>oiS`a=PLQie9*M<c7|yErmv(hQ=KE(Z@VAacMa4s~@?
z#AkrhSW#VPMG$s6n^ws7{Byl;4-s*mp3W1J3dVYeQ19BQqy%-JPN&1EWMZSqczZ0L
zOU<7b#w-1y0YK>tAYgY=r_<Bq^SPU{wE`#`5GXWV)z~0Ad`RWdoT=pY7Ra0gP_C>Y
z7(AJlfVse~AhK^TGaPCiOh>Ig8kxug_@wc~eMuRw^oI%nrHrZ~8I7mV3XMF-q7`z1
z0i>ovOS<{y!cdrJfc^p0_G_!k$?ao@%;OSUt`Wt^(10vF6^{*2o-1Frff)|>(y6XK
z>gw*4**)phSccD`W+4aT&*s=&5T@Jd4;=uYY;6E))YlA#CKo@v9#12B^X!hJofHtD
z>_!kJZMf9WgR&W|-xEfs#;oie2+kdcu{+-mj92<&0DzJm0NJ2G^w0<s;q|&2v;BoP
zB0Gcga&!@UvQooHTkB%qsj)<ObaZTIIz86HjDMpH-bG`)(jOB5lqLm%?KR9q2%B5x
zIbHmpLLPoC1HvXFFMGbAIZDb@yB5J`@qQ{j9>#Ha@^~<4TKInphjQl<!(Vj9EB!G7
zKq-{td1#X7)@!!`1b~Ad6Mf*0Jb=U{pHGY>!|7B~7|k!kEZLJeYiDDA_Gd2%{V@Z;
zPN6q=9?J3FWZ!=y$_Bs%i{Z})T`mAn3cbPWH~YD4Iu}jwwxY`o0NM0LjD4$;|7PC1
zq;$Ch;B53}m=Ai}GWl$D1pt>hT>-#lPFDbMnbQ>jT;_BI0GByk0l;NWR{(IC)Bgnp
WUo6VC!v|;p0000<MNUMnLSTYR@0UUV

literal 0
HcmV?d00001

diff --git a/www/resources/icons/debug.png b/www/resources/icons/debug.png
new file mode 100644
index 0000000000000000000000000000000000000000..5b78608a21cb1649da11ad6599a4f3c0821b9be1
GIT binary patch
literal 10724
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

literal 0
HcmV?d00001

diff --git a/www/resources/icons/lock.png b/www/resources/icons/lock.png
new file mode 100644
index 0000000000000000000000000000000000000000..11073e2969f6ada809e80a322549f19197cd288c
GIT binary patch
literal 14639
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

literal 0
HcmV?d00001

diff --git a/www/resources/icons/pencil.png b/www/resources/icons/pencil.png
new file mode 100644
index 0000000000000000000000000000000000000000..e79a164dc3d1699bafa050caa2d4a644dffa6f6d
GIT binary patch
literal 3004
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

literal 0
HcmV?d00001

diff --git a/www/resources/sprites.gif b/www/resources/sprites.gif
new file mode 100644
index 0000000000000000000000000000000000000000..ae69d83412dc91ea11333eeca56f19d5aef833db
GIT binary patch
literal 12536
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
MkQu~J4xsrz0I+fH?f?J)

literal 0
HcmV?d00001

diff --git a/www/saml2/idp/SSOService.php b/www/saml2/idp/SSOService.php
new file mode 100644
index 000000000..4d744c4fa
--- /dev/null
+++ b/www/saml2/idp/SSOService.php
@@ -0,0 +1,140 @@
+<?php
+
+
+require_once('../../../www/_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnRequest.php');
+require_once('SimpleSAML/XML/SAML20/AuthnResponse.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php');
+require_once('SimpleSAML/XHTML/Template.php');
+
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
+$idpmeta = $metadata->getMetaDataCurrent('saml20-idp-hosted');
+
+$requestid = null;
+$session = null;
+
+
+if (isset($_GET['SAMLRequest'])) {
+
+
+	try {
+		$binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+		$authnrequest = $binding->decodeRequest($_GET);
+		
+		$session = $authnrequest->createSession();
+	
+		$requestid = $authnrequest->getRequestID();
+		
+	
+		
+		$session->setAuthnRequest($requestid, $authnrequest);
+	
+	} catch(Exception $exception) {
+		
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+		
+		$et->data['header'] = 'Error getting incomming request';
+		$et->data['message'] = 'Something bad happened when simpleSAML got the incomming authentication request';	
+		$et->data['e'] = $exception;
+		
+		$et->show();
+
+	}
+
+} elseif(isset($_GET['RequestID'])) {
+
+	try {
+
+		$requestid = $_GET['RequestID'];
+		$session = SimpleSAML_Session::getInstance();
+		$authnrequest = $session->getAuthnRequest($requestid);
+		
+		if (!$authnrequest) throw new Exception('Could not retrieve cached RequestID = ' . $requestid);
+		
+	} catch(Exception $exception) {
+		
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+		
+		$et->data['header'] = 'Error retrieving authnrequest cache';
+		$et->data['message'] = 'simpleSAML cannot find the authnrequest that it earlier stored.';	
+		$et->data['e'] = $exception;
+		
+		$et->show();
+
+	}
+	
+	
+	/*	
+	$authnrequest = new SimpleSAML_XML_SAML20_AuthnRequest($config, $metadata);
+	$authnrequest->setXML($authnrequestXML);
+	*/
+	
+
+
+} else {
+
+	echo 'You must either provide a SAML Request message or a RequestID on this interface.';
+	exit(0);
+
+}
+
+
+
+
+if (!$session->isAuthenticated() ) {
+
+	$relaystate = SimpleSAML_Utilities::selfURLNoQuery() . '?RelayState=' . urlencode($_GET['RelayState']) .
+		'&RequestID=' . urlencode($requestid);
+	$authurl = SimpleSAML_Utilities::addURLparameter('/' . $config->getValue('baseurlpath') . $idpmeta['auth'], 
+		'RelayState=' . urlencode($relaystate));
+	header('Location: ' . $authurl);
+	exit(0);
+} else {
+
+	try {
+	
+		$session->add_sp_session($authnrequest->getIssuer());
+
+		$ar = new SimpleSAML_XML_SAML20_AuthnResponse($config, $metadata);
+		$authnResponseXML = $ar->generate($idpentityid, $authnrequest->getIssuer(), 
+			$requestid, null, $session->getAttributes());
+		
+		#echo $authnResponseXML;
+		#print_r($session);
+		
+		//sendResponse($response, $idpentityid, $spentityid, $relayState = null) {
+		$httppost = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata);
+		
+		//echo 'Relaystate[' . $authnrequest->getRelayState() . ']';
+		
+		$httppost->sendResponse($authnResponseXML, 
+			$idpentityid, $authnrequest->getIssuer(), $authnrequest->getRelayState());
+			
+	} catch(Exception $exception) {
+		
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+		
+		$et->data['header'] = 'Error sending response to service';
+		$et->data['message'] = 'Some error occured when trying to issue the authentication response, and send it back to the SP.';	
+		$et->data['e'] = $exception;
+		
+		$et->show();
+
+	}
+	
+}
+
+
+?>
\ No newline at end of file
diff --git a/www/saml2/idp/SingleLogoutService.php b/www/saml2/idp/SingleLogoutService.php
new file mode 100644
index 000000000..39ba55d17
--- /dev/null
+++ b/www/saml2/idp/SingleLogoutService.php
@@ -0,0 +1,146 @@
+<?php
+
+
+require_once('../../../www/_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/LogoutRequest.php');
+require_once('SimpleSAML/XML/SAML20/LogoutResponse.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+//require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php');
+require_once('SimpleSAML/XHTML/Template.php');
+
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
+
+$session = SimpleSAML_Session::getInstance();
+
+$session->dump_sp_sessions();
+
+/*
+ * If we get an LogoutRequest then we initiate the logout process.
+ */
+if (isset($_GET['SAMLRequest'])) {
+
+	$binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+	$logoutrequest = $binding->decodeLogoutRequest($_GET);
+	
+	$session->setAuthenticated(false);
+
+	//$requestid = $authnrequest->getRequestID();
+	//$session->setAuthnRequest($requestid, $authnrequest);
+	
+	//echo '<pre>' . htmlentities($logoutrequest->getXML()) . '</pre>';
+	
+	error_log('IdP LogoutService: got Logoutrequest from ' . $logoutrequest->getIssuer() . '  ');
+	
+	$session->set_sp_logout_completed($logoutrequest->getIssuer() );
+	$session->setLogoutRequest($logoutrequest);
+
+/*
+ * We receive a Logout Response to a Logout Request that we have issued earlier.
+ */
+} elseif (isset($_GET['SAMLResponse'])) {
+
+	$binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+	$loginresponse = $binding->decodeLogoutResponse($_GET);
+	
+	$session->set_sp_logout_completed($loginresponse->getIssuer());
+	
+	error_log('IdP LogoutService: got LogoutResponse from ' . $loginresponse->getIssuer() . '  ');
+}
+
+/*
+ * We proceed to send logout requests to all remaining SPs.
+ */
+$spentityid = $session->get_next_sp_logout();
+if ($spentityid) {
+
+	error_log('IdP LogoutService: next SP ' . $spentityid);
+
+	try {
+		$lr = new SimpleSAML_XML_SAML20_LogoutRequest($config, $metadata);
+	
+		// ($issuer, $receiver, $nameid, $nameidformat, $sessionindex, $mode) {
+		$req = $lr->generate($idpentityid, $spentityid, $session->getNameID(), $session->getNameIDFormat(), $session->getSessionIndex(), 'IdP');
+		
+		$httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+		
+		$relayState = SimpleSAML_Utilities::selfURL();
+		if (isset($_GET['RelayState'])) {
+			$relayState = $_GET['RelayState'];
+		}
+		
+		//$request, $remoteentityid, $relayState = null, $endpoint = 'SingleSignOnUrl', $direction = 'SAMLRequest', $mode = 'SP'
+		$httpredirect->sendMessage($req, $spentityid, $relayState, 'SingleLogOutUrl', 'SAMLRequest', 'IdP');
+		
+		exit();
+
+	} catch(Exception $exception) {
+		
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+		
+		$et->data['header'] = 'Error sending logout request to service';
+		$et->data['message'] = 'Some error occured when trying to issue the logout response, and send it to the SP.';	
+		$et->data['e'] = $exception;
+		
+		$et->show();
+		exit(0);
+	}
+
+
+}
+
+/*
+ * Logout procedure is done and we send a Logout Response back to the SP
+ */
+error_log('IdP LogoutService:  SPs done ');
+try {
+
+	$logoutrequest = $session->getLogoutRequest();
+	if (!$logoutrequest) {
+		throw new Exception('Could not get reference to the logout request.');
+	}
+
+	$rg = new SimpleSAML_XML_SAML20_LogoutResponse($config, $metadata);
+	
+	// generate($issuer, $receiver, $inresponseto, $mode )
+	
+	$logoutResponseXML = $rg->generate($idpentityid, $logoutrequest->getIssuer(), $logoutrequest->getRequestID(), 'IdP');
+	
+	//	echo '<pre>' . htmlentities($logoutResponseXML) . '</pre>';
+	//	exit();
+	
+	$httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+	
+	$relayState = SimpleSAML_Utilities::selfURL();
+	if (isset($_GET['RelayState'])) {
+		$relayState = $_GET['RelayState'];
+	}
+	
+	//$request, $remoteentityid, $relayState = null, $endpoint = 'SingleSignOnUrl', $direction = 'SAMLRequest', $mode = 'SP'
+	$httpredirect->sendMessage($logoutResponseXML, $logoutrequest->getIssuer(), $relayState, 'SingleLogOutUrl', 'SAMLResponse', 'IdP');
+
+} catch(Exception $exception) {
+	
+	$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+	
+	$et->data['header'] = 'Error sending response to service';
+	$et->data['message'] = 'Some error occured when trying to issue the logout response, and send it to the SP.';	
+	$et->data['e'] = $exception;
+	
+	$et->show();
+
+}
+
+
+
+?>
\ No newline at end of file
diff --git a/www/saml2/sp/AssertionConsumerService.php b/www/saml2/sp/AssertionConsumerService.php
new file mode 100644
index 000000000..2c2d99066
--- /dev/null
+++ b/www/saml2/sp/AssertionConsumerService.php
@@ -0,0 +1,52 @@
+<?php
+
+require_once('../../_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnRequest.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php');
+require_once('SimpleSAML/XHTML/Template.php');
+
+session_start();
+
+try {
+	
+	$config = SimpleSAML_Configuration::getInstance();	
+	$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+	$binding = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata);
+	$authnResponse = $binding->decodeResponse($_POST);
+	
+	$authnResponse->validate();
+	
+	$session = $authnResponse->createSession();
+	if (isset($session)) {
+	
+		$relayState = $authnResponse->getRelayState();
+		if (isset($relayState)) {
+			header("Location: " . $relayState);
+			exit(0);
+		} else {
+			echo 'Could not find RelayState parameter, you are stucked here.';
+		}
+	} else {
+		throw new Exception('Unkown error. Could not get session.');
+	}
+
+} catch(Exception $exception) {
+
+	$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+
+	$et->data['header'] = 'Error receiving response from IdP';
+	$et->data['message'] = 'Some error occured when trying to issue the authentication request to the IdP.';	
+	$et->data['e'] = $exception;
+	
+	$et->show();
+
+}
+
+
+?>
\ No newline at end of file
diff --git a/www/saml2/sp/SingleLogoutService.php b/www/saml2/sp/SingleLogoutService.php
new file mode 100644
index 000000000..c31ebd546
--- /dev/null
+++ b/www/saml2/sp/SingleLogoutService.php
@@ -0,0 +1,78 @@
+<?php
+
+require_once('../../_include.php');
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/LogoutRequest.php');
+require_once('SimpleSAML/XML/SAML20/LogoutResponse.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php');
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+
+
+
+
+// Get the local session
+$session = SimpleSAML_Session::getInstance();
+
+
+// Destroy local session if exists.
+if (isset($session) && $session->isAuthenticated() ) {	
+	$session->setAuthenticated(false);
+}
+
+
+
+
+if (isset($_GET['SAMLRequest'])) {
+		
+	// Create a HTTPRedirect binding
+	$binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+	
+	// Decode the LogoutRequest using the HTTP Redirect binding.
+	$logoutrequest = $binding->decodeLogoutRequest($_GET);
+	
+	// Extract some parameters from the logout request
+	$requestid = $logoutrequest->getRequestID();
+	$requester = $logoutrequest->getIssuer();
+	$relayState = $logoutrequest->getRelayState();
+	
+	
+	//$responder = $config->getValue('saml2-hosted-sp');
+	$responder = $metadata->getMetaDataCurrentEntityID();
+	
+
+	
+	// Create a logout response
+	$lr = new SimpleSAML_XML_SAML20_LogoutResponse($config, $metadata);
+	$logoutResponseXML = $lr->generate($responder, $requester, $requestid, 'SP');
+	
+	
+	// Create a HTTP Redirect binding.
+	$httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+	
+	// Send the Logout response using HTTP POST binding.
+	$httpredirect->sendMessage($logoutResponseXML, $requester, $logoutrequest->getRelayState(), 'SingleLogOutUrl', 'SAMLResponse');
+
+} elseif(isset($_GET['SAMLResponse'])) {
+	
+
+	if (isset($_GET['RelayState'])) {
+		header('Location: ' . $_GET['RelayState']);
+	} else {
+		
+		echo 'You are now successfully logged out.';
+		
+	}
+
+}
+
+
+
+?>
\ No newline at end of file
diff --git a/www/saml2/sp/initSLO.php b/www/saml2/sp/initSLO.php
new file mode 100644
index 000000000..e3aae4e17
--- /dev/null
+++ b/www/saml2/sp/initSLO.php
@@ -0,0 +1,66 @@
+<?php
+
+require_once('../../_include.php');
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/LogoutRequest.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+//require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php');
+
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+$session = SimpleSAML_Session::getInstance();
+
+$idpentityid = isset($_GET['idpentityid']) ? $_GET['idpentityid'] : $config->getValue('default-saml20-idp') ;
+$spentityid = isset($_GET['spentityid']) ? $_GET['spentityid'] : $metadata->getMetaDataCurrentEntityID();
+
+
+if (isset($session) ) {
+	
+	try {
+		$lr = new SimpleSAML_XML_SAML20_LogoutRequest($config, $metadata);
+	
+		// ($issuer, $receiver, $nameid, $nameidformat, $sessionindex, $mode) {
+		$req = $lr->generate($spentityid, $idpentityid, $session->getNameID(), $session->getNameIDFormat(), $session->getSessionIndex(), 'SP');
+		
+		$httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+		
+		$relayState = SimpleSAML_Utilities::selfURL();
+		if (isset($_GET['RelayState'])) {
+			$relayState = $_GET['RelayState'];
+		}
+		
+		//$request, $remoteentityid, $relayState = null, $endpoint = 'SingleSignOnUrl', $direction = 'SAMLRequest', $mode = 'SP'
+		$httpredirect->sendMessage($req, $idpentityid, $relayState, 'SingleLogOutUrl', 'SAMLRequest', 'SP');
+
+	} catch(Exception $exception) {
+		
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+
+		$et->$data['message'] = 'Some error occured when trying to issue the logout request to the IdP.';	
+		$et->$data['e'] = $exception;
+		
+		$et->show();
+
+	}
+
+} else {
+
+	
+	$relaystate = $session->getRelayState();
+	
+	header('Location: ' . $relaystate );
+	
+	#print_r($metadata->getMetaData('sam.feide.no'));
+	#print_r($req);
+
+}
+
+
+?>
\ No newline at end of file
diff --git a/www/saml2/sp/initSSO.php b/www/saml2/sp/initSSO.php
new file mode 100644
index 000000000..a5d5a403d
--- /dev/null
+++ b/www/saml2/sp/initSSO.php
@@ -0,0 +1,97 @@
+<?php
+
+require_once('../../_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XHTML/Template.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/SAML20/AuthnRequest.php');
+//require_once('SimpleSAML/XML/SAML20/AuthnResponse.php');
+require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+//require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php');
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+
+$session = SimpleSAML_Session::getInstance();
+		
+try {
+
+	$idpentityid = isset($_GET['idpentityid']) ? $_GET['idpentityid'] : $config->getValue('default-saml20-idp') ;
+	$spentityid = isset($_GET['spentityid']) ? $_GET['spentityid'] : $metadata->getMetaDataCurrentEntityID();
+
+} catch (Exception $exception) {
+
+	$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+	$et->data['message'] = 'Error loading SAML 2.0 metadata';	
+	$et->data['e'] = $exception;	
+	$et->show();
+	exit(0);
+}
+
+if (!isset($session) || !$session->isValid() ) {
+	
+	try {
+		$sr = new SimpleSAML_XML_SAML20_AuthnRequest($config, $metadata);
+	
+		$req = $sr->generate($spentityid);
+		
+	
+		
+		$httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
+		
+		$relayState = SimpleSAML_Utilities::selfURL();
+		if (isset($_GET['RelayState'])) {
+			$relayState = $_GET['RelayState'];
+		}
+		
+		$httpredirect->sendMessage($req, $idpentityid, $relayState);
+
+	
+	} catch(Exception $exception) {
+		
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+
+		$et->data['message'] = 'Some error occured when trying to issue the authentication request to the IdP.';	
+		$et->data['e'] = $exception;
+		
+		$et->show();
+
+	}
+
+} else {
+
+	
+	
+	$relaystate = $session->getRelayState();
+	
+	if (isset($relaystate) && !empty($relaystate)) {
+		header('Location: ' . $relaystate );
+	} else {
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+
+		$et->data['message'] = 'Could not get relay state, do not know where to send the user.';	
+		$et->data['e'] = new Exception();
+		
+		$et->show();
+
+	
+	}
+
+}
+
+
+
+
+#print_r($metadata->getMetaData('sam.feide.no'));
+#print_r($req);
+
+//echo 'Location: ' . $relaystate;
+
+
+?>
diff --git a/www/shib13/sp/AssertionConsumerService.php b/www/shib13/sp/AssertionConsumerService.php
new file mode 100644
index 000000000..20daca2af
--- /dev/null
+++ b/www/shib13/sp/AssertionConsumerService.php
@@ -0,0 +1,69 @@
+<?php
+
+require_once('../../_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/Shib13/AuthnRequest.php');
+require_once('SimpleSAML/Bindings/Shib13/HTTPPost.php');
+require_once('SimpleSAML/XHTML/Template.php');
+
+session_start();
+
+try {
+	
+	/*
+	echo '<pre>';
+	print_r($_POST);
+	echo '</pre>';
+	*/
+	$config = SimpleSAML_Configuration::getInstance();
+	$metadata = new SimpleSAML_XML_MetaDataStore($config);
+	
+	#print_r($metadata->getMetaData('sam.feide.no'));
+#	$sr = new SimpleSAML_XML_Shib13_AuthnResponse($config, $metadata);
+	
+	$binding = new SimpleSAML_Bindings_Shib13_HTTPPost($config, $metadata);
+	$authnResponse = $binding->decodeResponse($_POST);
+
+	$xml = $authnResponse->getXML();
+	/*
+	echo '<pre>';
+	echo $xml;
+	echo '</pre>';
+*/
+
+	$authnResponse->validate();
+	$session = $authnResponse->createSession();
+	
+
+
+	if (isset($session)) {
+		$relayState = $authnResponse->getRelayState();
+		if (isset($relayState)) {
+			header("Location: " . $relayState);
+			exit(0);
+		} else {
+			echo 'Could not find RelayState parameter, you are stucked here.';
+		}
+	} else {
+		throw new Exception('Unkown error. Could not get session.');
+	}
+
+
+} catch(Exception $exception) {
+
+	$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+
+	$et->data['message'] = 'Some error occured when trying to issue the authentication request to the IdP.';	
+	$et->data['e'] = $exception;
+	
+	$et->show();
+
+
+}
+
+
+?>
\ No newline at end of file
diff --git a/www/shib13/sp/initSSO.php b/www/shib13/sp/initSSO.php
new file mode 100644
index 000000000..ccb3a799d
--- /dev/null
+++ b/www/shib13/sp/initSSO.php
@@ -0,0 +1,99 @@
+<?php
+
+require_once('../../_include.php');
+
+
+require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Session.php');
+require_once('SimpleSAML/XHTML/Template.php');
+require_once('SimpleSAML/XML/MetaDataStore.php');
+require_once('SimpleSAML/XML/Shib13/AuthnRequest.php');
+//require_once('SimpleSAML/XML/SAML20/AuthnResponse.php');
+//require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
+//require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php');
+
+session_start();
+
+$config = SimpleSAML_Configuration::getInstance();
+$metadata = new SimpleSAML_XML_MetaDataStore($config);
+
+
+$session = SimpleSAML_Session::getInstance();
+		
+
+/*
+ * Incomming URL parameters
+ *
+ * idpentityid 		The entityid of the wanted IdP to authenticate with. If not provided will use default.
+ * spentityid		The entityid of the SP config to use. If not provided will use default to host.
+ * 
+ */
+
+try {
+
+	$idpentityid = isset($_GET['idpentityid']) ? $_GET['idpentityid'] : $config->getValue('default-shib13-idp') ;
+	$spentityid = isset($_GET['spentityid']) ? $_GET['spentityid'] : $metadata->getMetaDataCurrentEntityID('shib13-sp-hosted');
+
+} catch (Exception $exception) {
+
+	$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+	$et->data['message'] = 'Error loading SAML 2.0 metadata';	
+	$et->data['e'] = $exception;	
+	$et->show();
+	exit(0);
+}
+
+if (!isset($session) || !$session->isValid() ) {
+	
+	try {
+		$ar = new SimpleSAML_XML_Shib13_AuthnRequest($config, $metadata);
+		$ar->setIssuer($spentityid);	
+		if(isset($_GET['RelayState'])) 
+			$ar->setRelayState($_GET['RelayState']);
+
+		$url = $ar->createRedirect($idpentityid);
+		header('Location: ' . $url);
+//		echo 'IdP: '  . $idpentityid . ' SP: ' . $spentityid;
+		
+		exit(0);
+	
+	} catch(Exception $exception) {
+		
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+
+		$et->data['message'] = 'Some error occured when trying to issue the authentication request to the IdP.';	
+		$et->data['e'] = $exception;
+		
+		$et->show();
+
+	}
+
+} else {
+
+	
+	
+	$relaystate = $session->getRelayState();
+	
+	if (isset($relaystate) && !empty($relaystate)) {
+		header('Location: ' . $relaystate );
+	} else {
+		$et = new SimpleSAML_XHTML_Template($config, 'error.php');
+
+		$et->data['message'] = 'Could not get relay state, do not know where to send the user.';	
+		$et->data['e'] = new Exception();
+		
+		$et->show();
+
+	
+	}
+
+}
+
+
+#print_r($metadata->getMetaData('sam.feide.no'));
+#print_r($req);
+
+//echo 'Location: ' . $relaystate;
+
+
+?>
-- 
GitLab