Merge branch 'fix-ssl-error-reporting-2110' into 'v2.0'

Fix ssl error reporting (#2110)

See merge request lemonldap-ng/lemonldap-ng!132
This commit is contained in:
Christophe Maudoux 2020-04-17 10:51:42 +02:00
commit 427a0c7f9f
24 changed files with 165 additions and 63 deletions

View File

@ -69,6 +69,7 @@ sub encodings { $_[0]->env->{HTTP_ACCEPT_ENCODING} }
sub languages { $_[0]->env->{HTTP_ACCEPT_LANGUAGE} }
sub authorization { $_[0]->env->{HTTP_AUTHORIZATION} }
sub hostname { $_[0]->env->{HTTP_HOST} }
sub origin { $_[0]->env->{HTTP_ORIGIN} }
sub referer { $_[0]->env->{REFERER} }
sub query_string { $_[0]->env->{QUERY_STRING} }

View File

@ -392,6 +392,7 @@ site/templates/bootstrap/customLoginFooter.tpl
site/templates/bootstrap/customLoginHeader.tpl
site/templates/bootstrap/decryptvalue.tpl
site/templates/bootstrap/error.tpl
site/templates/bootstrap/errormsg.tpl
site/templates/bootstrap/ext2fcheck.tpl
site/templates/bootstrap/footer.tpl
site/templates/bootstrap/globallogout.tpl

View File

@ -31,6 +31,13 @@ sub init {
# @return Lemonldap::NG::Portal constant
sub extractFormInfo {
my ( $self, $req ) = @_;
# If this is the ajax query, allow response to contain HTML code
# to update the portal error message
if ( $req->wantJSON ) {
$req->wantErrorRender(1);
}
my $field = $self->conf->{SSLVar};
if ( $req->env->{SSL_CLIENT_I_DN} ) {
$self->logger->debug(
@ -55,6 +62,12 @@ sub extractFormInfo {
return PE_BADCERTIFICATE;
}
elsif ( $self->conf->{sslByAjax} and not $req->param('nossl') ) {
# If this is the AJAX query
if ( $req->wantJSON ) {
return PE_CERTIFICATEREQUIRED;
}
$self->logger->debug( 'Append ' . $self->{Name} . ' init/script' );
$req->data->{customScript} .= $self->{AjaxInitScript};
$self->logger->debug(
@ -68,6 +81,7 @@ sub extractFormInfo {
$req->data->{customScript} .= $self->{AjaxInitScript};
$self->logger->debug(
"Send init/script -> " . $req->data->{customScript} );
return PE_BADCERTIFICATE;
}
$self->userLogger->warn('No certificate found');
return PE_CERTIFICATEREQUIRED;

View File

@ -80,6 +80,10 @@ has captcha => ( is => 'rw' );
# Token
has token => ( is => 'rw' );
# Whether or not to include a HTML render of the error message
# in error responses
has wantErrorRender => ( is => 'rw' );
# Error type
sub error_type {
my $req = shift;

View File

@ -260,11 +260,25 @@ sub do {
if ( !$self->conf->{noAjaxHook} and $req->wantJSON ) {
$self->logger->debug('Processing to JSON response');
if ( ( $err > 0 and !$req->id ) or $err eq PE_SESSIONNOTGRANTED ) {
return [
401,
[ 'WWW-Authenticate' => "SSO " . $self->conf->{portal} ],
[qq'{"result":0,"error":$err}']
];
my $json = { result => 0, error => $err };
if ( $req->wantErrorRender ) {
$json->{html} = $self->loadTemplate(
$req,
'errormsg',
params => {
AUTH_ERROR => $err,
AUTH_ERROR_TYPE => $req->error_type,
}
);
}
return $self->sendJSONresponse(
$req, $json,
code => 401,
headers => [
'WWW-Authenticate' => "SSO " . $self->conf->{portal},
"Content-Type" => "application/javascript"
],
);
}
elsif ( $err > 0 and $err != PE_PASSWORD_OK and $err != PE_LOGOUT_OK ) {
return $self->sendJSONresponse(
@ -1041,7 +1055,7 @@ sub registerLogin {
}
my $history = $req->sessionInfo->{_loginHistory} ||= {};
my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login';
my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login';
$history->{$type} ||= [];
$self->logger->debug("Current login saved into $type");
@ -1096,7 +1110,19 @@ sub corsPreflight {
sub sendJSONresponse {
my ( $self, $req, $j, %args ) = @_;
my $res = Lemonldap::NG::Common::PSGI::sendJSONresponse(@_);
if ( $self->conf->{corsEnabled} ) {
# If this is a cross-domain request from the portal itself
# (Ajax SSL to a different VHost)
# we allow CORS
if ( $req->origin and index( $self->conf->{portal}, $req->origin ) == 0 ) {
$self->logger->debug('AJAX request from portal, allowing CORS');
push @{ $res->[1] },
"Access-Control-Allow-Origin" => $req->origin,
"Access-Control-Allow-Methods" => "*",
"Access-Control-Allow-Credentials" => "true";
}
elsif ( $self->conf->{corsEnabled} ) {
my @cors = split /;/, $self->cors;
push @{ $res->[1] }, @cors;
$self->logger->debug('Apply following CORS policy :');

View File

@ -227,6 +227,11 @@ datas = {}
$(window).on 'load', () ->
# Get application/init variables
datas = getValues()
# Keep the currently selected tab
if "datas" of window && "choicetab" of window.datas
datas.choicetab = window.datas.choicetab;
# Export datas for other scripts
window.datas = datas

View File

@ -5,12 +5,9 @@ tryssl = () ->
console.log 'path -> ', path
console.log 'Call URL -> ', window.datas.sslHost
$.ajax window.datas.sslHost,
dataType: 'jsonp'
# PE_BADCREDENTIALS
statusCode:
401: () ->
$('#lform').submit()
console.log 'Error code 401'
dataType: 'json',
xhrFields:
withCredentials: true
# If request succeed, cookie is set, posting form to get redirection
# or menu
success: (data) ->
@ -18,9 +15,23 @@ tryssl = () ->
console.log 'Success -> ', data
# Case else, will display PE_BADCREDENTIALS or fallback to next auth
# backend
error: () ->
sendUrl path
console.log 'Error'
error: (result) ->
# If the AJAX query didn't fire at all, it's probably
# a bad certificate
if result.status == 0
# We couldn't send the request.
# if client verification is optional, this means
# the certificate was rejected (or some network error)
sendUrl path
# For compatibility with earlier configs, handle PE9 by posting form
if result.responseJSON && 'error' of result.responseJSON && result.responseJSON.error == "9"
sendUrl path
# If the server sent a html error description, display it
if result.responseJSON && 'html' of result.responseJSON
$('#errormsg').html(result.responseJSON.html);
$(window).trigger('load');
console.log 'Error during AJAX SSL authentication', result
false
sendUrl = (path) ->
@ -34,4 +45,4 @@ sendUrl = (path) ->
$('#lform').submit()
$(document).ready ->
$('.sslclick').on 'click', tryssl
$('.sslclick').on 'click', tryssl

View File

@ -5,12 +5,9 @@ tryssl = () ->
console.log 'path -> ', path
console.log 'Call URL -> ', window.datas.sslHost
$.ajax window.datas.sslHost,
dataType: 'jsonp'
# PE_BADCREDENTIALS
statusCode:
401: () ->
$('#lformSSL').submit()
console.log 'Error code 401'
dataType: 'json',
xhrFields:
withCredentials: true
# If request succeed, cookie is set, posting form to get redirection
# or menu
success: (data) ->
@ -18,9 +15,23 @@ tryssl = () ->
console.log 'Success -> ', data
# Case else, will display PE_BADCREDENTIALS or fallback to next auth
# backend
error: () ->
sendUrl path
console.log 'Error'
error: (result) ->
# If the AJAX query didn't fire at all, it's probably
# a bad certificate
if result.status == 0
# We couldn't send the request.
# if client verification is optional, this means
# the certificate was rejected (or some network error)
sendUrl path
# For compatibility with earlier configs, handle PE9 by posting form
if result.responseJSON && 'error' of result.responseJSON && result.responseJSON.error == "9"
sendUrl path
# If the server sent a html error description, display it
if result.responseJSON && 'html' of result.responseJSON
$('#errormsg').html(result.responseJSON.html);
$(window).trigger('load');
console.log 'Error during AJAX SSL authentication', result
false
sendUrl = (path) ->
@ -34,4 +45,4 @@ sendUrl = (path) ->
$('#lformSSL').submit()
$(document).ready ->
$('.sslclick').on 'click', tryssl
$('.sslclick').on 'click', tryssl

View File

@ -1,4 +1,4 @@
$(document).ready(function() {
$(window).on("load", function() {
// Adapt some class to fit Bootstrap theme
$("div.message-positive").addClass("alert-success");
@ -16,4 +16,9 @@ $(document).ready(function() {
}
});
// Remember selected tab
$('#authMenu .nav-link').on('click', function (e) {
window.datas.choicetab = e.target.hash.substr(1)
});
});

View File

@ -1 +1 @@
$(document).ready(function(){$("div.message-positive").addClass("alert-success"),$("div.message-warning").addClass("alert-warning"),$("div.message-negative").addClass("alert-danger"),$("table.info").addClass("table"),$(".notifCheck").addClass("checkbox"),$('.collapse li[class!="dropdown"]').on("click",function(){$(".navbar-toggler").hasClass("collapsed")||$(".navbar-toggler").trigger("click")})});
$(window).on("load",function(){$("div.message-positive").addClass("alert-success"),$("div.message-warning").addClass("alert-warning"),$("div.message-negative").addClass("alert-danger"),$("table.info").addClass("table"),$(".notifCheck").addClass("checkbox"),$('.collapse li[class!="dropdown"]').on("click",function(){$(".navbar-toggler").hasClass("collapsed")||$(".navbar-toggler").trigger("click")}),$("#authMenu .nav-link").on("click",function(a){window.datas.choicetab=a.target.hash.substr(1)})});

View File

@ -1 +1 @@
{"version":3,"sources":["lemonldap-ng-portal/site/htdocs/static/bootstrap/js/skin.js"],"names":["$","document","ready","addClass","on","hasClass","trigger"],"mappings":"AAAAA,EAAEC,UAAUC,MAAM,WAGhBF,EAAE,wBAAwBG,SAAS,iBACnCH,EAAE,uBAAuBG,SAAS,iBAClCH,EAAE,wBAAwBG,SAAS,gBAEnCH,EAAE,cAAcG,SAAS,SAEzBH,EAAE,eAAeG,SAAS,YAG1BH,EAAE,mCAAmCI,GAAG,QAAS,WAC1CJ,EAAE,mBAAmBK,SAAS,cACjCL,EAAE,mBAAmBM,QAAQ"}
{"version":3,"sources":["lemonldap-ng-portal/site/htdocs/static/bootstrap/js/skin.js"],"names":["$","window","on","addClass","hasClass","trigger","e","datas","choicetab","target","hash","substr"],"mappings":"AAAAA,EAAEC,QAAQC,GAAG,OAAQ,WAGnBF,EAAE,wBAAwBG,SAAS,iBACnCH,EAAE,uBAAuBG,SAAS,iBAClCH,EAAE,wBAAwBG,SAAS,gBAEnCH,EAAE,cAAcG,SAAS,SAEzBH,EAAE,eAAeG,SAAS,YAG1BH,EAAE,mCAAmCE,GAAG,QAAS,WAC1CF,EAAE,mBAAmBI,SAAS,cACjCJ,EAAE,mBAAmBK,QAAQ,WAKjCL,EAAE,uBAAuBE,GAAG,QAAS,SAAUI,GAC3CL,OAAOM,MAAMC,UAAYF,EAAEG,OAAOC,KAAKC,OAAO"}

View File

@ -225,6 +225,9 @@ LemonLDAP::NG Portal jQuery scripts
$(window).on('load', function() {
var action, al, authMenuIndex, authMenuTabs, back_url, i, l, lang, langdiv, langs, langs2, len, len1, len2, len3, link, m, menuIndex, menuTabs, method, n, nl, nlangs, queryLang, queryString, re, ref, ref1, ref2, setCookieLang, urlParams;
datas = getValues();
if ("datas" in window && "choicetab" in window.datas) {
datas.choicetab = window.datas.choicetab;
}
window.datas = datas;
$("#appslist").sortable({
axis: "y",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8,20 +8,26 @@
console.log('path -> ', path);
console.log('Call URL -> ', window.datas.sslHost);
$.ajax(window.datas.sslHost, {
dataType: 'jsonp',
statusCode: {
401: function() {
$('#lform').submit();
return console.log('Error code 401');
}
dataType: 'json',
xhrFields: {
withCredentials: true
},
success: function(data) {
sendUrl(path);
return console.log('Success -> ', data);
},
error: function() {
sendUrl(path);
return console.log('Error');
error: function(result) {
if (result.status === 0) {
sendUrl(path);
}
if (result.responseJSON && 'error' in result.responseJSON && result.responseJSON.error === "9") {
sendUrl(path);
}
if (result.responseJSON && 'html' in result.responseJSON) {
$('#errormsg').html(result.responseJSON.html);
$(window).trigger('load');
}
return console.log('Error during AJAX SSL authentication', result);
}
});
return false;

View File

@ -1 +1 @@
(function(){var t,o;o=function(){var n;return n=window.location.pathname,console.log("path -> ",n),console.log("Call URL -> ",window.datas.sslHost),$.ajax(window.datas.sslHost,{dataType:"jsonp",statusCode:{401:function(){return $("#lform").submit(),console.log("Error code 401")}},success:function(o){return t(n),console.log("Success -> ",o)},error:function(){return t(n),console.log("Error")}}),!1},t=function(o){var n;return(n=$("#lform").attr("action")).match(/^#$/)?n=o:n+=o,console.log("form action URL -> ",n),$("#lform").attr("action",n),$("#lform").submit()},$(document).ready(function(){return $(".sslclick").on("click",o)})}).call(this);
(function(){var r,o;o=function(){var n;return n=window.location.pathname,console.log("path -> ",n),console.log("Call URL -> ",window.datas.sslHost),$.ajax(window.datas.sslHost,{dataType:"json",xhrFields:{withCredentials:!0},success:function(o){return r(n),console.log("Success -> ",o)},error:function(o){return 0===o.status&&r(n),o.responseJSON&&"error"in o.responseJSON&&"9"===o.responseJSON.error&&r(n),o.responseJSON&&"html"in o.responseJSON&&($("#errormsg").html(o.responseJSON.html),$(window).trigger("load")),console.log("Error during AJAX SSL authentication",o)}}),!1},r=function(o){var n;return(n=$("#lform").attr("action")).match(/^#$/)?n=o:n+=o,console.log("form action URL -> ",n),$("#lform").attr("action",n),$("#lform").submit()},$(document).ready(function(){return $(".sslclick").on("click",o)})}).call(this);

View File

@ -1 +1 @@
{"version":3,"sources":["lemonldap-ng-portal/site/htdocs/static/common/js/ssl.js"],"names":["sendUrl","tryssl","path","window","location","pathname","console","log","datas","sslHost","$","ajax","dataType","statusCode","401","submit","success","data","error","form_url","attr","match","document","ready","on","call","this"],"mappings":"CACA,WACE,IAAIA,EAASC,EAEbA,EAAS,WACP,IAAIC,EAqBJ,OApBAA,EAAOC,OAAOC,SAASC,SACvBC,QAAQC,IAAI,WAAYL,GACxBI,QAAQC,IAAI,eAAgBJ,OAAOK,MAAMC,SACzCC,EAAEC,KAAKR,OAAOK,MAAMC,QAAS,CAC3BG,SAAU,QACVC,WAAY,CACVC,IAAK,WAEH,OADAJ,EAAE,UAAUK,SACLT,QAAQC,IAAI,oBAGvBS,QAAS,SAASC,GAEhB,OADAjB,EAAQE,GACDI,QAAQC,IAAI,cAAeU,IAEpCC,MAAO,WAEL,OADAlB,EAAQE,GACDI,QAAQC,IAAI,aAGhB,GAGTP,EAAU,SAASE,GACjB,IAAIiB,EASJ,OARAA,EAAWT,EAAE,UAAUU,KAAK,WACfC,MAAM,OACjBF,EAAWjB,EAEXiB,GAAsBjB,EAExBI,QAAQC,IAAI,sBAAuBY,GACnCT,EAAE,UAAUU,KAAK,SAAUD,GACpBT,EAAE,UAAUK,UAGrBL,EAAEY,UAAUC,MAAM,WAChB,OAAOb,EAAE,aAAac,GAAG,QAASvB,OAGnCwB,KAAKC"}
{"version":3,"sources":["lemonldap-ng-portal/site/htdocs/static/common/js/ssl.js"],"names":["sendUrl","tryssl","path","window","location","pathname","console","log","datas","sslHost","$","ajax","dataType","xhrFields","withCredentials","success","data","error","result","status","responseJSON","html","trigger","form_url","attr","match","submit","document","ready","on","call","this"],"mappings":"CACA,WACE,IAAIA,EAASC,EAEbA,EAAS,WACP,IAAIC,EA2BJ,OA1BAA,EAAOC,OAAOC,SAASC,SACvBC,QAAQC,IAAI,WAAYL,GACxBI,QAAQC,IAAI,eAAgBJ,OAAOK,MAAMC,SACzCC,EAAEC,KAAKR,OAAOK,MAAMC,QAAS,CAC3BG,SAAU,OACVC,UAAW,CACTC,iBAAiB,GAEnBC,QAAS,SAASC,GAEhB,OADAhB,EAAQE,GACDI,QAAQC,IAAI,cAAeS,IAEpCC,MAAO,SAASC,GAWd,OAVsB,IAAlBA,EAAOC,QACTnB,EAAQE,GAENgB,EAAOE,cAAgB,UAAWF,EAAOE,cAA8C,MAA9BF,EAAOE,aAAaH,OAC/EjB,EAAQE,GAENgB,EAAOE,cAAgB,SAAUF,EAAOE,eAC1CV,EAAE,aAAaW,KAAKH,EAAOE,aAAaC,MACxCX,EAAEP,QAAQmB,QAAQ,SAEbhB,QAAQC,IAAI,uCAAwCW,OAGxD,GAGTlB,EAAU,SAASE,GACjB,IAAIqB,EASJ,OARAA,EAAWb,EAAE,UAAUc,KAAK,WACfC,MAAM,OACjBF,EAAWrB,EAEXqB,GAAsBrB,EAExBI,QAAQC,IAAI,sBAAuBgB,GACnCb,EAAE,UAAUc,KAAK,SAAUD,GACpBb,EAAE,UAAUgB,UAGrBhB,EAAEiB,UAAUC,MAAM,WAChB,OAAOlB,EAAE,aAAamB,GAAG,QAAS5B,OAGnC6B,KAAKC"}

View File

@ -8,20 +8,26 @@
console.log('path -> ', path);
console.log('Call URL -> ', window.datas.sslHost);
$.ajax(window.datas.sslHost, {
dataType: 'jsonp',
statusCode: {
401: function() {
$('#lformSSL').submit();
return console.log('Error code 401');
}
dataType: 'json',
xhrFields: {
withCredentials: true
},
success: function(data) {
sendUrl(path);
return console.log('Success -> ', data);
},
error: function() {
sendUrl(path);
return console.log('Error');
error: function(result) {
if (result.status === 0) {
sendUrl(path);
}
if (result.responseJSON && 'error' in result.responseJSON && result.responseJSON.error === "9") {
sendUrl(path);
}
if (result.responseJSON && 'html' in result.responseJSON) {
$('#errormsg').html(result.responseJSON.html);
$(window).trigger('load');
}
return console.log('Error during AJAX SSL authentication', result);
}
});
return false;

View File

@ -1 +1 @@
(function(){var t,o;o=function(){var n;return n=window.location.pathname,console.log("path -> ",n),console.log("Call URL -> ",window.datas.sslHost),$.ajax(window.datas.sslHost,{dataType:"jsonp",statusCode:{401:function(){return $("#lformSSL").submit(),console.log("Error code 401")}},success:function(o){return t(n),console.log("Success -> ",o)},error:function(){return t(n),console.log("Error")}}),!1},t=function(o){var n;return(n=$("#lformSSL").attr("action")).match(/^#$/)?n=o:n+=o,console.log("form action URL -> ",n),$("#lformSSL").attr("action",n),$("#lformSSL").submit()},$(document).ready(function(){return $(".sslclick").on("click",o)})}).call(this);
(function(){var r,o;o=function(){var n;return n=window.location.pathname,console.log("path -> ",n),console.log("Call URL -> ",window.datas.sslHost),$.ajax(window.datas.sslHost,{dataType:"json",xhrFields:{withCredentials:!0},success:function(o){return r(n),console.log("Success -> ",o)},error:function(o){return 0===o.status&&r(n),o.responseJSON&&"error"in o.responseJSON&&"9"===o.responseJSON.error&&r(n),o.responseJSON&&"html"in o.responseJSON&&($("#errormsg").html(o.responseJSON.html),$(window).trigger("load")),console.log("Error during AJAX SSL authentication",o)}}),!1},r=function(o){var n;return(n=$("#lformSSL").attr("action")).match(/^#$/)?n=o:n+=o,console.log("form action URL -> ",n),$("#lformSSL").attr("action",n),$("#lformSSL").submit()},$(document).ready(function(){return $(".sslclick").on("click",o)})}).call(this);

View File

@ -1 +1 @@
{"version":3,"sources":["lemonldap-ng-portal/site/htdocs/static/common/js/sslChoice.js"],"names":["sendUrl","tryssl","path","window","location","pathname","console","log","datas","sslHost","$","ajax","dataType","statusCode","401","submit","success","data","error","form_url","attr","match","document","ready","on","call","this"],"mappings":"CACA,WACE,IAAIA,EAASC,EAEbA,EAAS,WACP,IAAIC,EAqBJ,OApBAA,EAAOC,OAAOC,SAASC,SACvBC,QAAQC,IAAI,WAAYL,GACxBI,QAAQC,IAAI,eAAgBJ,OAAOK,MAAMC,SACzCC,EAAEC,KAAKR,OAAOK,MAAMC,QAAS,CAC3BG,SAAU,QACVC,WAAY,CACVC,IAAK,WAEH,OADAJ,EAAE,aAAaK,SACRT,QAAQC,IAAI,oBAGvBS,QAAS,SAASC,GAEhB,OADAjB,EAAQE,GACDI,QAAQC,IAAI,cAAeU,IAEpCC,MAAO,WAEL,OADAlB,EAAQE,GACDI,QAAQC,IAAI,aAGhB,GAGTP,EAAU,SAASE,GACjB,IAAIiB,EASJ,OARAA,EAAWT,EAAE,aAAaU,KAAK,WAClBC,MAAM,OACjBF,EAAWjB,EAEXiB,GAAsBjB,EAExBI,QAAQC,IAAI,sBAAuBY,GACnCT,EAAE,aAAaU,KAAK,SAAUD,GACvBT,EAAE,aAAaK,UAGxBL,EAAEY,UAAUC,MAAM,WAChB,OAAOb,EAAE,aAAac,GAAG,QAASvB,OAGnCwB,KAAKC"}
{"version":3,"sources":["lemonldap-ng-portal/site/htdocs/static/common/js/sslChoice.js"],"names":["sendUrl","tryssl","path","window","location","pathname","console","log","datas","sslHost","$","ajax","dataType","xhrFields","withCredentials","success","data","error","result","status","responseJSON","html","trigger","form_url","attr","match","submit","document","ready","on","call","this"],"mappings":"CACA,WACE,IAAIA,EAASC,EAEbA,EAAS,WACP,IAAIC,EA2BJ,OA1BAA,EAAOC,OAAOC,SAASC,SACvBC,QAAQC,IAAI,WAAYL,GACxBI,QAAQC,IAAI,eAAgBJ,OAAOK,MAAMC,SACzCC,EAAEC,KAAKR,OAAOK,MAAMC,QAAS,CAC3BG,SAAU,OACVC,UAAW,CACTC,iBAAiB,GAEnBC,QAAS,SAASC,GAEhB,OADAhB,EAAQE,GACDI,QAAQC,IAAI,cAAeS,IAEpCC,MAAO,SAASC,GAWd,OAVsB,IAAlBA,EAAOC,QACTnB,EAAQE,GAENgB,EAAOE,cAAgB,UAAWF,EAAOE,cAA8C,MAA9BF,EAAOE,aAAaH,OAC/EjB,EAAQE,GAENgB,EAAOE,cAAgB,SAAUF,EAAOE,eAC1CV,EAAE,aAAaW,KAAKH,EAAOE,aAAaC,MACxCX,EAAEP,QAAQmB,QAAQ,SAEbhB,QAAQC,IAAI,uCAAwCW,OAGxD,GAGTlB,EAAU,SAASE,GACjB,IAAIqB,EASJ,OARAA,EAAWb,EAAE,aAAac,KAAK,WAClBC,MAAM,OACjBF,EAAWrB,EAEXqB,GAAsBrB,EAExBI,QAAQC,IAAI,sBAAuBgB,GACnCb,EAAE,aAAac,KAAK,SAAUD,GACvBb,EAAE,aAAagB,UAGxBhB,EAAEiB,UAAUC,MAAM,WAChB,OAAOlB,EAAE,aAAamB,GAAG,QAAS5B,OAGnC6B,KAAKC"}

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

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

View File

@ -0,0 +1,7 @@
<TMPL_IF NAME="AUTH_ERROR">
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"><span trmsg="<TMPL_VAR NAME="AUTH_ERROR">"></span>
<TMPL_IF LOCKTIME>
<TMPL_VAR NAME="LOCKTIME"> <span trspan="seconds">seconds</span>.
</TMPL_IF>
</div>
</TMPL_IF>

View File

@ -4,13 +4,15 @@
<TMPL_INCLUDE NAME="customLoginHeader.tpl">
<TMPL_IF NAME="AUTH_ERROR">
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"><span trmsg="<TMPL_VAR NAME="AUTH_ERROR">"></span>
<TMPL_IF LOCKTIME>
<TMPL_VAR NAME="LOCKTIME"> <span trspan="seconds">seconds</span>.
</TMPL_IF>
</div>
</TMPL_IF>
<div id="errormsg">
<TMPL_IF NAME="AUTH_ERROR">
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"><span trmsg="<TMPL_VAR NAME="AUTH_ERROR">"></span>
<TMPL_IF LOCKTIME>
<TMPL_VAR NAME="LOCKTIME"> <span trspan="seconds">seconds</span>.
</TMPL_IF>
</div>
</TMPL_IF>
</div>
<TMPL_IF AUTH_LOOP>