lemonldap-ng/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthSAML.pm

302 lines
8.3 KiB
Perl
Raw Normal View History

2009-04-07 22:38:24 +02:00
## @file
2010-02-04 13:30:18 +01:00
# SAML Service Provider - Authentication
2009-04-07 22:38:24 +02:00
## @class
2010-02-04 13:30:18 +01:00
# SAML Service Provider - Authentication
2009-04-07 22:38:24 +02:00
package Lemonldap::NG::Portal::AuthSAML;
use strict;
use Lemonldap::NG::Portal::Simple;
2010-01-29 11:44:56 +01:00
use Lemonldap::NG::Portal::_SAML; #inherits
use Lemonldap::NG::Common::Conf::SAML::Metadata;
2009-04-07 22:38:24 +02:00
our $VERSION = '0.1';
2009-04-07 22:38:24 +02:00
## @apmethod int authInit()
2010-01-29 18:33:35 +01:00
# Load Lasso and metadata
2009-04-07 22:38:24 +02:00
# @return Lemonldap::NG::Portal error code
sub authInit {
my $self = shift;
2010-01-29 11:44:56 +01:00
# Load Lasso
return PE_ERROR unless $self->loadLasso();
2010-01-29 18:33:35 +01:00
# Activate SOAP
$self->{Soap} = 1;
2010-02-05 17:14:05 +01:00
# Check presence of private key in configuration
unless ( $self->{samlServicePrivateKey} ) {
$self->lmLog( "SAML private key not found in configuration", 'error' );
2010-02-04 13:30:18 +01:00
return PE_ERROR;
}
2010-02-01 18:07:40 +01:00
# Get metadata from configuration
2010-02-04 13:30:18 +01:00
$self->lmLog( "Get Metadata for this service", 'debug' );
my $service_metadata = Lemonldap::NG::Common::Conf::SAML::Metadata->new();
2010-02-01 18:07:40 +01:00
2010-02-04 13:30:18 +01:00
# Create Lasso server with service metadata
my $server = $self->createServer(
2010-02-05 17:14:05 +01:00
$service_metadata->serviceToXML(
$ENV{DOCUMENT_ROOT} . "/skins/common/saml2-metadata.tpl", $self
),
2010-02-04 13:30:18 +01:00
$self->{samlServicePrivateKey},
);
2010-02-01 18:07:40 +01:00
2010-02-04 13:30:18 +01:00
unless ($server) {
$self->lmLog( 'Unable to create Lasso server', 'error' );
2010-02-01 18:07:40 +01:00
return PE_ERROR;
}
2010-02-04 13:30:18 +01:00
$self->lmLog( "Service created", 'debug' );
# Check presence of at least one identity provider in configuration
unless ( $self->{samlIDPMetaData}
and keys %{ $self->{samlIDPMetaData} } )
{
$self->lmLog( "No IDP found in configuration", 'error' );
return PE_ERROR;
}
# Load identity provider metadata
# IDP are listed in $self->{samlIDPMetaData}
# Each key is the IDP name and value is the metadata
# Build IDP list for later use in extractFormInfo
foreach ( keys %{ $self->{samlIDPMetaData} } ) {
$self->lmLog( "Get Metadata for IDP $_", 'debug' );
# Get metadata from configuration
my $idp_metadata = Lemonldap::NG::Common::Conf::SAML::Metadata->new();
unless (
$idp_metadata->initializeFromConfHash(
$self->{samlIDPMetaData}->{$_}
)
)
{
$self->lmLog( "Fail to read IDP $_ Metadata from configuration",
'error' );
return PE_ERROR;
}
# Add this IDP to Lasso::Server
my $result = $self->addIDP( $server, $idp_metadata->toXML() );
unless ($result) {
$self->lmLog( "Fail to use IDP $_ Metadata", 'error' );
return PE_ERROR;
}
# Store IDP entityID and Organization Name
my $entityID = $idp_metadata->{entityID};
my $name = $self->getOrganizationName( $server, $entityID )
|| ucfirst($_);
2010-02-04 13:30:18 +01:00
$self->{_idpList}->{$_}->{entityID} = $entityID;
$self->{_idpList}->{$_}->{name} = $name;
$self->lmLog( "IDP $_ added", 'debug' );
}
2010-01-29 11:44:56 +01:00
2010-02-04 17:02:02 +01:00
# Store Lasso::Server object
$self->{_lassoServer} = $server;
2010-01-29 11:44:56 +01:00
PE_OK;
2009-04-07 22:38:24 +02:00
}
## @apmethod int extractFormInfo()
2010-02-04 13:30:18 +01:00
# Check authentication statement or create authentication request
2009-04-07 22:38:24 +02:00
# @return Lemonldap::NG::Portal error code
sub extractFormInfo {
2010-02-04 13:30:18 +01:00
my $self = shift;
2010-02-04 17:02:02 +01:00
my $server = $self->{_lassoServer};
2010-02-04 13:30:18 +01:00
my $idp;
# 1. Get authentication statement
# if ( authnStatement ) ...
# TODO - check authstatement
# else
# 2. IDP resolution
# Get IDP resolution cookie
my %cookies = fetch CGI::Cookie;
my $idp_cookie = $cookies{ $self->{samlIdPResolveCookie} };
if ($idp_cookie) {
$idp = $idp_cookie->value;
$self->lmLog( "IDP $idp found in IDP resolution cookie", 'debug' );
}
# If no IDP resolve cookie, find another way to get it
# Case 1: IDP was choosen from portal IDP list
$idp ||= $self->param("idp");
2010-02-04 17:02:02 +01:00
# TODO - other case (IP resolution, etc.)
2010-02-04 13:30:18 +01:00
# Get confirmation flag
my $confirm_flag = $self->param("confirm");
# If confirmation is -1, or IDP was not resolve, let the user choose its IDP
if ( $confirm_flag == -1 or !$idp ) {
$self->lmLog( "No IDP found, redirecting user to IDP list", 'debug' );
# IDP list
my $html = "<h3>";
$html .=
&Lemonldap::NG::Portal::_i18n::msg( PM_SAML_IDPSELECT,
$ENV{HTTP_ACCEPT_LANGUAGE} );
$html .= "</h3>\n";
$html .= "<table>\n";
2010-02-04 13:30:18 +01:00
foreach ( keys %{ $self->{_idpList} } ) {
$html .= "<tr><td>";
2010-02-04 13:30:18 +01:00
$html .=
"<input type=\"radio\" name=\"idp\" value=\""
. $self->{_idpList}->{$_}->{entityID}
. "\" />\n";
$html .= "</td><td>";
2010-02-04 13:30:18 +01:00
$html .= $self->{_idpList}->{$_}->{name};
$html .= "</td></tr>";
2010-02-04 13:30:18 +01:00
}
$html .=
"<tr><td><input type=\"checkbox\" name=\"cookie_type\" value=\"1\"></td>";
$html .= "<td>";
2010-02-04 13:30:18 +01:00
$html .=
&Lemonldap::NG::Portal::_i18n::msg( PM_REMEMBERCHOICE,
$ENV{HTTP_ACCEPT_LANGUAGE} );
$html .= "</td></tr>\n";
$html .= "</table>\n";
# Script to autoselect first choice
$html .=
"<script>\$('[type=radio]:first').attr('checked','checked');</script>\n";
2010-02-04 13:30:18 +01:00
$self->info($html);
# Delete existing IDP resolution cookie
push @{ $self->{cookie} },
$self->cookie(
-name => $self->{samlIdPResolveCookie},
-value => 0,
-domain => $self->{domain},
-path => "/",
-secure => 0,
-expires => '-1d',
);
return PE_CONFIRM;
}
# If IDP is found but not confirmed, let the user confirm it
if ( $confirm_flag != 1 ) {
$self->lmLog( "IDP $idp selected, need user confirmation", 'debug' );
# Choosen IDP
my $html = "<h3>";
$html .=
&Lemonldap::NG::Portal::_i18n::msg( PM_SAML_IDPCHOOSEN,
$ENV{HTTP_ACCEPT_LANGUAGE} );
$html .= "</h3>\n";
$html .= "<h4>$idp</h4>\n";
2010-02-04 13:30:18 +01:00
$html .= "<input type=\"hidden\" name=\"idp\" value=\"$idp\" />\n";
$self->info($html);
return PE_CONFIRM;
}
# Here confirmation is OK (confirm_flag == 1), store choosen IDP in cookie
unless ( $idp_cookie and ( $idp eq $idp_cookie->value ) ) {
$self->lmLog( "Build cookie to remember $idp as IDP choice", 'debug' );
# User can choose temporary (0) or persistent cookie (1)
my $cookie_type = $self->param("cookie_type") || "0";
push @{ $self->{cookie} },
$self->cookie(
-name => $self->{samlIdPResolveCookie},
-value => $idp,
-domain => $self->{domain},
-path => "/",
-secure => $self->{securedCookie},
-httponly => $self->{httpOnly},
-expires => $cookie_type ? "+365d" : "",
);
}
# 3. Build authentication request
2010-02-04 17:02:02 +01:00
my $login = $self->createAuthnRequest( $server, $idp );
unless ($login) {
$self->lmLog( "Could not create authentication request on $idp",
'error' );
return PE_ERROR;
}
$self->lmLog( "Authentication request created", 'debug' );
2010-02-04 13:30:18 +01:00
2009-04-07 22:38:24 +02:00
PE_OK;
}
## @apmethod int setAuthSessionInfo()
# TODO
# @return Lemonldap::NG::Portal error code
sub setAuthSessionInfo {
PE_OK;
}
## @apmethod int authenticate()
# Does nothing here
# @return PE_OK
sub authenticate {
PE_OK;
}
## @apmethod void authLogout()
# TODO
sub authLogout {
}
2009-04-08 18:31:13 +02:00
## @apmethod array SAMLIssuerLinks()
# TODO
# @return 2 arrays: HTTP links and SAML issuer names
sub SAMLIssuerLinks {
}
2009-04-07 22:38:24 +02:00
1;
__END__
=head1 NAME
=encoding utf8
2010-02-04 13:30:18 +01:00
Lemonldap::NG::Portal::AuthSAML - SAML Authentication backend
2009-04-07 22:38:24 +02:00
=head1 SYNOPSIS
use Lemonldap::NG::Portal::AuthSAML;
=head1 DESCRIPTION
2010-02-04 13:30:18 +01:00
Use SAML to authenticate users
2009-04-07 22:38:24 +02:00
=head1 SEE ALSO
2010-02-04 13:30:18 +01:00
L<Lemonldap::NG::Portal>, L<Lemonldap::NG::Portal::UserDBSAML>, L<Lemonldap::NG::Portal::_SAML>
2009-04-07 22:38:24 +02:00
=head1 AUTHOR
2010-02-04 13:30:18 +01:00
Xavier Guimard, E<lt>x.guimard@free.frE<gt>, Clement Oudot, E<lt>coudot@linagora.comE<gt>
2009-04-07 22:38:24 +02:00
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2009 by Xavier Guimard
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
=cut