Append unit test (#2338)
This commit is contained in:
parent
01031d8c4f
commit
9245fc4ee1
|
@ -223,13 +223,11 @@ site/htdocs/static/bwr/font-awesome/fonts/fontawesome-webfont.woff
|
|||
site/htdocs/static/bwr/font-awesome/fonts/fontawesome-webfont.woff2
|
||||
site/htdocs/static/bwr/jquery-ui/jquery-ui.js
|
||||
site/htdocs/static/bwr/jquery-ui/jquery-ui.min.js
|
||||
site/htdocs/static/bwr/jquery-ui/jquery-ui.min.js.map
|
||||
site/htdocs/static/bwr/jquery.cookie/jquery.cookie.js
|
||||
site/htdocs/static/bwr/jquery.cookie/jquery.cookie.min.js
|
||||
site/htdocs/static/bwr/jquery.cookie/jquery.cookie.min.js.map
|
||||
site/htdocs/static/bwr/jquery/dist/jquery.js
|
||||
site/htdocs/static/bwr/jquery/dist/jquery.min.js
|
||||
site/htdocs/static/bwr/jquery/dist/jquery.min.js.map
|
||||
site/htdocs/static/bwr/jquery/dist/jquery.min.map
|
||||
site/htdocs/static/bwr/qrious/dist/qrious.js
|
||||
site/htdocs/static/bwr/qrious/dist/qrious.js.map
|
||||
|
@ -658,16 +656,18 @@ t/67-CheckUser-with-rules.t
|
|||
t/67-CheckUser-with-token.t
|
||||
t/67-CheckUser-with-UnrestrictedUser.t
|
||||
t/67-CheckUser.t
|
||||
t/68-ContextSwitching-with-2F-allowed.t
|
||||
t/68-ContextSwitching-with-2F.t
|
||||
t/68-ContextSwitching-with-Impersonation.t
|
||||
t/68-ContextSwitching-with-Logout.t
|
||||
t/68-ContextSwitching-with-TOTP-and-Notification.t
|
||||
t/68-ContextSwitching-with-UnrestrictedUser.t
|
||||
t/68-ContextSwitching.t
|
||||
t/68-Impersonation-with-2F.t
|
||||
t/68-Impersonation-with-doubleCookies.t
|
||||
t/68-Impersonation-with-filtered-merge.t
|
||||
t/68-Impersonation-with-History.t
|
||||
t/68-Impersonation-with-merge.t
|
||||
t/68-Impersonation-with-SFA.t
|
||||
t/68-Impersonation-with-TOTP.t
|
||||
t/68-Impersonation-with-UnrestrictedUser.t
|
||||
t/68-Impersonation.t
|
||||
|
|
|
@ -38,7 +38,7 @@ sub run {
|
|||
|
||||
# Check if TOTP can be updated
|
||||
return $self->p->sendError( $req, 'notAuthorized', 400 )
|
||||
unless $self->allowedUpdateSfa($req, $action);
|
||||
unless $self->allowedUpdateSfa( $req, $action );
|
||||
|
||||
# Verification that user has a valid TOTP app
|
||||
if ( $action eq 'verify' ) {
|
||||
|
@ -292,18 +292,26 @@ sub run {
|
|||
if ( $_->{epoch} eq $epoch ) { $TOTPName = $_->{name}; () }
|
||||
else { $_ }
|
||||
} @$_2fDevices;
|
||||
$self->logger->debug(
|
||||
if ($TOTPName) {
|
||||
$self->logger->debug(
|
||||
"Delete 2F Device: { type => 'TOTP', epoch => $epoch, name => $TOTPName }"
|
||||
);
|
||||
$self->p->updatePersistentSession( $req,
|
||||
{ _2fDevices => to_json($_2fDevices) } );
|
||||
$self->userLogger->notice(
|
||||
"TOTP $TOTPName unregistration succeeds for $user");
|
||||
return [
|
||||
200,
|
||||
[ 'Content-Type' => 'application/json', 'Content-Length' => 12, ],
|
||||
['{"result":1}']
|
||||
];
|
||||
);
|
||||
$self->p->updatePersistentSession( $req,
|
||||
{ _2fDevices => to_json($_2fDevices) } );
|
||||
$self->userLogger->notice(
|
||||
"TOTP $TOTPName unregistration succeeds for $user");
|
||||
return [
|
||||
200,
|
||||
[
|
||||
'Content-Type' => 'application/json',
|
||||
'Content-Length' => 12,
|
||||
],
|
||||
['{"result":1}']
|
||||
];
|
||||
}
|
||||
else {
|
||||
$self->p->sendError( $req, '2FDeviceNotFound', 200 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$self->logger->error("Unknown TOTP action -> $action");
|
||||
|
|
|
@ -35,7 +35,7 @@ sub run {
|
|||
|
||||
# Check if U2F key can be updated
|
||||
return $self->p->sendError( $req, 'notAuthorized', 400 )
|
||||
unless $self->allowedUpdateSfa($req, $action);
|
||||
unless $self->allowedUpdateSfa( $req, $action );
|
||||
|
||||
if ( $action eq 'register' ) {
|
||||
|
||||
|
@ -279,18 +279,26 @@ sub run {
|
|||
if ( $_->{epoch} eq $epoch ) { $keyName = $_->{name}; () }
|
||||
else { $_ }
|
||||
} @$_2fDevices;
|
||||
$self->logger->debug(
|
||||
"Delete 2F Device : { type => 'U2F', epoch => $epoch, name => $keyName }"
|
||||
);
|
||||
$self->p->updatePersistentSession( $req,
|
||||
{ _2fDevices => to_json($_2fDevices) } );
|
||||
$self->userLogger->notice(
|
||||
"U2F key $keyName unregistration succeeds for $user");
|
||||
return [
|
||||
200,
|
||||
[ 'Content-Type' => 'application/json', 'Content-Length' => 12, ],
|
||||
['{"result":1}']
|
||||
];
|
||||
if ($keyName) {
|
||||
$self->logger->debug(
|
||||
"Delete 2F Device: { type => 'U2F', epoch => $epoch, name => $keyName }"
|
||||
);
|
||||
$self->p->updatePersistentSession( $req,
|
||||
{ _2fDevices => to_json($_2fDevices) } );
|
||||
$self->userLogger->notice(
|
||||
"U2F key $keyName unregistration succeeds for $user");
|
||||
return [
|
||||
200,
|
||||
[
|
||||
'Content-Type' => 'application/json',
|
||||
'Content-Length' => 12,
|
||||
],
|
||||
['{"result":1}']
|
||||
];
|
||||
}
|
||||
else {
|
||||
$self->p->sendError( $req, '2FDeviceNotFound', 200 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$self->logger->error("Unknown U2F action -> $action");
|
||||
|
|
|
@ -42,7 +42,7 @@ sub run {
|
|||
RAW_ERROR => 'notAuthorized',
|
||||
AUTH_ERROR_TYPE => 'warning',
|
||||
}
|
||||
) unless $self->allowedUpdateSfa($req, $action);
|
||||
) unless $self->allowedUpdateSfa( $req, $action );
|
||||
|
||||
if ( $action eq 'register' ) {
|
||||
my $otp = $req->param('otp');
|
||||
|
@ -190,18 +190,26 @@ sub run {
|
|||
if ( $_->{epoch} eq $epoch ) { $UBKName = $_->{name}; () }
|
||||
else { $_ }
|
||||
} @$_2fDevices;
|
||||
$self->logger->debug(
|
||||
if ($UBKName) {
|
||||
$self->logger->debug(
|
||||
"Delete 2F Device: { type => 'UBK', epoch => $epoch, name => $UBKName }"
|
||||
);
|
||||
$self->p->updatePersistentSession( $req,
|
||||
{ _2fDevices => to_json($_2fDevices) } );
|
||||
$self->userLogger->notice(
|
||||
"Yubikey $UBKName unregistration succeeds for $user");
|
||||
return [
|
||||
200,
|
||||
[ 'Content-Type' => 'application/json', 'Content-Length' => 12, ],
|
||||
['{"result":1}']
|
||||
];
|
||||
);
|
||||
$self->p->updatePersistentSession( $req,
|
||||
{ _2fDevices => to_json($_2fDevices) } );
|
||||
$self->userLogger->notice(
|
||||
"Yubikey $UBKName unregistration succeeds for $user");
|
||||
return [
|
||||
200,
|
||||
[
|
||||
'Content-Type' => 'application/json',
|
||||
'Content-Length' => 12,
|
||||
],
|
||||
['{"result":1}']
|
||||
];
|
||||
}
|
||||
else {
|
||||
$self->p->sendError( $req, '2FDeviceNotFound', 200 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$self->logger->error("Unknown Yubikey action -> $action");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
|
||||
/*
|
||||
LemonLDAP::NG 2F registration script
|
||||
|
|
|
@ -1 +1 @@
|
|||
(function(){var e,t,o;o=function(e,r){return $("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning alert-success alert-warning"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},t=function(e,r,t){var n;if(console.log("Error",t),(n=JSON.parse(e.responseText))&&n.error)return n=n.error.replace(/.* /,""),console.log("Returned error",n),n.match(/module/)?o("notAuthorized","warning"):o(n,"warning")},e=function(e,r){return"U2F"===e?e="u":"UBK"===e?e="yubikey":"TOTP"===e?e="totp":o("u2fFailed","warning"),$.ajax({type:"POST",url:portal+"2fregisters/"+e+"/delete",data:{epoch:r},dataType:"json",error:t,success:function(e){return e.error?e.error.match(/notAuthorized/)?o("notAuthorized","warning"):o("unknownAction","warning"):e.result?($("#delete-"+r).hide(),o("yourKeyIsUnregistered","positive")):void 0}})},$(document).ready(function(){return $("body").on("click",".btn-danger",function(){return e($(this).attr("device"),$(this).attr("epoch"))}),$("#goback").attr("href",portal),$(".data-epoch").each(function(){var e;return e=new Date(1e3*$(this).text()),$(this).text(e.toLocaleString())})})}).call(this);
|
||||
(function(){var e,t,o;o=function(e,r){return $("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning alert-success alert-warning"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},t=function(e,r,t){var n;if(console.log("Error",t),(n=JSON.parse(e.responseText))&&n.error)return n=n.error.replace(/.* /,""),console.log("Returned error",n),n.match(/module/)?o("notAuthorized","warning"):o(n,"warning")},e=function(e,r){return"U2F"===e?e="u":"UBK"===e?e="yubikey":"TOTP"===e?e="totp":o("u2fFailed","warning"),$.ajax({type:"POST",url:portal+"2fregisters/"+e+"/delete",data:{epoch:r},dataType:"json",error:t,success:function(e){return e.error?e.error.match(/notAuthorized/)?o("notAuthorized","warning"):o("unknownAction","warning"):e.result?($("#delete-"+r).hide(),o("yourKeyIsUnregistered","positive")):void 0},error:t})},$(document).ready(function(){return $("body").on("click",".btn-danger",function(){return e($(this).attr("device"),$(this).attr("epoch"))}),$("#goback").attr("href",portal),$(".data-epoch").each(function(){var e;return e=new Date(1e3*$(this).text()),$(this).text(e.toLocaleString())})})}).call(this);
|
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["2fregistration.js"],"names":["delete2F","displayError","setMsg","msg","level","$","html","window","translate","removeClass","addClass","j","status","err","res","console","log","JSON","parse","responseText","error","replace","match","device","epoch","ajax","type","url","portal","data","dataType","success","resp","result","hide","document","ready","on","this","attr","each","myDate","Date","text","toLocaleString","call"],"mappings":"CAMA,WACE,IAAIA,EAAUC,EAAcC,EAE5BA,EAAS,SAASC,EAAKC,GAOrB,OANAC,EAAE,QAAQC,KAAKC,OAAOC,UAAUL,IAChCE,EAAE,UAAUI,YAAY,gEACxBJ,EAAE,UAAUK,SAAS,WAAaN,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUK,SAAS,SAAWN,IAGzCH,EAAe,SAASU,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GAC1BA,EAAIQ,MAAM,UACLpB,EAAO,gBAAiB,WAExBA,EAAOY,EAAK,YAKzBd,EAAW,SAASuB,EAAQC,GAU1B,MATe,QAAXD,EACFA,EAAS,IACW,QAAXA,EACTA,EAAS,UACW,SAAXA,EACTA,EAAS,OAETrB,EAAO,YAAa,WAEfG,EAAEoB,KAAK,CAAAC,KACN,OADMC,IAEPC,OAAS,eAAiBL,EAAS,UAF5BM,KAGN,CACJL,MAAOA,GAJGM,SAMF,OANEV,MAoBLnB,EApBK8B,QAQH,SAASC,GAChB,OAAIA,EAAKZ,MACHY,EAAKZ,MAAME,MAAM,iBACZpB,EAAO,gBAAiB,WAExBA,EAAO,gBAAiB,WAExB8B,EAAKC,QACd5B,EAAE,WAAamB,GAAOU,OACfhC,EAAO,wBAAyB,kBAFlC,MASbG,EAAE8B,UAAUC,MAAM,WAKhB,OAJA/B,EAAE,QAAQgC,GAAG,QAAS,cAAe,WACnC,OAAOrC,EAASK,EAAEiC,MAAMC,KAAK,UAAWlC,EAAEiC,MAAMC,KAAK,YAEvDlC,EAAE,WAAWkC,KAAK,OAAQX,QACnBvB,EAAE,eAAemC,KAAK,WAC3B,IAAIC,EAEJ,OADAA,EAAS,IAAIC,KAAsB,IAAjBrC,EAAEiC,MAAMK,QACnBtC,EAAEiC,MAAMK,KAAKF,EAAOG,wBAI9BC,KAAKP"}
|
||||
{"version":3,"sources":["2fregistration.js"],"names":["delete2F","displayError","setMsg","msg","level","$","html","window","translate","removeClass","addClass","j","status","err","res","console","log","JSON","parse","responseText","error","replace","match","device","epoch","ajax","type","url","portal","data","dataType","success","resp","result","hide","document","ready","on","this","attr","each","myDate","Date","text","toLocaleString","call"],"mappings":"CAMA,WACE,IAAIA,EAAUC,EAAcC,EAE5BA,EAAS,SAASC,EAAKC,GAOrB,OANAC,EAAE,QAAQC,KAAKC,OAAOC,UAAUL,IAChCE,EAAE,UAAUI,YAAY,gEACxBJ,EAAE,UAAUK,SAAS,WAAaN,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUK,SAAS,SAAWN,IAGzCH,EAAe,SAASU,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GAC1BA,EAAIQ,MAAM,UACLpB,EAAO,gBAAiB,WAExBA,EAAOY,EAAK,YAKzBd,EAAW,SAASuB,EAAQC,GAU1B,MATe,QAAXD,EACFA,EAAS,IACW,QAAXA,EACTA,EAAS,UACW,SAAXA,EACTA,EAAS,OAETrB,EAAO,YAAa,WAEfG,EAAEoB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,eAAiBL,EAAS,UACxCM,KAAM,CACJL,MAAOA,GAETM,SAAU,OACVV,MAAOnB,EACP8B,QAAS,SAASC,GAChB,OAAIA,EAAKZ,MACHY,EAAKZ,MAAME,MAAM,iBACZpB,EAAO,gBAAiB,WAExBA,EAAO,gBAAiB,WAExB8B,EAAKC,QACd5B,EAAE,WAAamB,GAAOU,OACfhC,EAAO,wBAAyB,kBAFlC,GAKTkB,MAAOnB,KAIXI,EAAE8B,UAAUC,MAAM,WAKhB,OAJA/B,EAAE,QAAQgC,GAAG,QAAS,cAAe,WACnC,OAAOrC,EAASK,EAAEiC,MAAMC,KAAK,UAAWlC,EAAEiC,MAAMC,KAAK,YAEvDlC,EAAE,WAAWkC,KAAK,OAAQX,QACnBvB,EAAE,eAAemC,KAAK,WAC3B,IAAIC,EAEJ,OADAA,EAAS,IAAIC,KAAsB,IAAjBrC,EAAEiC,MAAMK,QACnBtC,EAAEiC,MAAMK,KAAKF,EAAOG,wBAI9BC,KAAKP"}
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
$(document).ready(function() {
|
||||
return $('#upgrd').submit();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
var renewCaptcha;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
var go, i, timer, timerIsEnabled;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
var go, i, timer;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
$(document).ready(function() {
|
||||
return $(".idploop").on('click', function() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
var _go, go, i, stop, timer;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
$(document).ready(function() {
|
||||
return $.ajax((window.location.href.match(/\/upgradesession/) ? window.location.href : portal) + '?kerberos=1', {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
$(document).ready(function() {
|
||||
return $.ajax(portal + '?kerberos=1', {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
|
||||
/*
|
||||
LemonLDAP::NG Notifications script
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
var values;
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
(function(){var o;o={},$(document).ready(function(){return $("script[type='application/init']").each(function(){var e,n,t;try{for(e in t=JSON.parse($(this).text()),n=[],t)n.push(o[e]=t[e]);return n}catch(e){return console.log("Parsing error",e)}}),window.addEventListener("message",function(e){var n,t,o,r,i;return t=e.data,console.log("message=",t),n=decodeURIComponent(t.split(" ")[0]),r=decodeURIComponent(t.split(" ")[1]),o=decodeURIComponent(r.split(".")[1]),i=r===btoa(n+" "+e.origin+" "+o)+"."+o?"unchanged":"changed",e.source.postMessage(i,e.origin)},!1)})}).call(this);
|
||||
(function(){var r;r={},$(document).ready(function(){return $("script[type='application/init']").each(function(){var n,e,t,o;try{for(e in o=JSON.parse($(this).text()),t=[],o)t.push(r[e]=o[e]);return t}catch(e){return n=e,console.log("Parsing error",n)}}),window.addEventListener("message",function(e){var n,t,o,r,i;return t=e.data,console.log("message=",t),n=decodeURIComponent(t.split(" ")[0]),r=decodeURIComponent(t.split(" ")[1]),o=decodeURIComponent(r.split(".")[1]),i=r===btoa(n+" "+e.origin+" "+o)+"."+o?"unchanged":"changed",e.source.postMessage(i,e.origin)},!1)})}).call(this);
|
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["oidcchecksession.js"],"names":["values","$","document","ready","each","k","results","tmp","JSON","parse","this","text","push","error","console","log","window","addEventListener","e","client_id","message","salt","session_state","stat","data","decodeURIComponent","split","btoa","origin","source","postMessage","call"],"mappings":"CACA,WACE,IAAIA,EAEJA,EAAS,GAETC,EAAEC,UAAUC,MAAM,WAehB,OAdAF,EAAE,mCAAmCG,KAAK,WACxC,IAAOC,EAAGC,EAASC,EACnB,IAGE,IAAKF,KAFLE,EAAMC,KAAKC,MAAMR,EAAES,MAAMC,QACzBL,EAAU,GACAC,EACRD,EAAQM,KAAKZ,EAAOK,GAAKE,EAAIF,IAE/B,OAAOC,EACP,MAAOO,GAEP,OAAOC,QAAQC,IAAI,gBADfF,MAIDG,OAAOC,iBAAiB,UAAW,SAASC,GACjD,IAAIC,EAAWC,EAASC,EAAMC,EAAmBC,EAYjD,OAXAH,EAAUF,EAAEM,KACZV,QAAQC,IAAI,WAAYK,GACxBD,EAAYM,mBAAmBL,EAAQM,MAAM,KAAK,IAClDJ,EAAgBG,mBAAmBL,EAAQM,MAAM,KAAK,IACtDL,EAAOI,mBAAmBH,EAAcI,MAAM,KAAK,IAGjDH,EADED,IADCK,KAAKR,EAAY,IAAMD,EAAEU,OAAS,IAAMP,GAAQ,IAAMA,EAElD,YAEA,UAEFH,EAAEW,OAAOC,YAAYP,EAAML,EAAEU,UACnC,OAGJG,KAAKrB"}
|
||||
{"version":3,"sources":["oidcchecksession.js"],"names":["values","$","document","ready","each","e","k","results","tmp","JSON","parse","this","text","push","error","console","log","window","addEventListener","client_id","message","salt","session_state","stat","data","decodeURIComponent","split","btoa","origin","source","postMessage","call"],"mappings":"CACA,WACE,IAAIA,EAEJA,EAAS,GAETC,EAAEC,UAAUC,MAAM,WAehB,OAdAF,EAAE,mCAAmCG,KAAK,WACxC,IAAIC,EAAGC,EAAGC,EAASC,EACnB,IAGE,IAAKF,KAFLE,EAAMC,KAAKC,MAAMT,EAAEU,MAAMC,QACzBL,EAAU,GACAC,EACRD,EAAQM,KAAKb,EAAOM,GAAKE,EAAIF,IAE/B,OAAOC,EACP,MAAOO,GAEP,OADAT,EAAIS,EACGC,QAAQC,IAAI,gBAAiBX,MAGjCY,OAAOC,iBAAiB,UAAW,SAASb,GACjD,IAAIc,EAAWC,EAASC,EAAMC,EAAmBC,EAYjD,OAXAH,EAAUf,EAAEmB,KACZT,QAAQC,IAAI,WAAYI,GACxBD,EAAYM,mBAAmBL,EAAQM,MAAM,KAAK,IAClDJ,EAAgBG,mBAAmBL,EAAQM,MAAM,KAAK,IACtDL,EAAOI,mBAAmBH,EAAcI,MAAM,KAAK,IAGjDH,EADED,IADCK,KAAKR,EAAY,IAAMd,EAAEuB,OAAS,IAAMP,GAAQ,IAAMA,EAElD,YAEA,UAEFhB,EAAEwB,OAAOC,YAAYP,EAAMlB,EAAEuB,UACnC,OAGJG,KAAKpB"}
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
document.onreadystatechange = function() {
|
||||
var redirect;
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
go = function() {
|
||||
return Fingerprint2.get(function(components) {
|
||||
var result, values;
|
||||
console.error(components);
|
||||
values = components.map((function(_this) {
|
||||
return function(component) {
|
||||
return component.value;
|
||||
|
|
|
@ -1 +1 @@
|
|||
(function(){var n;$(document).ready(function(){return window.requestIdleCallback?requestIdleCallback(function(){return n()}):setTimeout(n,500)}),n=function(){return Fingerprint2.get(function(n){var r,t;return console.error(n),t=n.map(function(n){return n.value}),r=Fingerprint2.x64hash128(t.join(""),31),$("#fg").attr("value",r),$("#form").submit()})}}).call(this);
|
||||
(function(){var n;$(document).ready(function(){return window.requestIdleCallback?requestIdleCallback(function(){return n()}):setTimeout(n,500)}),n=function(){return Fingerprint2.get(function(n){var t,r;return r=n.map(function(n){return n.value}),t=Fingerprint2.x64hash128(r.join(""),31),$("#fg").attr("value",t),$("#form").submit()})}}).call(this);
|
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["registerbrowser.js"],"names":["go","$","document","ready","window","requestIdleCallback","setTimeout","Fingerprint2","get","components","result","values","console","error","map","component","value","x64hash128","join","attr","submit","call","this"],"mappings":"CACA,WACE,IAAIA,EAEJC,EAAEC,UAAUC,MAAM,WAChB,OAAIC,OAAOC,oBACFA,oBAAoB,WACzB,OAAOL,MAGFM,WAAWN,EAAI,OAI1BA,EAAK,WACH,OAAOO,aAAaC,IAAI,SAASC,GAC/B,IAAIC,EAAQC,EASZ,OARAC,QAAQC,MAAMJ,GACdE,EAASF,EAAWK,IACX,SAASC,GACd,OAAOA,EAAUC,QAGrBN,EAASH,aAAaU,WAAWN,EAAOO,KAAK,IAAK,IAClDjB,EAAE,OAAOkB,KAAK,QAAST,GAChBT,EAAE,SAASmB,cAIrBC,KAAKC"}
|
||||
{"version":3,"sources":["registerbrowser.js"],"names":["go","$","document","ready","window","requestIdleCallback","setTimeout","Fingerprint2","get","components","result","values","map","component","value","x64hash128","join","attr","submit","call","this"],"mappings":"CACA,WACE,IAAIA,EAEJC,EAAEC,UAAUC,MAAM,WAChB,OAAIC,OAAOC,oBACFA,oBAAoB,WACzB,OAAOL,MAGFM,WAAWN,EAAI,OAI1BA,EAAK,WACH,OAAOO,aAAaC,IAAI,SAASC,GAC/B,IAAIC,EAAQC,EAQZ,OAPAA,EAASF,EAAWG,IACX,SAASC,GACd,OAAOA,EAAUC,QAGrBJ,EAASH,aAAaQ,WAAWJ,EAAOK,KAAK,IAAK,IAClDf,EAAE,OAAOgB,KAAK,QAASP,GAChBT,EAAE,SAASiB,cAIrBC,KAAKC"}
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
var sendUrl, tryssl;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
(function() {
|
||||
var sendUrl, tryssl;
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
(function(){var a=function(e,r){return $("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},r=function(e,r,t){var o;if(console.log("Error",t),(o=JSON.parse(e.responseText))&&o.error)return o=o.error.replace(/.* /,""),console.log("Returned error",o),a(o,"warning")},t="",e=function(e){return a("yourTotpKey","warning"),$.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",data:{newkey:e},error:r,success:function(e){var r;return e.error?(e.error.match(/totpExistingKey/)&&$("#divToHide").hide(),a(e.error,"warning")):e.portal&&e.user&&e.secret?($("#divToHide").show(),r="otpauth://totp/"+escape(e.portal)+":"+escape(e.user)+"?secret="+e.secret+"&issuer="+escape(e.portal),6!==e.digits&&(r+="&digits="+e.digits),30!==e.interval&&(r+="&period="+e.interval),new QRious({element:document.getElementById("qr"),value:r,size:150}),$("#serialized").text(r),e.newkey?a("yourNewTotpKey","warning"):a("yourTotpKey","success"),t=e.token):a("PE24","danger")}})},o=function(){var e=$("#code").val();return e?$.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:t,code:e,TOTPName:$("#TOTPName").val()},error:r,success:function(e){return e.error?e.error.match(/bad(Code|Name)/)?a(e.error,"warning"):a(e.error,"danger"):a("yourKeyIsRegistered","success")}}):a("fillTheForm","warning")};$(document).ready(function(){return e(0),$("#changekey").on("click",function(){return e(1)}),$("#verify").on("click",o)})}).call(this);
|
||||
(function(){var r,e,n,t,o;n=function(e,r){return $("#msg").html(window.translate(e)),$("#color").removeClass("message-positive message-warning message-danger alert-success alert-warning alert-danger"),$("#color").addClass("message-"+r),"positive"===r&&(r="success"),$("#color").addClass("alert-"+r)},r=function(e,r,t){var o;if(console.log("Error",t),(o=JSON.parse(e.responseText))&&o.error)return o=o.error.replace(/.* /,""),console.log("Returned error",o),n(o,"warning")},t="",e=function(e){return n("yourTotpKey","warning"),$.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",data:{newkey:e},error:r,success:function(e){var r;return e.error?(e.error.match(/totpExistingKey/)&&$("#divToHide").hide(),n(e.error,"warning")):e.portal&&e.user&&e.secret?($("#divToHide").show(),r="otpauth://totp/"+escape(e.portal)+":"+escape(e.user)+"?secret="+e.secret+"&issuer="+escape(e.portal),6!==e.digits&&(r+="&digits="+e.digits),30!==e.interval&&(r+="&period="+e.interval),new QRious({element:document.getElementById("qr"),value:r,size:150}),$("#serialized").text(r),e.newkey?n("yourNewTotpKey","warning"):n("yourTotpKey","success"),t=e.token):n("PE24","danger")}})},o=function(){var e;return(e=$("#code").val())?$.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:t,code:e,TOTPName:$("#TOTPName").val()},error:r,success:function(e){return e.error?e.error.match(/bad(Code|Name)/)?n(e.error,"warning"):n(e.error,"danger"):n("yourKeyIsRegistered","success")}}):n("fillTheForm","warning")},$(document).ready(function(){return e(0),$("#changekey").on("click",function(){return e(1)}),$("#verify").on("click",function(){return o()})})}).call(this);
|
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["totpregistration.js"],"names":["setMsg","msg","level","$","html","window","translate","removeClass","addClass","displayError","j","status","err","res","console","log","JSON","parse","responseText","error","replace","token","getKey","reset","ajax","type","url","portal","dataType","data","newkey","success","s","match","hide","user","secret","show","escape","digits","interval","QRious","element","document","getElementById","value","size","text","verify","val","code","TOTPName","ready","on","call","this"],"mappings":"CAMA,WACE,IAEAA,EAAS,SAASC,EAAKC,GAOrB,OANAC,EAAE,QAAQC,KAAKC,OAAOC,UAAUL,IAChCE,EAAE,UAAUI,YAAY,4FACxBJ,EAAE,UAAUK,SAAS,WAAaN,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUK,SAAS,SAAWN,IAGzCO,EAAe,SAASC,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GACvBb,EAAOa,EAAK,YAIvBQ,EAAQ,GAERC,EAAS,SAASC,GAEhB,OADAvB,EAAO,cAAe,WACfG,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJC,OAAQP,GAEVJ,MAAOV,EACPsB,QAAS,SAASF,GAChB,IAAQG,EACR,OAAIH,EAAKV,OACHU,EAAKV,MAAMc,MAAM,oBACnB9B,EAAE,cAAc+B,OAEXlC,EAAO6B,EAAKV,MAAO,YAEtBU,EAAKF,QAAUE,EAAKM,MAAQN,EAAKO,QAGvCjC,EAAE,cAAckC,OAChBL,EAAI,kBAAqBM,OAAOT,EAAKF,QAAW,IAAOW,OAAOT,EAAKM,MAAS,WAAaN,EAAKO,OAAS,WAAcE,OAAOT,EAAKF,QAC7G,IAAhBE,EAAKU,SACPP,GAAK,WAAaH,EAAKU,QAEH,KAAlBV,EAAKW,WACPR,GAAK,WAAaH,EAAKW,UAEpB,IAAIC,OAAO,CACdC,QAASC,SAASC,eAAe,MACjCC,MAAOb,EACPc,KAAM,MAER3C,EAAE,eAAe4C,KAAKf,GAClBH,EAAKC,OACP9B,EAAO,iBAAkB,WAEzBA,EAAO,cAAe,WAEjBqB,EAAQQ,EAAKR,OArBXrB,EAAO,OAAQ,cA0B9BgD,EAAS,WACP,IACAC,EAAM9C,EAAE,SAAS8C,MACjB,OAAKA,EAGI9C,EAAEqB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJR,MAAOA,EACP6B,KAAMD,EACNE,SAAUhD,EAAE,aAAa8C,OAE3B9B,MAAOV,EACPsB,QAAS,SAASF,GAChB,OAAIA,EAAKV,MACHU,EAAKV,MAAMc,MAAM,kBACZjC,EAAO6B,EAAKV,MAAO,WAEnBnB,EAAO6B,EAAKV,MAAO,UAGrBnB,EAAO,sBAAuB,cApBpCA,EAAO,cAAe,YA2BjCG,EAAEwC,UAAUS,MAAM,WAKhB,OAJA9B,EAAO,GACPnB,EAAE,cAAckD,GAAG,QAAS,WAC1B,OAAO/B,EAAO,KAETnB,EAAE,WAAWkD,GAAG,QACdL,OAIVM,KAAKC"}
|
||||
{"version":3,"sources":["totpregistration.js"],"names":["displayError","getKey","setMsg","token","verify","msg","level","$","html","window","translate","removeClass","addClass","j","status","err","res","console","log","JSON","parse","responseText","error","replace","reset","ajax","type","url","portal","dataType","data","newkey","success","s","match","hide","user","secret","show","escape","digits","interval","QRious","element","document","getElementById","value","size","text","val","code","TOTPName","ready","on","call","this"],"mappings":"CAMA,WACE,IAAIA,EAAcC,EAAQC,EAAQC,EAAOC,EAEzCF,EAAS,SAASG,EAAKC,GAOrB,OANAC,EAAE,QAAQC,KAAKC,OAAOC,UAAUL,IAChCE,EAAE,UAAUI,YAAY,4FACxBJ,EAAE,UAAUK,SAAS,WAAaN,GACpB,aAAVA,IACFA,EAAQ,WAEHC,EAAE,UAAUK,SAAS,SAAWN,IAGzCN,EAAe,SAASa,EAAGC,EAAQC,GACjC,IAAIC,EAGJ,GAFAC,QAAQC,IAAI,QAASH,IACrBC,EAAMG,KAAKC,MAAMP,EAAEQ,gBACRL,EAAIM,MAGb,OAFAN,EAAMA,EAAIM,MAAMC,QAAQ,MAAO,IAC/BN,QAAQC,IAAI,iBAAkBF,GACvBd,EAAOc,EAAK,YAIvBb,EAAQ,GAERF,EAAS,SAASuB,GAEhB,OADAtB,EAAO,cAAe,WACfK,EAAEkB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJC,OAAQP,GAEVF,MAAOtB,EACPgC,QAAS,SAASF,GAChB,IAAQG,EACR,OAAIH,EAAKR,OACHQ,EAAKR,MAAMY,MAAM,oBACnB3B,EAAE,cAAc4B,OAEXjC,EAAO4B,EAAKR,MAAO,YAEtBQ,EAAKF,QAAUE,EAAKM,MAAQN,EAAKO,QAGvC9B,EAAE,cAAc+B,OAChBL,EAAI,kBAAqBM,OAAOT,EAAKF,QAAW,IAAOW,OAAOT,EAAKM,MAAS,WAAaN,EAAKO,OAAS,WAAcE,OAAOT,EAAKF,QAC7G,IAAhBE,EAAKU,SACPP,GAAK,WAAaH,EAAKU,QAEH,KAAlBV,EAAKW,WACPR,GAAK,WAAaH,EAAKW,UAEpB,IAAIC,OAAO,CACdC,QAASC,SAASC,eAAe,MACjCC,MAAOb,EACPc,KAAM,MAERxC,EAAE,eAAeyC,KAAKf,GAClBH,EAAKC,OACP7B,EAAO,iBAAkB,WAEzBA,EAAO,cAAe,WAEjBC,EAAQ2B,EAAK3B,OArBXD,EAAO,OAAQ,cA0B9BE,EAAS,WACP,IAAI6C,EAEJ,OADAA,EAAM1C,EAAE,SAAS0C,OAIR1C,EAAEkB,KAAK,CACZC,KAAM,OACNC,IAAKC,OAAS,2BACdC,SAAU,OACVC,KAAM,CACJ3B,MAAOA,EACP+C,KAAMD,EACNE,SAAU5C,EAAE,aAAa0C,OAE3B3B,MAAOtB,EACPgC,QAAS,SAASF,GAChB,OAAIA,EAAKR,MACHQ,EAAKR,MAAMY,MAAM,kBACZhC,EAAO4B,EAAKR,MAAO,WAEnBpB,EAAO4B,EAAKR,MAAO,UAGrBpB,EAAO,sBAAuB,cApBpCA,EAAO,cAAe,YA2BjCK,EAAEqC,UAAUQ,MAAM,WAKhB,OAJAnD,EAAO,GACPM,EAAE,cAAc8C,GAAG,QAAS,WAC1B,OAAOpD,EAAO,KAETM,EAAE,WAAW8C,GAAG,QAAS,WAC9B,OAAOjD,UAIVkD,KAAKC"}
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
|
||||
/*
|
||||
LemonLDAP::NG U2F verify script
|
||||
|
|
|
@ -0,0 +1,469 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
use JSON qw(to_json from_json);
|
||||
|
||||
BEGIN {
|
||||
require 't/test-lib.pm';
|
||||
}
|
||||
my $maintests = 64;
|
||||
|
||||
SKIP: {
|
||||
require Lemonldap::NG::Common::TOTP;
|
||||
eval { require Crypt::U2F::Server; require Authen::U2F::Tester };
|
||||
if ( $@ or $Crypt::U2F::Server::VERSION < 0.42 ) {
|
||||
skip 'Missing U2F libraries', $maintests;
|
||||
}
|
||||
eval { require Convert::Base32 };
|
||||
if ($@) {
|
||||
skip 'Convert::Base32 is missing';
|
||||
}
|
||||
my $res;
|
||||
my $client = LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => 'error',
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
contextSwitchingRule => 1,
|
||||
contextSwitchingStopWithLogout => 0,
|
||||
contextSwitchingAllowed2fModifications => 1,
|
||||
totp2fSelfRegistration => 1,
|
||||
totp2fActivation => 1,
|
||||
u2fSelfRegistration => 1,
|
||||
u2fActivation => 1,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
## Try to authenticate
|
||||
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
|
||||
my ( $host, $url, $query ) =
|
||||
expectForm( $res, '#', undef, 'user', 'password' );
|
||||
|
||||
$query =~ s/user=/user=rtyler/;
|
||||
$query =~ s/password=/password=rtyler/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
);
|
||||
my $id = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
|
||||
# Get Menu
|
||||
# ------------------------
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html'
|
||||
),
|
||||
'Get Menu',
|
||||
);
|
||||
expectOK($res);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="connectedAs">Connected as</span> rtyler%,
|
||||
'Connected as rtyler'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
expectAuthenticatedAs( $res, 'rtyler' );
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="contextSwitching_ON">contextSwitching_ON</span>%,
|
||||
'contextSwitching allowed'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
## Try to register a TOTP
|
||||
# TOTP form
|
||||
my ( $key, $token, $code );
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters/totp',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form registration'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /totpregistration\.(?:min\.)?js/, 'Found TOTP js' );
|
||||
ok(
|
||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||
'Found custom Main Logo'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
# JS query
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/getkey', IO::String->new(''),
|
||||
cookie => "lemonldap=$id",
|
||||
length => 0,
|
||||
),
|
||||
'Get new key'
|
||||
);
|
||||
eval { $res = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), 'Content is JSON' )
|
||||
or explain( $res->[2]->[0], 'JSON content' );
|
||||
ok( $key = $res->{secret}, 'Found secret' ) or print STDERR Dumper($res);
|
||||
ok( $token = $res->{token}, 'Found token' ) or print STDERR Dumper($res);
|
||||
ok( $res->{user} eq 'rtyler', 'Found user' )
|
||||
or print STDERR Dumper($res);
|
||||
$key = Convert::Base32::decode_base32($key);
|
||||
|
||||
# Post code
|
||||
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
|
||||
'Code' );
|
||||
ok( $code =~ /^\d{6}$/, 'Code contains 6 digits' );
|
||||
my $s = "code=$code&token=$token&TOTPName=myTOTP";
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/verify',
|
||||
IO::String->new($s),
|
||||
length => length($s),
|
||||
cookie => "lemonldap=$id",
|
||||
),
|
||||
'Post code'
|
||||
);
|
||||
eval { $res = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), 'Content is JSON' )
|
||||
or explain( $res->[2]->[0], 'JSON content' );
|
||||
ok( $res->{result} == 1, 'TOTP is registered' );
|
||||
|
||||
## Try to register an U2F key
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters/u',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form registration'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /u2fregistration\.(?:min\.)?js/, 'Found U2F js' );
|
||||
ok(
|
||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||
'Found custom Main Logo'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
# Ajax registration request
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/u/register', IO::String->new(''),
|
||||
accept => 'application/json',
|
||||
cookie => "lemonldap=$id",
|
||||
length => 0,
|
||||
),
|
||||
'Get registration challenge'
|
||||
);
|
||||
expectOK($res);
|
||||
my $data;
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok( ( $data->{challenge} and $data->{appId} ), ' Get challenge and appId' )
|
||||
or explain( $data, 'challenge and appId' );
|
||||
|
||||
# Build U2F tester
|
||||
my $tester = Authen::U2F::Tester->new(
|
||||
certificate => Crypt::OpenSSL::X509->new_from_string(
|
||||
'-----BEGIN CERTIFICATE-----
|
||||
MIIB6DCCAY6gAwIBAgIJAJKuutkN2sAfMAoGCCqGSM49BAMCME8xCzAJBgNVBAYT
|
||||
AlVTMQ4wDAYDVQQIDAVUZXhhczEaMBgGA1UECgwRVW50cnVzdGVkIFUyRiBPcmcx
|
||||
FDASBgNVBAMMC3ZpcnR1YWwtdTJmMB4XDTE4MDMyODIwMTc1OVoXDTI3MTIyNjIw
|
||||
MTc1OVowTzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRowGAYDVQQKDBFV
|
||||
bnRydXN0ZWQgVTJGIE9yZzEUMBIGA1UEAwwLdmlydHVhbC11MmYwWTATBgcqhkjO
|
||||
PQIBBggqhkjOPQMBBwNCAAQTij+9mI1FJdvKNHLeSQcOW4ob3prvIXuEGJMrQeJF
|
||||
6OYcgwxrVqsmNMl5w45L7zx8ryovVOti/mtqkh2pQjtpo1MwUTAdBgNVHQ4EFgQU
|
||||
QXKKf+rrZwA4WXDCU/Vebe4gYXEwHwYDVR0jBBgwFoAUQXKKf+rrZwA4WXDCU/Ve
|
||||
be4gYXEwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAiCdOEmw5
|
||||
hknzHR1FoyFZKRrcJu17a1PGcqTFMJHTC70CIHeCZ8KVuuMIPjoofQd1l1E221rv
|
||||
RJY1Oz1fUNbrIPsL
|
||||
-----END CERTIFICATE-----', Crypt::OpenSSL::X509::FORMAT_PEM()
|
||||
),
|
||||
key => Crypt::PK::ECC->new(
|
||||
\'-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIOdbZw1swQIL+RZoDQ9zwjWY5UjA1NO81WWjwbmznUbgoAoGCCqGSM49
|
||||
AwEHoUQDQgAEE4o/vZiNRSXbyjRy3kkHDluKG96a7yF7hBiTK0HiRejmHIMMa1ar
|
||||
JjTJecOOS+88fK8qL1TrYv5rapIdqUI7aQ==
|
||||
-----END EC PRIVATE KEY-----'
|
||||
),
|
||||
);
|
||||
my $r = $tester->register( $data->{appId}, $data->{challenge} );
|
||||
ok( $r->is_success, ' Good challenge value' )
|
||||
or diag( $r->error_message );
|
||||
|
||||
my $registrationData = JSON::to_json( {
|
||||
clientData => $r->client_data,
|
||||
errorCode => 0,
|
||||
registrationData => $r->registration_data,
|
||||
version => "U2F_V2"
|
||||
}
|
||||
);
|
||||
( $host, $url, $query );
|
||||
$query = Lemonldap::NG::Common::FormEncode::build_urlencoded(
|
||||
registration => $registrationData,
|
||||
challenge => $res->[2]->[0],
|
||||
);
|
||||
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/u/registration', IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'application/json',
|
||||
cookie => "lemonldap=$id",
|
||||
),
|
||||
'Push registration data'
|
||||
);
|
||||
expectOK($res);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok( $data->{result} == 1, 'U2F key is registered' )
|
||||
or explain( $data, '"result":1' );
|
||||
|
||||
$client->logout($id);
|
||||
|
||||
## Try to authenticate
|
||||
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, '#', undef, 'user', 'password' );
|
||||
|
||||
$query =~ s/user=/user=rtyler/;
|
||||
$query =~ s/password=/password=rtyler/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
);
|
||||
( $host, $url, $query ) = expectForm( $res, undef, '/2fchoice', 'token' );
|
||||
$query .= '&sf=totp';
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fchoice',
|
||||
IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Post TOTP choice'
|
||||
);
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, undef, '/totp2fcheck', 'token' );
|
||||
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
|
||||
'Code' );
|
||||
$query =~ s/code=/code=$code/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/totp2fcheck', IO::String->new($query),
|
||||
length => length($query),
|
||||
),
|
||||
'Post code'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
|
||||
# Get Menu
|
||||
# ------------------------
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html'
|
||||
),
|
||||
'Get Menu',
|
||||
);
|
||||
expectOK($res);
|
||||
expectAuthenticatedAs( $res, 'rtyler' );
|
||||
|
||||
# Try to switch context 'dwho'
|
||||
# ContextSwitching form
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/switchcontext',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html'
|
||||
),
|
||||
'ContextSwitching form',
|
||||
);
|
||||
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, undef, '/switchcontext', 'spoofId' );
|
||||
ok( $res->[2]->[0] =~ m%<span trspan="contextSwitching_ON">%,
|
||||
'Found trspan="contextSwitching_ON"' )
|
||||
or explain( $res->[2]->[0], 'trspan="contextSwitching_ON"' );
|
||||
|
||||
## POST form
|
||||
$query =~ s/spoofId=/spoofId=dwho/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/switchcontext',
|
||||
IO::String->new($query),
|
||||
cookie => "lemonldap=$id",
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'POST switchcontext'
|
||||
);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
my $id2 = expectCookie($res);
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/',
|
||||
cookie => "lemonldap=$id2",
|
||||
accept => 'text/html'
|
||||
),
|
||||
'Get Menu',
|
||||
);
|
||||
expectAuthenticatedAs( $res, 'dwho' );
|
||||
ok( $res->[2]->[0] =~ m%<span trspan="contextSwitching_OFF">%,
|
||||
'Found trspan="contextSwitching_OFF"' )
|
||||
or explain( $res->[2]->[0], 'trspan="contextSwitching_OFF"' );
|
||||
|
||||
# 2fregisters
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters',
|
||||
cookie => "lemonldap=$id2",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form 2fregisters'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /<span id="msg" trspan="choose2f">/,
|
||||
'Found choose 2F' )
|
||||
or print STDERR Dumper( $res->[2]->[0] );
|
||||
my $devices;
|
||||
ok( $devices = $res->[2]->[0] =~ s%<span device=\'(TOTP|U2F)\' epoch=\'\d{10}\'%%g,
|
||||
'2F devices found' )
|
||||
or print STDERR Dumper( $res->[2]->[0] );
|
||||
ok( $devices == 2, 'two 2F devices found' )
|
||||
or explain( $devices, 'Two 2F devices registered' );
|
||||
|
||||
## Try to register a TOTP
|
||||
# TOTP form
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters/totp',
|
||||
cookie => "lemonldap=$id2",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form registration'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /totpregistration\.(?:min\.)?js/, 'Found TOTP js' )
|
||||
or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
ok(
|
||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||
'Found custom Main Logo'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
# JS query
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/getkey', IO::String->new(''),
|
||||
cookie => "lemonldap=$id2",
|
||||
length => 0,
|
||||
),
|
||||
'Get new key'
|
||||
);
|
||||
eval { $res = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), 'Content is JSON' )
|
||||
or explain( $res->[2]->[0], 'JSON content' );
|
||||
ok( $res->{error} eq 'totpExistingKey', 'TOTP already registered' )
|
||||
or explain( $res, 'Bad result' );
|
||||
|
||||
# Try to unregister TOTP
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/delete',
|
||||
IO::String->new("epoch=1234567890"),
|
||||
length => 16,
|
||||
cookie => "lemonldap=$id2",
|
||||
),
|
||||
'Delete TOTP query'
|
||||
);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok(
|
||||
$data->{error} eq '2FDeviceNotFound', '2F device not found'
|
||||
) or explain( $data, 'Bad result' );
|
||||
|
||||
# Try to verify TOTP
|
||||
$s = "code=123456&token=1234567890&TOTPName=myTOTP";
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/verify',
|
||||
IO::String->new($s),
|
||||
length => length($s),
|
||||
cookie => "lemonldap=$id2",
|
||||
),
|
||||
'Post code'
|
||||
);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok( $data->{error} eq 'PE82', 'PE82' )
|
||||
or explain( $data, 'Bad result' );
|
||||
|
||||
## Try to register an U2F key
|
||||
# U2F form
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters/u',
|
||||
cookie => "lemonldap=$id2",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form registration'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /u2fregistration\.(?:min\.)?js/, 'Found U2F js' );
|
||||
ok(
|
||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||
'Found custom Main Logo'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
# Ajax registration request
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/u/register', IO::String->new(''),
|
||||
accept => 'application/json',
|
||||
cookie => "lemonldap=$id2",
|
||||
length => 0,
|
||||
),
|
||||
'Get registration challenge'
|
||||
);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok(
|
||||
$data->{challenge} =~ /\w+/, 'Get challenge'
|
||||
) or explain( $data, 'Bad result' );
|
||||
|
||||
# Try to unregister U2F key
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/u/delete',
|
||||
IO::String->new("epoch=1234567890"),
|
||||
length => 16,
|
||||
cookie => "lemonldap=$id2",
|
||||
),
|
||||
'Delete U2F key query'
|
||||
);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok(
|
||||
$data->{error} eq '2FDeviceNotFound', '2F device not found'
|
||||
) or explain( $data, 'Bad result' );
|
||||
|
||||
$client->logout($id);
|
||||
$client->logout($id2);
|
||||
}
|
||||
|
||||
count($maintests);
|
||||
|
||||
clean_sessions();
|
||||
done_testing( count() );
|
|
@ -0,0 +1,469 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
use JSON qw(to_json from_json);
|
||||
|
||||
BEGIN {
|
||||
require 't/test-lib.pm';
|
||||
}
|
||||
my $maintests = 63;
|
||||
|
||||
SKIP: {
|
||||
require Lemonldap::NG::Common::TOTP;
|
||||
eval { require Crypt::U2F::Server; require Authen::U2F::Tester };
|
||||
if ( $@ or $Crypt::U2F::Server::VERSION < 0.42 ) {
|
||||
skip 'Missing U2F libraries', $maintests;
|
||||
}
|
||||
eval { require Convert::Base32 };
|
||||
if ($@) {
|
||||
skip 'Convert::Base32 is missing';
|
||||
}
|
||||
my $res;
|
||||
my $client = LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => 'error',
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
contextSwitchingRule => 1,
|
||||
contextSwitchingStopWithLogout => 0,
|
||||
contextSwitchingAllowed2fModifications => 0,
|
||||
totp2fSelfRegistration => 1,
|
||||
totp2fActivation => 1,
|
||||
u2fSelfRegistration => 1,
|
||||
u2fActivation => 1,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
## Try to authenticate
|
||||
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
|
||||
my ( $host, $url, $query ) =
|
||||
expectForm( $res, '#', undef, 'user', 'password' );
|
||||
|
||||
$query =~ s/user=/user=rtyler/;
|
||||
$query =~ s/password=/password=rtyler/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
);
|
||||
my $id = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
|
||||
# Get Menu
|
||||
# ------------------------
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html'
|
||||
),
|
||||
'Get Menu',
|
||||
);
|
||||
expectOK($res);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="connectedAs">Connected as</span> rtyler%,
|
||||
'Connected as rtyler'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
expectAuthenticatedAs( $res, 'rtyler' );
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="contextSwitching_ON">contextSwitching_ON</span>%,
|
||||
'contextSwitching allowed'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
## Try to register a TOTP
|
||||
# TOTP form
|
||||
my ( $key, $token, $code );
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters/totp',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form registration'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /totpregistration\.(?:min\.)?js/, 'Found TOTP js' );
|
||||
ok(
|
||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||
'Found custom Main Logo'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
# JS query
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/getkey', IO::String->new(''),
|
||||
cookie => "lemonldap=$id",
|
||||
length => 0,
|
||||
),
|
||||
'Get new key'
|
||||
);
|
||||
eval { $res = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), 'Content is JSON' )
|
||||
or explain( $res->[2]->[0], 'JSON content' );
|
||||
ok( $key = $res->{secret}, 'Found secret' ) or print STDERR Dumper($res);
|
||||
ok( $token = $res->{token}, 'Found token' ) or print STDERR Dumper($res);
|
||||
ok( $res->{user} eq 'rtyler', 'Found user' )
|
||||
or print STDERR Dumper($res);
|
||||
$key = Convert::Base32::decode_base32($key);
|
||||
|
||||
# Post code
|
||||
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
|
||||
'Code' );
|
||||
ok( $code =~ /^\d{6}$/, 'Code contains 6 digits' );
|
||||
my $s = "code=$code&token=$token&TOTPName=myTOTP";
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/verify',
|
||||
IO::String->new($s),
|
||||
length => length($s),
|
||||
cookie => "lemonldap=$id",
|
||||
),
|
||||
'Post code'
|
||||
);
|
||||
eval { $res = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), 'Content is JSON' )
|
||||
or explain( $res->[2]->[0], 'JSON content' );
|
||||
ok( $res->{result} == 1, 'TOTP is registered' );
|
||||
|
||||
## Try to register an U2F key
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters/u',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form registration'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /u2fregistration\.(?:min\.)?js/, 'Found U2F js' );
|
||||
ok(
|
||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||
'Found custom Main Logo'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
# Ajax registration request
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/u/register', IO::String->new(''),
|
||||
accept => 'application/json',
|
||||
cookie => "lemonldap=$id",
|
||||
length => 0,
|
||||
),
|
||||
'Get registration challenge'
|
||||
);
|
||||
expectOK($res);
|
||||
my $data;
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok( ( $data->{challenge} and $data->{appId} ), ' Get challenge and appId' )
|
||||
or explain( $data, 'challenge and appId' );
|
||||
|
||||
# Build U2F tester
|
||||
my $tester = Authen::U2F::Tester->new(
|
||||
certificate => Crypt::OpenSSL::X509->new_from_string(
|
||||
'-----BEGIN CERTIFICATE-----
|
||||
MIIB6DCCAY6gAwIBAgIJAJKuutkN2sAfMAoGCCqGSM49BAMCME8xCzAJBgNVBAYT
|
||||
AlVTMQ4wDAYDVQQIDAVUZXhhczEaMBgGA1UECgwRVW50cnVzdGVkIFUyRiBPcmcx
|
||||
FDASBgNVBAMMC3ZpcnR1YWwtdTJmMB4XDTE4MDMyODIwMTc1OVoXDTI3MTIyNjIw
|
||||
MTc1OVowTzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRowGAYDVQQKDBFV
|
||||
bnRydXN0ZWQgVTJGIE9yZzEUMBIGA1UEAwwLdmlydHVhbC11MmYwWTATBgcqhkjO
|
||||
PQIBBggqhkjOPQMBBwNCAAQTij+9mI1FJdvKNHLeSQcOW4ob3prvIXuEGJMrQeJF
|
||||
6OYcgwxrVqsmNMl5w45L7zx8ryovVOti/mtqkh2pQjtpo1MwUTAdBgNVHQ4EFgQU
|
||||
QXKKf+rrZwA4WXDCU/Vebe4gYXEwHwYDVR0jBBgwFoAUQXKKf+rrZwA4WXDCU/Ve
|
||||
be4gYXEwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAiCdOEmw5
|
||||
hknzHR1FoyFZKRrcJu17a1PGcqTFMJHTC70CIHeCZ8KVuuMIPjoofQd1l1E221rv
|
||||
RJY1Oz1fUNbrIPsL
|
||||
-----END CERTIFICATE-----', Crypt::OpenSSL::X509::FORMAT_PEM()
|
||||
),
|
||||
key => Crypt::PK::ECC->new(
|
||||
\'-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIOdbZw1swQIL+RZoDQ9zwjWY5UjA1NO81WWjwbmznUbgoAoGCCqGSM49
|
||||
AwEHoUQDQgAEE4o/vZiNRSXbyjRy3kkHDluKG96a7yF7hBiTK0HiRejmHIMMa1ar
|
||||
JjTJecOOS+88fK8qL1TrYv5rapIdqUI7aQ==
|
||||
-----END EC PRIVATE KEY-----'
|
||||
),
|
||||
);
|
||||
my $r = $tester->register( $data->{appId}, $data->{challenge} );
|
||||
ok( $r->is_success, ' Good challenge value' )
|
||||
or diag( $r->error_message );
|
||||
|
||||
my $registrationData = JSON::to_json( {
|
||||
clientData => $r->client_data,
|
||||
errorCode => 0,
|
||||
registrationData => $r->registration_data,
|
||||
version => "U2F_V2"
|
||||
}
|
||||
);
|
||||
( $host, $url, $query );
|
||||
$query = Lemonldap::NG::Common::FormEncode::build_urlencoded(
|
||||
registration => $registrationData,
|
||||
challenge => $res->[2]->[0],
|
||||
);
|
||||
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/u/registration', IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'application/json',
|
||||
cookie => "lemonldap=$id",
|
||||
),
|
||||
'Push registration data'
|
||||
);
|
||||
expectOK($res);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok( $data->{result} == 1, 'U2F key is registered' )
|
||||
or explain( $data, '"result":1' );
|
||||
|
||||
$client->logout($id);
|
||||
|
||||
## Try to authenticate
|
||||
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, '#', undef, 'user', 'password' );
|
||||
|
||||
$query =~ s/user=/user=rtyler/;
|
||||
$query =~ s/password=/password=rtyler/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
);
|
||||
( $host, $url, $query ) = expectForm( $res, undef, '/2fchoice', 'token' );
|
||||
$query .= '&sf=totp';
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fchoice',
|
||||
IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Post TOTP choice'
|
||||
);
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, undef, '/totp2fcheck', 'token' );
|
||||
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
|
||||
'Code' );
|
||||
$query =~ s/code=/code=$code/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/totp2fcheck', IO::String->new($query),
|
||||
length => length($query),
|
||||
),
|
||||
'Post code'
|
||||
);
|
||||
$id = expectCookie($res);
|
||||
|
||||
# Get Menu
|
||||
# ------------------------
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html'
|
||||
),
|
||||
'Get Menu',
|
||||
);
|
||||
expectOK($res);
|
||||
expectAuthenticatedAs( $res, 'rtyler' );
|
||||
|
||||
# Try to switch context 'dwho'
|
||||
# ContextSwitching form
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/switchcontext',
|
||||
cookie => "lemonldap=$id",
|
||||
accept => 'text/html'
|
||||
),
|
||||
'ContextSwitching form',
|
||||
);
|
||||
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, undef, '/switchcontext', 'spoofId' );
|
||||
ok( $res->[2]->[0] =~ m%<span trspan="contextSwitching_ON">%,
|
||||
'Found trspan="contextSwitching_ON"' )
|
||||
or explain( $res->[2]->[0], 'trspan="contextSwitching_ON"' );
|
||||
|
||||
## POST form
|
||||
$query =~ s/spoofId=/spoofId=dwho/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/switchcontext',
|
||||
IO::String->new($query),
|
||||
cookie => "lemonldap=$id",
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'POST switchcontext'
|
||||
);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
my $id2 = expectCookie($res);
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/',
|
||||
cookie => "lemonldap=$id2",
|
||||
accept => 'text/html'
|
||||
),
|
||||
'Get Menu',
|
||||
);
|
||||
expectAuthenticatedAs( $res, 'dwho' );
|
||||
ok( $res->[2]->[0] =~ m%<span trspan="contextSwitching_OFF">%,
|
||||
'Found trspan="contextSwitching_OFF"' )
|
||||
or explain( $res->[2]->[0], 'trspan="contextSwitching_OFF"' );
|
||||
|
||||
# 2fregisters
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters',
|
||||
cookie => "lemonldap=$id2",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form 2fregisters'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /<span id="msg" trspan="choose2f">/,
|
||||
'Found choose 2F' )
|
||||
or print STDERR Dumper( $res->[2]->[0] );
|
||||
ok( $res->[2]->[0] !~ m%<span device=\'(TOTP|U2F)\' epoch=\'\d{10}\'%g,
|
||||
'No 2F device found' )
|
||||
or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
## Try to register a TOTP
|
||||
# TOTP form
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters/totp',
|
||||
cookie => "lemonldap=$id2",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form registration'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /totpregistration\.(?:min\.)?js/, 'Found TOTP js' )
|
||||
or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
ok(
|
||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||
'Found custom Main Logo'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
# JS query
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/getkey', IO::String->new(''),
|
||||
cookie => "lemonldap=$id2",
|
||||
length => 0,
|
||||
),
|
||||
'Get new key'
|
||||
);
|
||||
eval { $res = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), 'Content is JSON' )
|
||||
or explain( $res->[2]->[0], 'JSON content' );
|
||||
ok( $res->{error} eq 'notAuthorized', 'Not authorized to register a TOTP' )
|
||||
or explain( $res, 'Bad result' );
|
||||
|
||||
# Try to unregister TOTP
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/delete',
|
||||
IO::String->new("epoch=1234567890"),
|
||||
length => 16,
|
||||
cookie => "lemonldap=$id2",
|
||||
),
|
||||
'Delete TOTP query'
|
||||
);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok(
|
||||
$data->{error} eq 'notAuthorized',
|
||||
'Not authorized to unregister a TOTP'
|
||||
) or explain( $data, 'Bad result' );
|
||||
|
||||
# Try to verify TOTP
|
||||
$s = "code=123456&token=1234567890&TOTPName=myTOTP";
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/totp/verify',
|
||||
IO::String->new($s),
|
||||
length => length($s),
|
||||
cookie => "lemonldap=$id2",
|
||||
),
|
||||
'Post code'
|
||||
);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok( $data->{error} eq 'notAuthorized', 'Not authorized to verify a TOTP' )
|
||||
or explain( $data, 'Bad result' );
|
||||
|
||||
## Try to register an U2F key
|
||||
# U2F form
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/2fregisters/u',
|
||||
cookie => "lemonldap=$id2",
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Form registration'
|
||||
);
|
||||
ok( $res->[2]->[0] =~ /u2fregistration\.(?:min\.)?js/, 'Found U2F js' );
|
||||
ok(
|
||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||
'Found custom Main Logo'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
|
||||
# Ajax registration request
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/u/register', IO::String->new(''),
|
||||
accept => 'application/json',
|
||||
cookie => "lemonldap=$id2",
|
||||
length => 0,
|
||||
),
|
||||
'Get registration challenge'
|
||||
);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok(
|
||||
$data->{error} eq 'notAuthorized',
|
||||
'Not authorized to register an U2F key'
|
||||
) or explain( $data, 'Bad result' );
|
||||
|
||||
# Try to unregister U2F key
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/2fregisters/u/delete',
|
||||
IO::String->new("epoch=1234567890"),
|
||||
length => 16,
|
||||
cookie => "lemonldap=$id2",
|
||||
),
|
||||
'Delete U2F key query'
|
||||
);
|
||||
eval { $data = JSON::from_json( $res->[2]->[0] ) };
|
||||
ok( not($@), ' Content is JSON' )
|
||||
or explain( [ $@, $res->[2] ], 'JSON content' );
|
||||
ok(
|
||||
$data->{error} eq 'notAuthorized',
|
||||
'Not authorized to unregister an U2F key'
|
||||
) or explain( $data, 'Bad result' );
|
||||
|
||||
$client->logout($id);
|
||||
$client->logout($id2);
|
||||
}
|
||||
|
||||
count($maintests);
|
||||
|
||||
clean_sessions();
|
||||
done_testing( count() );
|
|
@ -68,7 +68,7 @@ expectAuthenticatedAs( $res, 'dwho' );
|
|||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="contextSwitching_ON">contextSwitching_ON</span>%,
|
||||
'Connected as dwho'
|
||||
'contextSwitching allowed'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
count(3);
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ expectAuthenticatedAs( $res, 'rtyler' );
|
|||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="contextSwitching_ON">contextSwitching_ON</span>%,
|
||||
'Connected as rtyler'
|
||||
'contextSwitching allowed'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
count(2);
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ expectAuthenticatedAs( $res, 'rtyler' );
|
|||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="contextSwitching_ON">contextSwitching_ON</span>%,
|
||||
'Connected as rtyler'
|
||||
'contextSwitching allowed'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
count(3);
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ expectAuthenticatedAs( $res, 'rtyler' );
|
|||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="contextSwitching_ON">contextSwitching_ON</span>%,
|
||||
'Connected as rtyler'
|
||||
'contextSwitching allowed'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
count(2);
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ expectAuthenticatedAs( $res, 'dwho' );
|
|||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%<span trspan="contextSwitching_ON">contextSwitching_ON</span>%,
|
||||
'Connected as dwho'
|
||||
'contextSwitching allowed'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
count(2);
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ SKIP: {
|
|||
impersonationRule => 1,
|
||||
totp2fSelfRegistration => 1,
|
||||
totp2fActivation => 1,
|
||||
totp2fAuthnLevel => 8,
|
||||
u2fSelfRegistration => 1,
|
||||
u2fActivation => 1,
|
||||
}
|
Loading…
Reference in New Issue