Commit 46ee6389 authored by Christophe Maudoux's avatar Christophe Maudoux

Merge branch 'v2.0'

parents 622df5b5 e41be10a
......@@ -120,7 +120,7 @@ sub defaultValues {
'logoutServices' => {},
'macros' => {},
'mail2fActivation' => 0,
'mail2fCodeRegex' => '\\d\\d\\d\\d\\d\\d',
'mail2fCodeRegex' => '\\d{6}',
'mailCharset' => 'utf-8',
'mailFrom' => 'noreply@example.com',
'mailSessionKey' => 'mail',
......
......@@ -27,10 +27,11 @@ sub set_header_in {
sub unset_header_in {
my ( $class, $req, $header ) = @_;
$req->{respHeaders} = [ grep { $_ ne $header } @{ $req->{respHeaders} } ];
$req->{respHeaders} = [ grep { $_ ne $header and $_ ne cgiName($header) }
@{ $req->{respHeaders} } ];
delete $req->{env}->{ cgiName($header) };
$header =~ s/-/_/g;
delete $req->{env}->{$header};
delete $req->{env}->{"HTTP_$header"};
}
# Inheritence is broken in this case with Debian >= jessie
......
......@@ -67,11 +67,8 @@ sub handler {
my ( $self, $req ) = @_;
my $hdrs = $req->{respHeaders};
$req->{respHeaders} = [];
my $cookie = $req->env->{HTTP_COOKIE};
my $cn = $self->Lemonldap::NG::Handler::Main::tsv->{cookieName};
$cookie =~ s/\b$cn(http)?=[^,;]*[,;\s]*//og;
my @convertedHdrs =
( 'Content-Length' => 0, Cookie => ( $cookie // '' ) );
( 'Content-Length' => 0, Cookie => ( $req->env->{HTTP_COOKIE} // '' ) );
my $i = 0;
while ( my $k = shift @$hdrs ) {
my $v = shift @$hdrs;
......
......@@ -8,17 +8,17 @@ sub types {
'array' => {
'test' => sub {
1;
}
}
},
'authParamsText' => {
'test' => sub {
1;
}
}
},
'blackWhiteList' => {
'test' => sub {
1;
}
}
},
'bool' => {
'msgFail' => '__notABoolean__',
......@@ -36,17 +36,17 @@ sub types {
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'catAndAppList' => {
'test' => sub {
1;
}
}
},
'file' => {
'test' => sub {
1;
}
}
},
'hostname' => {
'form' => 'text',
......@@ -80,48 +80,48 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
if $_ =~ /exportedvars$/i and defined $conf->{$_}{$val};
}
return 1, "__unknownAttrOrMacro__: $val";
}
}
},
'longtext' => {
'test' => sub {
1;
}
}
},
'menuApp' => {
'test' => sub {
1;
}
}
},
'menuCat' => {
'test' => sub {
1;
}
}
},
'oidcmetadatajson' => {
'test' => sub {
1;
}
}
},
'oidcmetadatajwks' => {
'test' => sub {
1;
}
}
},
'oidcOPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'oidcRPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'password' => {
'msgFail' => '__malformedValue__',
'test' => sub {
1;
}
}
},
'pcre' => {
'form' => 'text',
......@@ -132,7 +132,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
}
};
return $@ ? ( 0, "__badRegexp__: $@" ) : 1;
}
}
},
'PerlModule' => {
'form' => 'text',
......@@ -142,17 +142,17 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
'portalskin' => {
'test' => sub {
1;
}
}
},
'portalskinbackground' => {
'test' => sub {
1;
}
}
},
'post' => {
'test' => sub {
1;
}
}
},
'RSAPrivateKey' => {
'test' => sub {
......@@ -160,7 +160,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?(?:Proc-Type:.*\r?\nDEK-Info:.*\r?\n[\r\n]*)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:RSA\s+)PRIVATE\s+KEY\s*\-+)?[\r\n]*)?$]s
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'RSAPublicKey' => {
'test' => sub {
......@@ -168,7 +168,7 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?(?:Proc-Type:.*\r?\n
m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+PUBLIC\s+KEY\s*\-+)?[\r\n]*)?$]s
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'RSAPublicKeyOrCertificate' => {
'test' => sub {
......@@ -176,37 +176,37 @@ m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\
m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+)?[\r\n]*)?$]s
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'rule' => {
'test' => sub {
1;
}
}
},
'samlAssertion' => {
'test' => sub {
1;
}
}
},
'samlAttribute' => {
'test' => sub {
1;
}
}
},
'samlIDPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'samlService' => {
'test' => sub {
1;
}
}
},
'samlSPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'select' => {
'test' => sub {
......@@ -216,19 +216,19 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\
return $test
? 1
: ( 1, "Invalid value '$_[0]' for this select" );
}
}
},
'subContainer' => {
'keyTest' => qr/\w/,
'test' => sub {
1;
}
}
},
'text' => {
'msgFail' => '__malformedValue__',
'test' => sub {
1;
}
}
},
'trool' => {
'msgFail' => '__authorizedValues__: -1, 0, 1',
......@@ -1058,7 +1058,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'type' => 'keyTextContainer'
},
......@@ -1231,7 +1231,7 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
and defined $conf->{$_}{$val};
}
return 1, "__unknownAttrOrMacro__: $val";
}
}
},
'type' => 'doubleHash'
},
......@@ -1518,7 +1518,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'type' => 'ruleContainer'
},
......@@ -1573,7 +1573,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'type' => 'longtext'
},
'mail2fCodeRegex' => {
'default' => '\\d\\d\\d\\d\\d\\d',
'default' => '\\d{6}',
'type' => 'pcre'
},
'mail2fLogo' => {
......@@ -3095,19 +3095,19 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => 0,
'select' => [
{
'k' => 0,
'k' => '0',
'v' => 'unsecuredCookie'
},
{
'k' => 1,
'k' => '1',
'v' => 'securedCookie'
},
{
'k' => 2,
'k' => '2',
'v' => 'doubleCookie'
},
{
'k' => 3,
'k' => '3',
'v' => 'doubleCookieForSingleSession'
}
],
......
......@@ -1319,7 +1319,7 @@ sub attributes {
},
mail2fCodeRegex => {
type => 'pcre',
default => '\d\d\d\d\d\d',
default => '\d{6}',
documentation => 'Regular expression to create a mail OTP code',
},
mail2fTimeout => {
......
......@@ -509,6 +509,7 @@ sub tree {
'upgradeSession',
{ title => 'portalServers',
help => 'portalservers.html',
form => 'simpleInputContainer',
nodes => [
'wsdlServer',
'restSessionServer',
......@@ -516,7 +517,6 @@ sub tree {
'soapSessionServer',
'soapConfigServer',
'exportedAttr',
]
},
{ title => 'loginHistory',
......
......@@ -678,8 +678,6 @@ llapp.controller 'TreeCtrl', [
else
node.data = data.value
# Cast int as int (remember that booleans are int for Perl)
#if node.type and node.type.match /^(bool|trool|boolOrExpr)$/
#node.data = node.data.toString()
if node.type and node.type.match /^int$/
node.data = parseInt(node.data, 10)
# Split SAML types
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -147,11 +147,13 @@ site/coffee/confirm.coffee
site/coffee/idpchoice.coffee
site/coffee/info.coffee
site/coffee/kerberos.coffee
site/coffee/kerberosChoice.coffee
site/coffee/oidcchecksession.coffee
site/coffee/portal.coffee
site/coffee/redirect.coffee
site/coffee/registerbrowser.coffee
site/coffee/ssl.coffee
site/coffee/sslChoice.coffee
site/coffee/totpregistration.coffee
site/coffee/u2fcheck.coffee
site/coffee/u2fregistration.coffee
......@@ -265,6 +267,8 @@ site/htdocs/static/common/js/info.js
site/htdocs/static/common/js/info.min.js
site/htdocs/static/common/js/kerberos.js
site/htdocs/static/common/js/kerberos.min.js
site/htdocs/static/common/js/kerberosChoice.js
site/htdocs/static/common/js/kerberosChoice.min.js
site/htdocs/static/common/js/oidcchecksession.js
site/htdocs/static/common/js/oidcchecksession.min.js
site/htdocs/static/common/js/portal.js
......@@ -275,6 +279,8 @@ site/htdocs/static/common/js/registerbrowser.js
site/htdocs/static/common/js/registerbrowser.min.js
site/htdocs/static/common/js/ssl.js
site/htdocs/static/common/js/ssl.min.js
site/htdocs/static/common/js/sslChoice.js
site/htdocs/static/common/js/sslChoice.min.js
site/htdocs/static/common/js/totpregistration.js
site/htdocs/static/common/js/totpregistration.min.js
site/htdocs/static/common/js/u2f-api.js
......@@ -356,6 +362,7 @@ site/templates/bootstrap/samlSpSoapLogout.tpl
site/templates/bootstrap/sessionArray.tpl
site/templates/bootstrap/simpleInfo.tpl
site/templates/bootstrap/sslform.tpl
site/templates/bootstrap/sslformChoice.tpl
site/templates/bootstrap/standardform.tpl
site/templates/bootstrap/totp2fcheck.tpl
site/templates/bootstrap/totp2fregister.tpl
......
......@@ -2,9 +2,10 @@ package Lemonldap::NG::Portal::Auth::Choice;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_FIRSTACCESS);
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_FIRSTACCESS PE_ERROR);
use Data::Dumper;
our $VERSION = '2.0.0';
our $VERSION = '2.0.2';
extends 'Lemonldap::NG::Portal::Lib::Choice';
......@@ -25,12 +26,37 @@ sub _authCancel {
sub extractFormInfo {
my ( $self, $req ) = @_;
unless ( $self->checkChoice($req) ) {
$self->logger->debug("Initializing Auth modules...");
foreach my $mod ( values %{ $self->modules } ) {
if ( $mod->{AjaxInitScript} ) {
$self->logger->debug(
'Append ' . $mod->{Name} . ' init/script' )
if $mod->{Name};
$req->data->{customScript} .= $mod->AjaxInitScript;
}
if ( $mod->{InitCmd} ) {
$self->logger->debug(
'Launch ' . $mod->{Name} . ' init command' )
if $mod->{Name};
my $res = eval( $mod->{InitCmd} );
if ($@) {
$self->logger("Auth error: $@");
return PE_ERROR;
}
}
}
$self->logger->debug("@@@@ Req -> " . Dumper($req) );
foreach my $mod ( values %{ $self->modules } ) {
if ( $mod->can('setSecurity') ) {
$mod->setSecurity($req);
last;
}
}
$self->logger->debug(
"Send init/script -> " . $req->data->{customScript} )
if $req->data->{customScript};
return PE_FIRSTACCESS;
}
my $res = $req->data->{enabledMods0}->[0]->extractFormInfo($req);
......
......@@ -139,6 +139,8 @@ sub getDisplayType {
sub authLogout {
my ( $self, $req ) = @_;
$self->getStack( $req, 'extractFormInfo' ) or return PE_ERROR;
# Avoid warning msg at first access
$req->userData->{_combinationTry} ||= '';
my ( $res, $name ) =
$req->data->{combinationStack}->[ $req->userData->{_combinationTry} ]
->[0]->( 'authLogout', $req );
......
......@@ -7,7 +7,6 @@ use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADCREDENTIALS
PE_ERROR
PE_FIRSTACCESS
PE_FORMEMPTY
PE_NOTOKEN
PE_OK
......
......@@ -5,18 +5,24 @@ use Mouse;
use GSSAPI;
use MIME::Base64;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADCREDENTIALS
PE_ERROR
PE_FIRSTACCESS
PE_OK
PE_SENDRESPONSE
PE_BADCREDENTIALS
PE_ERROR
PE_FIRSTACCESS
PE_OK
PE_SENDRESPONSE
);
our $VERSION = '2.0.0';
our $VERSION = '2.0.2';
extends 'Lemonldap::NG::Portal::Main::Auth';
has keytab => ( is => 'rw' );
has keytab => ( is => 'rw' );
has AjaxInitScript => ( is => 'rw', default => '' );
has Name => ( is => 'ro', default => 'Kerberos' );
has InitCmd => (
is => 'ro',
default => q@$self->p->setHiddenFormValue( $req, kerberos => 0, '', 0 )@
);
# INITIALIZATION
......@@ -28,6 +34,10 @@ sub init {
return 0;
}
$self->keytab("FILE:$file");
$self->AjaxInitScript( '<script type="text/javascript" src="'
. $self->p->staticPrefix
. '/common/js/kerberosChoice.js"></script>' )
if $self->conf->{krbByJs};
return 1;
}
......@@ -35,8 +45,8 @@ sub extractFormInfo {
my ( $self, $req ) = @_;
if ( $req->data->{_krbUser} ) {
$self->logger->debug(
'Kerberos ticket already validated for ' . $req->data->{_krbUser} );
$self->logger->debug( 'Kerberos ticket already validated for '
. $req->data->{_krbUser} );
return PE_OK;
}
......@@ -51,10 +61,8 @@ sub extractFormInfo {
# Case 1.1: Ajax request
if ( $req->wantJSON ) {
$req->response(
[
401,
[
'WWW-Authenticate' => 'Negotiate',
[ 401,
[ 'WWW-Authenticate' => 'Negotiate',
'Content-Type' => 'application/json',
'Content-Length' => 35
],
......@@ -67,7 +75,8 @@ sub extractFormInfo {
# dialog
else {
$req->error(PE_BADCREDENTIALS);
push @{ $req->respHeaders }, 'WWW-Authenticate' => 'Negotiate';
push @{ $req->respHeaders },
'WWW-Authenticate' => 'Negotiate';
my ( $tpl, $prms ) = $self->p->display($req);
$req->response(
$self->p->sendHtml(
......@@ -80,10 +89,10 @@ sub extractFormInfo {
return PE_SENDRESPONSE;
}
# Case 2: Ajax Kerberos request has failed, and javascript has reloaded
# page with "kerberos=0". Return an error to be able to switch to
# another backend (Combination)
# switch to another backend
# Case 2: Ajax Kerberos request has failed, and javascript has reloaded
# page with "kerberos=0". Return an error to be able to switch to
# another backend (Combination)
# switch to another backend
elsif ( defined $req->param('kerberos') ) {
$self->userLogger->warn(
'Kerberos authentication has failed, back to portal');
......@@ -93,12 +102,18 @@ sub extractFormInfo {
# Case 3: Display kerberos auth page (with javascript)
else {
$self->logger->debug('Send Kerberos javascript');
$req->data->{customScript} .=
'<script type="text/javascript" src="'
. $self->p->staticPrefix
. '/common/js/kerberos.js"></script>';
$self->p->setHiddenFormValue( $req, kerberos => 0, '', 0 );
$self->logger->debug( 'Append ' . $self->Name . ' init/script' );
# Call kerberos.js if Kerberos is the only Auth module
# kerberosChoice.js is used by Choice
$self->{AjaxInitScript} =~ s/kerberosChoice/kerberos/;
$req->data->{customScript} .= $self->{AjaxInitScript};
$self->logger->debug(
"Send init/script -> " . $req->data->{customScript} );
#$self->p->setHiddenFormValue( $req, kerberos => 0, '', 0 );
eval( $self->InitCmd );
die 'Unable to launch init commmand ' . $self->{InitCmd} if ($@);
return PE_FIRSTACCESS;
}
}
......
......@@ -3,19 +3,27 @@ package Lemonldap::NG::Portal::Auth::SSL;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADCERTIFICATE
PE_CERTIFICATEREQUIRED
PE_FIRSTACCESS
PE_OK
PE_BADCERTIFICATE
PE_CERTIFICATEREQUIRED
PE_FIRSTACCESS
PE_OK
);
our $VERSION = '2.0.1';
our $VERSION = '2.0.2';
extends 'Lemonldap::NG::Portal::Main::Auth';
# INITIALIZATION
has AjaxInitScript => ( is => 'rw', default => '' );
has Name => ( is => 'ro', default => 'SSL' );
sub init {
my ($self) = @_;
$self->AjaxInitScript( '<script type="application/init">{"sslHost":"'
. $self->conf->{sslHost}
. '"}</script>' )
if $self->conf->{sslByAjax};
return 1;
}
......@@ -25,13 +33,14 @@ sub extractFormInfo {
my ( $self, $req ) = @_;
my $field = $self->conf->{SSLVar};
if ( $req->env->{SSL_CLIENT_I_DN}
and my $tmp =
$self->conf->{SSLVarIf}->{ $req->env->{SSL_CLIENT_I_DN} } )
and my $tmp
= $self->conf->{SSLVarIf}->{ $req->env->{SSL_CLIENT_I_DN} } )
{
$field = $tmp;
}
if ( $req->user( $req->env->{$field} ) ) {
$self->userLogger->notice( "GoodSSL authentication for " . $req->user );
$self->userLogger->notice(
"GoodSSL authentication for " . $req->user );
return PE_OK;
}
elsif ( $req->env->{SSL_CLIENT_S_DN} ) {
......@@ -39,14 +48,20 @@ sub extractFormInfo {
return PE_BADCERTIFICATE;
}
elsif ( $self->conf->{sslByAjax} and not $req->param('nossl') ) {
$self->logger->debug('Send SSL javascript');
$req->data->{customScript} .=
'<script type="application/init">{"sslHost":"'
. $self->conf->{sslHost}
. '"}</script>';
$self->logger->debug( 'Append ' . $self->{Name} . ' init/script' );
$req->data->{customScript} .= $self->{AjaxInitScript};
$self->logger->debug(
"Send init/script -> " . $req->data->{customScript} );
return PE_FIRSTACCESS;
}
else {
if ( $self->conf->{sslByAjax} ) {
$self->logger->debug(
'Append ' . $self->{Name} . ' init/script' );
$req->data->{customScript} .= $self->{AjaxInitScript};
$self->logger->debug(
"Send init/script -> " . $req->data->{customScript} );
}
$self->userLogger->warn('No certificate found');
return PE_CERTIFICATEREQUIRED;
}
......
......@@ -460,7 +460,9 @@ sub buildHiddenForm {
if $self->checkXSSAttack( $_, $req->{portalHiddenFormValues}->{$_} );
# Build hidden input HTML code
$val .= qq{<input type="hidden" name="$_" id="$_" value="}
# 'id' is removed to avoid warning with Choice
#$val .= qq{<input type="hidden" name="$_" id="$_" value="}
$val .= qq{<input type="hidden" name="$_" value="}
. $req->{portalHiddenFormValues}->{$_} . '" />';
}
......
......@@ -607,7 +607,7 @@ sub autoPost {
# Add element into $self->{portalHiddenFormValues}, those values could be
# used to hide values into HTML form.
# @param fieldname The field name which will contain the correponding value
# @param fieldname The field name which will contain the corresponding value
# @param value The associated value
# @param prefix Prefix of the field key
# @param base64 Encode value in base64
......
# Launch Kerberos request
$(document).ready ->
$.ajax portal + '?kerberos=1',
dataType: 'json'
# Called if browser can't find Kerberos ticket, will display
# PE_BADCREDENTIALS
statusCode:
401: () ->
$('#lformKerberos').submit()
# If request succeed cookie is set, posting form to get redirection
# or menu
success: (data) ->
$('#lformKerberos').submit()
# Case else, will display PE_BADCREDENTIALS or fallback to next auth
# backend
error: () ->
$('#lformKerberos').submit()
# Launch SSL request
tryssl = () ->
console.log 'Call URL -> ', window.datas.sslHost
$.ajax window.datas.sslHost,
dataType: 'json'
# Called if browser can't find Kerberos ticket will display
# PE_BADCREDENTIALS
statusCode: