diff --git a/build/lemonldap-ng/changelog b/build/lemonldap-ng/changelog index af2d49e88..3d60d8c2c 100644 --- a/build/lemonldap-ng/changelog +++ b/build/lemonldap-ng/changelog @@ -1,3 +1,9 @@ +lemonldap-ng (0.9) unstable; urgency=low + + * Liberty Alliance module issued of the FederID project is now included. + + -- Xavier Guimard Sun, 14 Oct 2007 12:02:33 +0200 + lemonldap-ng (0.8.3) unstable; urgency=high * Syntax errors in configuration are now displayed diff --git a/build/lemonldap-ng/debian/changelog b/build/lemonldap-ng/debian/changelog index e69de29bb..706b2d846 100644 --- a/build/lemonldap-ng/debian/changelog +++ b/build/lemonldap-ng/debian/changelog @@ -0,0 +1,5 @@ +lemonldap-ng (0.8.3-0) unstable; urgency=low + + * Local build + + -- Xavier Guimard Sun, 14 Oct 2007 09:11:36 +0200 diff --git a/build/lemonldap-ng/debian/control b/build/lemonldap-ng/debian/control index cbe38bfbf..918747625 100644 --- a/build/lemonldap-ng/debian/control +++ b/build/lemonldap-ng/debian/control @@ -55,8 +55,7 @@ Description: Lemonldap::NG apache manager part Package: liblemonldap-ng-portal-perl Architecture: all -Depends: libapache-session-perl, libnet-ldap-perl, liblemonldap-ng-conf-perl (>=0.8.2.3) -Recommends: liblasso-perl +Depends: libapache-session-perl, libnet-ldap-perl, liblemonldap-ng-conf-perl (>=0.8.2.3), liblasso-perl Description: Lemonldap::NG apache authentication portal part Lemonldap::NG is a complete Web-SSO system that can run with reverse-proxies or directly on application apache servers. diff --git a/build/lemonldap-ng/debian/copyright b/build/lemonldap-ng/debian/copyright index 16f03523a..e354baabf 100644 --- a/build/lemonldap-ng/debian/copyright +++ b/build/lemonldap-ng/debian/copyright @@ -6,13 +6,12 @@ Copyright: Copyright 2004, 2005, 2006 by Xavier Guimard Licence: - -Lemonldap::NG is distributed under your choice of the GNU General Public -License or the Artistic License. On Debian GNU/Linux systems, the copyright -terms for Perl itself are located in `/usr/share/doc/perl/copyright'. On Debian -GNU/Linux systems, the complete text of the GNU General Public License version -2 can be found in `/usr/share/common-licenses/GPL' and the Artistic Licence in -`/usr/share/common-licenses/Artistic'. +Lemonldap::NG is distributed under your choice under the GNU General Public +License or the Artistic License. +On Debian GNU/Linux systems, the complete text of the GNU General Public +License version 2 can be found in `/usr/share/common-licenses/GPL' and the +Artistic Licence in `/usr/share/common-licenses/Artistic'. File lemonldap-ng-manager/example/lemonldap-ng-manager.js is distributed under GNU General Public License version 2. + diff --git a/build/lemonldap-ng/debian/rules b/build/lemonldap-ng/debian/rules index 4b4d2d6bd..ae8b9fafa 100755 --- a/build/lemonldap-ng/debian/rules +++ b/build/lemonldap-ng/debian/rules @@ -67,7 +67,7 @@ binary-indep: build install binary-arch: build install dh_testdir dh_testroot - dh_installchangelogs changelogs + dh_installchangelogs changelog dh_installdocs mkdir debian/tmp/var/lib/lemonldap-ng/protected cp _example/index.pl debian/tmp/var/lib/lemonldap-ng/protected diff --git a/modules/lemonldap-ng-portal/MANIFEST b/modules/lemonldap-ng-portal/MANIFEST index ea302c7af..cd4dcb8a4 100644 --- a/modules/lemonldap-ng-portal/MANIFEST +++ b/modules/lemonldap-ng-portal/MANIFEST @@ -1,4 +1,67 @@ Changes +example/AuthLA/idps.xml +example/AuthLA/index.pl +example/AuthLA/la.log +example/AuthLA/liberty/assertionConsumer.pl +example/AuthLA/liberty/federationTermination.pl +example/AuthLA/liberty/federationTerminationReturn.pl +example/AuthLA/liberty/singleLogout.pl +example/AuthLA/liberty/singleLogoutReturn.pl +example/AuthLA/liberty/soapCall.pl +example/AuthLA/liberty/soapEndpoint.pl +example/AuthLA/ressources/db/liberty_tables.sql +example/AuthLA/ressources/db/taccounts.sql +example/AuthLA/ressources/db/tnameid.sql +example/AuthLA/ressources/db/tsessions.sql +example/AuthLA/ressources/lemonsp-metadata.xml +example/AuthLA/tpl/auth.tpl +example/AuthLA/tpl/themes/bouton_authentic.png +example/AuthLA/tpl/themes/bouton_federid.png +example/AuthLA/tpl/themes/bouton_interldap.png +example/AuthLA/tpl/themes/bouton_lemonldap::ng.png +example/AuthLA/tpl/themes/CHANGELOG +example/AuthLA/tpl/themes/dc2/button-hover.png +example/AuthLA/tpl/themes/dc2/button-normal.png +example/AuthLA/tpl/themes/dc2/default.css +example/AuthLA/tpl/themes/dc2/dotclear-logo.png +example/AuthLA/tpl/themes/dc2/drag.png +example/AuthLA/tpl/themes/dc2/head-bg.png +example/AuthLA/tpl/themes/dc2/head-logo.png +example/AuthLA/tpl/themes/dc2/magnifier.png +example/AuthLA/tpl/themes/dc2/msg-error.png +example/AuthLA/tpl/themes/dc2/msg-std.png +example/AuthLA/tpl/themes/dc2/page-bg.png +example/AuthLA/tpl/themes/dc2/tab-bg.png +example/AuthLA/tpl/themes/dc2/tab-c-l.png +example/AuthLA/tpl/themes/dc2/tab-c-r.png +example/AuthLA/tpl/themes/dc2/tab-l-l.png +example/AuthLA/tpl/themes/dc2/tab-l-r.png +example/AuthLA/tpl/themes/dc2/tab-n-l.png +example/AuthLA/tpl/themes/dc2/tab-n-r.png +example/AuthLA/tpl/themes/federid-dc2/button-hover.png +example/AuthLA/tpl/themes/federid-dc2/button-normal.png +example/AuthLA/tpl/themes/federid-dc2/default.css +example/AuthLA/tpl/themes/federid-dc2/head-bg.png +example/AuthLA/tpl/themes/federid-dc2/head-logo.png +example/AuthLA/tpl/themes/federid-dc2/msg-error.png +example/AuthLA/tpl/themes/federid-dc2/msg-std.png +example/AuthLA/tpl/themes/federid-dc2/page-bg.png +example/AuthLA/tpl/themes/federid/button-hover.png +example/AuthLA/tpl/themes/federid/button-normal.png +example/AuthLA/tpl/themes/federid/default.css +example/AuthLA/tpl/themes/federid/fond.jpg +example/AuthLA/tpl/themes/federid/head-bg.png +example/AuthLA/tpl/themes/federid/head-logo.png +example/AuthLA/tpl/themes/federid/idp.css +example/AuthLA/tpl/themes/federid/laap.css +example/AuthLA/tpl/themes/federid/msg-error.png +example/AuthLA/tpl/themes/federid/msg-std.png +example/AuthLA/tpl/themes/federid/page-bg.png +example/AuthLA/tpl/themes/federid/sso.css +example/AuthLA/tpl/themes/federid/wui.css +example/AuthLA/tpl/themes/README +example/AuthLA/tpl/themes/styleswitcher.js +example/AuthLA/tpl/themes/template.html example/index.pl example/scripts/purgeCentralCache example/scripts/purgeCentralCache.cron.d diff --git a/modules/lemonldap-ng-portal/example/AuthLA/idps.xml b/modules/lemonldap-ng-portal/example/AuthLA/idps.xml new file mode 100644 index 000000000..efebb3912 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/idps.xml @@ -0,0 +1,15 @@ + + + http://idp1/liberty/metadata + /path/to/idp1-metadata.xml + /path/to/idp1-key-public.pem + /path/to/idp1-key-public.pem + + + http://idp2/liberty/metadata + /path/to/idp2-metadata.xml + /path/to/idp2-key-public.pem + /path/to/idp2-key-public.pem + + + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/index.pl b/modules/lemonldap-ng-portal/example/AuthLA/index.pl new file mode 100644 index 000000000..3e796ad48 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/index.pl @@ -0,0 +1,70 @@ +#!/usr/bin/perl + +use strict ; +use warnings ; + +use HTML::Template ; +use Lemonldap::NG::Portal::AuthLA; + + + +my $portal = Lemonldap::NG::Portal::AuthLA->new({ + configStorage => { + type => 'File' , + dirName => '/var/lib/lemonldap-ng/config' , + } , + + # Liberty Parameters + laSp => { + certificate => '/var/lib/lemonldap-ng/web/portal/ressources/lemonsp-key-public.pem' , + metadata => '/var/lib/lemonldap-ng/web/portal/ressources/lemonsp-metadata.xml' , + privkey => '/var/lib/lemonldap-ng/web/portal/ressources/lemonsp-key-private.pem' , + secretkey => '/var/lib/lemonldap-ng/web/portal/ressources/lemonsp-key-private.pem' , + } , + laIdpsFile => '/var/lib/lemonldap-ng/web/portal/idps.xml' , + laStorage => 'Apache::Session::File', + laStorageOptions => { + Directory => '/var/lib/lemonldap-ng/var/assertion' , + LockDirectory => '/var/lib/lemonldap-ng/var/lock' , + } , + laDebug => 1 , + laLdapLoginAttribute => 'uid' , + + # Parameters that permit to access lemonldap::NG::Handler local cache + localStorage => 'Cache::FileCache' , + localStorageOptions => {} , +}); + + + +if( $portal->process() ) { + + # Print protected URLs + + print $portal->header ; + print " $_
" + foreach ($portal->getProtectedURLs) ; + +} else { + + # Retrieve IDP list. + + my @idps = () ; + foreach ($portal->getIdpIDs) { + my %row_data ; + $row_data{IDPNAME} = $_ ; + push (@idps, \%row_data) ; + } + @idps = sort {$a cmp $b} @idps ; + + # Print template + + print $portal->header ; + my $template = HTML::Template->new( filename => '/var/lib/lemonldap-ng/web/portal/tpl/auth.tpl' ) ; + $template->param( AUTH_ERROR => $portal->error ) ; + $template->param( AUTH_URL => $portal->param('url') ) ; + $template->param( AUTH_IDPS => \@idps ) ; + print $template->output ; + +} + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/la.log b/modules/lemonldap-ng-portal/example/AuthLA/la.log new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/la.log @@ -0,0 +1 @@ + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/liberty/assertionConsumer.pl b/modules/lemonldap-ng-portal/example/AuthLA/liberty/assertionConsumer.pl new file mode 120000 index 000000000..aaea3e99b --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/liberty/assertionConsumer.pl @@ -0,0 +1 @@ +../index.pl \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/liberty/federationTermination.pl b/modules/lemonldap-ng-portal/example/AuthLA/liberty/federationTermination.pl new file mode 120000 index 000000000..aaea3e99b --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/liberty/federationTermination.pl @@ -0,0 +1 @@ +../index.pl \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/liberty/federationTerminationReturn.pl b/modules/lemonldap-ng-portal/example/AuthLA/liberty/federationTerminationReturn.pl new file mode 120000 index 000000000..aaea3e99b --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/liberty/federationTerminationReturn.pl @@ -0,0 +1 @@ +../index.pl \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/liberty/singleLogout.pl b/modules/lemonldap-ng-portal/example/AuthLA/liberty/singleLogout.pl new file mode 120000 index 000000000..aaea3e99b --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/liberty/singleLogout.pl @@ -0,0 +1 @@ +../index.pl \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/liberty/singleLogoutReturn.pl b/modules/lemonldap-ng-portal/example/AuthLA/liberty/singleLogoutReturn.pl new file mode 120000 index 000000000..aaea3e99b --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/liberty/singleLogoutReturn.pl @@ -0,0 +1 @@ +../index.pl \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/liberty/soapCall.pl b/modules/lemonldap-ng-portal/example/AuthLA/liberty/soapCall.pl new file mode 120000 index 000000000..aaea3e99b --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/liberty/soapCall.pl @@ -0,0 +1 @@ +../index.pl \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/liberty/soapEndpoint.pl b/modules/lemonldap-ng-portal/example/AuthLA/liberty/soapEndpoint.pl new file mode 120000 index 000000000..aaea3e99b --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/liberty/soapEndpoint.pl @@ -0,0 +1 @@ +../index.pl \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/liberty/tpl b/modules/lemonldap-ng-portal/example/AuthLA/liberty/tpl new file mode 120000 index 000000000..b3a91eee2 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/liberty/tpl @@ -0,0 +1 @@ +../tpl \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/liberty_tables.sql b/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/liberty_tables.sql new file mode 100644 index 000000000..d531fa9b8 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/liberty_tables.sql @@ -0,0 +1,37 @@ +create table taccounts +( + id_account int NOT NULL AUTO_INCREMENT, + uid blob NOT NULL, + identity_dump blob NOT NULL, + timestamp TIMESTAMP, + divers blob NULL, + unique index (id_account), + primary key (id_account) +); + +create table tnameid +( + id_nameid int NOT NULL AUTO_INCREMENT, + nameid varchar(100) NOT NULL, + id_account int NOT NULL, + timestamp TIMESTAMP, + divers blob NULL, + unique index (id_nameid), + primary key (id_nameid) +); + +create table tsessions +( + id_session int NOT NULL AUTO_INCREMENT, + session_nb blob NOT NULL, + id_account int NOT NULL, + id_nameid int NOT NULL, + session_dump blob NULL, + timestamp TIMESTAMP, + divers blob NULL, + unique index (id_session), + primary key (id_session) +); + + + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/taccounts.sql b/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/taccounts.sql new file mode 100644 index 000000000..0faea2a5a --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/taccounts.sql @@ -0,0 +1,11 @@ +create table taccounts +( + id_account int NOT NULL AUTO_INCREMENT, + uid blob NOT NULL, + identity_dump blob NULL, + timestamp TIMESTAMP, + divers blob NULL, + unique index (id_account), + primary key (id_account) +); + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/tnameid.sql b/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/tnameid.sql new file mode 100644 index 000000000..0d63a7aa5 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/tnameid.sql @@ -0,0 +1,12 @@ +create table tnameid +( + id_nameid int NOT NULL AUTO_INCREMENT, + nameid varchar(100) NOT NULL, + id_account int NOT NULL, + timestamp TIMESTAMP, + divers blob NULL, + unique index (id_nameid), + primary key (id_nameid) +); + + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/tsessions.sql b/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/tsessions.sql new file mode 100644 index 000000000..b0d0aa5bc --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/ressources/db/tsessions.sql @@ -0,0 +1,14 @@ +create table tsessions +( + id_session int NOT NULL AUTO_INCREMENT, + session_nb blob NOT NULL, + id_account int NOT NULL, + id_nameid int NOT NULL, + session_dump blob NULL, + timestamp TIMESTAMP, + divers blob NULL, + unique index (id_session), + primary key (id_session) +); + + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/ressources/lemonsp-metadata.xml b/modules/lemonldap-ng-portal/example/AuthLA/ressources/lemonsp-metadata.xml new file mode 100644 index 000000000..5f0fd27cf --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/ressources/lemonsp-metadata.xml @@ -0,0 +1,51 @@ + + + + + + + http://auth.example.com/liberty/assertionConsumer.pl + + http://auth.example.com/liberty/singleLogout.pl + http://auth.example.com/liberty/singleLogoutReturn.pl + + http://projectliberty.org/profiles/slo-idp-soap + http://projectliberty.org/profiles/slo-idp-http + http://projectliberty.org/profiles/slo-sp-soap + http://projectliberty.org/profiles/slo-sp-http + + http://auth.example.com/liberty/federationTermination.pl + http://auth.example.com/liberty/federationTerminationReturn.pl + http://projectliberty.org/profiles/fedterm-idp-soap + http://projectliberty.org/profiles/fedterm-idp-http + http://projectliberty.org/profiles/fedterm-sp-soap + http://projectliberty.org/profiles/fedterm-sp-http + + + + http://auth.example.com/liberty/soapEndpoint.pl + + + + true + + + + + + Lemonldap-NG Service Provider + Lemonldap-NG Service Provider + http://auth.example.com/ + + + + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/auth.tpl b/modules/lemonldap-ng-portal/example/AuthLA/tpl/auth.tpl new file mode 100644 index 000000000..f42a31b7d --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/auth.tpl @@ -0,0 +1,54 @@ + + + + + LemonLDAP::NG Portal - Authentication + + + + + + +
+

 

+

FederID WebSSO

LemonLDAP::NG Portal - Authentication

+
+ +
+ +

+ + " /> + +
Authentication on this service (no Identity federation) + + + " /> +
+ +
+
+ + + +
+ +
Liberty Alliance authentication + +
+ +
Submit your choice + + +
+
+ + + + + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/CHANGELOG b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/CHANGELOG new file mode 100644 index 000000000..dbc8e0db9 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/CHANGELOG @@ -0,0 +1,11 @@ +- 22/O7/2007 - Clement OUDOT : + * Remove old skins + * Create alternatives for all FederID components, based on specifc colors +- 20/07/2007 - Clement OUDOT: + * Modifiy layout -> template.html + * Import DotClear 2 admin theme + * Build a first FederID theme based upon DC2 admin + * Build a real FederID theme +- 08/07/2007 - Clement OUDOT : + * Import default theme from Authentic project, based on DotClear 2 theme + * Create sample test page diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/README b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/README new file mode 100644 index 000000000..4d8ea8c1d --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/README @@ -0,0 +1,13 @@ +================================================================================ + README +================================================================================ + +These are the themes for FederID project. The goal is to provide to all FederID +components the same Look 'n Feel. + +Each theme has its own directory (eg. default/) and can have alternatives. + +A sample page test (template.html) must be modified to allow switching between +the themes that are created. + +You can use this page locally to test your theme. diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_authentic.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_authentic.png new file mode 100644 index 000000000..eb62ae21f Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_authentic.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_federid.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_federid.png new file mode 100644 index 000000000..77a7e79fd Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_federid.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_interldap.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_interldap.png new file mode 100644 index 000000000..623c149b1 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_interldap.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_lemonldap::ng.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_lemonldap::ng.png new file mode 100644 index 000000000..b50979c7d Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/bouton_lemonldap::ng.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/button-hover.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/button-hover.png new file mode 100644 index 000000000..43d298b95 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/button-hover.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/button-normal.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/button-normal.png new file mode 100644 index 000000000..b5b9d4de8 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/button-normal.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/default.css b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/default.css new file mode 100644 index 000000000..8c9025b03 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/default.css @@ -0,0 +1,731 @@ +body { + font: 62.5%/1.5em "DejaVu Sans","Lucida Grande","Lucida Sans Unicode",Arial,sans-serif; + color : #000; + background : #fff url(page-bg.png) repeat-y top left; + margin : 0; + padding : 0; +} +body.auth { + background-image: none; +} +body.install #content { + margin-top: 1em; + font-size: 1.1em; +} + +a img,:link img,:visited img { border:none } + +a, a:link, a:visited { + color : #06c; + text-decoration : none; + border-bottom : 1px dotted #f90; +} +a:hover, a:active, a:focus { + +} + +h1, h2, h3, h4, h5, h6, p { + margin-top : 0; + margin-bottom: 0.6em; +} + +h2 { + font-family : Arial,Helvetica,sans-serif; + color : #069; + font-size : 1.4em; +} + +h3 { + color : #333; + font-size : 1.2em; +} + +p, div.p { + margin : 0 0 1em 0; +} + +hr { + height : 1px; + border-width : 1px 0 0 0; + border-color : #999; + border-style : solid; +} + +pre, code { + font: 100% "Andale Mono","Courier New",monospace; +} + +/* LAYOUT +-------------------------------------------------------- */ +/* General font-size */ +#top, #info-box, #main, #main-menu, #footer { + font-size: 1.1em; +} + +#top { + margin : 0; + padding : 0; + background : transparent url(head-bg.png) repeat-x; +} +#top h1 { + padding : 0; + margin : 0; + height : 58px; + text-indent : -1000px; + background : transparent url(head-logo.png) no-repeat 0 0; +} +#top h1 a { + position: absolute; + top: 3px; + left: 0; + width: 170px; + height: 35px; + border: none; +} + +#info-box { + position : absolute; + right : 20px; + top : 6px; + margin : 0; + padding : 3px 3px 4px 15px; +} +#info-box div { + margin: 0; padding: 0; +} +#info-box div div { + display: inline; +} +#info-box select { + width : 160px; +} +#info-box a { + font-weight : bold; +} + +#main { + width : 100%; + float : right; + margin-left : -155px; + margin-top : 0; +} + +#content { + margin-left : 155px; + margin-bottom : 10px; + padding-top : 1px; + margin-right : 15px; +} + +#main-menu { + width : 135px; + float : left; + margin-top : 0; + margin-bottom : 10px; +} +#main-menu h3 { + margin : 0; + padding : 0 0 0 5px; +} +#main-menu ul { + margin : 0 0 1em 0; + padding : 0; + list-style : none; +} +#main-menu li { + display : block; + margin : 0.5em 0 0 5px; + padding : 2px 0 1px 20px; + background-repeat: no-repeat; + background-position: 0 0; +} +#main-menu a { + font-weight : bold; +} +#main-menu .active a { + border-bottom-style: solid; +} + +#default-blog { + position: absolute; + top: 58px; + right: 30px; + height: 1.5em; + font-size : 140%; + font-weight: bold; +} + +#footer { + clear : both; + padding : 3px 5px 0 25px; +} +#footer a { + border: none; +} + +#debug { + position: absolute; + top: 0; + width: 100%; + height: 4px; + background: #d99; +} +#debug div { + display: none; + padding: 3px 0.5em 2px; +} +#debug p { + margin : 0.5em 0; +} +#debug:hover { + height: auto; +} +#debug:hover div { + display: block; +} + +/* DASHBOARD */ +#dashboard { + font-size: 120%; + padding-top: 2em; + clear: left; +} +#dashboard p img { + vertical-align: middle; +} +#dashboard ul { + display: block; + margin: 0; + padding-left: 1.5em; + list-style: square; +} +#dashboard li { + margin: 0.25em 0 0 0; + color: #666; +} + +#dashboard-icons p { + float: left; + width: 32%; + text-align: center; + margin: 2em 0 0 0; +} +#dashboard-icons span { + display: block; +} +#dashboard-icons a { + border-bottom-width: 0; +} +#dashboard-icons span a { + border-bottom-width: 1px; +} + +/* POST */ +#entry-sidebar { + width : 200px; + float : right; +} +#entry-content { + margin-right : 220px; +} +#comments { + clear : both; +} + +/* MEDIA */ +#media-icon { + float: left; +} +#media-details { + margin-left: 70px; +} +#media-details ul { + display: block; + margin-left: 0; + padding: 0; +} +#media-details li { + list-style: square inside; + margin: 0; + padding: 0; +} +#media-original-image { + overflow: auto; +} +#media-original-image.overheight { + height: 500px; +} + +#add-file-f { + position: relative; +} +#add-file-f .more-file { + position:absolute; + right: 0.5em; + background: #999; + color: #fff; + border: none; +} + +/* POPUP */ +body.popup { + background-position : -120px 0; +} +body.popup #top h1 { + background-position : -120px 0; +} +body.popup #main { + margin-left : -35px; +} +body.popup #content { + margin-left : 35px; +} +body.popup #footer { + clear : both; + padding-top : 20px; + padding-left : 35px; +} + +/* CLASSES +-------------------------------------------------------- */ +a.help-link { + border: none; +} + +.help-content dt { + font-weight: bold; + color: #666; + margin: 0; +} +.help-content dd { + margin: 0.3em 0 1.5em 0; +} + +.clear { + clear : both; +} +.lclear { + clear : left; +} +div.clearer { + height : 1px; + font-size : 1px; +} + +.hide { + display : none; +} + +.right { + text-align : right; +} + +.frame-shrink { + border: 1px solid #666; + padding: 0.5em; + margin-bottom: 1em; + height: 120px; + overflow: auto; +} + +div.error { + border : 2px solid #c00; + padding : 0.5em 0.5em 0.5em 40px; + margin-bottom : 1em; + background : transparent url(msg-error.png) no-repeat 5px 50%; +} + + +.line p { + margin : 0; +} + +.message, .static-msg { + font-weight : bold; + color : #f60; + padding : 0.5em 0.5em 0.5em 40px; + border : 1px solid #ccc; + background : transparent url(msg-std.png) no-repeat 5px 50%; +} + +.offline { + color : #666; +} + +ul.nice { + margin: 1em 0; + padding: 0 0 0 2em; + list-style: square; +} +ul.nice li { + margin:0; + padding: 0; +} + +.three-cols { +} +.three-cols .col { + width : 32.3%; + float : left; + margin-left : 1%; +} +.three-cols .col:first-child { + width : 33.3%; + margin-left : 0; +} + +.two-cols { + position : static; +} +.two-cols .col { + width : 49%; + margin-left : 1%; + float : left; +} +.two-cols .col:first-child { + width : 50%; + margin-left : 0; +} + +.comment { + border-top : 2px solid #ccc; + margin-bottom : 1em; + padding : 2em 0 1em 0; + position : relative; +} +.comment form p { + margin : 0; + position : absolute; + top : 2px; + right : 0; +} + + +.part-tabs { + float: left; + width: 100%; + background: transparent url(tab-bg.png) repeat-x bottom; + margin-bottom: 2em; +} +.part-tabs ul { + margin: 0; + padding: 10px 10px 0; + list-style: none; +} +.part-tabs li { + float: left; + background: transparent url(tab-n-l.png) no-repeat top left; + margin: 0 3px 0 0; + padding: 0 0 0 5px; +} +.part-tabs a { + display: block; + background: transparent url(tab-n-r.png) no-repeat top right; + padding: 1px 10px 1px 5px; + border: none; +} +.part-tabs li.part-tabs-active { + background-image: url(tab-c-l.png); +} +.part-tabs li.part-tabs-active a { + background-image: url(tab-c-r.png); + padding-bottom: 2px; + font-weight : bold; +} +.part-tabs li.part-tabs-link { + background-image: url(tab-l-l.png); +} +.part-tabs li.part-tabs-link a { + background-image: url(tab-l-r.png); +} + + +.screenshot { + width: 250px; + float: left; + margin-left: 10px; +} +.screenshot img { + border : 1px solid #333; +} +.screenshot p { + font-size: 0.9em; +} + +.media-list { + position : static; +} +.media-col-0 { + clear: left; +} +.media-item { + position: relative; + border-top: 1px solid #ccc; + margin-bottom: 1em; + padding: 5px 0; +} +div.media-list .media-item { + width: 49%; + float: left; + margin-right: 1%; +} +a.media-icon { + display: block; + border-bottom: none; + float: left; +} +.media-icon img { + display: block; +} +.media-item ul { + display: block; + list-style: none; + margin: 0 0 0 60px; + padding: 0; +} +li.media-action { + display: block; + position: absolute; + top: 5px; + right: 5px; + height: 16px; +} +li.media-action a { + border: none; +} +li.media-action form { + display: inline; +} +li.media-action input { + border: none; +} + +select.l10n option { + padding-left: 16px; +} +option.avail10n { + background: transparent url(../images/check-on.png) no-repeat 0 50%; +} + +/* TABLES +-------------------------------------------------------- */ +table { + font-size : 1em; + border-collapse : collapse; + margin : 0 0 1em 0; +} +tr.line:hover { + background : #ddd; +} +th, td { + border-width : 0 0 1px 0; + border-style : solid; + border-color : #ccc; + padding : 2px 5px; + vertical-align : top; +} +th { + text-align : left; + border-bottom-color : #666; +} + +.noborder td, td.noborder, .noborder th, th.noborder { + border-width : 0; +} + +table .maximal, table.maximal { + width : 100%; +} +table .minimal { + width : 1px; +} + +table .nowrap { + white-space : nowrap; +} + +td.status { + vertical-align: middle; +} +td.status img { + margin-bottom: -2px; +} +td.status a { + border: none; +} + +tr.line img.expand { + margin-right: 10px; + margin-bottom: -2px; +} +tr.expand td { + border-bottom: none; +} +td.expand { + padding: 1em; +} + +.dragable { + border-collapse: separate; +} +.dragable tbody td { + +} +.handle { + padding : 0; +} +.handler { + cursor : move; + background : transparent url(drag.png) no-repeat 0 50%; + padding-left : 15px; +} + +/* FORMS +-------------------------------------------------------- */ +form { + display : block; + margin : 0; + padding : 0; +} + +fieldset { + display : block; + margin : 0 0 1em 0; + padding : 1em 0.5em; + border-width : 1px 0; + border-style: solid; + border-color: #ccc; + background: #fbfbfb; +} +legend { + font-weight : bold; + padding: 0.2em 0.6em; + border-width: 1px; + border-style: solid; + border-color: #ccc; + background: #fbfbfb; +} +optgroup { + font-weight : bold; + font-style : normal; +} +option { + font-weight : normal; +} + +input, textarea, select { + background : #f9f9f9; + border-width : 1px; + border-style : solid; + border-color : #000 #ccc #ccc #000; +} +input, textarea, select, option { + font: 1em "DejaVu Sans","Lucida Grande","Lucida Sans Unicode",Arial,sans-serif; +} +input[type=text], input[type=password], textarea { + padding : 2px 0; +} +input[type=checkbox], input[type=radio] { + border: none; +} +textarea { + padding : 2px 0; +} +/*input[type=text]:focus, input[type=password]:focus, textarea:focus, option { + background : #dfdcc7; +} can't select text with opera */ +input[type=submit], input[type=reset], input[type=button] { + padding : 1px 2px; + background : #d2e0e6 url(button-normal.png) repeat-x bottom left; + border-width : 1px; + border-style : outset; + border-color : #ccc; + +} +input[type=submit]:hover, input[type=reset]:hover, input[type=button]:hover { + background-color : #fc3; + background-image : url(button-hover.png); +} + +input[type=submit] { + font-weight : bold; +} + +input[type=checkbox], input[type=radio] { + margin : 0; + padding : 0; + background : transparent; +} + +label { + display : block; +} +label input, label select, label span { + display : block; +} +p.form-note { + margin-top : -1em; + color : #f60; +} + +label.classic { + display : inline; +} +label.classic input, label span input, label.classic select, label span select { + display : inline; +} + +label.area, p.area { + width: inherit !important; + margin-right : 6px !important; +} +.area textarea { + display : block; + width : 100%; +} + +label.required { + font-weight : bold; +} +label.required:before { + content : '* '; + color : #c00; +} + +label .maximal, textarea.maximal, input.maximal { + width : 100%; +} + +a.form-control { + display : none; + font-weight: bold; + background: url(magnifier.png) no-repeat 0 0; + color: green; + padding-left: 20px; +} + +fieldset.constrained { + margin: 0; + padding: 0; + border: none; + background: transparent; +} + +#login-screen { + display: block; + width : 180px; + margin : 30px auto 0; + font-size: 1.1em; +} +#login-screen h1 { + text-indent: -2000px; + background: transparent url(dotclear-logo.png) no-repeat top left; + height: 25px; +} +#login-screen fieldset { + border: 1px solid #999; + padding: 1em 10px; +} +#login-screen input[type=text], #login-screen input[type=password] { + width: 100%; +} \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/dotclear-logo.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/dotclear-logo.png new file mode 100644 index 000000000..f373df195 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/dotclear-logo.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/drag.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/drag.png new file mode 100644 index 000000000..3e3a78dcd Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/drag.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/head-bg.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/head-bg.png new file mode 100644 index 000000000..1622ef8bf Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/head-bg.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/head-logo.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/head-logo.png new file mode 100644 index 000000000..0981e096a Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/head-logo.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/magnifier.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/magnifier.png new file mode 100644 index 000000000..4e959630a Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/magnifier.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/msg-error.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/msg-error.png new file mode 100644 index 000000000..db6f2b5bc Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/msg-error.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/msg-std.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/msg-std.png new file mode 100644 index 000000000..2fe993c68 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/msg-std.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/page-bg.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/page-bg.png new file mode 100644 index 000000000..729154ede Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/page-bg.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-bg.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-bg.png new file mode 100644 index 000000000..875d66168 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-bg.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-c-l.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-c-l.png new file mode 100644 index 000000000..b7a865d83 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-c-l.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-c-r.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-c-r.png new file mode 100644 index 000000000..c34402c60 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-c-r.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-l-l.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-l-l.png new file mode 100644 index 000000000..3ef3c827e Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-l-l.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-l-r.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-l-r.png new file mode 100644 index 000000000..7daecc100 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-l-r.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-n-l.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-n-l.png new file mode 100644 index 000000000..a3fb8b95c Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-n-l.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-n-r.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-n-r.png new file mode 100644 index 000000000..1d1cbc2cc Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/dc2/tab-n-r.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/button-hover.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/button-hover.png new file mode 100644 index 000000000..43d298b95 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/button-hover.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/button-normal.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/button-normal.png new file mode 100644 index 000000000..b5b9d4de8 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/button-normal.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/default.css b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/default.css new file mode 100644 index 000000000..1d598eb6e --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/default.css @@ -0,0 +1,252 @@ +body { + font: 62.5%/1.5em "DejaVu Sans","Lucida Grande","Lucida Sans Unicode",Arial,sans-serif; + color : #000; + background : #fff url(page-bg.png) repeat-y top left; + margin : 0; + padding : 0; +} + +a img,:link img,:visited img { border:none } + +a, a:link, a:visited { + color : #06c; + text-decoration : none; + border-bottom : 1px dotted #f90; +} +a:hover, a:active, a:focus { + +} + +h1, h2, h3, h4, h5, h6, p { + margin-top : 0; + margin-bottom: 0.6em; +} + +h2 { + font-family : Arial,Helvetica,sans-serif; + color : #069; + font-size : 1.4em; +} + +h3 { + color : #333; + font-size : 1.2em; +} + +p, div.p { + margin : 0 0 1em 0; +} + +hr { + height : 1px; + border-width : 1px 0 0 0; + border-color : #999; + border-style : solid; +} + +pre, code { + font: 100% "Andale Mono","Courier New",monospace; +} + +/* LAYOUT +-------------------------------------------------------- */ +/* General font-size */ +#top, #info-box, #content, #main-menu, #footer { + font-size: 1.1em; +} + +#top { + margin : 0; + padding : 0; + background : transparent url(head-bg.png) repeat-x; +} + +#top h1 { + padding : 0; + margin : 0; + height : 58px; + text-indent : -1000px; + background : transparent url(head-logo.png) no-repeat 0 0; +} + +#info-box { + position : absolute; + right : 20px; + top : 6px; + margin : 0; + padding : 3px 3px 4px 15px; +} + +#main-menu { + width : 135px; + float : left; + margin-top : 0; + margin-bottom : 10px; +} +#main-menu h3 { + margin : 0; + padding : 0 0 0 5px; +} +#main-menu ul { + margin : 0 0 1em 0; + padding : 0; + list-style : none; +} +#main-menu li { + display : block; + margin : 0.5em 0 0 5px; + padding : 2px 0 1px 20px; + background-repeat: no-repeat; + background-position: 0 0; +} +#main-menu a { + font-weight : bold; +} +#main-menu .active a { + border-bottom-style: solid; +} + +#content { + margin-left : 155px; + margin-bottom : 10px; + padding-top : 1px; + margin-right : 15px; +} + +#footer { + clear : both; + padding : 3px 5px 0 25px; +} +#footer a { + border: none; +} + +/* CLASSES +-------------------------------------------------------- */ +.error { + border : 2px solid #c00; + padding : 0.5em 0.5em 0.5em 40px; + margin-bottom : 1em; + background : transparent url(msg-error.png) no-repeat 5px 50%; +} + + +.message { + font-weight : bold; + color : #f60; + padding : 0.5em 0.5em 0.5em 40px; + border : 1px solid #ccc; + background : transparent url(msg-std.png) no-repeat 5px 50%; +} + +/* TABLES +-------------------------------------------------------- */ +table { + font-size : 1em; + border-collapse : collapse; + margin : 0 0 1em 0; +} +tr.line:hover { + background : #ddd; +} +th, td { + border-width : 0 0 1px 0; + border-style : solid; + border-color : #ccc; + padding : 2px 5px; + vertical-align : top; +} +th { + text-align : left; + border-bottom-color : #666; +} + +/* FORMS +-------------------------------------------------------- */ +form { + display : block; + margin : 0; + padding : 0; +} + +fieldset { + display : block; + margin : 0 0 1em 0; + padding : 1em 0.5em; + border-width : 1px 0; + border-style: solid; + border-color: #ccc; + background: #fbfbfb; +} +legend { + font-weight : bold; + padding: 0.2em 0.6em; + border-width: 1px; + border-style: solid; + border-color: #ccc; + background: #fbfbfb; +} +optgroup { + font-weight : bold; + font-style : normal; +} +option { + font-weight : normal; +} + +input, textarea, select { + background : #f9f9f9; + border-width : 1px; + border-style : solid; + border-color : #000 #ccc #ccc #000; +} +input, textarea, select, option { + font: 1em "DejaVu Sans","Lucida Grande","Lucida Sans Unicode",Arial,sans-serif; +} +input[type=text], input[type=password], textarea { + padding : 2px 0; +} +input[type=checkbox], input[type=radio] { + border: none; +} +textarea { + padding : 2px 0; +} +input[type=submit], input[type=reset], input[type=button] { + padding : 1px 2px; + background : #d2e0e6 url(button-normal.png) repeat-x bottom left; + border-width : 1px; + border-style : outset; + border-color : #ccc; + +} +input[type=submit]:hover, input[type=reset]:hover, input[type=button]:hover { + background-color : #fc3; + background-image : url(button-hover.png); +} + +input[type=submit] { + font-weight : bold; +} + +input[type=checkbox], input[type=radio] { + margin : 0; + padding : 0; + background : transparent; +} + +label { + display : block; +} +label input, label select, label span { + display : block; +} + +label.required { + font-weight : bold; +} +label.required:before { + content : '* '; + color : #c00; +} + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/head-bg.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/head-bg.png new file mode 100644 index 000000000..1622ef8bf Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/head-bg.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/head-logo.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/head-logo.png new file mode 100644 index 000000000..e4e6a8b38 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/head-logo.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/msg-error.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/msg-error.png new file mode 100644 index 000000000..db6f2b5bc Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/msg-error.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/msg-std.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/msg-std.png new file mode 100644 index 000000000..2fe993c68 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/msg-std.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/page-bg.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/page-bg.png new file mode 100644 index 000000000..729154ede Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid-dc2/page-bg.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/button-hover.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/button-hover.png new file mode 100644 index 000000000..43d298b95 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/button-hover.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/button-normal.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/button-normal.png new file mode 100644 index 000000000..b5b9d4de8 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/button-normal.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/default.css b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/default.css new file mode 100644 index 000000000..97aa55278 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/default.css @@ -0,0 +1,265 @@ +/* Default CSS */ +/* Main color : gray */ +/* Link color : cyan and red underlined*/ + +body { + font: 62.5%/1.5em sans-serif; + color : #000; + background : #fff url(page-bg.png) repeat top left; + margin : 0; + padding : 0; +} + +a img,:link img,:visited img { border:none } + +a, a:link, a:visited { + color : navy; + text-decoration : none; + border-bottom : 1px dotted red; +} +a:hover, a:active, a:focus { + +} + +h1, h2, h3, h4, h5, h6 { + margin-top : 0.5em; + margin-bottom : 0.5em; + color : gray ; +} + +h1 {font-size : 2em;} + +h2 {font-size : 1.8em;} + +h3 {font-size : 1.6em;} + +hr { + border-width : 3px 0 0 0; + border-color : gray; + border-style : dotted; +} + +pre, code { + font: 1.5em monospace; + border-left : 5px gray solid; + padding: 0 0 0 10px; + background: #eeeee6; +} + +/* LAYOUT +-------------------------------------------------------- */ +/* General font-size */ +#top, #info-box, #content, #main-menu, #footer { + font-size: 1.3em; +} + +#page { + margin : 0 100px 0 100px; + padding : 10px; + background : white; + border-width : 0 3px 0 3px; + border-color : gray; + border-style : dotted; +} + +#top { + margin : 0 0 50px 0; + padding : 0; + background : transparent url(head-bg.png) repeat-y top right; +} + +#top h1 { + padding : 0; + margin : 0; + height : 100px; + text-indent : -1000px; + background : transparent url(head-logo.png) no-repeat 0 0; +} +#info-box { + position : absolute; + right : 120px; + top : 30px; + margin : 0; + padding : 0; + letter-spacing : 0.2em ; + text-align : right; +} + +#main-menu { + width : 170px; + float : left; + margin : 0; + padding : 0 10px 10px 10px ; + background : transparent url(head-bg.png) repeat-y top right; +} +#main-menu h3 { + text-align: center; +} +#main-menu ul { + margin : 0 0 1em 0; + padding : 0; + list-style : none; +} +#main-menu li { + display : block; + margin : 0.5em 0 0 5px; + padding : 2px 0 1px 20px; + background-repeat: no-repeat; + background-position: 0 0; +} +#main-menu a { + font-weight : bold; +} +#main-menu .active a { + border-bottom-style: solid; +} + +#content { + margin-left : 200px; + margin-right : 10px; + margin-bottom : 10px; + padding-top : 0; +} + +#footer { + clear : both; + margin-left : 200px; + padding : 10px 0 10px 0 ; + border-top : 3px gray dotted; + text-align : center; +} +#footer a { + border: none; +} + +/* CLASSES +-------------------------------------------------------- */ +.error { + border : 2px solid red; + padding : 0.5em 0.5em 0.5em 40px; + margin-bottom : 1em; + background : transparent url(msg-error.png) no-repeat 5px 50%; +} + + +.message { + font-weight : bold; + padding : 0.5em 0.5em 0.5em 40px; + border : 2px solid gray; + background : transparent url(msg-std.png) no-repeat 5px 50%; +} + +/* TABLES +-------------------------------------------------------- */ +table { + font-size : 1em; + border-collapse : collapse; + margin : 0.5em; +} +tr.line:hover { + background : #ddd; +} +th, td { + border-style : dotted; + border-color : gray; + vertical-align : middle; + padding : 0.5em; +} +td { + border-width : 2px; +} +th { + text-align : center; + border-bottom-color : #666; + border-width : 0 0 2px 0; +} + +/* FORMS +-------------------------------------------------------- */ +form { + display : block; + margin : 0; + padding : 0; +} + +fieldset { + display : block; + margin : 0 0 1em 0; + padding : 1em 0.5em; + border-width : 1px 0; + border-style : solid; + border-color : gray; + background : #fbfbfb; +} +legend { + font-weight : bold; + padding : 0.2em 0.6em; + border-width : 1px; + border-style : solid; + border-color : gray; + background : #fbfbfb; +} +optgroup { + font-weight : bold; + font-style : normal; +} +option { + font-weight : normal; +} + +input, textarea, select { + background : #f9f9f9; + border-width : 1px; + border-style : solid; + border-color : gray; +} +input, textarea, select, option { + font : 1em sans-serif; +} +input[type=text], input[type=password], textarea { + padding : 2px 0; +} + +textarea { + padding : 2px 0; +} + +input[type=submit], input[type=reset], input[type=button] { + padding : 1px 2px; + background : #d2e0e6 url(button-normal.png) repeat-x bottom left; + border-width : 1px; + border-style : outset; + border-color : #ccc; + +} +input[type=submit]:hover, input[type=reset]:hover, input[type=button]:hover { + background-color : #fc3; + background-image : url(button-hover.png); +} + +input[type=submit] { + font-weight : bold; +} + +input[type=checkbox], input[type=radio] { + margin : 0.2em; + padding : 0; + background : transparent; + border : 1px solid gray; +} + +label { + display : block; + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +label.required { + font-weight : bold; +} + +label.required:before { + content : '* '; + color : red; +} + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/fond.jpg b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/fond.jpg new file mode 100644 index 000000000..bfd94dcfd Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/fond.jpg differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/head-bg.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/head-bg.png new file mode 100644 index 000000000..812ee2570 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/head-bg.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/head-logo.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/head-logo.png new file mode 100644 index 000000000..65225f0b6 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/head-logo.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/idp.css b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/idp.css new file mode 100644 index 000000000..14969557c --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/idp.css @@ -0,0 +1,15 @@ +/* CSS for Identity Provider */ +/* Main color : green #8cd749 */ + +@import url(default.css); + +h1, h2, h3, h4, h5, h6 { color : #8cd749; } + +#page { border-color : #8cd749; } + +#footer { border-top : #8cd749; } + +.message { border-color : #8cd749; } + +hr, pre, code, th, td, fieldset, legend { border-color : #8cd749; } + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/laap.css b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/laap.css new file mode 100644 index 000000000..cee30783b --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/laap.css @@ -0,0 +1,15 @@ +/* CSS for LAAP */ +/* Main color : clear blue #6699ff */ + +@import url(default.css); + +h1, h2, h3, h4, h5, h6 { color : #6699ff; } + +#page { border-color : #6699ff; } + +#footer { border-top : #6699ff; } + +.message { border-color : #6699ff; } + +hr, pre, code, th, td, fieldset, legend { border-color : #6699ff; } + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/msg-error.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/msg-error.png new file mode 100644 index 000000000..db6f2b5bc Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/msg-error.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/msg-std.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/msg-std.png new file mode 100644 index 000000000..2fe993c68 Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/msg-std.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/page-bg.png b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/page-bg.png new file mode 100644 index 000000000..581ed9d5f Binary files /dev/null and b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/page-bg.png differ diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/sso.css b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/sso.css new file mode 100644 index 000000000..c5f126914 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/sso.css @@ -0,0 +1,15 @@ +/* CSS for SSO */ +/* Main color : orange #d9b500 */ + +@import url(default.css); + +h1, h2, h3, h4, h5, h6 { color : #d9b500; } + +#page { border-color : #d9b500; } + +#footer { border-top : #d9b500; } + +.message { border-color : #d9b500; } + +hr, pre, code, th, td, fieldset, legend { border-color : #d9b500; } + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/wui.css b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/wui.css new file mode 100644 index 000000000..3e7a94dd2 --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/federid/wui.css @@ -0,0 +1,15 @@ +/* CSS for LDAP Content Management (WUI) */ +/* Main color : blue #1335e2 */ + +@import url(default.css); + +h1, h2, h3, h4, h5, h6 { color : #1335e2; } + +#page { border-color : #1335e2; } + +#footer { border-top : #1335e2; } + +.message { border-color : #1335e2; } + +hr, pre, code, th, td, fieldset, legend { border-color : #1335e2; } + diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/styleswitcher.js b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/styleswitcher.js new file mode 100644 index 000000000..3a7d9f7ee --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/styleswitcher.js @@ -0,0 +1 @@ +function setActiveStyleSheet(title) { var i, a, main; for(i=0; (a = document.getElementsByTagName("link")[i]); i++) { if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) { a.disabled = true; if(a.getAttribute("title") == title) a.disabled = false; } } } function getActiveStyleSheet() { var i, a; for(i=0; (a = document.getElementsByTagName("link")[i]); i++) { if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title") && !a.disabled) return a.getAttribute("title"); } return null; } function getPreferredStyleSheet() { var i, a; for(i=0; (a = document.getElementsByTagName("link")[i]); i++) { if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("rel").indexOf("alt") == -1 && a.getAttribute("title") ) return a.getAttribute("title"); } return null; } function createCookie(name,value,days) { if (days) { var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); var expires = "; expires="+date.toGMTString(); } else expires = ""; document.cookie = name+"="+value+expires+"; path=/"; } function readCookie(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } window.onload = function(e) { var cookie = readCookie("style"); var title = cookie ? cookie : getPreferredStyleSheet(); setActiveStyleSheet(title); } window.onunload = function(e) { var title = getActiveStyleSheet(); createCookie("style", title, 365); } var cookie = readCookie("style"); var title = cookie ? cookie : getPreferredStyleSheet(); setActiveStyleSheet(title); \ No newline at end of file diff --git a/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/template.html b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/template.html new file mode 100644 index 000000000..cf02826ab --- /dev/null +++ b/modules/lemonldap-ng-portal/example/AuthLA/tpl/themes/template.html @@ -0,0 +1,92 @@ + + + + + Themes for FederID Project + + + + + + + + + + + + + + + +
+

 

+

Title

Other text

+ +
+

H2 Title in content div

+
+

Some text in content div

+

FederID special themes

+

Change style to FederID Test

+

Change style to FederID Test Authentic

+

Change style to FederID Test WUI

+

Change style to FederID Test LAAP

+

Change style to FederID Test SSO

+

Old themes

+

Change style to DC2

+

Change style to FederID DC2

+

Div and messages

+

Error

+

Info

+

A table

+ + + + +
Title 1Title 2
Content 1Content 2
Content 3Content 4
+

A form

+
+
Identification + + +
+ +
Informations + + + + Yes + No + + 1 + 2 + + +
+ +
Submit + + +
+
+ +

Texts

+
Text in "pre"
+ Text in "code" +
+ +
+ + diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal.pm index cf2ff37df..3fba4c059 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal.pm @@ -2,7 +2,7 @@ package Lemonldap::NG::Portal; print STDERR "See Lemonldap::NG::Portal(3) to know which Lemonldap::NG::Portal::* module to use."; -our $VERSION = "0.77"; +our $VERSION = "0.8"; 1; diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthLA.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthLA.pm index 4a867f412..d0b4c542f 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthLA.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthLA.pm @@ -1,8 +1,9 @@ -#============================================================================== + +#=============================================================================== # Liberty Alliance Authentication for LemonLDAP. # # This file is part of the LemonLDAP project and released under GPL. -#============================================================================== +#=============================================================================== package Lemonldap::NG::Portal::AuthLA; @@ -11,166 +12,1423 @@ use warnings; use Lemonldap::NG::Portal::SharedConf qw(:all); use lasso; +use CGI qw/:standard/; +use CGI::Cookie; +use DBI; +use HTTP::Request; +use HTTP::Response; +use LWP::UserAgent; +use MIME::Base64; +use XML::Simple; +use XML::Parser; +use XML::XPath; +use UNIVERSAL qw( isa can VERSION ); *EXPORT_OK = *Lemonldap::NG::Portal::SharedConf::EXPORT_OK; *EXPORT_TAGS = *Lemonldap::NG::Portal::SharedConf::EXPORT_TAGS; *EXPORT = *Lemonldap::NG::Portal::SharedConf::EXPORT; -our $VERSION = '0.1'; +our $VERSION = '0.2'; +our @ISA = qw(Lemonldap::NG::Portal::SharedConf); -our @ISA = qw(Lemonldap::NG::Portal::SharedConf); +#=============================================================================== +# Global Constants +#=============================================================================== -#============================================================================== -# Overloaded methods -#============================================================================== +sub PE_LA_FAILED { 500 } +sub PE_LA_ARTFAILED { 501 } +sub PE_LA_DEFEDFAILED { 502 } +sub PE_LA_QUERYEMPTY { 503 } +sub PE_LA_SOAPFAILED { 504 } +sub PE_LA_SLOFAILED { 505 } +sub PE_LA_SSOFAILED { 506 } +sub PE_LA_SSOINITFAILED { 507 } +sub PE_LA_SESSIONERROR { 508 } +sub PE_LA_SEPFAILED { 509 } -# Main process as described in Portal::Simple module +sub PC_LA_URLAC { '/liberty/assertionConsumer.pl' } +sub PC_LA_URLFT { '/liberty/federationTermination.pl' } +sub PC_LA_URLFTR { '/liberty/federationTerminationReturn.pl' } +sub PC_LA_URLSL { '/liberty/singleLogout.pl' } +sub PC_LA_URLSLR { '/liberty/singleLogoutReturn.pl' } +sub PC_LA_URLSC { '/liberty/soapCall.pl' } +sub PC_LA_URLSE { '/liberty/soapEndpoint.pl' } -# 1. Retrieve source URL -# Not overloaded +#=============================================================================== +#=============================================================================== +# +# TODO +# ------------------------------------------------------------------------------ +# - category / function : comments +# ------------------------------------------------------------------------------ +# - association / store : Replace files by hastable or DBI implementation +# - optimization / libertySignOn : Catching error when retrieving $providerID +# - optimization / _getAttributeValuesOfSamlAssertion : Checking errors +# - security / process : Check if URL figures in locationRules +# - security / libertyFederationTermination : Implementation +# - security / libertySoapEndpoint : Does Lemonldap::NG do defederation ? +# - wsf / setSessionInfo : Code for getting informations via wsf protocol +# +#=============================================================================== +#=============================================================================== -# 2. Control existing sessions -# Not overloaded +################################################################################ +################################################################################ +## ## +## Lemonldap::NG::Portal functions ## +## ## +################################################################################ +################################################################################ -# 3. Retrieve user credentials -# Test here if the user was authenticated by IdP -sub extractFormInfo { - my $self = shift; - &_lasso_init(); - my $libertyFilesDir = $self->{libertyFilesDir} ; - my $server = &_lasso_create_server($libertyFilesDir); - my $login = &_lasso_create_authnrequest($server); +#=============================================================================== +# new +#=============================================================================== +# +# Instanciate this class. This constructor takes special parameters with +# classical Lemonldap::NG::SharedConf parameters. +# +#=============================================================================== - print STDERR $server->dump(); - print STDERR $login->dump(); +sub new { + my $class = shift; + my $this = $class->SUPER::new(@_); - return PE_OK; + $this->{isLibertyProcess} = 1; + $this->{laDebug} = 0 unless ( $this->{laDebug} ); + + die('No Liberty Alliance Service Provider data defined') + unless ( $this->{laSp} ); + die('No Liberty Alliance Identity Provider file defined') + unless ( $this->{laIdpsFile} ); + die('No laStorage configuration defined') + unless ( $this->{laStorage} ); + die('No laLdapLoginAttribute configuration defined') + unless ( $this->{laLdapLoginAttribute} ); + die('No localStorage configuration defined') + unless ( $this->{localStorage} and $this->{localStorageOptions} ); + + bless( $this, $class ); + + # Create LassoServer + + $this->{laServer} = lasso::Server->new( + $this->{laSp}->{metadata}, + $this->{laSp}->{privkey}, + undef, #$this->{laSp}->{secretkey} , + undef, #$this->{laSp}->{certificate} , + ); + + $this->_loadXmlIdpFile(); + return $this; } -# 4. LDAP format filter for attributes reading -# We must retrive user DN in SAML response -# Or use WSF to retrieve attributes -sub formateFilter { - my $self = shift; +#=============================================================================== +# authenticate +#=============================================================================== +# +# User is authenticated automatically, no ldap authentication. +# +#=============================================================================== - # Get DN in SAML response (TODO) - my $dn = "uid=clement,ou=personnes,dc=linagora,dc=com"; - - # Explode DN to build RDN - my @rdn = split /,/ , $dn; - - $self->{filter}="(".shift(@rdn).")"; - - return PE_OK; -} - -# 5. LDAP connection -# Overload only if WSF is used to retrieve attributes -#sub connectLDAP { -# return PE_OK; -#} - -# 6. LDAP bind (with Directory Manager or anonymous) -# Overload only if WSF is used to retrieve attributes -#sub bind { -# return PE_OK; -#} - - -# 7. Search the DN -# Overload only if WSF is used to retrieve attributes -#sub search { -# return PE_OK; -#} - -# 8. Load parameters -# Overload only if WSF is used to retrieve attributes -#sub setSessionInfo { -# # Use WSF to get "exprotedVars" -# return PE_OK; -#} - -# 9. Set macros -# Not overloaded - -# 10. Set groups -# Not overloaded - -# 11. LDAP unbind -# Overload only if WSF is used to retrieve attributes -#sub unbind { -# return PE_OK; -#} - -# 12. Authentication -# Authentication is done by IdP, so we disable this step sub authenticate { - return PE_OK; + my $this = shift; + return $this->SUPER::authenticate() + unless ( $this->{isLibertyProcess} ); + return PE_BADCREDENTIALS + unless ( defined $this->{user} ); + return PE_OK; } -# 13. Store parameters in session -# Not overloaded +#=============================================================================== +# extractFormInfo +#=============================================================================== +# +# This function is just override to do nothing. +# $this->{user} is already fixed in libertySetSessionInfo function. +# +#=============================================================================== -# 14. Build cookie -# Not overloaded - -# 15. Log -# Not overloaded - -# 16. Redirection -# Not overloaded - -#============================================================================== -# Liberty Alliance methods -#============================================================================== -# Lasso intialisation -sub _lasso_init { - lasso::init; +sub extractFormInfo { + my $this = shift; + return $this->SUPER::extractFormInfo() + unless ( $this->{isLibertyProcess} ); + return PE_OK; } -# Create server object -sub _lasso_create_server { +#=============================================================================== +# formateFilter +#=============================================================================== +# +# By default, the user is searched in the LDAP server with its UID. Here, +# $this->{user} contains nameIdentifier of the user, which is already stored +# in LDAP directory. +# +#=============================================================================== - # TODO: file names in global configuration - - my $libertyFilesDir = shift; - - my $server = lasso::Server->new( - "$libertyFilesDir/lemonldapng-metadata.xml", - "private-key.pem", - undef, undef); - - $server->addProvider( - $lasso::PROVIDER_ROLE_IDP, - "$libertyFilesDir/idp-http-authentic.demo.interldap.org-liberty-metadata-metadata.xml", - "$libertyFilesDir/idp-http-authentic.demo.interldap.org-liberty-metadata-publickey.pem", - undef); - - return $server; +sub formateFilter { + my $this = shift; + return $this->SUPER::formateFilter() + unless ( $this->{isLibertyProcess} ); + $this->{filter} = + "(&(uid=" . $this->{user} . ")(objectClass=inetOrgPerson))"; + return PE_OK; } -# Create AuthnRequest -sub _lasso_create_authnrequest { +#=============================================================================== +# process +#=============================================================================== +# +# Do portal Lemonldap::NG processing. Actions based on Lemonldap::NG structure +# and philosophy. +# +#=============================================================================== - my $server = shift; +sub process { + my $this = shift; + $this->{error} = PE_OK; - my $login = lasso::Login->new($server); + # Trace param() + # my @params = $this->param() ; + # foreach( @params ) { + # $this->_debug("parameter : $_ = " . $this->param($_)) ; + # } + # while(my($k,$v) = each(%ENV)) { + # $this->_debug("env : $k = $v") ; + # } - return $login; + #-------- + # Nothing to do if user access to portal directly. We have to verify if + # user was redirected from a protected host. + #-------- + + my $url = $this->url(); + my $urlr = $url . substr( $ENV{'SCRIPT_NAME'}, 1 ); + + if ( not $this->param('url') + and ( $url eq $this->{portal} or $urlr eq $this->{portal} ) ) + { + + # TODO Security tricks : + # - Check if URL figures in locationRules + $this->{error} = PE_DONE; + return $this->{error}; + } + + #-------- + # Authentication process + #-------- + + my $urldir = $this->url( -absolute => 1 ); + + # assertionCustomer + if ( $urldir eq $this->PC_LA_URLAC ) { + + $this->{error} = $this->_subProcess( + qw( libertyAssertionConsumer libertySetSessionInfo )); + + $this->_debug( "Login user = '" . $this->{user} . "'" ); + + # federationTermination + } + elsif ( $urldir eq $this->PC_LA_URLFT ) { + + $this->{error} = $this->_subProcess( + qw( libertyFederationTermination log autoRedirect )); + + # federationTerminationReturn + } + elsif ( $urldir eq $this->PC_LA_URLFTR ) { + + $this->{error} = $this->_subProcess( + qw( libertyFederationTerminationReturn log + autoRedirect ) + ); + + # singleLogout : called when IDP request Logout. + } + elsif ( $urldir eq $this->PC_LA_URLSL ) { + + $this->{error} = $this->_subProcess( + qw( libertyRetrieveExistingSession libertySingleLogout + libertyDeletingExistingSession ) + ); + + $this->_debug( "Logout user = '" . $this->{'dn'} . "'" ); + + # OK : $this->{urldc} is fixed at the end of this process. + + # singleLogoutReturn + } + elsif ( $urldir eq $this->PC_LA_URLSLR ) { + + $this->{error} = + $this->_subProcess(qw( libertySingleLogoutReturn log autoRedirect )); + + # soapCall + } + elsif ( $urldir eq $this->PC_LA_URLSC ) { + + $this->{error} = $this->_subProcess(qw( libertySoapCall log )); + + # soapEndpoint + } + elsif ( $urldir eq $this->PC_LA_URLSE ) { + + $this->{error} = + $this->_subProcess(qw( libertySoapEndpoint log autoRedirect )); + + # Direct access or simple access -> main + # WARNING : we permit authentication on service. + } + elsif ( not $this->param('user') and not $this->param('password') ) { + + $this->{error} = $this->_subProcess( + qw( libertyRetrieveExistingSession + libertyExtractFormInfo libertySignOn log + autoRedirect ) + ); + + # Not in liberty authentication process. + } + else { + $this->{isLibertyProcess} = 0; + } + + # $this->_debug("ERROR = " . $this->{error} . "\n") ; + + return 0 + if ( $this->{error} ); + + # Liberty Process OK -> do Lemonldap::NG process. + my $err = $this->SUPER::process(@_); + $this->_subProcess(qw( log autoRedirect )) + if ( $this->{urldc} ); + return $err; } +#=============================================================================== +# setSessionInfo +#=============================================================================== +# +# Après une consommation d'assertion d'auth valide cette fonction est appelée +# pour initialiser les infos de session dans le cas où c'est le wsf qui est +# choisi pour récup les infos du user (sera par défaut en ldap). +# +# TODO : +# * Faire de cette fonction un override de setSessionInfo avec par défaut +# le comportement de l'ancienne version et si dans la conf recup +# attribut par wsf... recup en wsf2.0. +# +#=============================================================================== + +sub setSessionInfo { + my $this = shift; + + # Si configuration fixée à WSF + # Alors + # Traitement de récupération des informations par WSF + # Sinon + # Traitement de récupération des informations en appelant la fonction + # SUPER::setSessionInfo. + + # $this->{sessionInfo}->{dn} = "cn=tutu,ou=people,dc=example,dc=com" ; + # $this->{sessionInfo}->{cn} = "tutu" ; + # $this->{sessionInfo}->{mail} = "tutu@example;com" ; + # $this->{sessionInfo}->{uid} = "ttutu" ; + + return $this->SUPER::setSessionInfo; +} + +#=============================================================================== +# store +#=============================================================================== +# +# This function store existing association between userNameIdentifier from IDP +# and Apache session ID of Lemonldap::NG. +# +#=============================================================================== + +sub store { + my $this = shift; + + my $err = $this->SUPER::store(); + return $err if ( $err or not $this->{isLibertyProcess} ); + + return PE_APACHESESSIONERROR + unless ( defined $this->{laStorageOptions}->{Directory} + and defined $this->{id} ); + + my $dir = $this->{laStorageOptions}->{Directory}; + $dir =~ s/(.*)\/?$/$1/; + + # We have to store association. + # Create a file named by userNameIdentifier from IDP, single, which + # contains session ID from Apache. + + if ( defined $this->{userNameIdentifier} ) { + + #my %h; + #eval { + # tie %h, $this->{laStorage}, + # substr($this->{userNameIdentifier},1), + # $this->{laStorageOptions}; + #}; + #if ( $@ ) { + # $this->_debug("$@\n"); + # return PE_APACHESESSIONERROR; + #} + #$h{id} = $this->{id} ; + #$h{_utime} = time(); + #untie %h; + + my $file = $dir . '/' . $this->{userNameIdentifier}; + $this->_debug("$file already exists : override association") + if ( -e $file ); + open( MYFILE, '> ' . $file ); + print MYFILE $this->{id}; + close MYFILE; + + # In other case, we considere that store action failed. + # So, we have to delete Apache session file. + + } + else { + my $file = $dir . '/' . $this->{id}; + unlink $file; + return PE_APACHESESSIONERROR; + } + + return PE_OK; +} + +#=============================================================================== +#=============================================================================== + +################################################################################ +################################################################################ +## ## +## Some Data Access functions ## +## ## +################################################################################ +################################################################################ + +#=============================================================================== +# getIdpURLs +#=============================================================================== +# +# Returns all IDP URLs +# +#=============================================================================== + +sub getIdpIDs { + my $this = shift; + my @tab = (); + + if ( $this->{laIdps} ) { + push @tab, $_ foreach ( keys %{ $this->{laIdps} } ); + } + + return @tab; +} + +#=============================================================================== +# getProtectedURLs +#=============================================================================== +# +# Returns all protected URLs +# +#=============================================================================== + +sub getProtectedURLs { + my $this = shift; + my @tab = (); + + if ( $this->{locationRules} ) { + push @tab, $_ foreach ( keys %{ $this->{locationRules} } ); + } + + return @tab; +} + +#=============================================================================== +#=============================================================================== + +################################################################################ +################################################################################ +## ## +## Liberty Alliance functions ## +## ## +################################################################################ +################################################################################ + +#=============================================================================== +# libertyArtefactResolution +#=============================================================================== +# +# This function do Liberty artefact resolution. Verification is already made +# if this function is called, normaly it is authorized. +# +#=============================================================================== + +sub libertyArtefactResolution { + my $this = shift; + + my $lassoLogin = undef; + my $lassoHttpMethod = + ( defined( $ENV{'REQUEST_METHOD'} ) and $ENV{'REQUEST_METHOD'} eq 'GET' ) + ? $lasso::HTTP_METHOD_REDIRECT + : $lasso::HTTP_METHOD_POST; + + # Retrieve or create lassoLogin. + + if ( $this->{laLogin} and defined( $this->{laLogin} ) ) { + $lassoLogin = $this->{laLogin}; + } + else { + $lassoLogin = lasso::Login->new( $this->{laServer} ); + } + + # POST + + if ( $lassoHttpMethod == $lasso::HTTP_METHOD_POST + and $this->param('LARES') ) + { + + my $formLares = $this->param('LARES'); + + if ( my $error = $lassoLogin->processAuthnResponseMsg($formLares) ) { + $this->_debug("lassoLogin->initRequest(...) : error = $error"); + return PE_LA_ARTFAILED; + } + + if ( my $error = $lassoLogin->acceptSso() ) { + $this->_debug("lassoLogin->acceptSso(...) : error = $error"); + return PE_LA_SSOFAILED; + } + + # GET : artefact is in QUERY_STRING param + + } + elsif ( $lassoHttpMethod == $lasso::HTTP_METHOD_REDIRECT + and defined $ENV{'QUERY_STRING'} ) + { + + # NOTES : + # Documentation indicates that $formLareq is QUERY_STRING HTTP + # header. We should have + # $formLareq = $this->param('QUERY_STRING'). + # But initRequest method on lassoLogin returns -502 error code + # (LASSO_PARAM_ERROR_INVALID_VALUE) when QUERY_STRING is like + # 'SAMLart=...&RelayState=...'. So, $formLareq is rebuild so + # that it only contains 'SAMLart=...'. + + my $formLareq = $ENV{'QUERY_STRING'}; + if ( $this->param('SAMLart') ) { + $formLareq = 'SAMLart=' . $this->param('SAMLart'); + } + + if ( my $error = + $lassoLogin->initRequest( $formLareq, $lassoHttpMethod ) ) + { + $this->_debug( +"libertyArtefactResolution : lassoLogin->initRequest(...) : error = $error" + ); + return PE_LA_ARTFAILED; + } + + if ( my $error = $lassoLogin->buildRequestMsg() ) { + $this->_debug( +"libertyArtefactResolution : lassoLogin->buildRequestMsg(...) : error = $error" + ); + return PE_LA_ARTFAILED; + } + + # Check if SSO is OK + # Successed = $soapResponseMsg contains code 200. + + my $soapResponseMsg = + $this->_soapRequest( $lassoLogin->{msgUrl}, $lassoLogin->{msgBody} ); + + if ( my $error = $lassoLogin->processResponseMsg($soapResponseMsg) ) { + $this->_debug( +"libertyArtefactResolution : lassoLogin->processResponseMsg(...) : error = $error" + ); + return PE_LA_SOAPFAILED; + } + + if ( my $error = $lassoLogin->acceptSso() ) { + $this->_debug( +"libertyArtefactResolution : lassoLogin->acceptSso(...) : error = $error" + ); + return PE_LA_SSOFAILED; + } + + } + else { + return PE_LA_SSOFAILED; + } + + # Backup $lassoLogin object + $this->{laLogin} = $lassoLogin; + + # Save RelayState. + + if ( $this->param('RelayState') ) { + $this->{urldc} = $this->param('RelayState'); + } + + return PE_OK; +} + +#=============================================================================== +# libertyAssertionConsumption +#=============================================================================== +# +# Realize assertion. +# +#=============================================================================== + +sub libertyAssertionConsumer { + my $this = shift; + + $this->{laLogin} = lasso::Login->new( $this->{laServer} ); + + return PE_LA_SSOFAILED + unless ( $this->{laLogin} + and defined( $this->{laLogin} ) + and defined( $this->param('SAMLart') ) ); + + return $this->libertyArtefactResolution(@_); +} + +#=============================================================================== +# libertyDeletingExistingSession +#=============================================================================== +# +# Delete existing Apache session file and Apache session ID <-> nameIdentifier +# association file. +# +#=============================================================================== + +sub libertyDeletingExistingSession { + my $this = shift; + + # Deleting local cache session shared by all Lemonldap::NG::Handler. + + if ( $this->{datas} ) { + my $refLocalStorage = undef; + my $localStorage = $this->{localStorage}; + my $localStorageOptions = {}; + $localStorageOptions->{namespace} ||= "lemonldap"; + $localStorageOptions->{default_expires_in} ||= 600; + + eval "use $localStorage;"; + die("Unable to load $localStorage: $@") if ($@); + + eval '$refLocalStorage = new ' + . $localStorage + . '($localStorageOptions);'; + if ( defined $refLocalStorage ) { + $refLocalStorage->remove( ${ $this->{datas} }{_session_id} ); + + #$refLocalStorage->remove(substr($this->{userNameIdentifier},1)) ; + $refLocalStorage->purge(); + $this->_debug("Deleting apache session succeed"); + } + else { + $this->_debug("Deleting apache session failed"); + } + } + + # Deleting association file, which is created when asserting consumer, + # in store function. + + if ( $this->{sessionInfo}->{'laNameIdentifier'} + and $this->{globalStorageOptions}->{Directory} ) + { + my $dir = $this->{globalStorageOptions}->{Directory}; + $dir =~ s/(.*)\/?$/$1/; + my $file = $dir . '/' . $this->{sessionInfo}->{'laNameIdentifier'}; + + if ( not unlink $file ) { + $this->_debug("Deleting liberty-apache association file failed"); + } + else { + $this->_debug("Deleting liberty-apache association file succeed"); + } + } + + return PE_OK; +} + +#=============================================================================== +# libertyExtractFormInfo +#=============================================================================== +# +# Verify that user has choose a IDP for authentication. +# +#=============================================================================== + +sub libertyExtractFormInfo { + my $this = shift; + + # If only one IDP -> redirect automatically on this IDP + my $idp; + my @idps = keys %{ $this->{laIdps} }; + if ( $#idps >= 0 && $this->param('idpChoice') ) { + $idp = $this->param('idpChoice'); + } + return PE_FIRSTACCESS + unless $idp; + $this->{idp}->{id} = $idp; + return PE_OK; +} + +#=============================================================================== +# libertyFederationTermination +#=============================================================================== +# +# Terminate federation. +# +# TO BE DONE. +# +#=============================================================================== + +sub libertyFederationTermination { + my $this = shift; + + $this->_debug("Processing federation termination..."); + + my $query = $ENV{'QUERY_STRING'}; + return PE_LA_QUERYEMPTY + unless $query; + + if ( lasso::isLibertyQuery($query) ) { + $this->{lassoDefederation} = + lasso::Defederation->new( $this->{laServer} ); + + return PE_LA_DEFEDFAILED + unless ( $this->{lassoDefederation} + and defined( $this->{lassoDefederation} ) + and $this->{lassoDefederation}->processNotificationMsg($query) ); + + $this->_debug("lassoDefederation->processNotificationMsg... OK"); + + # TODO : + # $this->fedTerm(); + + return PE_OK; + } + return PE_DONE; +} + +#=============================================================================== +# libertyFederationTerminationReturn +#=============================================================================== +# +# Quand cet appel ce produit t'il? +# +# TO BE DONE. +# +#=============================================================================== + +sub libertyFederationTerminationReturn { + my $this = @_; + + $this->_debug("The Return of the federation termination..."); + $this->{urldc} = $this->{portal}; + return PE_OK; +} + +#=============================================================================== +# libertyRetrieveExistingSession +#=============================================================================== +# +# Try to restore session whithin userNameIdentifier. +# +#=============================================================================== + +sub libertyRetrieveExistingSession { + my $this = shift; + + # To retrieve current Liberty session, there are two ways : + # - 1/ We have Lemonldap::NG cookie. Then we have lassoLoginDump ; + # - 2/ We have a query string that contains the userNameIdentifier. + # Then, we could retrieve apache session from cache files. + + return PE_LA_SESSIONERROR + unless ( defined $this->{laStorageOptions}->{Directory} ); + + # TODO : + # Retrieve NameIdentifier by catching and parsing $ENV{'QUERY_STRING'} + + # 2/ + + if ( $this->param('NameIdentifier') ) { + + # Retrieve apache session id from userNameIdentifier. + # $id contains apache session id. + + my $dir = $this->{laStorageOptions}->{Directory}; + $dir =~ s/(.*)\/?$/$1/; + my $file = $dir . '/' . $this->param('NameIdentifier'); + + return PE_LA_SESSIONERROR + unless ( open( MYFILE, $file ) ); + + my $id = readline(*MYFILE); + chomp($id); + close(MYFILE); + + # We can not rebuild factice cookie for Lemonldap::NG retrieving + # itself the session. So, we retrieve here directly the session. + # Lemonldap::NG::Simple code of controlExistingSession function. + + # Trying to recover session from global session storage + my %h; + eval { + tie %h, $this->{globalStorage}, $id, $this->{globalStorageOptions}; + }; + if ( $@ or not tied(%h) ) { + + # Session not available (expired ?) + print STDERR + "Session $id isn't yet available ($ENV{REMOTE_ADDR})\n"; + return PE_OK; + } + $this->{id} = $id; + + # A session has been find => calling &existingSession + my $r; + %{ $this->{datas} } = %h; + untie(%h); + if ( $this->{existingSession} ) { + $r = &{ $this->{existingSession} }( $this, $id, $this->{datas} ); + } + else { + $r = $this->existingSession( $id, $this->{datas} ); + } + + # Save datas in sessionInfo. + while ( my ( $k, $v ) = each( %{ $this->{datas} } ) ) { + $this->{sessionInfo}->{$k} = $v; + } + + $this->_debug("No existing liberty session found") + unless ( $r == PE_OK ); + } + + return PE_OK; +} + +#=============================================================================== +# libertySetSessionInfo +#=============================================================================== +# +# This function store in session cache information retrieve from IDP. If +# ID-WSF option is specified, it also store ID-WSF-attributes. +# In all cases, it fixes username of user who is authenticated on IDP. +# +#=============================================================================== + +sub libertySetSessionInfo { + my $this = shift; + + return PE_LA_FAILED + unless ( defined $this->{laLogin} ); + + my $lassoLogin = $this->{laLogin}; + + # Store identity in LDAP Directory, if identity not exists. Good + # opportunity to ask user some more informations. + + return PE_LA_FAILED + unless ( + defined $lassoLogin->{session} + + # and defined $lassoLogin->{identity} + and $lassoLogin->{nameIdentifier}->{content} + ); + + # Here, we store liberty identity and session in Apache session. + # We just store informations in cache, then those are saved by + # store function. Saved nameIdentifier too. + + # $this->{sessionInfo}->{laIdentityDump} = $lassoLogin->{identity}->dump() ; + $this->{sessionInfo}->{laSessionDump} = $lassoLogin->{session}->dump(); + $this->{sessionInfo}->{laNameIdentifier} = + $lassoLogin->{nameIdentifier}->{content}; + + # Get username from assertion and restore it in param('user'). Be + # carefull, IDP does not return username but an id for user assertion. + # The Lemonldap::NG search consists to perform a search with a filter + # using nameIdentifier, instead of username. + + $this->{userNameIdentifier} = $lassoLogin->{nameIdentifier}->{content}; + $this->{user} = $this->{userNameIdentifier}; + $this->{password} = 'none'; + + # Try to retrieve uid in SAML response form assertion statement. + # For the moment, uid have to be unique in LDAP directory. + my @uidValues = + $this->_getAttributeValuesOfSamlAssertion( $lassoLogin->{response}, + $this->{laLdapLoginAttribute} ); + $this->{user} = $uidValues[0] + if (@uidValues); + + return PE_OK; +} + +#=============================================================================== +# libertySignOn +#=============================================================================== +# +# Init SSO request. If successfull, $this->{urldc} contains Liberty IDP Url +# for redirection. +# +#=============================================================================== + +sub libertySignOn { + my $this = shift; + + my $lassoLogin = lasso::Login->new( $this->{laServer} ); + + return PE_LA_FAILED + unless ( $lassoLogin and defined($lassoLogin) ); + + # TODO : + # Catching error when retrieving $providerID. + + my $providerID = $this->{LAidps}->{ $this->{idp}->{id} }->{url}; + + if ( + my $error = $lassoLogin->initAuthnRequest( + $providerID, $lasso::HTTP_METHOD_REDIRECT + ) + ) + { + $this->_debug("lassoLogin->initAuthnRequest(...) : error = $error"); + return PE_LA_SSOINITFAILED; + } + + # We do one time federation, IDP doe not have to store nameIdentifier. + + $lassoLogin->{request}->{consent} = $lasso::LIB_CONSENT_OBTAINED; + $lassoLogin->{request}->{nameIdPolicy} = + $lasso::LIB_NAMEID_POLICY_TYPE_ONE_TIME; + + #$lassoLogin->{request}->{nameIdPolicy} = $lasso::LIB_NAMEID_POLICY_TYPE_FEDERATED ; + $lassoLogin->{request}->{isPassive} = 0; + + if ( $this->param('url') ) { + my $url = decode_base64( $this->param('url') ); + chomp $url; + $lassoLogin->{request}->{relayState} = $url; + } + + if ( my $error = $lassoLogin->buildAuthnRequestMsg() ) { + $this->_debug("lassoLogin->buildAuthnRequestMsg(..) : error = $error"); + return PE_LA_SSOINITFAILED; + } + + $this->{urldc} = $lassoLogin->{msgUrl}; + return PE_OK; +} + +#=============================================================================== +# libertySingleLogout +#=============================================================================== +# +# Two cases : +# * Portal or applications requiere singleLogout -> SP request ; +# * IDP requiere singleLogout -> IDP request with $ENV{'QUERY_STRING'} +# specified. +# +#=============================================================================== + +sub libertySingleLogout { + my $this = shift; + + my $lassoLogout = lasso::Logout->new( $this->{laServer} ); + return PE_LA_FAILED + unless ( $lassoLogout + and defined($lassoLogout) + and defined $ENV{'QUERY_STRING'} ); + + if ( lasso::isLibertyQuery( $ENV{'QUERY_STRING'} ) ) { + + # We retrieve query string and verify it. + # If it is OK, we set lemonldap::ng logout parameter, so we can perform + # it in Lemonldap::NG normal process. Then, we remove our stored liberty + # association file. + + $this->param( 'logout' => '1' ); + + if ( my $error = + $lassoLogout->processRequestMsg( $ENV{'QUERY_STRING'} ) ) + { + $this->_debug( + "lassoLogout->processRequestMsg(...) : error = $error"); + return PE_LA_SLOFAILED; + } + + # my $lassoIdentity = lasso::Identity::newFromDump($this->{sessionInfo}->{laIdentityDump}) ; + # $lassoLogout->{identity} = $lassoIdentity ; + my $lassoSession = + lasso::Session::newFromDump( $this->{sessionInfo}->{laSessionDump} ); + $lassoLogout->{session} = $lassoSession; + + # Logout by soap call could failed with those two errors. + if ( my $error = $lassoLogout->validateRequest() ) { + if ( $error != $lasso::PROFILE_ERROR_SESSION_NOT_FOUND + and $error != $lasso::PROFILE_ERROR_IDENTITY_NOT_FOUND ) + { + $this->_debug( + "lassoLogout->validateRequest(...) : error = $error"); + return PE_LA_SLOFAILED; + } + } + + if ( my $error = $lassoLogout->buildResponseMsg() ) { + $this->_debug( + "lassoLogout->buildResponseMsg(...) : error = $error"); + return PE_LA_SLOFAILED; + } + + # Confirm logout by soap request + if ( defined $lassoLogout->{msgBody} ) { + my $soapResponseMsg = $this->_soapRequest( $lassoLogout->{msgUrl}, + $lassoLogout->{msgBody} ); + } + } + + # Fixes redirection. + $this->{urldc} = $lassoLogout->{msgUrl}; + + # If $this->{urldc} empty, then we try to use HTTP referer if it exists + $this->{urldc} = $ENV{'HTTP_REFERER'} + if ( not $this->{urldc} and $ENV{'HTTP_REFERER'} ); + + return PE_OK; +} + +#=============================================================================== +# libertySingleLogoutReturn +#=============================================================================== +# +# SP provides singleLogout, it calls IDP which has done Liberty logout. Then IDP +# requests http://portal/liberty/singleLogoutReturn. +# Here, as there is no more liberty session on IDP, we suppress liberty session +# on Lemon. +# +# TODO : Modifier le redirect pour appeler le handler logout configuré dans la +# directive location (portal ou handler dédié, plus besoin du relaystate). +# +# TO BE DONE. +# +#=============================================================================== + +sub libertySingleLogoutReturn { + my $this = shift; + + $this->{lassoLogout} = lasso::Logout->new( $this->{laServer} ); + return PE_LA_SLOFAILED + unless ( $this->{lassoLogout} and defined( $this->{lassoLogout} ) ); + + $this->_debug("Processing single logout return..."); + + my %cookies = fetch CGI::Cookie; + + # Test if Lemonldap::NG cookie is available + if ( $cookies{ $this->{cookieName} } + and my $id = $cookies{ $this->{cookieName} }->value ) + { + + $this->{session_nb} = $cookies{ $this->{cookieName} }; + + $this->_debug("Cookie: $this->{cookieName} found..."); + $this->_debug("session number: $this->{session_nb}"); + + my $query = $ENV{'QUERY_STRING'}; + return PE_LA_QUERYEMPTY + unless $query; + + $this->_debug("Processing response message..."); + + return PE_LA_SLOFAILED + unless ( $this->{lassoLogout}->processResponseMsg($query) ); + + $this->_debug("lassoLogout->processResponseMsg... OK"); + + $this->delLibertySession(); + + $this->_debug("delete liberty session... OK"); + + my $formRelayState = $this->param('RelayState'); + return PE_LA_SLOFAILED + unless ( $formRelayState and defined($formRelayState) ); + + $this->_debug("formRelayState: $formRelayState"); + $this->{urldc} = $formRelayState . '/logout'; + + return PE_OK; + } + return PE_LA_SLOFAILED; +} + +#=============================================================================== +# libertySoapCall +#=============================================================================== +# +# IDP request defederation by SOAP calls. +# +# TO BE DONE. +# +#=============================================================================== + +sub libertySoapCall { + my $this = shift; + + $this->_debug("Soap call processing..."); + + my $contentType = $ENV{'CONTENT_TYPE'}; + my $soapMsg = $ENV{'QUERY_STRING'}; + + return PE_LA_SOAPFAILED + unless ( $contentType and $soapMsg and $contentType eq 'text/xml' ); + + $this->_debug("contentType: $contentType"); + $this->_debug("soapMsg: $soapMsg"); + + my $requestType = lasso::getRequestTypeFromSoapMsg($soapMsg); + + # Logout request + return $this->libertySingleLogout + if ( $requestType eq $lasso::REQUEST_TYPE_LOGOUT ); + + # Defederation request + return $this->libertyFederationTermination + if ( $requestType eq $lasso::REQUEST_TYPE_DEFEDERATION ); + + return PE_DONE; +} + +#=============================================================================== +# libertySoapEndpoint +#=============================================================================== +# +# Requests arrive in SOAP. We MUST traited them. +# Work as process function : call other functions. +# +#=============================================================================== + +sub libertySoapEndpoint { + my $this = shift; + + $this->_debug("SoapEndpoint processing..."); + + my $soapRequest = $this->param('POSTDATA'); + return PE_LA_SEPFAILED + unless $soapRequest; + + my $soapRequestType = lasso::getRequestTypeFromSoapMsg($soapRequest); + + $this->_debug("RequestType = $soapRequestType"); + + # Logout SOAP request + if ( $soapRequestType == $lasso::REQUEST_TYPE_LOGOUT ) { + $ENV{'QUERY_STRING'} = $soapRequest; + return $this->libertySingleLogout(); + + # Defederation SOAP request + } + elsif ( $soapRequestType == $lasso::REQUEST_TYPE_DEFEDERATION ) { + + # TODO + # Lemonldap do defederation ? + } + + return PE_OK; +} + +#=============================================================================== +#=============================================================================== + +################################################################################ +################################################################################ +## ## +## Private functions ## +## ## +################################################################################ +################################################################################ + +#=============================================================================== +# _getAttributeValuesOfSamlAssertion +#=============================================================================== +# +# Retrieve attribute value from a SAMLP response specified in first parameter. +# Return a table of values corresponding to the attribute name specified in +# second parameter. +# +#=============================================================================== + +sub _getAttributeValuesOfSamlAssertion { + my $this = shift; + my $samlp = shift; + my $attributeName = shift; + my @tab = (); + + # Search the specific attribute. + + my $attribute = undef; + + for ( + my $i = 0 ; + not defined $attribute + and $i < lasso::NodeList::length( $samlp->{assertion} ) ; + $i++ + ) + { + my $assertion = lasso::NodeList::getItem( $samlp->{assertion}, $i ); + my $attributeStatement = $assertion->{attributeStatement}; + + for ( + my $j = 0 ; + not defined $attribute + and $j < + lasso::NodeList::length( $attributeStatement->{attribute} ) ; + $j++ + ) + { + my $attr = + lasso::NodeList::getItem( $attributeStatement->{attribute}, $j ); + + if ( $attr->{attributeName} eq $attributeName ) { + $attribute = $attr; + } + } + } + + return @tab + unless ( defined $attribute ); + + # Then get values + # Values are only lasso::MiscTextNode type. + + for ( + my $k = 0 ; + $k < lasso::NodeList::length( $attribute->{attributeValue} ) ; + $k++ + ) + { + my $attributeValue = + lasso::NodeList::getItem( $attribute->{attributeValue}, $k ); + my $valueList = $attributeValue->{any}; + for ( my $l = 0 ; $l < lasso::NodeList::length($valueList) ; $l++ ) { + my $value = lasso::NodeList::getItem( $valueList, $l ); + push @tab, $value->{content} + if ( isa( $value, "lasso::MiscTextNode" ) ); + } + } + + return @tab; +} + +#=============================================================================== +# _loadXMLIdpFile +#=============================================================================== +# +# Load Identity Providers file. +# File is a XML file which contains providers definition. +# Only one service provider for multiple identity provider. +# +#=============================================================================== + +sub _loadXmlIdpFile { + my $this = shift; + my $file = shift; + + my $xml = XML::Simple::XMLin( $this->{laIdpsFile}, ForceArray => ['idp'] ); + $this->{laIdps} = $xml->{idp}; + + # Adding all IDPs in laIdpsFile in laServer. + # Have to be done one time -> no choice : in constructor. + + foreach ( keys %{ $this->{laIdps} } ) { + my $hash = $this->{laIdps}->{$_}; + $this->{laServer}->addProvider( + $lasso::PROVIDER_ROLE_IDP, $hash->{'metadata'}, + $hash->{'pubkey'}, $hash->{'certificate'}, + ); + } +} + +#=============================================================================== +# _soapRequest +#=============================================================================== +# +# Do soap request with only two parameters : +# - URI string ; +# - Body string ; +# Thus function return body's response message. +# +#=============================================================================== + +sub _soapRequest { + my $this = shift; + my ( $uri, $body ) = @_; + + my $soapHeaders = new HTTP::Headers( Content_Type => "text/xml" ); + my $soapRequest = new HTTP::Request( "POST", $uri, $soapHeaders, $body ); + my $soapAgent = LWP::UserAgent->new( agent => 'Mozilla/5.0 [en]' ); + my $soapResponse = $soapAgent->request($soapRequest); + + return $soapResponse->content(); +} + +#=============================================================================== +# _subProcess +#=============================================================================== +# +# Externalise functions' execution. +# +#=============================================================================== + +sub _subProcess { + my $this = shift; + my @subs = @_; + my $err = undef; + + foreach my $sub (@subs) { + if ( $this->{$sub} ) { + last if ( $err = &{ $this->{$sub} }($this) ); + } + else { + last if ( $err = $this->$sub ); + } + } + + return $err; +} + +#=============================================================================== +# _debug +#=============================================================================== +# +# Private tracing function. +# +#=============================================================================== + +sub _debug { + my $this = shift; + my $str = shift; + my ( + $package, $filename, $line, $subroutine, $hasargs, + $wantarray, $evaltext, $is_require, $hints, $bitmask + ) = caller(1); + print STDERR $subroutine . " : " . $str . "\n"; +} + +#=============================================================================== +#=============================================================================== + +################################################################################ +################################################################################ +## ## +## Documentation ## +## ## +################################################################################ +################################################################################ 1; __END__ =head1 NAME -Lemonldap::NG::Portal::AuthLA - Provide Liberty Alliance Authentication +Lemonldap::NG::Portal::AuthLA - Provide Liberty Alliance Authentication for +FederID project. + =head1 SYNOPSIS + use Lemonldap::NG::Portal::AuthLA; + my $portal = Lemonldap::NG::Portal::AuthLA->new({ + configStorage => { + type => 'DBI', + dbiChain => "dbi:mysql:...", + dbiUser => "lemonldap", + dbiPassword => "password", + dbiTable => "lmConfig", + } , + + # Liberty Parameters + laSp => { + certificate => '/path/to/public/key.pem' , + metadata => '/path/to/metadata.xml' , + privkey => '/path/to/private/key.pem' , + secretkey => '/path/to/private/key.pem' , + } , + laIdpsFile => '/path/to/idps/file.xml' , + laStorage => 'Apache::Session::File', + laStorageOptions => { + Directory => '/path/to/session/directory' , + LockDirectory => '/path/to/lockedsession/directory' , + } , + laDebug => 1 , + laLdapLoginAttribute => 'uid' , + + # Parameters that permit to access lemonldap::NG::Handler local cache + localStorage => 'Cache::FileCache' , + localStorageOptions => {} , + }); + + if( $portal->process() ) { + # Print protected URLs + print $portal->header ; + print " $_
" + foreach ($portal->getProtectedURLs) ; + + } else { + print $portal->header ; + print '...' ; + + # Print simple template + print 'Simple Authentication
' ; + print '' ; + print 'Login :' ; + if ($portal->param('user')) { + print '' ; + } else { + print '' ; + } + print 'Password : ' ; + + # Retrieve IDP list. + my @idps = () ; + foreach ($portal->getIdpIDs) { + my %row_data ; + $row_data{IDPNAME} = $_ ; + push (@idps, \%row_data) ; + } + @idps = sort {$a cmp $b} @idps ; + + # Print SSO template + print 'SSO Authentication
' ; + print '' ; + print '' ; + } + =head1 DESCRIPTION +Lemonldap::NG::Portal::AuthLA is the base module for building Lemonldap::NG +compatible portals using a authentication mechanism based on Liberty Alliance. +You have to use by inheritance. + =head1 SEE ALSO L, L, @@ -180,6 +1438,8 @@ http://wiki.lemonldap.objectweb.org/xwiki/bin/view/NG/Presentation =head1 AUTHOR Clement Oudot, Ecoudot@linagora.comE +Mikaël Ates, Emikael.ates@univ-st-etienne.frE +Thomas Chemineau, Etchemineau@linagora.comE =head1 BUG REPORT @@ -193,10 +1453,11 @@ L =head1 COPYRIGHT AND LICENSE -Copyright (C) 2007 by Clement Oudot, Ecoudot@linagora.comE +Copyright (C) 2007 by FederID Consortium, Email@FederIDE This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.4 or, at your option, any later version of Perl 5 you may have available. =cut +