SAML in progress (#595)

This commit is contained in:
Xavier Guimard 2016-11-16 15:27:01 +00:00
parent 4bb0b3936b
commit b3e18e2f35
5 changed files with 114 additions and 91 deletions

View File

@ -23,11 +23,45 @@ our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Auth::Base', 'Lemonldap::NG::Portal::Lib::SAML';
has sloAssConsumerRe => ( is => 'rw' );
has sloRe => ( is => 'rw' );
has artRe => ( is => 'rw' );
# INITIALIZATION
sub init {
my ($self) = @_;
my $saml_acs_art_url = $self->getMetaDataURL(
"samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact");
my $saml_acs_post_url = $self->getMetaDataURL(
"samlSPSSODescriptorAssertionConsumerServiceHTTPPost");
my $saml_acs_get_url = $self->getMetaDataURL(
"samlSPSSODescriptorAssertionConsumerServiceHTTPRedirect");
$self->sloAssConsumerRe(
qr/^\Q($saml_acs_art_url|$saml_acs_post_url|$saml_acs_get_url)\E$/i);
my $saml_slo_soap_url =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceSOAP", 1 );
my $saml_slo_soap_url_ret =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceSOAP", 1 );
my $saml_slo_get_url = $self->getMetaDataURL(
"samlSPSSODescriptorSingleLogoutServiceHTTPRedirect", 1 );
my $saml_slo_get_url_ret = $self->getMetaDataURL(
"samlSPSSODescriptorSingleLogoutServiceHTTPRedirect", 2 );
my $saml_slo_post_url =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceHTTPPost",
1 );
my $saml_slo_post_url_ret =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceHTTPPost",
2 );
$self->sloRe(
qr/^\Q($saml_slo_soap_url|$saml_slo_soap_url_ret|$saml_slo_get_url|$saml_slo_get_url_ret|$saml_slo_post_url|$saml_slo_post_url_ret)\E$/i
);
my $saml_ars_url = $self->getMetaDataURL(
"samlSPSSODescriptorArtifactResolutionServiceArtifact");
$self->artRe(qr/^(\Q$saml_ars_url\E)$/i);
# Load SAML service and SAML IdP list
return ( $self->SUPER::init and $self->loadIDPs );
}
@ -43,34 +77,8 @@ sub extractFormInfo {
my $request_method = $req->method;
my $content_type = $req->contentType;
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(
"samlSPSSODescriptorSingleLogoutServiceHTTPRedirect", 1 );
my $saml_slo_get_url_ret = $self->getMetaDataURL(
"samlSPSSODescriptorSingleLogoutServiceHTTPRedirect", 2 );
my $saml_slo_post_url =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceHTTPPost",
1 );
my $saml_slo_post_url_ret =
$self->getMetaDataURL( "samlSPSSODescriptorSingleLogoutServiceHTTPPost",
2 );
my $saml_ars_url = $self->getMetaDataURL(
"samlSPSSODescriptorArtifactResolutionServiceArtifact");
# 1.1 SSO assertion consumer
if ( $url =~
/^(\Q$saml_acs_art_url\E|\Q$saml_acs_post_url\E|\Q$saml_acs_get_url\E)$/io
)
{
if ( $url =~ $self->sloAssConsumerRe ) {
$self->lmLog( "URL $url detected as an SSO assertion consumer URL",
'debug' );
@ -379,10 +387,7 @@ sub extractFormInfo {
}
# 1.2 SLO
elsif ( $url =~
/^\Q($saml_slo_soap_url|$saml_slo_soap_url_ret|$saml_slo_get_url|$saml_slo_get_url_ret|$saml_slo_post_url|$saml_slo_post_url_ret)\E$/io
)
{
elsif ( $url =~ $self->sloRe ) {
$self->lmLog( "URL $url detected as an SLO URL", 'debug' );
# Check SAML Message
@ -756,13 +761,13 @@ sub extractFormInfo {
}
# 1.3 Artifact
elsif ( $url =~ /^(\Q$saml_ars_url\E)$/io ) {
elsif ( $url =~ $self->artRe ) {
$self->lmLog( "URL $url detected as an artifact resolution service URL",
'debug' );
# Artifact request are sent with SOAP trough POST
my $art_request = $self->param('POSTDATA');
my $art_request = $req->param('POSTDATA');
my $art_response;
# Create Login object
@ -806,7 +811,7 @@ sub extractFormInfo {
my ( $idp, $idp_cookie ) = $self->getIDP($req);
# Get confirmation flag
my $confirm_flag = $self->param("confirm");
my $confirm_flag = $req->param("confirm");
# If confirmation is -1 from resolved IDP screen,
# or IDP was not resolve, let the user choose its IDP
@ -814,7 +819,7 @@ sub extractFormInfo {
$self->lmLog( "Redirecting user to IDP list", 'debug' );
# Control url parameter
my $urlcheck = $self->controlUrlOrigin();
my $urlcheck = $self->p->controlUrl($req);
return $urlcheck unless ( $urlcheck == PE_OK );
# IDP list
@ -831,7 +836,7 @@ sub extractFormInfo {
# Delete existing IDP resolution cookie
push @{ $req->respHeaders },
'Set-Cookie' => $self->cookie(
'Set-Cookie' => $self->p->cookie(
name => $self->conf->{samlIdPResolveCookie},
value => 0,
domain => $self->conf->{domain},
@ -863,7 +868,7 @@ sub extractFormInfo {
. $idp
. "</i></p>\n"
. "<input type=\"hidden\" name=\"url\" value=\""
. $self->param("url") . "\" />"
. $req->param("url") . "\" />"
. "<input type=\"hidden\" name=\"idp\" value=\"$idp\" />\n";
$self->info($html);
@ -881,7 +886,7 @@ sub extractFormInfo {
return $urlcheck unless ( $urlcheck == PE_OK );
# User can choose temporary (0) or persistent cookie (1)
my $cookie_type = $self->param("cookie_type") || "0";
my $cookie_type = $req->param("cookie_type") || "0";
push @{ $req->{respHeaders} },
'Set-Cookie' => $self->cookie(
@ -1385,17 +1390,17 @@ sub getIDP {
my $idpName;
my $idp_cookie;
if ( $req->cookie
&& $req->cookie =~ /$self->{conf}->{samlIdPResolveCookie}=([^,; ]+)/o )
if ( $req->cookies
&& $req->cookies =~ /$self->{conf}->{samlIdPResolveCookie}=([^,; ]+)/o )
{
$idp_cookie = $1;
}
# Case 1: Recover IDP from idp URL Parameter
unless ( $idp = $self->param("idp") ) {
unless ( $idp = $req->param("idp") ) {
# Case 2: Recover IDP from idpName URL Parameter
if ( $idpName = $self->param("idpName") ) {
if ( $idpName = $req->param("idpName") ) {
foreach ( keys %{ $self->idpList } ) {
my $idpConfKey = $self->idpList->{$_}->{confKey};
if ( $idpName eq $idpConfKey ) {

View File

@ -19,10 +19,55 @@ our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Main::Issuer',
'Lemonldap::NG::Portal::Lib::SAML';
has ssoUrlRe => ( is => 'rw' );
has sloRe => ( is => 'rw' );
# INITIALIZATION
sub init {
my ($self) = @_;
# Get configuration parameter
my $saml_sso_soap_url =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceSOAP", 1 );
my $saml_sso_soap_url_ret =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceSOAP", 2 );
my $saml_sso_get_url = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect", 1 );
my $saml_sso_get_url_ret = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect", 2 );
my $saml_sso_post_url =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceHTTPPost",
1 );
my $saml_sso_post_url_ret =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceHTTPPost",
2 );
my $saml_sso_art_url = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact", 1 );
my $saml_sso_art_url_ret = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact", 2 );
$self->ssoUrlRe(
qr/^(\Q$saml_sso_soap_url\E|\Q$saml_sso_soap_url_ret\E|\Q$saml_sso_get_url\E|\Q$saml_sso_get_url_ret\E|\Q$saml_sso_post_url\E|\Q$saml_sso_post_url_ret\E|\Q$saml_sso_art_url\E|\Q$saml_sso_art_url_ret\E)$/i
);
my $saml_slo_soap_url =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceSOAP", 1 );
my $saml_slo_soap_url_ret =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceSOAP", 2 );
my $saml_slo_get_url = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect", 1 );
my $saml_slo_get_url_ret = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect", 2 );
my $saml_slo_post_url =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceHTTPPost",
1 );
my $saml_slo_post_url_ret =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceHTTPPost",
2 );
$self->sloRe(
qr/^(\Q$saml_slo_soap_url\E|\Q$saml_slo_soap_url_ret\E|\Q$saml_slo_get_url\E|\Q$saml_slo_get_url_ret\E|\Q$saml_slo_post_url\E|\Q$saml_slo_post_url_ret\E)$/i
);
return (
$self->Lemonldap::NG::Portal::Main::Issuer::init()
@ -54,40 +99,6 @@ sub run {
# Session creation timestamp
my $time = $req->{sessionInfo}->{_utime} || time();
# Get configuration parameter
my $saml_sso_soap_url =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceSOAP", 1 );
my $saml_sso_soap_url_ret =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceSOAP", 2 );
my $saml_sso_get_url = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect", 1 );
my $saml_sso_get_url_ret = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect", 2 );
my $saml_sso_post_url =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceHTTPPost",
1 );
my $saml_sso_post_url_ret =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceHTTPPost",
2 );
my $saml_sso_art_url = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact", 1 );
my $saml_sso_art_url_ret = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact", 2 );
my $saml_slo_soap_url =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceSOAP", 1 );
my $saml_slo_soap_url_ret =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceSOAP", 2 );
my $saml_slo_get_url = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect", 1 );
my $saml_slo_get_url_ret = $self->getMetaDataURL(
"samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect", 2 );
my $saml_slo_post_url =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceHTTPPost",
1 );
my $saml_slo_post_url_ret =
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceHTTPPost",
2 );
# Get HTTP request informations to know
# if we are receving SAML request or response
my $url = $self->url( -absolute => 1 );
@ -98,10 +109,7 @@ sub run {
my $idp_initiated_spConfKey = $self->param('spConfKey');
# 1.1. SSO (SSO URL or Proxy Mode)
if ( $url =~
/^(\Q$saml_sso_soap_url\E|\Q$saml_sso_soap_url_ret\E|\Q$saml_sso_get_url\E|\Q$saml_sso_get_url_ret\E|\Q$saml_sso_post_url\E|\Q$saml_sso_post_url_ret\E|\Q$saml_sso_art_url\E|\Q$saml_sso_art_url_ret\E)$/io
or $req->datas->{_proxiedRequest} )
{
if ( $url =~ $self->ssoUrlRe or $req->datas->{_proxiedRequest} ) {
$self->lmLog( "URL $url detected as an SSO request URL", 'debug' );
@ -918,11 +926,7 @@ sub run {
}
# 1.2. SLO
if ( $url =~
/^(\Q$saml_slo_soap_url\E|\Q$saml_slo_soap_url_ret\E|\Q$saml_slo_get_url\E|\Q$saml_slo_get_url_ret\E|\Q$saml_slo_post_url\E|\Q$saml_slo_post_url_ret\E)$/io
)
{
if ( $url =~ $self->sloRe ) {
$self->lmLog( "URL $url detected as an SLO URL", 'debug' );
# Check SAML Message

View File

@ -1416,13 +1416,13 @@ sub setIdentityFromDump {
# @param full Return full URL instead of path
# @return url
sub getMetaDataURL {
my ( $self, $req, $key, $index, $full ) = @_;
my ( $self, $key, $index, $full ) = @_;
$index = 3 unless defined $index;
$full = 0 unless defined $full;
return unless defined $req->{$key};
return unless defined $self->conf->{$key};
my $url = ( split( /;/, $req->{$key} ) )[$index];
my $url = ( split( /;/, $self->conf->{$key} ) )[$index];
# Get portal value
my $portal = $self->conf->{portal};

View File

@ -463,4 +463,9 @@ sub isTrustedUrl {
return $url =~ $self->trustedDomainsRe ? 1 : 0;
}
sub stamp {
my $self = shift;
return $self->conf->{cipher} ? $self->conf->{cipher}->encrypt( time() ) : 1;
}
1;

View File

@ -3,7 +3,7 @@ use strict;
require 't/test-lib.pm';
my $tests = 0;
my $tests = 3;
my $debug = 'debug';
my $res;
my %handlerOR = ( issuer => [], sp => [] );
@ -13,12 +13,21 @@ SKIP: {
if ($@) {
skip 'Lasso not found', $tests;
}
my $issuer = issuer();
my $issuer;
ok( $issuer = issuer(), 'Issuer portal' );
$handlerOR{issuer} = \@Lemonldap::NG::Handler::Main::Reload::_onReload;
switch ('sp');
my $sp = sp();
my $sp;
ok( $sp = sp(), 'SP portal' );
$handlerOR{sp} = \@Lemonldap::NG::Handler::Main::Reload::_onReload;
ok(
$sp->_get(
'/', accept => 'text/html',
),
'Unauth SP request'
);
}
count($tests);