SAML in progress (#595)
This commit is contained in:
parent
4bb0b3936b
commit
b3e18e2f35
|
@ -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 ) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user