Commit 2efb4455 authored by Christophe Maudoux's avatar Christophe Maudoux 🐛

Merge branch 'v2.0'

parents 9231711a c01c26af
Pipeline #7009 canceled with stage
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
.\" ======================================================================== .\" ========================================================================
.\" .\"
.IX Title "llng-fastcgi-server 8" .IX Title "llng-fastcgi-server 8"
.TH llng-fastcgi-server 8 "2019-09-24" "perl v5.28.1" "User Contributed Perl Documentation" .TH llng-fastcgi-server 8 "2019-10-30" "perl v5.26.1" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents. .\" way too many mistakes in technical documents.
.if n .ad l .if n .ad l
......
...@@ -305,9 +305,10 @@ languages = en, fr, vi, it, ar, de, fi ...@@ -305,9 +305,10 @@ languages = en, fr, vi, it, ar, de, fi
; Read Lemonldap::NG::Portal::Main::Plugin(3pm) man page. ; Read Lemonldap::NG::Portal::Main::Plugin(3pm) man page.
;customPlugins = My::Package1, My::Package2 ;customPlugins = My::Package1, My::Package2
; To avoid bad/expired OTT if authssl and auth are served by different Load Balancers ; To avoid bad/expired OTT if "authssl" and "auth" are served by different Load Balancers
; you can override OTT configuration to store Upgrade OTT into global storage ; you can override OTT configuration to store Upgrade or Issuer OTT into global storage
;forceGlobalStorageUpgradeOTT = 1 ;forceGlobalStorageUpgradeOTT = 1
;forceGlobalStorageIssuerOTT = 1
[handler] [handler]
......
...@@ -260,8 +260,7 @@ sub defaultValues { ...@@ -260,8 +260,7 @@ sub defaultValues {
'samlAuthnContextMapPassword' => 2, 'samlAuthnContextMapPassword' => 2,
'samlAuthnContextMapPasswordProtectedTransport' => 3, 'samlAuthnContextMapPasswordProtectedTransport' => 3,
'samlAuthnContextMapTLSClient' => 5, 'samlAuthnContextMapTLSClient' => 5,
'samlEntityID' => '#PORTAL#/saml/metadata', 'samlEntityID' => '#PORTAL#/saml/metadata',
'samlIdPResolveCookie' => 'lemonldapidp',
'samlIDPSSODescriptorArtifactResolutionServiceArtifact' => 'samlIDPSSODescriptorArtifactResolutionServiceArtifact' =>
'1;0;urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/artifact', '1;0;urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/artifact',
'samlIDPSSODescriptorSingleLogoutServiceHTTPPost' => 'samlIDPSSODescriptorSingleLogoutServiceHTTPPost' =>
......
...@@ -195,9 +195,11 @@ sub virtualHosts { ...@@ -195,9 +195,11 @@ sub virtualHosts {
type => 'keyText', type => 'keyText',
}; };
# If rule contains a comment, split it # If rule contains a comment or an AuthLevel, split them
if ( $query eq 'locationRules' ) { if ( $query eq 'locationRules' ) {
$res->{comment} = ''; $res->{comment} = '';
$res->{level} = '';
$res->{level} = $1 if ( $r =~ s/\(\?#AuthnLevel=(-?\d+)\)// );
if ( $r =~ s/\(\?#(.*?)\)// ) { if ( $r =~ s/\(\?#(.*?)\)// ) {
$res->{title} = $res->{comment} = $1; $res->{title} = $res->{comment} = $1;
} }
......
...@@ -67,7 +67,7 @@ our $issuerParameters = { ...@@ -67,7 +67,7 @@ our $issuerParameters = {
issuerDBSAML => [qw(issuerDBSAMLActivation issuerDBSAMLPath issuerDBSAMLRule)], issuerDBSAML => [qw(issuerDBSAMLActivation issuerDBSAMLPath issuerDBSAMLRule)],
issuerOptions => [qw(issuersTimeout)], issuerOptions => [qw(issuersTimeout)],
}; };
our $samlServiceParameters = [qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlServiceSignatureMethod samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlIdPResolveCookie samlMetadataForceUTF8 samlStorage samlStorageOptions samlRelayStateTimeout samlUseQueryStringSpecific samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter samlDiscoveryProtocolActivation samlDiscoveryProtocolURL samlDiscoveryProtocolPolicy samlDiscoveryProtocolIsPassive samlOverrideIDPEntityID)]; our $samlServiceParameters = [qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlServiceSignatureMethod samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlMetadataForceUTF8 samlStorage samlStorageOptions samlRelayStateTimeout samlUseQueryStringSpecific samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter samlDiscoveryProtocolActivation samlDiscoveryProtocolURL samlDiscoveryProtocolPolicy samlDiscoveryProtocolIsPassive samlOverrideIDPEntityID)];
our $oidcServiceParameters = [qw(oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataIntrospectionURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcStorage oidcStorageOptions)]; our $oidcServiceParameters = [qw(oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataIntrospectionURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcStorage oidcStorageOptions)];
1; 1;
...@@ -43,11 +43,11 @@ sub run { ...@@ -43,11 +43,11 @@ sub run {
# Catch Secure Token parameters # Catch Secure Token parameters
my $localConfig = $class->localConfig; my $localConfig = $class->localConfig;
my $secureTokenMemcachedServers = our $secureTokenMemcachedServers =
$localConfig->{secureTokenMemcachedServers} || ['127.0.0.1:11211']; $localConfig->{secureTokenMemcachedServers} || ['127.0.0.1:11211'];
my $secureTokenExpiration = $localConfig->{secureTokenExpiration} || 60; my $secureTokenExpiration = $localConfig->{secureTokenExpiration} || 60;
my $secureTokenAttribute = $localConfig->{secureTokenAttribute} || 'uid'; my $secureTokenAttribute = $localConfig->{secureTokenAttribute} || 'uid';
my $secureTokenUrls = $localConfig->{'secureTokenUrls'} || ['.*']; our $secureTokenUrls = $localConfig->{'secureTokenUrls'} || ['.*'];
my $secureTokenHeader = $localConfig->{secureTokenHeader} || 'Auth-Token'; my $secureTokenHeader = $localConfig->{secureTokenHeader} || 'Auth-Token';
my $secureTokenAllowOnError = $localConfig->{'secureTokenAllowOnError'} my $secureTokenAllowOnError = $localConfig->{'secureTokenAllowOnError'}
// 1; // 1;
......
...@@ -281,6 +281,7 @@ sub locationRulesInit { ...@@ -281,6 +281,7 @@ sub locationRulesInit {
$class->tsv->{locationProtection}->{$vhost} = []; $class->tsv->{locationProtection}->{$vhost} = [];
$class->tsv->{locationRegexp}->{$vhost} = []; $class->tsv->{locationRegexp}->{$vhost} = [];
$class->tsv->{locationConditionText}->{$vhost} = []; $class->tsv->{locationConditionText}->{$vhost} = [];
$class->tsv->{locationAuthnLevel}->{$vhost} = [];
foreach my $url ( sort keys %{$rules} ) { foreach my $url ( sort keys %{$rules} ) {
my ( $cond, $prot ) = $class->conditionSub( $rules->{$url} ); my ( $cond, $prot ) = $class->conditionSub( $rules->{$url} );
...@@ -300,10 +301,14 @@ sub locationRulesInit { ...@@ -300,10 +301,14 @@ sub locationRulesInit {
push @{ $class->tsv->{locationCondition}->{$vhost} }, $cond; push @{ $class->tsv->{locationCondition}->{$vhost} }, $cond;
push @{ $class->tsv->{locationProtection}->{$vhost} }, $prot; push @{ $class->tsv->{locationProtection}->{$vhost} }, $prot;
push @{ $class->tsv->{locationRegexp}->{$vhost} }, qr/$url/; push @{ $class->tsv->{locationRegexp}->{$vhost} }, qr/$url/;
push @{ $class->tsv->{locationAuthnLevel}->{$vhost} },
$url =~ /\(\?#AuthnLevel=(-?\d+)\)/
? $1
: undef;
push @{ $class->tsv->{locationConditionText}->{$vhost} }, push @{ $class->tsv->{locationConditionText}->{$vhost} },
$url =~ /^\(\?#(.*?)\)/ ? $1 $url =~ /^\(\?#(.*?)\)/ ? $1
: $url =~ /^(.*?)##(.+)$/ ? $2 : $url =~ /^(.*?)##(.+)$/ ? $2
: $url; : $url;
$class->tsv->{locationCount}->{$vhost}++; $class->tsv->{locationCount}->{$vhost}++;
} }
} }
...@@ -451,6 +456,7 @@ sub postUrlInit { ...@@ -451,6 +456,7 @@ sub postUrlInit {
# @return array (ref(sub), int) # @return array (ref(sub), int)
sub conditionSub { sub conditionSub {
my ( $class, $cond ) = @_; my ( $class, $cond ) = @_;
$cond =~ s/\(\?#(\d+)\)$//;
my ( $OK, $NOK ) = ( sub { 1 }, sub { 0 } ); my ( $OK, $NOK ) = ( sub { 1 }, sub { 0 } );
# Simple cases : accept and deny # Simple cases : accept and deny
......
...@@ -267,10 +267,31 @@ sub checkMaintenanceMode { ...@@ -267,10 +267,31 @@ sub checkMaintenanceMode {
# @return True if the user is granted to access to the current URL # @return True if the user is granted to access to the current URL
sub grant { sub grant {
my ( $class, $req, $session, $uri, $cond, $vhost ) = @_; my ( $class, $req, $session, $uri, $cond, $vhost ) = @_;
my $level;
return $cond->( $req, $session ) if ($cond); return $cond->( $req, $session ) if ($cond);
$vhost ||= $class->resolveAlias($req); $vhost ||= $class->resolveAlias($req);
if ( my $level = $class->tsv->{authnLevel}->{$vhost} ) {
# Using URL authentification level if exists
for (
my $i = 0 ;
$i < ( $class->tsv->{locationCount}->{$vhost} || 0 ) ;
$i++
)
{
if ( $uri =~ $class->tsv->{locationRegexp}->{$vhost}->[$i] ) {
$level = $class->tsv->{locationAuthnLevel}->{$vhost}->[$i];
last;
}
}
$level
? $class->logger->debug(
'Found AuthnLevel=' . $level . ' for "' . "$vhost$uri" . '"' )
: $class->logger->debug("No URL authentication level found...");
# Using VH authentification level if exists
if ( $level ||= $class->tsv->{authnLevel}->{$vhost} ) {
if ( $session->{authenticationLevel} < $level ) { if ( $session->{authenticationLevel} < $level ) {
$class->logger->debug( $class->logger->debug(
"User authentication level = $session->{authenticationLevel}"); "User authentication level = $session->{authenticationLevel}");
......
...@@ -10,6 +10,7 @@ init('Lemonldap::NG::Handler::PSGI'); ...@@ -10,6 +10,7 @@ init('Lemonldap::NG::Handler::PSGI');
my $res; my $res;
# Unauthentified query # Unauthentified query
# --------------------
ok( $res = $client->_get('/'), 'Unauthentified query' ); ok( $res = $client->_get('/'), 'Unauthentified query' );
ok( ref($res) eq 'ARRAY', 'Response is an array' ) or explain( $res, 'array' ); ok( ref($res) eq 'ARRAY', 'Response is an array' ) or explain( $res, 'array' );
ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 ); ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 );
...@@ -24,17 +25,14 @@ ok( ...@@ -24,17 +25,14 @@ ok(
'Location => http://auth.example.com/?url=' 'Location => http://auth.example.com/?url='
. encode_base64( 'http://test1.example.com/', '' ) . encode_base64( 'http://test1.example.com/', '' )
); );
count(4); count(4);
# Authentified queries # Authentified queries
# -------------------- # --------------------
# Authorized query # Authorized query
ok( $res = $client->_get( '/', undef, undef, "lemonldap=$sessionId" ), ok( $res = $client->_get( '/', undef, undef, "lemonldap=$sessionId" ),
'Authentified query' ); 'Authentified query' );
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 ); ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
count(2); count(2);
ok( $res = $client->_get( '/user_dwho/', undef, undef, "lemonldap=$sessionId" ), ok( $res = $client->_get( '/user_dwho/', undef, undef, "lemonldap=$sessionId" ),
...@@ -47,7 +45,12 @@ count(2); ...@@ -47,7 +45,12 @@ count(2);
ok( $res = $client->_get( '/deny', undef, undef, "lemonldap=$sessionId" ), ok( $res = $client->_get( '/deny', undef, undef, "lemonldap=$sessionId" ),
'Denied query' ); 'Denied query' );
ok( $res->[0] == 403, 'Code is 403' ) or explain( $res->[0], 403 ); ok( $res->[0] == 403, 'Code is 403' ) or explain( $res->[0], 403 );
count(2);
# Required AuthnLevel = 1
ok( $res = $client->_get( '/AuthWeak', undef, undef, "lemonldap=$sessionId" ),
'Weak Authentified query' );
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
count(2); count(2);
ok( $res = $client->_get( '/user_rtyler/', undef, undef, "lemonldap=$sessionId" ), ok( $res = $client->_get( '/user_rtyler/', undef, undef, "lemonldap=$sessionId" ),
...@@ -56,6 +59,25 @@ ok( $res->[0] == 403, 'Code is 403' ) or explain( $res, 403 ); ...@@ -56,6 +59,25 @@ ok( $res->[0] == 403, 'Code is 403' ) or explain( $res, 403 );
count(2); count(2);
# Required AuthnLevel = 5
ok(
$res = $client->_get( '/AuthStrong', undef, undef, "lemonldap=$sessionId" ),
'Strong Authentified query'
);
ok( $res->[0] == 302, 'Code is 302' ) or explain( $res, 302 );
%h = @{ $res->[1] };
ok(
$h{Location} eq 'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test1.example.com/AuthStrong', '' ),
'Redirection points to http://test1.example.com/AuthStrong'
)
or explain(
\%h,
'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test1.example.com/AuthStrong', '' )
);
count(3);
# Bad cookie # Bad cookie
ok( ok(
$res = $client->_get( $res = $client->_get(
...@@ -70,9 +92,38 @@ ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 ); ...@@ -70,9 +92,38 @@ ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 );
unlink( unlink(
't/sessions/lock/Apache-Session-e5eec18ebb9bc96352595e2d8ce962e8ecf7af7c9a98cb9a43f9cd181cf4b545.lock' 't/sessions/lock/Apache-Session-e5eec18ebb9bc96352595e2d8ce962e8ecf7af7c9a98cb9a43f9cd181cf4b545.lock'
); );
count(2);
# Required AuthnLevel = 1
ok(
$res = $client->_get(
'/AuthWeak', undef, 'test2.example.com', "lemonldap=$sessionId"
),
'Weak Authentified query'
);
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
count(2); count(2);
# Required AuthnLevel = 5
ok(
$res =
$client->_get( '/', undef, 'test2.example.com', "lemonldap=$sessionId" ),
'Default Authentified query'
);
ok( $res->[0] == 302, 'Code is 302' ) or explain( $res, 302 );
%h = @{ $res->[1] };
ok(
$h{Location} eq 'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test2.example.com/', '' ),
'Redirection points to http://test2.example.com/'
)
or explain(
\%h,
'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test2.example.com/', '' )
);
count(3);
done_testing( count() ); done_testing( count() );
clean(); clean();
......
...@@ -9,6 +9,7 @@ init('Lemonldap::NG::Handler::Server'); ...@@ -9,6 +9,7 @@ init('Lemonldap::NG::Handler::Server');
my $res; my $res;
# Unauthentified query # Unauthentified query
# --------------------
ok( $res = $client->_get('/'), 'Unauthentified query' ); ok( $res = $client->_get('/'), 'Unauthentified query' );
ok( ref($res) eq 'ARRAY', 'Response is an array' ) or explain( $res, 'array' ); ok( ref($res) eq 'ARRAY', 'Response is an array' ) or explain( $res, 'array' );
ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 ); ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 );
...@@ -23,17 +24,14 @@ ok( ...@@ -23,17 +24,14 @@ ok(
'Location => http://auth.example.com/?url=' 'Location => http://auth.example.com/?url='
. encode_base64( 'http://test1.example.com/', '' ) . encode_base64( 'http://test1.example.com/', '' )
); );
count(4); count(4);
# Authentified queries # Authentified queries
# -------------------- # --------------------
# Authorized query # Authorized query
ok( $res = $client->_get( '/', undef, undef, "lemonldap=$sessionId" ), ok( $res = $client->_get( '/', undef, undef, "lemonldap=$sessionId" ),
'Authentified query' ); 'Authentified query' );
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res->[0], 200 ); ok( $res->[0] == 200, 'Code is 200' ) or explain( $res->[0], 200 );
count(2); count(2);
# Check headers # Check headers
...@@ -46,9 +44,33 @@ count(1); ...@@ -46,9 +44,33 @@ count(1);
ok( $res = $client->_get( '/deny', undef, undef, "lemonldap=$sessionId" ), ok( $res = $client->_get( '/deny', undef, undef, "lemonldap=$sessionId" ),
'Denied query' ); 'Denied query' );
ok( $res->[0] == 403, 'Code is 403' ) or explain( $res->[0], 403 ); ok( $res->[0] == 403, 'Code is 403' ) or explain( $res->[0], 403 );
count(2);
# Required AuthnLevel = 1
ok( $res = $client->_get( '/AuthWeak', undef, undef, "lemonldap=$sessionId" ),
'Weak Authentified query' );
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
count(2); count(2);
# Required AuthnLevel = 5
ok(
$res = $client->_get( '/AuthStrong', undef, undef, "lemonldap=$sessionId" ),
'Strong Authentified query'
);
ok( $res->[0] == 302, 'Code is 302' ) or explain( $res, 302 );
%h = @{ $res->[1] };
ok(
$h{Location} eq 'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test1.example.com/AuthStrong', '' ),
'Redirection points to http://test1.example.com/AuthStrong'
)
or explain(
\%h,
'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test1.example.com/AuthStrong', '' )
);
count(3);
# Bad cookie # Bad cookie
ok( ok(
$res = $client->_get( $res = $client->_get(
...@@ -63,9 +85,38 @@ ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 ); ...@@ -63,9 +85,38 @@ ok( $res->[0] == 302, 'Code is 302' ) or explain( $res->[0], 302 );
unlink( unlink(
't/sessions/lock/Apache-Session-e5eec18ebb9bc96352595e2d8ce962e8ecf7af7c9a98cb9a43f9cd181cf4b545.lock' 't/sessions/lock/Apache-Session-e5eec18ebb9bc96352595e2d8ce962e8ecf7af7c9a98cb9a43f9cd181cf4b545.lock'
); );
count(2);
# Required AuthnLevel = 1
ok(
$res = $client->_get(
'/AuthWeak', undef, 'test2.example.com', "lemonldap=$sessionId"
),
'Weak Authentified query'
);
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
count(2); count(2);
# Required AuthnLevel = 5
ok(
$res =
$client->_get( '/', undef, 'test2.example.com', "lemonldap=$sessionId" ),
'Default Authentified query'
);
ok( $res->[0] == 302, 'Code is 302' ) or explain( $res, 302 );
%h = @{ $res->[1] };
ok(
$h{Location} eq 'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test2.example.com/', '' ),
'Redirection points to http://test2.example.com/'
)
or explain(
\%h,
'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test2.example.com/', '' )
);
count(3);
done_testing( count() ); done_testing( count() );
clean(); clean();
...@@ -34,7 +34,6 @@ count(4); ...@@ -34,7 +34,6 @@ count(4);
ok( $res = $client->_get( '/', undef, undef, "lemonldap=$sessionId" ), ok( $res = $client->_get( '/', undef, undef, "lemonldap=$sessionId" ),
'Authentified query' ); 'Authentified query' );
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res->[0], 200 ); ok( $res->[0] == 200, 'Code is 200' ) or explain( $res->[0], 200 );
count(2); count(2);
# Check headers # Check headers
...@@ -49,9 +48,33 @@ count(2); ...@@ -49,9 +48,33 @@ count(2);
ok( $res = $client->_get( '/deny', undef, undef, "lemonldap=$sessionId" ), ok( $res = $client->_get( '/deny', undef, undef, "lemonldap=$sessionId" ),
'Denied query' ); 'Denied query' );
ok( $res->[0] == 403, 'Code is 403' ) or explain( $res->[0], 403 ); ok( $res->[0] == 403, 'Code is 403' ) or explain( $res->[0], 403 );
count(2);
# Required AuthnLevel = 1
ok( $res = $client->_get( '/AuthWeak', undef, undef, "lemonldap=$sessionId" ),
'Weak Authentified query' );
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
count(2); count(2);
# Required AuthnLevel = 5
ok(
$res = $client->_get( '/AuthStrong', undef, undef, "lemonldap=$sessionId" ),
'Strong Authentified query'
);
ok( $res->[0] == 401, 'Code is 401' ) or explain( $res, 401 );
%h = @{ $res->[1] };
ok(
$h{Location} eq 'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test1.example.com/AuthStrong', '' ),
'Redirection points to http://test1.example.com/AuthStrong'
)
or explain(
\%h,
'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test1.example.com/AuthStrong', '' )
);
count(3);
# Bad cookie # Bad cookie
ok( ok(
$res = $client->_get( $res = $client->_get(
...@@ -66,9 +89,38 @@ ok( $res->[0] == 401, 'Code is 401' ) or explain( $res->[0], 401 ); ...@@ -66,9 +89,38 @@ ok( $res->[0] == 401, 'Code is 401' ) or explain( $res->[0], 401 );
unlink( unlink(
't/sessions/lock/Apache-Session-e5eec18ebb9bc96352595e2d8ce962e8ecf7af7c9a98cb9a43f9cd181cf4b545.lock' 't/sessions/lock/Apache-Session-e5eec18ebb9bc96352595e2d8ce962e8ecf7af7c9a98cb9a43f9cd181cf4b545.lock'
); );
count(2);
# Required AuthnLevel = 1
ok(
$res = $client->_get(
'/AuthWeak', undef, 'test2.example.com', "lemonldap=$sessionId"
),
'Weak Authentified query'
);
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
count(2); count(2);
# Required AuthnLevel = 5
ok(
$res =
$client->_get( '/', undef, 'test2.example.com', "lemonldap=$sessionId" ),
'Default Authentified query'
);
ok( $res->[0] == 401, 'Code is 401' ) or explain( $res, 401 );
%h = @{ $res->[1] };
ok(
$h{Location} eq 'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test2.example.com/', '' ),
'Redirection points to http://test2.example.com/'
)
or explain(
\%h,
'http://auth.example.com//upgradesession?url='
. encode_base64( 'http://test2.example.com/', '' )
);
count(3);
done_testing( count() ); done_testing( count() );
clean(); clean();
...@@ -41,12 +41,15 @@ ...@@ -41,12 +41,15 @@
"default": "$uid eq \"dwho\"" "default": "$uid eq \"dwho\""
}, },
"test1.example.com": { "test1.example.com": {
"^/AuthStrong(?#AuthnLevel=5)": "accept",
"^/AuthWeak(?#AuthnLevel=1)": "accept",
"^/logout": "logout_sso", "^/logout": "logout_sso",
"^/deny": "deny", "^/deny": "deny",
"^/user_(\\w+)/": "$uid eq $_rulematch[1]", "^/user_(\\w+)/": "$uid eq $_rulematch[1]",
"default": "accept" "default": "accept"
}, },
"test2.example.com": { "test2.example.com": {
"^/AuthWeak(?#AuthnLevel=1)": "accept",
"^/logout": "logout_sso", "^/logout": "logout_sso",
"default": "accept" "default": "accept"
}, },
...@@ -61,5 +64,10 @@ ...@@ -61,5 +64,10 @@
"portal": "http://auth.example.com/", "portal": "http://auth.example.com/",
"reloadUrls": {}, "reloadUrls": {},
"userDB": "Demo", "userDB": "Demo",
"vhostOptions": {
"test2.example.com": {
"vhostAuthnLevel": 5
}
},
"whatToTrace": "_whatToTrace" "whatToTrace": "_whatToTrace"
} }
...@@ -1254,6 +1254,9 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][ ...@@ -1254,6 +1254,9 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'default' => 3, 'default' => 3,
'type' => 'int' 'type' => 'int'
}, },
'forceGlobalStorageIssuerOTT' => {
'type' => 'bool'
},
'forceGlobalStorageUpgradeOTT' => { 'forceGlobalStorageUpgradeOTT' => {
'type' => 'bool' 'type' => 'bool'
}, },
...@@ -3032,10 +3035,6 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.] ...@@ -3032,10 +3035,6 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
}, },
'type' => 'file' 'type' => 'file'
}, },
'samlIdPResolveCookie' => {
'default' => 'lemonldapidp',
'type' => 'text'
},
'samlIDPSSODescriptorArtifactResolutionServiceArtifact' => { 'samlIDPSSODescriptorArtifactResolutionServiceArtifact' => {
'default' => 'default' =>
'1;0;urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/artifact', '1;0;urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/artifact',
......
...@@ -553,6 +553,11 @@ sub attributes { ...@@ -553,6 +553,11 @@ sub attributes {
documentation => documentation =>
'Avoid asking confirmation when an Issuer asks to renew auth', 'Avoid asking confirmation when an Issuer asks to renew auth',
}, },
forceGlobalStorageIssuerOTT => {
type => 'bool',