Commit 2c584cf7 authored by Clément OUDOT's avatar Clément OUDOT
Browse files

SAML:

* Use authForce method to know if authentication should be forced
* Use a common method to store replay protection data
* Use _utime in relaystate state
* Let Lasso choose the defaut transport and binding for requests
parent d2c015c5
......@@ -118,7 +118,6 @@ sub extractFormInfo {
my $response;
my $artifact;
my $relaystate;
my %h;
# 1. Get HTTP request informations to know
# if we are receving SAML request or response
......@@ -807,24 +806,10 @@ sub extractFormInfo {
$self->lmLog( "Authentication request created", 'debug' );
# Keep assertion ID in memory to prevent replay
my $assertion_id = $login->request()->ID;
eval {
tie %h, $self->{globalStorage}, undef, $self->{globalStorageOptions};
};
if ( $@ or !$assertion_id ) {
unless ( $self->storeReplayProtection( $login->request()->ID ) ) {
$self->lmLog( "Unable to store assertion ID", 'error' );
return PE_ERROR;
}
$h{type} = 'assertion'; # Session type
$h{_utime} = time(); # Creation time
$h{ID} = $assertion_id;
my $assertion_session_id = $h{_session_id};
untie %h;
$self->lmLog(
"Keep assertion ID $assertion_id in assertion session $assertion_session_id",
'debug'
);
# Send SSO request depending on request method
# HTTP-REDIRECT
......@@ -953,7 +938,6 @@ sub authenticate {
# @return nothing
sub authLogout {
my $self = shift;
my %h;
my $method;
# Get Lasso Server
......@@ -985,24 +969,10 @@ sub authLogout {
$self->lmLog( "Logout request created", 'debug' );
# Keep request ID in memory to prevent replay
my $logout_request_id = $logout->request()->ID;
eval {
tie %h, $self->{globalStorage}, undef, $self->{globalStorageOptions};
};
if ( $@ or !$logout_request_id ) {
unless ( $self->storeReplayProtection( $logout->request()->ID ) ) {
$self->lmLog( "Unable to store Logout request ID", 'error' );
return PE_ERROR;
}
$h{type} = 'assertion'; # Session type
$h{_utime} = time(); # Creation time
$h{ID} = $logout_request_id;
my $logout_request_session_id = $h{_session_id};
untie %h;
$self->lmLog(
"Keep Logout request ID $logout_request_id in assertion session $logout_request_session_id",
'debug'
);
# Send request depending on request method
# HTTP-REDIRECT
......@@ -1069,6 +1039,37 @@ sub authLogout {
}
## @apmethod boolean authForce()
# Check if authentication should be forced
# @return nothing
sub authForce {
my $self = shift;
my $url = $self->url();
my $saml_acs_art_url = $self->getMetaDataURL(
"samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact");
my $saml_acs_post_url = $self->getMetaDataURL(
"samlSPSSODescriptorAssertionConsumerServiceHTTPPost");
my $saml_acs_get_url = $self->getMetaDataURL(
"samlSPSSODescriptorAssertionConsumerServiceHTTPRedirect");
my $saml_slo_soap_url =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceSOAP", 1 );
my $saml_slo_soap_url_ret =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceSOAP", 2 );
my $saml_slo_get_url =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceHTTP", 1 );
my $saml_slo_get_url_ret =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceHTTP", 2 );
return 1
if ( $url =~
/^($saml_acs_art_url|$saml_acs_post_url|$saml_acs_get_url|$saml_slo_soap_url|$saml_slo_soap_url_ret|$saml_slo_get_url|$saml_slo_get_url_ret)$/
);
return 0;
}
1;
__END__
......
......@@ -850,7 +850,8 @@ sub controlExistingSession {
return $self->{error} if $self->{error};
# Redirect or Post if asked by authLogout
$self->_subProcess(qw(autoRedirect)) if ( $self->{urldc} );
$self->_subProcess(qw(autoRedirect))
if ( $self->{urldc} and $self->{urldc} ne $self->{portal} );
$self->_subProcess(qw(autoPost)) if ( $self->{postUrl} );
# Display logout message
......@@ -890,9 +891,18 @@ sub controlExistingSession {
#@return Lemonldap::NG::Portal constant
sub existingSession {
my $self = shift;
my $forceAuthn;
# Check portalForceAuthn parameter
if ( $self->{portalForceAuthn} ) {
# and authForce method
eval { $forceAuthn = $self->authForce(); };
if ($@) {
$self->lmLog( "Error when calling authForce: $@", 'debug' );
}
$forceAuthn = 1 if ( $self->{portalForceAuthn} );
if ($forceAuthn) {
my $referer = $self->referer();
my $id = $self->{id};
......
......@@ -228,10 +228,6 @@ sub createAuthnRequest {
return;
}
# Default method: HTTP REDIRECT
$method = Lasso::Constants::HTTP_METHOD_REDIRECT unless defined $method;
$self->lmLog( "Use HTTP method $method", 'debug' );
# Init authentication request
unless ( $self->initAuthnRequest( $login, $idp, $method ) ) {
$self->lmLog( "Could not initiate authentication request on $idp",
......@@ -254,8 +250,6 @@ sub createAuthnRequest {
$request->NameIDPolicy()
->Format(Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT);
$request->NameIDPolicy()->AllowCreate(1);
$request
->ProtocolBinding(Lasso::Constants::SAML2_METADATA_BINDING_ARTIFACT);
# Build authentication request
unless ( $self->buildAuthnRequestMsg($login) ) {
......@@ -291,20 +285,6 @@ sub createLogin {
return $login;
}
## @method int getHttpMethod(Lasso::Server server, string idp)
# Find a compatible HTTP method
# @param Lasso::Server server
# @param string entityID
# @return int HTTP method
sub getHttpMethod {
my ( $self, $server, $idp ) = splice @_;
# TODO
# By default, use HTTP REDIRECT
return Lasso::Constants::HTTP_METHOD_REDIRECT;
}
## @method boolean initAuthnRequest(Lasso::Login login, string idp, int method)
# Init authentication request
# @param Lasso::Login login
......@@ -440,6 +420,9 @@ sub storeRelayState {
# Session type
$h{_type} = "relaystate";
# UNIX time
$h{_utime} = time();
# Store infos in relaystate session
foreach ( keys %$infos ) {
$h{$_} = $infos->{$_};
......@@ -478,7 +461,7 @@ sub extractRelayState {
# Push values in $self
foreach ( keys %h ) {
next if $_ =~ /(type|_session_id)/;
next if $_ =~ /(type|_session_id|_utime)/;
$self->{$_} = $h{$_};
}
......@@ -582,12 +565,9 @@ sub createLogoutRequest {
# Create Lasso Logout
my $logout = $self->createLogout($server);
# Default method: SOAP
$method = Lasso::Constants::HTTP_METHOD_SOAP unless defined $method;
$self->lmLog( "Use HTTP method $method", 'debug' );
unless ( $self->setSessionFromDump( $logout, $session_dump ) ) {
$self->lmLog( "Could not fill Lasso::Logout with session dump", 'error' );
$self->lmLog( "Could not fill Lasso::Logout with session dump",
'error' );
return;
}
......@@ -728,6 +708,37 @@ sub buildLogoutResponseMsg {
return $self->checkLassoError($@);
}
## @method boolean storeReplayProtection(string samlID)
# Store ID of an SAML message in Replay Protection base
# @param samlID ID of SAML message
# @return result
sub storeReplayProtection {
my ( $self, $samlID ) = splice @_;
my %h;
eval {
tie %h, $self->{globalStorage}, undef, $self->{globalStorageOptions};
};
if ( $@ or !$samlID ) {
$self->lmLog( "Unable to create replay protection session", 'error' );
return 0;
}
$h{type} = 'assertion'; # Session type
$h{_utime} = time(); # Creation time
$h{ID} = $samlID;
my $session_id = $h{_session_id};
untie %h;
$self->lmLog(
"Keep Logout request ID $samlID in assertion session $session_id",
'debug' );
return 1;
}
## @method boolean replayProtection(string samlID)
# Check if SAML message do not correspond to a previously responded message
# @param samlID ID of initial SAML message
......@@ -780,7 +791,6 @@ sub replayProtection {
}
return 0;
}
## @method string resolveArtifact(Lasso::Profile profile, string artifact, int method)
......@@ -928,10 +938,6 @@ Create authentication request for selected IDP
Create Lasso::Login object
=head2 getHttpMethod
Find a compatible HTTP method
=head2 initAuthnRequest
Init authentication request
......@@ -1021,6 +1027,10 @@ Validate logout request
Build logout response msg
=head2 storeReplayProtection
Store ID of an SAML message in Replay Protection base
=head2 replayProtection
Check if SAML message do not correspond to a previously responded message
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment