diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SAML.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SAML.pm index 0a98bd029..baaf36f08 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SAML.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SAML.pm @@ -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 . "

\n" . "param("url") . "\" />" + . $req->param("url") . "\" />" . "\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 ) { diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/SAML.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/SAML.pm index e8d4aa9d6..eb3b86e0d 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/SAML.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Issuer/SAML.pm @@ -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 diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm index 709590785..b3d7eb6d7 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm @@ -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}; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index 3c9b715b3..85086141c 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -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; diff --git a/lemonldap-ng-portal/t/30-Auth-and-issuer-SAML.t b/lemonldap-ng-portal/t/30-Auth-and-issuer-SAML.t index 4e9fa9c98..86b9a40b0 100644 --- a/lemonldap-ng-portal/t/30-Auth-and-issuer-SAML.t +++ b/lemonldap-ng-portal/t/30-Auth-and-issuer-SAML.t @@ -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);