Merge branch 'v2.0'

This commit is contained in:
Christophe Maudoux 2019-09-18 21:13:42 +02:00
commit 52be87b012
31 changed files with 94 additions and 57 deletions

View File

@ -5,6 +5,11 @@
# ~/CN=(?<CN>[^/]+) $CN;
#}
# FastCGI backend definition
upstream llng_portal_upstream {
server unix:__FASTCGISOCKDIR__/llng-fastcgi.sock;
}
server {
listen __PORT__;
server_name auth.__DNSDOMAIN__;
@ -30,7 +35,7 @@ server {
# FastCGI configuration
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:__FASTCGISOCKDIR__/llng-fastcgi.sock;
fastcgi_pass llng_portal_upstream;
fastcgi_param LLTYPE psgi;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_split_path_info ^(.*\.psgi)(/.*)$;
@ -47,6 +52,30 @@ server {
# Uncomment this if you use Auth SSL:
#uwsgi_param SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn;
# REST/SOAP functions for sessions management (disabled by default)
location ~ ^/index.psgi/adminSessions {
fastcgi_pass llng_portal_upstream;
deny all;
}
# REST/SOAP functions for sessions access (disabled by default)
location ~ ^/index.psgi/sessions {
fastcgi_pass llng_portal_upstream;
deny all;
}
# REST/SOAP functions for configuration access (disabled by default)
location ~ ^/index.psgi/config {
fastcgi_pass llng_portal_upstream;
deny all;
}
# REST/SOAP functions for notification insertion (disabled by default)
location ~ ^/index.psgi/notification {
fastcgi_pass llng_portal_upstream;
deny all;
}
}
index index.psgi;
@ -61,26 +90,6 @@ server {
alias __PORTALSTATICDIR__;
}
# REST/SOAP functions for sessions management (disabled by default)
location /index.psgi/adminSessions {
deny all;
}
# REST/SOAP functions for sessions access (disabled by default)
location /index.psgi/sessions {
deny all;
}
# REST/SOAP functions for configuration access (disabled by default)
location /index.psgi/config {
deny all;
}
# REST/SOAP functions for notification insertion (disabled by default)
location /index.psgi/notification {
deny all;
}
# DEBIAN
# If install was made with USEDEBIANLIBS (official releases), uncomment this
#location /javascript/ {

View File

@ -1153,7 +1153,7 @@ lemonldap-ng (1.2.3) stable; urgency=low
urn:/Lemonldap::NG::Common::CGI::SOAPService
* [LEMONLDAP-546] - Form replay: POST request is not sent
* [LEMONLDAP-541] - Handler SOAP errors : setAttributes is not an
authorizated function
authorized function
* [LEMONLDAP-547] - Update Browseable documentation in case of SAML in use
* [LEMONLDAP-565] - Update META.yml files
* [LEMONLDAP-581] - Clean Perl dependencies

View File

@ -98,7 +98,7 @@ Then, go in <code>OpenID parameters</code>:
</li>
<li class="level1"><div class="li"> <strong>Secret token</strong>: used to check integrity of OpenID response.</div>
</li>
<li class="level1"><div class="li"> <strong>Authorizated domain</strong>:</div>
<li class="level1"><div class="li"> <strong>Authorized domain</strong>:</div>
<ul>
<li class="level2"><div class="li"> <strong>List type</strong>: choose white list to define allowed domains or black list to define forbidden domains</div>
</li>

View File

@ -97,7 +97,7 @@ Sessions for connected users <em>(used by <a href="authproxy.html" class="wikili
Authorizations for connected users (always enabled):
</p>
<ul>
<li class="level1"><div class="li"> GET /mysession/?authorizationfor=&lt;base64-encoded-url&gt;: ask if url is authorizated</div>
<li class="level1"><div class="li"> GET /mysession/?authorizationfor=&lt;base64-encoded-url&gt;: ask if url is authorized</div>
</li>
</ul>

View File

@ -98,7 +98,7 @@ To configure sessions, go in Manager, <code>General Parameters</code> » <code>S
<h1 class="sectionedit2" id="command-line_tools">Command-line tools</h1>
<div class="level1">
<ul>
<li class="level1"><div class="li"> LLNG Portal provides a simple tool to delete a session: <code>llngDeleteSession</code>. To use it, simply give it the user identifier <em>(wildcard are authorizated)</em>:</div>
<li class="level1"><div class="li"> LLNG Portal provides a simple tool to delete a session: <code>llngDeleteSession</code>. To use it, simply give it the user identifier <em>(wildcard are authorized)</em>:</div>
</li>
</ul>
<pre class="code shell"># Delete all sessions opened by user &quot;dwho&quot;

View File

@ -68,7 +68,7 @@ SOAP functions are not accessible by network by default. SOAP functions are prot
</li>
<li class="level2"><div class="li"> <strong>isAuthorizedURI(cookieValue,url)</strong>: check if user is granted to access to the function</div>
</li>
<li class="level2"><div class="li"> <strong>getMenuApplications(cookieValue)</strong>: return a list of authorizated applications (based on menu calculation)</div>
<li class="level2"><div class="li"> <strong>getMenuApplications(cookieValue)</strong>: return a list of authorized applications (based on menu calculation)</div>
</li>
</ul>
</li>

View File

@ -11,8 +11,8 @@ our $VERSION = '2.1.0';
## @cmethod Lemonldap::NG::Common::PSGI::SOAPService new(object obj,string @func)
# Constructor
# @param $obj object which will be called for SOAP authorizated methods
# @param @func authorizated methods
# @param $obj object which will be called for SOAP authorized methods
# @param @func authorized methods
# @return Lemonldap::NG::Common::PSGI::SOAPService object
sub new {
my ( $class, $obj, $req, @func ) = @_;
@ -24,7 +24,7 @@ sub new {
# Call the wanted function with the object given to the constructor.
# AUTOLOAD() is a magic method called by Perl interpreter fon non existent
# functions. Here, we use it to call the wanted function (given by $AUTOLOAD)
# if it is authorizated
# if it is authorized
# @return data provided by the exported function
sub AUTOLOAD {
my $self = shift;

View File

@ -96,6 +96,7 @@ sub set_custom {
sub set_header_in {
my ( $class, $request, %headers ) = @_;
while ( my ( $h, $v ) = each %headers ) {
utf8::downgrade($v);
$request->env->{'psgi.r'}->headers_in->set( $h => $v );
}
}

View File

@ -29,7 +29,7 @@ count(4);
# Authentified queries
# --------------------
# Authorizated query
# Authorized query
ok( $res = $client->_get( '/', undef, undef, "lemonldap=$sessionId" ),
'Authentified query' );
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res->[0], 200 );

View File

@ -19,7 +19,7 @@ ok(
'test3.example.com', "lemonldap=$sessionId",
VHOSTTYPE => 'DevOps'
),
'Authorizated query'
'Authorized query'
);
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res->[0], 200 );
count(2);
@ -30,7 +30,7 @@ ok(
'test3.example.com', "lemonldap=$sessionId",
VHOSTTYPE => 'DevOps'
),
'Authorizated query'
'Authorized query'
);
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res->[0], 200 );
count(2);

View File

@ -32,7 +32,7 @@ count(4);
# Authentified queries
# --------------------
# Authorizated query
# Authorized query
ok(
$res =
$client->_get( '/', undef, 'test.example.org', "lemonldap=$sessionId" ),

View File

@ -498,7 +498,7 @@ EOF
printf STDERR $format, $self->handlerStatusConstantsFile;
# Handler Status file
my $content = <<EOF;
$content = <<EOF;
# This file is generated by $module. Don't modify it by hand
package Lemonldap::NG::Handler::Lib::StatusConstants;

View File

@ -91,7 +91,6 @@ sub tree {
'passwordPolicyMinUpper',
'passwordPolicyMinDigit',
'portalDisplayPasswordPolicy',
'portalDisplayGeneratePassword',
]
},
{
@ -660,7 +659,9 @@ sub tree {
title => 'mailOther',
form => 'simpleInputContainer',
nodes => [
'mailUrl', 'mailTimeout',
'mailUrl',
'mailTimeout',
'portalDisplayGeneratePassword',
'randomPasswordRegexp',
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -301,12 +301,18 @@ sub run {
}
# Delete TOTP 2F device
my $TOTPName;
foreach (@$_2fDevices) {
$TOTPName = $_->{name} if $_->{epoch} eq $epoch;
}
@$_2fDevices = grep { $_->{epoch} ne $epoch } @$_2fDevices;
$self->logger->debug(
"Delete 2F Device : { type => 'TOTP', epoch => $epoch }");
"Delete 2F Device : { type => 'TOTP', epoch => $epoch, name => $TOTPName }"
);
$self->p->updatePersistentSession( $req,
{ _2fDevices => to_json($_2fDevices) } );
$self->userLogger->notice('TOTP deletion succeed');
$self->userLogger->notice(
"TOTP $TOTPName unregistration succeeds for $user");
return [
200,
[ 'Content-Type' => 'application/json', 'Content-Length' => 12, ],

View File

@ -288,12 +288,18 @@ sub run {
}
# Delete U2F device
my $keyName;
foreach (@$_2fDevices) {
$keyName = $_->{name} if $_->{epoch} eq $epoch;
}
@$_2fDevices = grep { $_->{epoch} ne $epoch } @$_2fDevices;
$self->logger->debug(
"Delete 2F Device : { type => 'U2F', epoch => $epoch }");
"Delete 2F Device : { type => 'U2F', epoch => $epoch, name => $keyName }"
);
$self->p->updatePersistentSession( $req,
{ _2fDevices => to_json($_2fDevices) } );
$self->userLogger->notice('U2F key unregistration succeed');
$self->userLogger->notice(
"U2F key $keyName unregistration succeeds for $user");
return [
200,
[ 'Content-Type' => 'application/json', 'Content-Length' => 12, ],

View File

@ -181,12 +181,18 @@ sub run {
}
# Delete Yubikey device
my $UBKName;
foreach (@$_2fDevices) {
$UBKName = $_->{name} if $_->{epoch} eq $epoch;
}
@$_2fDevices = grep { $_->{epoch} ne $epoch } @$_2fDevices;
$self->logger->debug(
"Delete 2F Device : { type => 'UBK', epoch => $epoch }");
"Delete 2F Device : { type => 'UBK', epoch => $epoch, name => $UBKName }"
);
$self->p->updatePersistentSession( $req,
{ _2fDevices => to_json($_2fDevices) } );
$self->userLogger->notice('Yubikey deletion succeed');
$self->userLogger->notice(
"Yubikey $UBKName unregistration succeeds for $user");
return [
200,
[ 'Content-Type' => 'application/json', 'Content-Length' => 12, ],

View File

@ -255,7 +255,7 @@ sub run {
unless ( $rule->( $req, $req->sessionInfo ) ) {
$self->userLogger->warn( 'User '
. $req->sessionInfo->{ $self->conf->{whatToTrace} }
. "was not authorized to access to $rp" );
. " was not authorized to access to $rp" );
return PE_UNAUTHORIZEDPARTNER;
}
}

View File

@ -388,7 +388,7 @@ sub run {
unless ( $rule->( $req, $req->sessionInfo ) ) {
$self->userLogger->warn( 'User '
. $req->sessionInfo->{ $self->conf->{whatToTrace} }
. "was not authorizated to access to $sp" );
. " was not authorized to access to $sp" );
return PE_UNAUTHORIZEDPARTNER;
}
}

View File

@ -291,7 +291,12 @@ sub display {
# 3 Authentication has been refused OR first access
$skinfile = 'login';
my $login = $self->userId($req);
$login = '' if ( $login eq 'anonymous' );
if ( $login eq 'anonymous' ) {
$login = '';
}
elsif ( $req->user ) {
$login = $req->{user};
}
%templateParams = (
AUTH_ERROR => $req->error,
AUTH_ERROR_TYPE => $req->error_type,

View File

@ -509,6 +509,9 @@ sub buildCookie {
);
}
}
$self->userLogger->notice(
"User $req->{user} successfully authenticated at level $req->{sessionInfo}->{authenticationLevel}"
);
PE_OK;
}

View File

@ -36,7 +36,7 @@
# - Authorizations for connected users (always):
# * GET /mysession/?whoami : get "my" uid
# * GET /mysession/?authorizationfor=<base64-encoded-url>: ask if url is
# authorizated
# authorized
# * PUT /mysession/<type> : update some
# persistent data
# (restricted)

View File

@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
/*
LemonLDAP::NG TOTP registration script

View File

@ -117,7 +117,7 @@ m#iframe src="http://auth.idp.com(/saml/relaySingleLogoutPOST)\?(relay=.*?)"#s,
ok(
getHeader( $res, 'Content-Security-Policy' ) =~
/child-src auth.idp.com/,
' Frame is authorizated'
' Frame is authorized'
)
or explain( $res->[1],
'Content-Security-Policy => ...child-src auth.idp.com' );
@ -132,7 +132,7 @@ m#iframe src="http://auth.idp.com(/saml/relaySingleLogoutPOST)\?(relay=.*?)"#s,
'Get iframe'
);
ok( getHeader( $res, 'Content-Security-Policy' ) !~ /frame-ancestors/,
' Framing authorizated' )
' Framing authorized' )
or explain( $res->[1], 'No frame-ancestors' );
( $host, $url, $query ) =
expectAutoPost( $res, 'auth.sp.com', '/saml/proxySingleLogout',

View File

@ -126,7 +126,7 @@ m#iframe src="http://auth.sp.com(/saml/proxySingleLogout)\?(SAMLRequest=.*?)"#,
my $query = $2;
ok(
getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.sp.com/,
'Frame is authorizated'
'Frame is authorized'
)
or explain( $res->[1],
'Content-Security-Policy => ...child-src auth.idp.com' );

View File

@ -209,7 +209,7 @@ count(1);
my $url = $1;
$query = $2;
ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/,
'Frame is authorizated' )
'Frame is authorized' )
or
explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' );
count(1);

View File

@ -209,7 +209,7 @@ count(1);
my $url = $1;
$query = $2;
ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/,
'Frame is authorizated' )
'Frame is authorized' )
or
explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' );
count(1);

View File

@ -177,7 +177,7 @@ count(1);
my $url = $1;
$query = $2;
ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/,
'Frame is authorizated' )
'Frame is authorized' )
or
explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' );
count(1);

View File

@ -169,7 +169,7 @@ count(1);
my $url = $1;
$query = $2;
ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/,
'Frame is authorizated' )
'Frame is authorized' )
or
explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' );
count(1);

View File

@ -262,7 +262,7 @@ SKIP: {
ok(
getHeader( $res, 'Content-Security-Policy' ) =~
/child-src auth.idp.com/,
'Frame is authorizated'
'Frame is authorized'
)
or explain( $res->[1],
'Content-Security-Policy => ...child-src auth.idp.com' );