Commit aba27302 authored by Yadd's avatar Yadd
Browse files

Split SLO from run [SAML] (#595)

parent a2be61bb
...@@ -26,10 +26,14 @@ our $VERSION = '2.0.0'; ...@@ -26,10 +26,14 @@ our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Auth::Base', 'Lemonldap::NG::Portal::Lib::SAML'; extends 'Lemonldap::NG::Portal::Auth::Base', 'Lemonldap::NG::Portal::Lib::SAML';
# INTERFACE
has sloAssConsumerRe => ( is => 'rw' ); has sloAssConsumerRe => ( is => 'rw' );
has sloRe => ( is => 'rw' ); has sloRe => ( is => 'rw' );
has artRe => ( is => 'rw' ); has artRe => ( is => 'rw' );
sub forAuthUser { 'handleAuthRequests' }
# INITIALIZATION # INITIALIZATION
sub init { sub init {
...@@ -707,8 +711,7 @@ sub extractFormInfo { ...@@ -707,8 +711,7 @@ sub extractFormInfo {
$req->urldc($slo_url); $req->urldc($slo_url);
$req->steps( [] ); return PE_OK;
return PE_REDIRECT;
} }
# HTTP-POST # HTTP-POST
...@@ -719,15 +722,14 @@ sub extractFormInfo { ...@@ -719,15 +722,14 @@ sub extractFormInfo {
my $slo_body = $logout->msg_body; my $slo_body = $logout->msg_body;
$req->postUrl($slo_url); $req->postUrl($slo_url);
$req->postFields = { 'SAMLResponse' => $slo_body }; $req->postFields( { 'SAMLResponse' => $slo_body } );
# RelayState # RelayState
$req->postFields->{'RelayState'} = $relaystate $req->postFields->{'RelayState'} = $relaystate
if ($relaystate); if ($relaystate);
# TODO: verify this # TODO: verify this
$req->steps( ['autoPost'] ); push @{ $req->steps }, 'autoPost';
$req->continue(1);
return PE_OK; return PE_OK;
} }
...@@ -1389,6 +1391,14 @@ sub authLogout { ...@@ -1389,6 +1391,14 @@ sub authLogout {
} }
} }
sub handleAuthRequests {
my ( $self, $req ) = @_;
if ( $req->uri =~ $self->sloRe ) {
return $self->extractFormInfo($req);
}
PE_OK;
}
# TODO: authForce # TODO: authForce
sub getDisplayType { sub getDisplayType {
......
...@@ -401,6 +401,7 @@ sub checkMessage { ...@@ -401,6 +401,7 @@ sub checkMessage {
# 2.2.1. POST # 2.2.1. POST
if ( $content_type !~ /xml/ ) { if ( $content_type !~ /xml/ ) {
$req->parseBody unless(%{$req->params});
$method = Lasso::Constants::HTTP_METHOD_POST; $method = Lasso::Constants::HTTP_METHOD_POST;
$self->lmLog( "SAML method: HTTP-POST", 'debug' ); $self->lmLog( "SAML method: HTTP-POST", 'debug' );
...@@ -2330,8 +2331,7 @@ sub sendLogoutResponseToServiceProvider { ...@@ -2330,8 +2331,7 @@ sub sendLogoutResponseToServiceProvider {
# Logout response # Logout response
unless ( $self->buildLogoutResponseMsg($logout) ) { unless ( $self->buildLogoutResponseMsg($logout) ) {
$self->lmLog( "Unable to build SLO response", 'error' ); return $self->p->sendError( $req, "Unable to build SLO response", 500 );
return PE_SAML_SLO_ERROR;
} }
# Send response depending on request method # Send response depending on request method
...@@ -2340,11 +2340,7 @@ sub sendLogoutResponseToServiceProvider { ...@@ -2340,11 +2340,7 @@ sub sendLogoutResponseToServiceProvider {
# Redirect user to response URL # Redirect user to response URL
my $slo_url = $logout->msg_url; my $slo_url = $logout->msg_url;
$req->urldc($slo_url); return [ 302, [ Location => $slo_url ], [] ];
$self->lmLog( "Redirect user to $slo_url", 'debug' );
return PE_REDIRECT;
} }
# HTTP-POST # HTTP-POST
...@@ -2363,13 +2359,10 @@ sub sendLogoutResponseToServiceProvider { ...@@ -2363,13 +2359,10 @@ sub sendLogoutResponseToServiceProvider {
$req->{postFields}->{'RelayState'} = $relaystate $req->{postFields}->{'RelayState'} = $relaystate
if ($relaystate); if ($relaystate);
$req->steps( [ 'deleteSession', 'autoPost' ] ); return $self->p->do( $req, ['autoPost'] );
return PE_OK;
} }
$self->lmLog( "Lasso method '$method' should not be handle here...", return $self->p->sendError( $req,
'error' ); "Lasso method '$method' should not be handle here...", 400 );
return PE_SAML_SLO_ERROR;
} }
## @pmethod int sendLogoutRequestToProvider(Lasso::Logout $logout, string $providerID, int $method, boolean $relay, string $relayState) ## @pmethod int sendLogoutRequestToProvider(Lasso::Logout $logout, string $providerID, int $method, boolean $relay, string $relayState)
...@@ -2969,15 +2962,15 @@ sub sendSLOErrorResponse { ...@@ -2969,15 +2962,15 @@ sub sendSLOErrorResponse {
'<Session xmlns="http://www.entrouvert.org/namespaces/lasso/0.0"/>'; '<Session xmlns="http://www.entrouvert.org/namespaces/lasso/0.0"/>';
unless ( $self->setSessionFromDump( $logout, $session ) ) { unless ( $self->setSessionFromDump( $logout, $session ) ) {
$self->lmLog( "Could not set empty session in logout object", 'error' ); return $self->p->sendError( $req,
return PE_SAML_SLO_ERROR; "Could not set empty session in logout object", 500 );
} }
# Send unvalidated SLO response # Send unvalidated SLO response
return $self->sendLogoutResponseToServiceProvider( $req, $logout, $method ); return $self->sendLogoutResponseToServiceProvider( $req, $logout, $method );
} }
## @method void sendSLOErrorResponse(Lasso::Logout logout, string method) ## @method void sendSLOSoapErrorResponse(Lasso::Logout logout, string method)
# Send an SLO error response # Send an SLO error response
# @param logout Lasso::Logout object # @param logout Lasso::Logout object
# @param method HTTP method # @param method HTTP method
...@@ -2990,8 +2983,8 @@ sub sendSLOSoapErrorResponse { ...@@ -2990,8 +2983,8 @@ sub sendSLOSoapErrorResponse {
'<Session xmlns="http://www.entrouvert.org/namespaces/lasso/0.0"/>'; '<Session xmlns="http://www.entrouvert.org/namespaces/lasso/0.0"/>';
unless ( $self->setSessionFromDump( $logout, $session ) ) { unless ( $self->setSessionFromDump( $logout, $session ) ) {
return $self->p->sendError( return $self->p->sendError( $req,
"Could not set empty session in logout object"); "Could not set empty session in logout object" );
} }
my $slo_body = $logout->msg_body; my $slo_body = $logout->msg_body;
$self->lmLog( "SOAP response $slo_body", 'debug' ); $self->lmLog( "SOAP response $slo_body", 'debug' );
......
...@@ -53,6 +53,7 @@ sub init { ...@@ -53,6 +53,7 @@ sub init {
sub _redirect { sub _redirect {
my ( $self, $req, @path ) = @_; my ( $self, $req, @path ) = @_;
$self->lmLog('Processing _redirect','debug');
my $prms = $req->params; my $prms = $req->params;
foreach my $k ( keys %$prms ) { foreach my $k ( keys %$prms ) {
$self->p->setHiddenFormValue( $req, $k, $prms->{$k}, '', 0 ); $self->p->setHiddenFormValue( $req, $k, $prms->{$k}, '', 0 );
...@@ -83,7 +84,7 @@ sub _redirect { ...@@ -83,7 +84,7 @@ sub _redirect {
sub _pRedirect { sub _pRedirect {
my ( $self, $req, @path ) = @_; my ( $self, $req, @path ) = @_;
$self->lmLog( 'Parsing posted datas', 'debug' ); $self->lmLog( '_pRedirect: parsing posted datas', 'debug' );
$req->parseBody; $req->parseBody;
return $self->_redirect( $req, @path ); return $self->_redirect( $req, @path );
} }
...@@ -91,6 +92,7 @@ sub _pRedirect { ...@@ -91,6 +92,7 @@ sub _pRedirect {
# Case 3: authentified user, launch # Case 3: authentified user, launch
sub _forAuthUser { sub _forAuthUser {
my ( $self, $req, @path ) = @_; my ( $self, $req, @path ) = @_;
$self->lmLog('Processing _forAuthUser','debug');
return $self->p->do( return $self->p->do(
$req, $req,
[ [
......
...@@ -7,7 +7,7 @@ BEGIN { ...@@ -7,7 +7,7 @@ BEGIN {
require 't/test-lib.pm'; require 't/test-lib.pm';
} }
my $maintests = 15; my $maintests = 20;
my $debug = 'error'; my $debug = 'error';
my ( $issuer, $sp, $res ); my ( $issuer, $sp, $res );
my %handlerOR = ( issuer => [], sp => [] ); my %handlerOR = ( issuer => [], sp => [] );
...@@ -98,9 +98,9 @@ SKIP: { ...@@ -98,9 +98,9 @@ SKIP: {
ok( ok(
$res->[2]->[0] =~ $res->[2]->[0] =~
m#img src="http://auth.idp.com(/saml/relaySingleLogoutSOAP)\?(relay=.*?)"#s, m#iframe src="http://auth.idp.com(/saml/relaySingleLogoutPOST)\?(relay=.*?)"#s,
'Get image request' 'Get iframe request'
); ) or explain($res,'');
ok( ok(
$res = $issuer->_get( $res = $issuer->_get(
...@@ -109,10 +109,58 @@ m#img src="http://auth.idp.com(/saml/relaySingleLogoutSOAP)\?(relay=.*?)"#s, ...@@ -109,10 +109,58 @@ m#img src="http://auth.idp.com(/saml/relaySingleLogoutSOAP)\?(relay=.*?)"#s,
cookie => "lemonldap=$idpId", cookie => "lemonldap=$idpId",
accept => 'text/html' accept => 'text/html'
), ),
'Get image' 'Get iframe'
);
expectOK($res);
ok(
$res->[2]->[0] =~
m#<form.+?action="http://auth.sp.com(/saml/proxySingleLogout)".+?method="post"#,
'Form method is POST'
);
$url = $1;
ok(
$res->[2]->[0] =~
/<input type="hidden".+?name="SAMLRequest".+?value="(.+?)"/s,
'Found SAML response'
);
$s = "SAMLRequest=$1";
# Post SAML logout request to SP
switch ('sp');
ok(
$res = $sp->_post(
$url, IO::String->new($s),
accept => 'text/html',
length => length($s),
cookie => "lemonldap=$spId",
),
'Post SAML logout request to SP'
);
expectOK($res);
ok(
$res->[2]->[0] =~
m#<form.+?action="http://auth.idp.com(/saml/singleLogoutReturn)".+?method="post"#,
'Form method is POST'
);
$url = $1;
ok(
$res->[2]->[0] =~
/<input type="hidden".+?name="SAMLResponse".+?value="(.+?)"/s,
'Found SAML response'
);
$s = "SAMLResponse=$1";
# Post SAML logout response to IdP
switch('issuer');
ok(
$res = $sp->_post(
$url, IO::String->new($s),
accept => 'text/html',
length => length($s),
cookie => "lemonldap=$spId",
),
'Post SAML logout response to IdP'
); );
ok( getHeader( $res, 'Content-Type' ) eq 'image/png', 'Get an image' )
or explain( [ $res->[0], $res->[1] ], 'Content-Type => image/png' );
# Test if logout is done # Test if logout is done
switch ('issuer'); switch ('issuer');
...@@ -144,6 +192,7 @@ m#img src="http://auth.idp.com(/saml/relaySingleLogoutSOAP)\?(relay=.*?)"#s, ...@@ -144,6 +192,7 @@ m#img src="http://auth.idp.com(/saml/relaySingleLogoutSOAP)\?(relay=.*?)"#s,
$res->[2], $res->[2],
' <input type="hidden" name="SAMLRequest" id="SAMLRequest" value="...' ' <input type="hidden" name="SAMLRequest" id="SAMLRequest" value="...'
); );
#print STDERR Dumper($res);
} }
count($maintests); count($maintests);
...@@ -341,11 +390,6 @@ entityID="http://auth.sp.com/saml/metadata"> ...@@ -341,11 +390,6 @@ entityID="http://auth.sp.com/saml/metadata">
<ArtifactResolutionService isDefault="true" index="0" <ArtifactResolutionService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.sp.com/saml/artifact" /> Location="http://auth.sp.com/saml/artifact" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.sp.com/saml/singleLogoutSOAP" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://auth.sp.com/saml/singleLogout"
ResponseLocation="http://auth.sp.com/saml/singleLogoutReturn" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://auth.sp.com/saml/singleLogout" Location="http://auth.sp.com/saml/singleLogout"
ResponseLocation="http://auth.sp.com/saml/singleLogoutReturn" /> ResponseLocation="http://auth.sp.com/saml/singleLogoutReturn" />
...@@ -361,14 +405,8 @@ entityID="http://auth.sp.com/saml/metadata"> ...@@ -361,14 +405,8 @@ entityID="http://auth.sp.com/saml/metadata">
urn:oasis:names:tc:SAML:2.0:nameid-format:entity</NameIDFormat> urn:oasis:names:tc:SAML:2.0:nameid-format:entity</NameIDFormat>
<NameIDFormat> <NameIDFormat>
urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat> urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://auth.sp.com/saml/singleSignOn" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://auth.sp.com/saml/singleSignOn" /> Location="http://auth.sp.com/saml/singleSignOn" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="http://auth.sp.com/saml/singleSignOnArtifact" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.sp.com/saml/singleSignOnSOAP" />
</IDPSSODescriptor> </IDPSSODescriptor>
<SPSSODescriptor AuthnRequestsSigned="true" <SPSSODescriptor AuthnRequestsSigned="true"
WantAssertionsSigned="true" WantAssertionsSigned="true"
...@@ -407,11 +445,6 @@ entityID="http://auth.sp.com/saml/metadata"> ...@@ -407,11 +445,6 @@ entityID="http://auth.sp.com/saml/metadata">
<ArtifactResolutionService isDefault="true" index="0" <ArtifactResolutionService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.sp.com/saml/artifact" /> Location="http://auth.sp.com/saml/artifact" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.sp.com/saml/proxySingleLogoutSOAP" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://auth.sp.com/saml/proxySingleLogout"
ResponseLocation="http://auth.sp.com/saml/proxySingleLogoutReturn" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://auth.sp.com/saml/proxySingleLogout" Location="http://auth.sp.com/saml/proxySingleLogout"
ResponseLocation="http://auth.sp.com/saml/proxySingleLogoutReturn" /> ResponseLocation="http://auth.sp.com/saml/proxySingleLogoutReturn" />
...@@ -430,9 +463,6 @@ entityID="http://auth.sp.com/saml/metadata"> ...@@ -430,9 +463,6 @@ entityID="http://auth.sp.com/saml/metadata">
<AssertionConsumerService isDefault="true" index="0" <AssertionConsumerService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://auth.sp.com/saml/proxySingleSignOnPost" /> Location="http://auth.sp.com/saml/proxySingleSignOnPost" />
<AssertionConsumerService isDefault="false" index="1"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="http://auth.sp.com/saml/proxySingleSignOnArtifact" />
</SPSSODescriptor> </SPSSODescriptor>
<AttributeAuthorityDescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <AttributeAuthorityDescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
...@@ -570,11 +600,6 @@ entityID="http://auth.idp.com/saml/metadata"> ...@@ -570,11 +600,6 @@ entityID="http://auth.idp.com/saml/metadata">
<ArtifactResolutionService isDefault="true" index="0" <ArtifactResolutionService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.idp.com/saml/artifact" /> Location="http://auth.idp.com/saml/artifact" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.idp.com/saml/singleLogoutSOAP" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://auth.idp.com/saml/singleLogout"
ResponseLocation="http://auth.idp.com/saml/singleLogoutReturn" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://auth.idp.com/saml/singleLogout" Location="http://auth.idp.com/saml/singleLogout"
ResponseLocation="http://auth.idp.com/saml/singleLogoutReturn" /> ResponseLocation="http://auth.idp.com/saml/singleLogoutReturn" />
...@@ -590,14 +615,8 @@ entityID="http://auth.idp.com/saml/metadata"> ...@@ -590,14 +615,8 @@ entityID="http://auth.idp.com/saml/metadata">
urn:oasis:names:tc:SAML:2.0:nameid-format:entity</NameIDFormat> urn:oasis:names:tc:SAML:2.0:nameid-format:entity</NameIDFormat>
<NameIDFormat> <NameIDFormat>
urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat> urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://auth.idp.com/saml/singleSignOn" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://auth.idp.com/saml/singleSignOn" /> Location="http://auth.idp.com/saml/singleSignOn" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="http://auth.idp.com/saml/singleSignOnArtifact" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.idp.com/saml/singleSignOnSOAP" />
</IDPSSODescriptor> </IDPSSODescriptor>
<SPSSODescriptor AuthnRequestsSigned="true" <SPSSODescriptor AuthnRequestsSigned="true"
WantAssertionsSigned="true" WantAssertionsSigned="true"
...@@ -636,11 +655,6 @@ entityID="http://auth.idp.com/saml/metadata"> ...@@ -636,11 +655,6 @@ entityID="http://auth.idp.com/saml/metadata">
<ArtifactResolutionService isDefault="true" index="0" <ArtifactResolutionService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.idp.com/saml/artifact" /> Location="http://auth.idp.com/saml/artifact" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://auth.idp.com/saml/proxySingleLogoutSOAP" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://auth.idp.com/saml/proxySingleLogout"
ResponseLocation="http://auth.idp.com/saml/proxySingleLogoutReturn" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://auth.idp.com/saml/proxySingleLogout" Location="http://auth.idp.com/saml/proxySingleLogout"
ResponseLocation="http://auth.idp.com/saml/proxySingleLogoutReturn" /> ResponseLocation="http://auth.idp.com/saml/proxySingleLogoutReturn" />
...@@ -659,9 +673,6 @@ entityID="http://auth.idp.com/saml/metadata"> ...@@ -659,9 +673,6 @@ entityID="http://auth.idp.com/saml/metadata">
<AssertionConsumerService isDefault="true" index="0" <AssertionConsumerService isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://auth.idp.com/saml/proxySingleSignOnPost" /> Location="http://auth.idp.com/saml/proxySingleSignOnPost" />
<AssertionConsumerService isDefault="false" index="1"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="http://auth.idp.com/saml/proxySingleSignOnArtifact" />
</SPSSODescriptor> </SPSSODescriptor>
<AttributeAuthorityDescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <AttributeAuthorityDescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
......
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