Merge branch 'v2.0'

This commit is contained in:
Yadd 2021-05-13 10:37:41 +02:00
commit ecebe2a349
16 changed files with 321 additions and 32 deletions

View File

@ -141,7 +141,7 @@ sonar-upload:
stage: deploy
image: sonarsource/sonar-scanner-cli
script:
- sonar-scanner
- /usr/bin/entrypoint.sh
only:
variables:
- $SONARJOB == "1"

View File

@ -375,7 +375,7 @@ Import them:
set \
oidcServicePrivateKeySig "`cat oidc.key`" \
oidcServicePublicKeySig "`cat oidc_pub.key`" \
oidcServiceKeyIdSig "`genpasswd`"
oidcServiceKeyIdSig "randomstring"
If needed you can allow implicit and hybrid flows:

View File

@ -92,7 +92,7 @@ run for example each week:
Session management
------------------
LL::NG implements the `OpenID Connect Chance Notification specification <http://openid.net/specs/openid-connect-session-1_0.html#ChangeNotification>`__
LL::NG implements the `OpenID Connect Change Notification specification <http://openid.net/specs/openid-connect-session-1_0.html#ChangeNotification>`__
A ``changed`` state will be sent if the user is disconnected from LL::NG
portal (or has destroyed its SSO cookie). Else the ``unchanged`` state

View File

@ -487,6 +487,7 @@ t/01-Reject-Hashes-in-URL.t
t/01-Unauth-Logout.t
t/02-Password-Demo-Local-noPpolicy.t
t/02-Password-Demo-Local-Ppolicy.t
t/02-Password-Demo-Local-SpeChars-Ppolicy.t
t/02-Password-Demo.t
t/03-ConfTimeout.t
t/03-SessionTimeout.t
@ -571,7 +572,7 @@ t/32-OIDC-Code-Flow-with-2F.t
t/32-OIDC-Hooks.t
t/32-OIDC-Macro.t
t/32-OIDC-Offline-Session.t
t/32-OIDC-Password-Grant-with-Bruteforce.t
t/32-OIDC-Password-Grant-with-Bruteforce-and-Choice.t
t/32-OIDC-Refresh-Token.t
t/32-OIDC-Register.t
t/32-OIDC-RP-rule.t
@ -696,11 +697,13 @@ t/68-FindUser-with-BadChoice-and-token.t
t/68-FindUser-with-Choice-and-token.t
t/68-FindUser-with-Combination.t
t/68-FindUser-with-DBI.t
t/68-FindUser-with-Demo-and-captcha.t
t/68-FindUser-with-Demo-and-required-select.t
t/68-FindUser-with-Demo-and-token.t
t/68-FindUser-with-Demo.t
t/68-FindUser-with-LDAP.t
t/68-FindUser-with-REST.t
t/68-FindUser-with-UpgradeSession.t
t/68-FindUser-without-attribute.t
t/68-FindUser-without-Impersonation.t
t/68-Impersonation-with-2F.t

View File

@ -32,6 +32,8 @@ sub init {
my ($self) = @_;
( my $imp = grep /::Plugins::Impersonation$/, $self->p->enabledPlugins )
? $self->addUnauthRoute( finduser => 'provideUser', ['POST'] )
->addAuthRoute( finduser => 'provideUser',
['POST'] ) # Allow findUser with reAuth
: $self->logger->warn('FindUser plugin enabled without Impersonation');
$self->logger->warn('FindUser plugin enabled without searching attribute')
unless keys %{ $self->conf->{findUserSearchingAttributes} };

View File

@ -36,7 +36,7 @@ sub run {
sub sortByComment {
my $A = ( $a =~ /^.*?##(.*)$/ )[0];
my $B = ( $b =~ /^.*?##(.*)$/ )[0];
return !$A ? 1 : !$B ? -1 : $A cmp $B;
return !( $A or $B ) ? $a cmp $b : !$A ? 1 : !$B ? -1 : $A cmp $B;
}
# Avoid display notification if AuthResult is not null

View File

@ -556,7 +556,7 @@ $(window).on 'load', () ->
event.preventDefault()
document.body.style.cursor = 'progress'
str = $("#finduserForm").serialize()
console.log 'Send findUser request with', str
console.log 'Send findUser request with parameters', str
$.ajax
type: "POST"
url: "#{portal}finduser"
@ -566,7 +566,7 @@ $(window).on 'load', () ->
success: (data) ->
document.body.style.cursor = 'default'
user = data.user
console.log 'Suggested spoofId', user
console.log 'Suggested spoofId=', user
$('#spoofIdfield').attr 'value', user
$('#captcha').attr 'src', data.captcha if data.captcha
if data.token

View File

@ -7,7 +7,6 @@ require 't/test-lib.pm';
my $res;
my $json;
my $request;
my $maintests = 24;
SKIP: {
@ -43,7 +42,7 @@ SKIP: {
my ( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'password', 'spoofId' );
$request = '';
my $request = '';
ok(
$res = $client->_post(
'/finduser', IO::String->new($request),

View File

@ -15,7 +15,6 @@ SKIP: {
}
my $res;
my $json;
my $request;
my $dbh = DBI->connect("dbi:SQLite:dbname=$userdb");
$dbh->do(
'CREATE TABLE users (uid text,password text,cn text,type text,guy text, room text)'
@ -77,7 +76,7 @@ SKIP: {
expectForm( $res, '#', undef, 'user', 'password', 'spoofId' );
( $host, $url, $query ) =
expectForm( $res, '#', undef, 'uid', 'guy', 'cn', 'room' );
$request = '';
my $request = '';
ok(
$res = $client->_post(
'/finduser', IO::String->new($request),

View File

@ -0,0 +1,108 @@
use Test::More;
use strict;
use JSON;
use IO::String;
require 't/test-lib.pm';
my $res;
my $json;
my $ts;
my $captcha;
my $maintests = 16;
SKIP: {
eval 'use GD::SecurityImage;use Image::Magick;';
if ($@) {
skip 'Image::Magick not found', $maintests;
}
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
authentication => 'Demo',
userDB => 'Same',
useSafeJail => 1,
captcha_login_enabled => 1,
findUser => 1,
impersonationRule => 1,
findUserSearchingAttributes =>
{ uid => 'Login', guy => 'Kind', cn => 'Name' }
}
}
);
## Simple access
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Portal', );
my ( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'password', 'spoofId', 'token' );
( $host, $url, $query ) =
expectForm( $res, '#', undef, 'uid', 'guy', 'cn', 'token' );
ok(
$res->[2]->[0] =~
m%<input id="token" type="hidden" name="token" value="([\d_]+?)" />%,
'Token value found'
) or explain( $res->[2]->[0], 'Token value' );
my $count = $res->[2]->[0] =~ s/$1//g;
ok( $count == 2, 'Two token found' )
or explain( $res->[2]->[0], 'Two token found' );
ok( $res->[2]->[0] =~ m#<img id="captcha" src="data:image/png;base64#,
' Captcha image inserted' );
ok(
$res->[2]->[0] =~
m#<img class="renewcaptchaclick" src="/static/common/icons/arrow_refresh.png" alt="Renew Captcha" title="Renew Captcha" class="img-thumbnail mb-3" />#,
' Renew Captcha button found'
) or explain( $res->[2]->[0], 'Renew captcha button not found' );
ok( $res->[2]->[0] =~ /captcha\.(?:min\.)?js/, 'Get captcha javascript' );
## FindUser request
$query =~ s/uid=/uid=rt*/;
ok(
$res = $client->_post(
'/finduser', IO::String->new($query),
accept => 'application/json',
length => length($query)
),
'Post FindUser request'
);
ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' )
or print STDERR "$@\n" . Dumper($res);
ok( $json->{user} eq 'rtyler', ' Good user' )
or explain( $json, 'user => rtyler' );
ok( $json->{token} =~ /\w+/, ' Token found' )
or explain( $json, 'Token renewed' );
ok( $json->{captcha} =~ /^data:image\/png;base64/, ' Captcha found' )
or explain( $json, 'Captcha renewed' );
ok( $json->{result} == 1, ' result => 1' )
or explain( $json, 'Result => 1' );
my $token = $json->{token};
ok( $ts = getCache()->get($token), ' Found token session' );
$ts = eval { JSON::from_json($ts) };
ok( $captcha = $ts->{captcha}, ' Found captcha value' );
## Authentication request
$query =
"user=dwho&password=dwho&spoofId=rtyler&token=$token&captcha=$captcha";
ok(
$res = $client->_post(
'/', IO::String->new($query),
accept => 'application/json',
length => length($query)
),
'Post Auth request with token'
);
my $id = expectCookie($res);
ok(
$res = $client->_get(
'/',
accept => 'text/html',
cookie => "lemonldap=$id",
),
'GET Portal'
);
expectOK($res);
expectAuthenticatedAs( $res, 'rtyler' );
$client->logout($id);
}
count($maintests);
clean_sessions();
done_testing( count() );

View File

@ -9,7 +9,6 @@ my $maintests = 25;
my $res;
my $json;
my $request;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
@ -39,7 +38,7 @@ ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Portal', );
my ( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'password', 'spoofId' );
$request = '';
my $request = '';
ok(
$res = $client->_post(
'/finduser', IO::String->new($request),

View File

@ -74,7 +74,9 @@ ok( $json->{error} == 82, ' Token expired' )
or explain( $json, 'Token expired' );
ok( $json->{result} == 0, ' result => 0' )
or explain( $json, 'Result => 0' );
count(5);
ok( $json->{token} =~ /\w+/, ' Token found' )
or explain( $json, 'Token renewed' );
count(6);
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Portal', );
( $host, $url, $query ) =
@ -94,7 +96,9 @@ ok( $json->{error} == 81, ' No Token' )
or explain( $json, 'No token' );
ok( $json->{result} == 0, ' result => 0' )
or explain( $json, 'Result => 0' );
count(5);
ok( $json->{token} =~ /\w+/, ' Token found' )
or explain( $json, 'Token renewed' );
count(6);
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Portal', );
( $host, $url, $query ) =
@ -115,24 +119,17 @@ ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' )
or print STDERR "$@\n" . Dumper($res);
ok( $json->{result} == 1, ' result => 1' )
or explain( $json, 'Result => 1' );
$query = 'uid=dwho';
ok(
$res = $client->_post(
'/finduser',
IO::String->new($query),
accept => 'application/json',
length => length($query),
cookie => "lemonldap=$id"
$res = $client->_get(
'/',
accept => 'text/html',
cookie => "lemonldap=$id",
),
'Get findUser'
'GET Portal'
);
expectOK($res);
expectAuthenticatedAs( $res, 'rtyler' );
ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' )
or print STDERR "$@\n" . Dumper($res);
ok( $json->{result} == 1, ' result => 1' )
or explain( $json, 'Result => 1' );
count(7);
count(5);
$client->logout($id);
clean_sessions();

View File

@ -0,0 +1,183 @@
use Test::More;
use strict;
use JSON;
use IO::String;
require 't/test-lib.pm';
my $maintests = 14;
my $res;
my $json;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
authentication => 'Choice',
userDB => 'Same',
apacheAuthnLevel => 5,
upgradeSession => 1,
useSafeJail => 1,
requireToken => 0,
findUser => 1,
impersonationRule => 1,
findUserControl => '^[\w*\s]+$',
findUserWildcard => '*',
findUserSearchingAttributes => {
uid => 'User',
},
authChoiceModules => {
strong => 'Apache;Demo;Null;;;{}',
weak => 'Demo;Demo;Null;;;{}'
},
vhostOptions => {
'test1.example.com' => {
vhostAuthnLevel => 3
},
locationRules => {
'test1.example.com' => {
default => 'accept',
},
},
}
}
}
);
use Lemonldap::NG::Portal::Main::Constants 'PE_USERNOTFOUND';
## Simple access
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Portal', );
my ( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'password', 'spoofId' );
my $request = '';
ok(
$res = $client->_post(
'/finduser', IO::String->new($request),
accept => 'text/html',
length => length($request)
),
'Post empty FindUser request'
);
( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'password', 'spoofId' );
( $host, $url, $query ) = expectForm( $res, '#', undef, 'uid' );
ok(
$res->[2]->[0] =~
m%<input id="spoofIdfield" name="spoofId" type="text" class="form-control" value="" autocomplete="off"%,
'value=""'
) or explain( $res->[2]->[0], 'value=""' );
ok(
$res->[2]->[0] =~
m%<input id="findUser_uid" name="uid" type="text" autocomplete="off" class="form-control" placeholder="User" />%,
'id="findUser_uid"'
) or explain( $res->[2]->[0], 'id="findUser_uid"' );
# Try to authenticate
# -------------------
ok(
$res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho&lmAuth=weak'),
length => 35,
accept => 'text/html',
),
'Auth query'
);
my $id = expectCookie($res);
# Portal IS NOT a handler
#########################
ok(
$res = $client->_get(
'/',
accept => 'text/html',
cookie => "lemonldap=$id",
host => 'test1.example.com',
),
'GET http://test1.example.com/'
);
expectOK($res);
# After attempting to access test1,
# the handler sends up back to /upgradesession
# --------------------------------------------
ok(
$res = $client->_get(
'/upgradesession',
query => 'url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29t',
accept => 'text/html',
cookie => "lemonldap=$id",
),
'Upgrade session query'
);
( $host, $url, $query ) =
expectForm( $res, undef, '/upgradesession', 'confirm', 'url' );
# Accept session upgrade
# ----------------------
ok(
$res = $client->_post(
'/upgradesession',
IO::String->new($query),
length => length($query),
accept => 'text/html',
cookie => "lemonldap=$id",
),
'Accept session upgrade query'
);
my $pdata = expectCookie( $res, 'lemonldappdata' );
( $host, $url, $query ) = expectForm( $res, '#', undef, 'upgrading', 'url' );
$request = 'uid=rt*';
ok(
$res = $client->_post(
'/finduser',
IO::String->new($request),
length => length($request),
cookie => "lemonldap=$id;lemonldappdata=$pdata",
custom => {
REMOTE_USER => 'dwho',
},
),
'Post FindUser request'
);
ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' )
or print STDERR "$@\n" . Dumper($res);
ok( $json->{result} == 1, ' Good result' )
or explain( $json, 'result => 1' );
ok( $json->{user} eq 'rtyler', ' Good user' )
or explain( $json, "user => 'rtyler'" );
# Attempt login
$query = $query . "&spoofId=rtyler&lmAuth=strong";
ok(
$res = $client->_post(
'/upgradesession',
IO::String->new($query),
length => length($query),
accept => 'text/html',
cookie => "lemonldap=$id;lemonldappdata=$pdata",
custom => {
REMOTE_USER => 'dwho',
},
),
'Post login'
);
$pdata = expectCookie( $res, 'lemonldappdata' );
$id = expectCookie($res);
expectRedirection( $res, 'http://test1.example.com' );
ok(
$res = $client->_get(
'/',
accept => 'text/html',
cookie => "lemonldap=$id;lemonldappdata=$pdata",
),
'GET Portal'
);
expectOK($res);
expectAuthenticatedAs( $res, 'rtyler' );
count($maintests);
done_testing( count() );

View File

@ -9,7 +9,6 @@ my $maintests = 6;
my $res;
my $json;
my $request;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
@ -35,7 +34,7 @@ ok(
m%<span trspan="searchAccount">Search for an account</span>%,
'Search an account not found'
) or explain( $res->[2]->[0], 'Found search for an account' );
$request = 'uid=dwho';
my $request = 'uid=dwho';
ok(
$res = $client->_post(
'/finduser', IO::String->new($request),

View File

@ -9,7 +9,6 @@ my $maintests = 6;
my $res;
my $json;
my $request;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
@ -34,7 +33,7 @@ ok(
m%<span trspan="searchAccount">Search for an account</span>%,
'Search an account not found'
) or explain( $res->[2]->[0], 'Found search for an account' );
$request = 'uid=dwho';
my $request = 'uid=dwho';
ok(
$res = $client->_post(
'/finduser', IO::String->new($request),

View File

@ -1,5 +1,6 @@
#!/bin/sh
apt update
mk-build-deps --install --remove \
--tool "apt-get -o Debug::pkgProblemResolver=yes -q -y" \
debian/control