Building Auth/CAS (#595)
This commit is contained in:
parent
c7da9254a2
commit
f6ea9b5df3
|
@ -32,6 +32,7 @@ lib/Lemonldap/NG/Portal/Auth/AD.pm
|
|||
lib/Lemonldap/NG/Portal/Auth/Apache.pm
|
||||
lib/Lemonldap/NG/Portal/Auth/Base.pm
|
||||
lib/Lemonldap/NG/Portal/Auth/BrowserID.pm
|
||||
lib/Lemonldap/NG/Portal/Auth/CAS.pm
|
||||
lib/Lemonldap/NG/Portal/Auth/Choice.pm
|
||||
lib/Lemonldap/NG/Portal/Auth/DBI.pm
|
||||
lib/Lemonldap/NG/Portal/Auth/Demo.pm
|
||||
|
|
284
lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/CAS.pm
Normal file
284
lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/CAS.pm
Normal file
|
@ -0,0 +1,284 @@
|
|||
package Lemonldap::NG::Portal::Auth::SAML;
|
||||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use URI::Escape;
|
||||
use Lemonldap::NG::Portal::Main::Constants qw(
|
||||
PE_ERROR
|
||||
PE_OK
|
||||
PE_REDIRECT
|
||||
PE_SENDRESPONSE
|
||||
);
|
||||
|
||||
our $VERSION = '2.0.0';
|
||||
|
||||
extends 'Lemonldap::NG::Portal::Auth::Base', 'Lemonldap::NG::Portal::Lib::SAML';
|
||||
|
||||
# PROPERTIES
|
||||
|
||||
# Act as a proxy if proxied services configured
|
||||
has proxy => (
|
||||
is => 'rw',
|
||||
builder => sub {
|
||||
return
|
||||
ref( $_[0]->conf->{CASproxiedServices} ) eq 'HASH'
|
||||
? ( %{ $_[0]->conf->{CASproxiedServices} } ? 1 : 0 )
|
||||
: 0;
|
||||
}
|
||||
);
|
||||
|
||||
has cas => ( is => 'rw' );
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
sub init {
|
||||
my ($self) = @_;
|
||||
eval { require AuthCAS };
|
||||
if ($@) {
|
||||
$self->error("Unable to load AuthCAS: $@");
|
||||
return 0;
|
||||
}
|
||||
$self->cas(
|
||||
AuthCAS->new(
|
||||
casUrl => $self->conf->{CASurl},
|
||||
CAFile => $self->conf->{CASCAFile},
|
||||
)
|
||||
);
|
||||
return ( $self->SUPER::init );
|
||||
}
|
||||
|
||||
# RUNNING METHODS
|
||||
|
||||
sub extractFormInfo {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
# Local URL
|
||||
my $local_url = $req->uri;
|
||||
|
||||
# Add request state parameters
|
||||
if ( $req->datas->{_url} ) {
|
||||
my $url_param = 'url=' . uri_escape( $req->datas->{_url} );
|
||||
$local_url .= ( $local_url =~ /\?/ ? '&' : '?' ) . $url_param;
|
||||
}
|
||||
if ( my $tmp = $req->param( $self->conf->{authChoiceParam} ) ) {
|
||||
my $url_param = $self->conf->{authChoiceParam} . '=' . uri_escape($tmp);
|
||||
$local_url .= ( $local_url =~ /\?/ ? '&' : '?' ) . $url_param;
|
||||
}
|
||||
|
||||
# Forward hidden fields
|
||||
if ( $req->{portalHiddenFormValues}
|
||||
and %{ $req->{portalHiddenFormValues} } )
|
||||
{
|
||||
|
||||
$self->lmLog( "Add hidden values to CAS redirect URL\n", 'debug' );
|
||||
|
||||
foreach ( keys %{ $req->{portalHiddenFormValues} } ) {
|
||||
$local_url .=
|
||||
( $local_url =~ /\?/ ? '&' : '?' )
|
||||
. $_ . '='
|
||||
. uri_escape( $req->{portalHiddenFormValues}->{$_} );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $self->proxy ) {
|
||||
$self->lmLog( "CAS: Proxy mode activated", 'debug' );
|
||||
my $proxy_url = $req->uri . '?casProxy=1';
|
||||
|
||||
if ( my $tmp = $req->param( $self->conf->{authChoiceParam} ) ) {
|
||||
$proxy_url .= '&' . $self->conf->{authChoiceParam} . "=$tmp";
|
||||
}
|
||||
|
||||
$self->lmLog( "CAS Proxy URL: $proxy_url", 'debug' );
|
||||
|
||||
$self->cas->proxyMode(
|
||||
pgtFile => $self->{CASpgtFile},
|
||||
pgtCallbackUrl => $proxy_url
|
||||
);
|
||||
}
|
||||
|
||||
# Catch proxy callback
|
||||
if ( $req->param('casProxy') ) {
|
||||
$self->lmLog( "CAS: Proxy callback detected", 'debug' );
|
||||
|
||||
my $pgtIou = $req->param('pgtIou');
|
||||
my $pgtId = $req->param('pgtId');
|
||||
|
||||
if ( $pgtIou and $pgtId ) {
|
||||
|
||||
# Store pgtId and pgtIou
|
||||
unless ( $self->cas->storePGT( $pgtIou, $pgtId ) ) {
|
||||
$self->lmLog( "CAS: error " . &AuthCAS::get_errors(), 'error' );
|
||||
}
|
||||
else {
|
||||
$self->lmLog( "CAS: Store pgtIou $pgtIou and pgtId $pgtId",
|
||||
'debug' );
|
||||
}
|
||||
}
|
||||
|
||||
# Exit
|
||||
$req->response( [ 200, [ 'Content-Length' => 0 ], [] ] );
|
||||
return PE_SENDRESPONSE;
|
||||
}
|
||||
|
||||
# Build login URL
|
||||
my $login_url = $self->cas->getServerLoginURL($local_url);
|
||||
$login_url .= '&renew=true' if $self->conf->{CASrenew};
|
||||
$login_url .= '&gateway=true' if $self->conf->{CASgateway};
|
||||
|
||||
# Check Service Ticket
|
||||
my $ticket = $req->param('ticket');
|
||||
|
||||
# Unless a ticket has been found, we redirect the user
|
||||
unless ($ticket) {
|
||||
$self->lmLog( "CAS: Redirect user to $login_url", 'debug' );
|
||||
$req->{urldc} = $login_url;
|
||||
$req->steps( [] );
|
||||
return PE_REDIRECT;
|
||||
}
|
||||
|
||||
$self->lmLog( "CAS: Service Ticket received: $ticket", 'debug' );
|
||||
|
||||
# Ticket found, try to validate it
|
||||
unless ( $req->{user} = $self->cas->validateST( $local_url, $ticket ) ) {
|
||||
$self->lmLog( "CAS: error " . &AuthCAS::get_errors(), 'error' );
|
||||
return PE_ERROR;
|
||||
}
|
||||
else {
|
||||
$self->lmLog( "CAS: User $req->{user} found", 'debug' );
|
||||
}
|
||||
|
||||
# Request proxy tickets for proxied services
|
||||
if ( $self->proxy ) {
|
||||
|
||||
# Check we received a PGT
|
||||
my $pgtId = $self->cas->{pgtId};
|
||||
|
||||
unless ($pgtId) {
|
||||
$self->lmLog( "CAS: Proxy mode activated, but no PGT received",
|
||||
'error' );
|
||||
return PE_ERROR;
|
||||
}
|
||||
|
||||
# Get a proxy ticket for each proxied service
|
||||
foreach ( keys %{ $self->conf->{CASproxiedServices} } ) {
|
||||
my $service = $self->conf->{CASproxiedServices}->{$_};
|
||||
my $pt = $self->cas->retrievePT($service);
|
||||
|
||||
unless ($pt) {
|
||||
$self->lmLog(
|
||||
"CAS: No proxy ticket recevied for service $service",
|
||||
'error' );
|
||||
return PE_ERROR;
|
||||
}
|
||||
|
||||
$self->lmLog( "CAS: Received proxy ticket $pt for service $service",
|
||||
'debug' );
|
||||
|
||||
# Store it in session
|
||||
$req->{sessionInfo}->{ '_casPT' . $_ } = $pt;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return PE_OK;
|
||||
}
|
||||
|
||||
sub authenticate {
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
# Set authenticationLevel.
|
||||
sub setAuthSessionInfo {
|
||||
my ( $self, $req ) = @_;
|
||||
$req->{sessionInfo}->{authenticationLevel} = $self->{CASauthnLevel};
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
sub authLogout {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
# Build CAS logout URL
|
||||
my $logout_url = $self->cas->getServerLogoutURL( $req->uri );
|
||||
|
||||
$self->lmLog( "Build CAS logout URL: $logout_url", 'debug' );
|
||||
|
||||
# Register CAS logout URL in logoutServices
|
||||
$req->datas->{logoutServices}->{CASserver} = $logout_url;
|
||||
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
sub getDisplayType {
|
||||
return "logo";
|
||||
}
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
=encoding utf8
|
||||
|
||||
Lemonldap::NG::Portal::Auth::CAS - Perl extension for building Lemonldap::NG
|
||||
compatible portals with CAS authentication.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This library just overload few methods of Lemonldap::NG::Portal::Simple to use
|
||||
CAS mechanism: we've just try to get CAS ticket.
|
||||
|
||||
See L<Lemonldap::NG::Portal::Simple> for usage and other methods.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Lemonldap::NG::Portal>, L<Lemonldap::NG::Portal::Simple>,
|
||||
L<http://lemonldap-ng.org/>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
=over
|
||||
|
||||
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=item Thomas Chemineau, E<lt>thomas.chemineau@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUG REPORT
|
||||
|
||||
Use OW2 system to report bug or ask for features:
|
||||
L<http://jira.ow2.org>
|
||||
|
||||
=head1 DOWNLOAD
|
||||
|
||||
Lemonldap::NG is available at
|
||||
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
=over
|
||||
|
||||
=item Copyright (C) 2007-2010 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=item Copyright (C) 2009-2016 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=item Copyright (C) 2009 by Thomas Chemineau, E<lt>thomas.chemineau@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see L<http://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
|
@ -140,47 +140,50 @@ sub deleteSession {
|
|||
|
||||
# TODO
|
||||
# Collect logout services and build hidden iFrames
|
||||
#if ( $self->{logoutServices} and %{ $self->{logoutServices} } ) {
|
||||
if ( $req->datas->{logoutServices} and %{ $req->datas->{logoutServices} } )
|
||||
{
|
||||
|
||||
# $self->lmLog( "Create iFrames to forward logout to services",
|
||||
# 'debug' );
|
||||
$self->lmLog( "Create iFrames to forward logout to services", 'debug' );
|
||||
|
||||
# $self->info( "<h3>" . $self->msg(PM_LOGOUT) . "</h3>" );
|
||||
$self->info('<h3 trmsg="logoutFromOtherApp"></h3>');
|
||||
|
||||
# foreach ( keys %{ $self->{logoutServices} } ) {
|
||||
# my $logoutServiceName = $_;
|
||||
# my $logoutServiceUrl =
|
||||
# $self->{logoutServices}->{$logoutServiceName};
|
||||
foreach ( keys %{ $req->datas->{logoutServices} } ) {
|
||||
my $logoutServiceName = $_;
|
||||
my $logoutServiceUrl =
|
||||
$req->datas->{logoutServices}->{$logoutServiceName};
|
||||
|
||||
# $self->lmLog(
|
||||
#"Find lo#gout service $logoutServiceName ($logoutServiceUrl)",
|
||||
$self->lmLog(
|
||||
"Find lo#gout service $logoutServiceName ($logoutServiceUrl)",
|
||||
|
||||
# 'debug'
|
||||
# );
|
||||
'debug'
|
||||
);
|
||||
|
||||
# my $iframe =
|
||||
# "<iframe src=\"$logoutServiceUrl\""
|
||||
# . " alt=\"$logoutServiceName\" marginwidth=\"0\""
|
||||
# . " marginheight=\"0\" scrolling=\"no\" style=\"border: none;display: hidden;margin: 0\""
|
||||
# . " width=\"0\" height=\"0\" frameborder=\"0\">"
|
||||
# . "</iframe>";
|
||||
my $iframe =
|
||||
"<iframe src=\"$logoutServiceUrl\""
|
||||
. " alt=\"$logoutServiceName\" marginwidth=\"0\""
|
||||
. " marginheight=\"0\" scrolling=\"no\" style=\"border: none;display: hidden;margin: 0\""
|
||||
. " width=\"0\" height=\"0\" frameborder=\"0\">"
|
||||
. "</iframe>";
|
||||
|
||||
# $self->info($iframe);
|
||||
# }
|
||||
$self->info($iframe);
|
||||
}
|
||||
|
||||
# # Redirect on logout page if no other target defined
|
||||
# if ( !$self->{urldc} and !$self->{postUrl} ) {
|
||||
# $self->{urldc} = $ENV{SCRIPT_NAME} . "?logout=1";
|
||||
# }
|
||||
#}
|
||||
# Redirect on logout page if no other target defined
|
||||
if ( !$req->urldc and !$req->postUrl ) {
|
||||
$req->urldc( $req->scriptname . "?logout=1" );
|
||||
}
|
||||
}
|
||||
|
||||
# Redirect or Post if asked by authLogout
|
||||
#return $self->_subProcess(qw(autoRedirect))
|
||||
# if ( $self->{urldc}
|
||||
# and $self->{urldc} ne $self->{portal} );
|
||||
if ( $req->urldc and $req->urldc ne $self->conf->{portal} ) {
|
||||
$req->steps( [] );
|
||||
return PE_REDIRECT;
|
||||
}
|
||||
|
||||
#return $self->_subProcess(qw(autoPost))
|
||||
# if ( $self->{postUrl} );
|
||||
if ( $req->postUrl ) {
|
||||
$req->steps( ['autoPost'] );
|
||||
return PE_OK;
|
||||
}
|
||||
|
||||
# If logout redirects to another URL, just remove next steps for the
|
||||
# request so autoRedirect will be called
|
||||
|
@ -304,7 +307,8 @@ sub setSessionInfo {
|
|||
sub setMacros {
|
||||
my ( $self, $req ) = @_;
|
||||
foreach ( sort keys %{ $self->_macros } ) {
|
||||
$req->{sessionInfo}->{$_} = $self->_macros->{$_}->( $req->sessionInfo );
|
||||
$req->{sessionInfo}->{$_} =
|
||||
$self->_macros->{$_}->( $req->sessionInfo );
|
||||
}
|
||||
PE_OK;
|
||||
}
|
||||
|
|
|
@ -92,7 +92,6 @@
|
|||
"PM12":"Redirection in progress...",
|
||||
"PM13":"Go back to service provider",
|
||||
"PM14":"The application you just logged out of has provided a link it would like you to follow",
|
||||
"PM15":"Logout from other applications...",
|
||||
"PM16":"Do you want to authenticate yourself on %s ?",
|
||||
"PM17":"Update Common Domain Cookie",
|
||||
"PM18":"Parameter %s requested for federation isn't available",
|
||||
|
@ -156,6 +155,7 @@
|
|||
"loginHistory":"Login history",
|
||||
"login":"Login",
|
||||
"logout":"Logout",
|
||||
"logoutFromOtherApp":"Logout from other applications...",
|
||||
"mail":"Mail",
|
||||
"mailSent2":"A message has been sent to your mail address.",
|
||||
"maintenanceMode":"This application is in maintenance, please try to connect later",
|
||||
|
|
|
@ -92,7 +92,6 @@
|
|||
"PM12":"Redirection en cours...",
|
||||
"PM13":"Retourner sur le fournisseur de service",
|
||||
"PM14":"Le service duquel vous arrivez a fourni un lien que vous êtes invité à suivre",
|
||||
"PM15":"Déconnexion des autres applications...",
|
||||
"PM16":"Souhaitez-vous vous identifier sur le site %s ?",
|
||||
"PM17":"Mise à jour du cookie de domaine commun",
|
||||
"PM18":"Le paramètre %s exigé pour la fédération n'est pas disponible",
|
||||
|
@ -156,6 +155,7 @@
|
|||
"loginHistory":"Historique des connexions",
|
||||
"login":"Identifiant",
|
||||
"logout":"Déconnexion",
|
||||
"logoutFromOtherApp":"Déconnexion des autres applications...",
|
||||
"mail":"Adresse mail",
|
||||
"mailSent2":"Un message a été envoyé à votre adresse mail.",
|
||||
"maintenanceMode":"Cette application est en maintenance, merci de réessayer plus tard",
|
||||
|
|
Loading…
Reference in New Issue
Block a user