SAML in progress (#595)

This commit is contained in:
Xavier Guimard 2016-11-22 20:55:10 +00:00
parent b1f2ac6a73
commit fb741f9bea
7 changed files with 88 additions and 87 deletions

View File

@ -361,6 +361,7 @@ t/90-translations.t
t/99-pod.t t/99-pod.t
t/lmConf-1.js t/lmConf-1.js
t/sessions/lock/.exists t/sessions/lock/.exists
t/sessions/saml/lock/.exists
t/sessions2/6e30af4ffa5689b3e49a104d1b160d316db2b2161a0f45776994eed19dbdc101 t/sessions2/6e30af4ffa5689b3e49a104d1b160d316db2b2161a0f45776994eed19dbdc101
t/sessions2/lock/Apache-Session-6e30af4ffa5689b3e49a104d1b160d316db2b2161a0f45776994eed19dbdc101.lock t/sessions2/lock/Apache-Session-6e30af4ffa5689b3e49a104d1b160d316db2b2161a0f45776994eed19dbdc101.lock
t/test-lib.pm t/test-lib.pm

View File

@ -60,55 +60,52 @@ sub display {
} }
# 1. Good authentication # 1. Good authentication
# 1.1 Image mode
if ( $req->{error} == PE_IMG_OK || $req->{error} == PE_IMG_NOK ) {
$self->lmLog( 'Request for file', 'debug' );
return staticFile( "common/"
. ( $req->{error} == PE_IMG_OK ? 'ok.png' : 'warning.png' ) );
}
# 1.2 Case : there is a message to display
elsif ( my $info = $req->info() ) {
$skinfile = 'info';
%templateParams = (
AUTH_ERROR_TYPE => $req->error_type,
MSG => $info,
URL => $req->{urldc},
HIDDEN_INPUTS => $self->buildHiddenForm(),
ACTIVE_TIMER => $self->conf->{activeTimer},
FORM_METHOD => $self->conf->{infoFormMethod},
);
}
# 1.3 Redirection
elsif ( $req->{error} == PE_REDIRECT ) {
$skinfile = "redirect";
%templateParams = (
URL => $req->{urldc},
HIDDEN_INPUTS => $self->buildHiddenForm($req),
FORM_METHOD => $req->datas->{redirectFormMethod} || 'get',
);
}
# 1.4 Case : display menu
elsif ( $req->error == PE_OK ) { elsif ( $req->error == PE_OK ) {
# 1.1 Image mode $skinfile = 'menu';
if ( $req->{error} == PE_IMG_OK || $req->{error} == PE_IMG_NOK ) {
$self->lmLog( 'Request for file', 'debug' );
return staticFile( "common/"
. ( $req->{error} == PE_IMG_OK ? 'ok.png' : 'warning.png' ) );
}
# 1.2 Case : there is a message to display #utf8::decode($auth_user);
elsif ( my $info = $req->info() ) {
$skinfile = 'info';
%templateParams = (
AUTH_ERROR_TYPE => $req->error_type,
MSG => $info,
URL => $req->{urldc},
HIDDEN_INPUTS => $self->buildHiddenForm(),
ACTIVE_TIMER => $self->conf->{activeTimer},
FORM_METHOD => $self->conf->{infoFormMethod},
);
}
# 1.3 Redirection %templateParams = (
elsif ( $req->{error} == PE_REDIRECT ) { AUTH_USER => $req->{sessionInfo}->{ $self->conf->{portalUserAttr} },
$skinfile = "redirect"; NEWWINDOW => $self->conf->{portalOpenLinkInNewWindow},
%templateParams = ( LOGOUT_URL => $self->conf->{portal} . "?logout=1",
URL => $req->{urldc}, APPSLIST_ORDER => $req->{sessionInfo}->{'appsListOrder'},
HIDDEN_INPUTS => $self->buildHiddenForm(), PING => $self->conf->{portalPingInterval},
FORM_METHOD => $req->datas->{redirectFormMethod} || 'get', $self->menu->params($req),
); );
}
# 1.4 Case : display menu
else {
$skinfile = 'menu';
#utf8::decode($auth_user);
%templateParams = (
AUTH_USER =>
$req->{sessionInfo}->{ $self->conf->{portalUserAttr} },
NEWWINDOW => $self->conf->{portalOpenLinkInNewWindow},
LOGOUT_URL => $self->conf->{portal} . "?logout=1",
APPSLIST_ORDER => $req->{sessionInfo}->{'appsListOrder'},
PING => $self->conf->{portalPingInterval},
$self->menu->params($req),
);
}
} }
# 2. Authentication not complete # 2. Authentication not complete
@ -120,7 +117,7 @@ sub display {
%templateParams = ( %templateParams = (
AUTH_ERROR_TYPE => $req->error_type, AUTH_ERROR_TYPE => $req->error_type,
NOTIFICATION => $notif, NOTIFICATION => $notif,
HIDDEN_INPUTS => $self->buildHiddenForm(), HIDDEN_INPUTS => $self->buildHiddenForm($req),
AUTH_URL => $req->{datas}->{_url}, AUTH_URL => $req->{datas}->{_url},
CHOICE_PARAM => $self->conf->{authChoiceParam}, CHOICE_PARAM => $self->conf->{authChoiceParam},
CHOICE_VALUE => $req->{_authChoice}, CHOICE_VALUE => $req->{_authChoice},
@ -136,7 +133,7 @@ sub display {
AUTH_ERROR_TYPE => $req->error_type, AUTH_ERROR_TYPE => $req->error_type,
AUTH_URL => $req->{datas}->{_url}, AUTH_URL => $req->{datas}->{_url},
MSG => $req->info, MSG => $req->info,
HIDDEN_INPUTS => $self->buildHiddenForm(), HIDDEN_INPUTS => $self->buildHiddenForm($req),
ACTIVE_TIMER => $self->conf->{activeTimer}, ACTIVE_TIMER => $self->conf->{activeTimer},
FORM_METHOD => $self->conf->{confirmFormMethod}, FORM_METHOD => $self->conf->{confirmFormMethod},
CHOICE_PARAM => $self->conf->{authChoiceParam}, CHOICE_PARAM => $self->conf->{authChoiceParam},
@ -158,7 +155,7 @@ sub display {
AUTH_ERROR_TYPE => $req->error_type, AUTH_ERROR_TYPE => $req->error_type,
MSG => $info, MSG => $info,
URL => $req->{urldc}, URL => $req->{urldc},
HIDDEN_INPUTS => $self->buildHiddenForm(), HIDDEN_INPUTS => $self->buildHiddenForm($req),
ACTIVE_TIMER => $self->conf->{activeTimer}, ACTIVE_TIMER => $self->conf->{activeTimer},
FORM_METHOD => $self->conf->{infoFormMethod}, FORM_METHOD => $self->conf->{infoFormMethod},
CHOICE_PARAM => $self->conf->{authChoiceParam}, CHOICE_PARAM => $self->conf->{authChoiceParam},
@ -201,7 +198,7 @@ sub display {
DISPLAY_REGISTER => $self->conf->{portalDisplayRegister}, DISPLAY_REGISTER => $self->conf->{portalDisplayRegister},
MAIL_URL => $self->conf->{mailUrl}, MAIL_URL => $self->conf->{mailUrl},
REGISTER_URL => $self->conf->{registerUrl}, REGISTER_URL => $self->conf->{registerUrl},
HIDDEN_INPUTS => $self->buildHiddenForm(), HIDDEN_INPUTS => $self->buildHiddenForm($req),
); );
# Display captcha if it's enabled # Display captcha if it's enabled
@ -367,16 +364,15 @@ sub staticFile {
} }
sub buildHiddenForm { sub buildHiddenForm {
my ($self) = @_; my ( $self, $req ) = @_;
my @keys = keys %{ $self->conf->{portalHiddenFormValues} }; my @keys = keys %{ $req->{portalHiddenFormValues} };
my $val = ''; my $val = '';
foreach (@keys) { foreach (@keys) {
# Check XSS attacks # Check XSS attacks
next next
if $self->checkXSSAttack( $_, if $self->checkXSSAttack( $_, $req->{portalHiddenFormValues}->{$_} );
$self->conf->{portalHiddenFormValues}->{$_} );
# Build hidden input HTML code # Build hidden input HTML code
$val .= qq{<input type="hidden" name="$_" id="$_" value="} $val .= qq{<input type="hidden" name="$_" id="$_" value="}

View File

@ -153,7 +153,16 @@ sub do {
} }
} }
else { else {
if ( $err and $err != PE_LOGOUT_OK and $err != PE_REDIRECT ) { if (
$err
and $err != PE_LOGOUT_OK
and (
$err != PE_REDIRECT
or ( $err == PE_REDIRECT
and $req->datas->{redirectFormMethod} eq 'post' )
)
)
{
my ( $tpl, $prms ) = $self->display($req); my ( $tpl, $prms ) = $self->display($req);
return $self->sendHtml( $req, $tpl, params => $prms ); return $self->sendHtml( $req, $tpl, params => $prms );
} }
@ -488,7 +497,7 @@ sub autoPost {
return PE_INFO; return PE_INFO;
} }
$self->{redirectFormMethod} = "post"; $req->datas->{redirectFormMethod} = "post";
return PE_REDIRECT; return PE_REDIRECT;
} }
@ -563,26 +572,4 @@ sub clearHiddenFormValue {
return; return;
} }
##@method public string buildHiddenForm()
# Return an HTML representation of hidden values.
# @return HTML code
sub buildHiddenForm {
my ( $self, $req ) = @_;
my @keys = keys %{ $req->{portalHiddenFormValues} // {} };
my $val = '';
foreach (@keys) {
# Check XSS attacks
next
if $self->checkXSSAttack( $_, $req->{portalHiddenFormValues}->{$_} );
# Build hidden input HTML code
$val .= qq{<input type="hidden" name="$_" id="$_" value="}
. $req->{portalHiddenFormValues}->{$_} . '" />';
}
return $val;
}
1; 1;

View File

@ -4,7 +4,7 @@ use IO::String;
require 't/test-lib.pm'; require 't/test-lib.pm';
my $maintests = 7; my $maintests = 9;
my $debug = 'debug'; my $debug = 'debug';
my $res; my $res;
my %handlerOR = ( issuer => [], sp => [] ); my %handlerOR = ( issuer => [], sp => [] );
@ -40,7 +40,7 @@ SKIP: {
defined( $cookies->{lemonldapidp} ) defined( $cookies->{lemonldapidp} )
and $cookies->{lemonldapidp} == 0 and $cookies->{lemonldapidp} == 0
), ),
'IDP cookie defined' 'IDP cookie deleted'
) )
or explain( $res->[1], or explain( $res->[1],
'Set-Cookie => lemonldapidp=0; domain=.sp.com; path=/; expires=-1d' ); 'Set-Cookie => lemonldapidp=0; domain=.sp.com; path=/; expires=-1d' );
@ -63,13 +63,26 @@ SKIP: {
"confirm=$confirm&idp=https://auth.idp.com/saml/metadata"), "confirm=$confirm&idp=https://auth.idp.com/saml/metadata"),
accept => 'text/html', accept => 'text/html',
length => length($confirm) + 47, length => length($confirm) + 47,
cookie => 'lemonldapidp=0',
), ),
'Select IDP' 'Select IDP'
); );
ok( $res->[0] == 200, 'Return code is 200' );
$cookies = $sp->getCookies($res);
ok(
(
defined( $cookies->{lemonldapidp} )
and $cookies->{lemonldapidp} eq 'https://auth.idp.com/saml/metadata'
),
'IDP cookie defined'
)
or explain(
$res->[1],
'Set-Cookie => lemonldapidp=https://auth.idp.com/saml/metadata; domain=.sp.com; path=/'
);
} }
count($maintests); count($maintests);
clean_sessions();
done_testing( count() ); done_testing( count() );
sub switch { sub switch {
@ -346,7 +359,7 @@ sub sp {
samlIDPMetaDataOptions => { samlIDPMetaDataOptions => {
idp => { idp => {
samlIDPMetaDataOptionsEncryptionMode => 'none', samlIDPMetaDataOptionsEncryptionMode => 'none',
samlIDPMetaDataOptionsSSOBinding => 'POST', samlIDPMetaDataOptionsSSOBinding => 'POST',
} }
}, },
samlIDPMetaDataXML => { samlIDPMetaDataXML => {

View File

@ -56,8 +56,8 @@
"portal": "http://auth.example.com/", "portal": "http://auth.example.com/",
"samlStorage": "Apache::Session::File", "samlStorage": "Apache::Session::File",
"samlStorageOptions": { "samlStorageOptions": {
"Directory": "t/sessions", "Directory": "t/sessions/saml",
"LockDirectory": "t/sessions/lock", "LockDirectory": "t/sessions/saml/lock",
"generateModule": "Lemonldap::NG::Common::Apache::Session::Generate::SHA256" "generateModule": "Lemonldap::NG::Common::Apache::Session::Generate::SHA256"
}, },
"reloadUrls": {}, "reloadUrls": {},

View File

@ -28,9 +28,13 @@ sub clean_sessions {
foreach ( grep { /^[^\.]/ } readdir(D) ) { foreach ( grep { /^[^\.]/ } readdir(D) ) {
unlink "t/sessions/$_", "t/sessions/lock/Apache-Session-$_.lock"; unlink "t/sessions/$_", "t/sessions/lock/Apache-Session-$_.lock";
} }
opendir D, 't/sessions/lock' or die $!; foreach my $dir (qw(t/sessions/lock t/sessions/saml/lock t/sessions/saml)) {
foreach ( grep { /^[^\.]/ } readdir(D) ) { if ( -d $dir ) {
unlink "t/sessions/lock/$_"; opendir D, $dir or die $!;
foreach ( grep { /^[^\.]/ } readdir(D) ) {
unlink "$dir/$_";
}
}
} }
} }