From 9245fc4ee132b57532b153670d9a62b592a1761e Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Fri, 9 Oct 2020 22:29:56 +0200 Subject: [PATCH] Append unit test (#2338) --- lemonldap-ng-portal/MANIFEST | 6 +- .../Lemonldap/NG/Portal/2F/Register/TOTP.pm | 32 +- .../Lemonldap/NG/Portal/2F/Register/U2F.pm | 34 +- .../NG/Portal/2F/Register/Yubikey.pm | 32 +- .../htdocs/static/common/js/2fregistration.js | 2 +- .../static/common/js/2fregistration.min.js | 2 +- .../common/js/2fregistration.min.js.map | 2 +- .../site/htdocs/static/common/js/autoRenew.js | 2 +- .../site/htdocs/static/common/js/captcha.js | 2 +- .../site/htdocs/static/common/js/confirm.js | 2 +- .../htdocs/static/common/js/globalLogout.js | 2 +- .../site/htdocs/static/common/js/idpchoice.js | 2 +- .../site/htdocs/static/common/js/info.js | 2 +- .../site/htdocs/static/common/js/kerberos.js | 2 +- .../htdocs/static/common/js/kerberosChoice.js | 2 +- .../htdocs/static/common/js/notifications.js | 2 +- .../static/common/js/oidcchecksession.js | 2 +- .../static/common/js/oidcchecksession.min.js | 2 +- .../common/js/oidcchecksession.min.js.map | 2 +- .../site/htdocs/static/common/js/redirect.js | 2 +- .../static/common/js/registerbrowser.js | 1 - .../static/common/js/registerbrowser.min.js | 2 +- .../common/js/registerbrowser.min.js.map | 2 +- .../site/htdocs/static/common/js/ssl.js | 2 +- .../site/htdocs/static/common/js/sslChoice.js | 2 +- .../static/common/js/totpregistration.min.js | 2 +- .../common/js/totpregistration.min.js.map | 2 +- .../site/htdocs/static/common/js/u2fcheck.js | 2 +- .../t/68-ContextSwitching-with-2F-allowed.t | 469 ++++++++++++++++++ .../t/68-ContextSwitching-with-2F.t | 469 ++++++++++++++++++ .../68-ContextSwitching-with-Impersonation.t | 2 +- .../t/68-ContextSwitching-with-Logout.t | 2 +- ...textSwitching-with-TOTP-and-Notification.t | 2 +- ...8-ContextSwitching-with-UnrestrictedUser.t | 2 +- lemonldap-ng-portal/t/68-ContextSwitching.t | 2 +- ...-with-SFA.t => 68-Impersonation-with-2F.t} | 1 - 36 files changed, 1030 insertions(+), 70 deletions(-) create mode 100644 lemonldap-ng-portal/t/68-ContextSwitching-with-2F-allowed.t create mode 100644 lemonldap-ng-portal/t/68-ContextSwitching-with-2F.t rename lemonldap-ng-portal/t/{68-Impersonation-with-SFA.t => 68-Impersonation-with-2F.t} (99%) diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index 36031605c..48f227bf8 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -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 diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm index 158d26d54..d6827707c 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm @@ -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"); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/U2F.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/U2F.pm index 9d27162f9..a8cb2103d 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/U2F.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/U2F.pm @@ -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"); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm index 5e18551de..58d16f478 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm @@ -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"); diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.js b/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.js index c18ec9eb4..3196e5410 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 /* LemonLDAP::NG 2F registration script diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.min.js b/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.min.js index 9ac8ff2e0..82bd4d42b 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.min.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.min.js @@ -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); \ No newline at end of file +(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); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.min.js.map b/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.min.js.map index ac2a8ffd1..3436c92c5 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.min.js.map +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/2fregistration.min.js.map @@ -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"} \ No newline at end of file +{"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"} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/autoRenew.js b/lemonldap-ng-portal/site/htdocs/static/common/js/autoRenew.js index 137d3077d..d81876f31 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/autoRenew.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/autoRenew.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { $(document).ready(function() { return $('#upgrd').submit(); diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/captcha.js b/lemonldap-ng-portal/site/htdocs/static/common/js/captcha.js index 0d8797a93..220b180da 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/captcha.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/captcha.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { var renewCaptcha; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/confirm.js b/lemonldap-ng-portal/site/htdocs/static/common/js/confirm.js index 8fca7d160..2d63e379f 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/confirm.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/confirm.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { var go, i, timer, timerIsEnabled; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/globalLogout.js b/lemonldap-ng-portal/site/htdocs/static/common/js/globalLogout.js index fad1f323e..ea03c28c6 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/globalLogout.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/globalLogout.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { var go, i, timer; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/idpchoice.js b/lemonldap-ng-portal/site/htdocs/static/common/js/idpchoice.js index 69ddfed0a..02947496c 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/idpchoice.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/idpchoice.js @@ -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() { diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/info.js b/lemonldap-ng-portal/site/htdocs/static/common/js/info.js index 6bf8ecf1f..81246c62a 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/info.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/info.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { var _go, go, i, stop, timer; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/kerberos.js b/lemonldap-ng-portal/site/htdocs/static/common/js/kerberos.js index 6168144a1..c8779304c 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/kerberos.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/kerberos.js @@ -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', { diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/kerberosChoice.js b/lemonldap-ng-portal/site/htdocs/static/common/js/kerberosChoice.js index 329b94055..c6c4f7f48 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/kerberosChoice.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/kerberosChoice.js @@ -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', { diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/notifications.js b/lemonldap-ng-portal/site/htdocs/static/common/js/notifications.js index cb108ec9f..c2315d22a 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/notifications.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/notifications.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 /* LemonLDAP::NG Notifications script diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.js b/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.js index e11f8eb23..c0607384b 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { var values; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.min.js b/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.min.js index d91f5a301..05d834a13 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.min.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.min.js @@ -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); \ No newline at end of file +(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); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.min.js.map b/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.min.js.map index b1077f76a..f787aa8cc 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.min.js.map +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/oidcchecksession.min.js.map @@ -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"} \ No newline at end of file +{"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"} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/redirect.js b/lemonldap-ng-portal/site/htdocs/static/common/js/redirect.js index 5a32e6e20..acba6e604 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/redirect.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/redirect.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { document.onreadystatechange = function() { var redirect; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.js b/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.js index 300f1d77e..03318bdf9 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.js @@ -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; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.min.js b/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.min.js index d2b008001..918346ac4 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.min.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.min.js @@ -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); \ No newline at end of file +(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); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.min.js.map b/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.min.js.map index 92b44a523..a3bea04d9 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.min.js.map +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/registerbrowser.min.js.map @@ -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"} \ No newline at end of file +{"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"} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/ssl.js b/lemonldap-ng-portal/site/htdocs/static/common/js/ssl.js index 4a369e024..2a9f924d3 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/ssl.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/ssl.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { var sendUrl, tryssl; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/sslChoice.js b/lemonldap-ng-portal/site/htdocs/static/common/js/sslChoice.js index a2923cbb6..6495d7883 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/sslChoice.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/sslChoice.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 (function() { var sendUrl, tryssl; diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.min.js b/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.min.js index bcb855165..3089b99f6 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.min.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.min.js @@ -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); \ No newline at end of file +(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); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.min.js.map b/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.min.js.map index 39652ec7c..faf728c05 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.min.js.map +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.min.js.map @@ -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"} \ No newline at end of file +{"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"} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/u2fcheck.js b/lemonldap-ng-portal/site/htdocs/static/common/js/u2fcheck.js index e8a9de9d0..75bd92fd0 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/u2fcheck.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/u2fcheck.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.12.8 /* LemonLDAP::NG U2F verify script diff --git a/lemonldap-ng-portal/t/68-ContextSwitching-with-2F-allowed.t b/lemonldap-ng-portal/t/68-ContextSwitching-with-2F-allowed.t new file mode 100644 index 000000000..694513e95 --- /dev/null +++ b/lemonldap-ng-portal/t/68-ContextSwitching-with-2F-allowed.t @@ -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%Connected as rtyler%, + 'Connected as rtyler' + ) or print STDERR Dumper( $res->[2]->[0] ); + expectAuthenticatedAs( $res, 'rtyler' ); + ok( + $res->[2]->[0] =~ + m%contextSwitching_ON%, + '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%[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%[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%%, + '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%%, + '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] =~ //, + 'Found choose 2F' ) + or print STDERR Dumper( $res->[2]->[0] ); + my $devices; + ok( $devices = $res->[2]->[0] =~ s%[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%[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%[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() ); diff --git a/lemonldap-ng-portal/t/68-ContextSwitching-with-2F.t b/lemonldap-ng-portal/t/68-ContextSwitching-with-2F.t new file mode 100644 index 000000000..9f017d3ae --- /dev/null +++ b/lemonldap-ng-portal/t/68-ContextSwitching-with-2F.t @@ -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%Connected as rtyler%, + 'Connected as rtyler' + ) or print STDERR Dumper( $res->[2]->[0] ); + expectAuthenticatedAs( $res, 'rtyler' ); + ok( + $res->[2]->[0] =~ + m%contextSwitching_ON%, + '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%[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%[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%%, + '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%%, + '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] =~ //, + 'Found choose 2F' ) + or print STDERR Dumper( $res->[2]->[0] ); + ok( $res->[2]->[0] !~ m%[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%[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%[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() ); diff --git a/lemonldap-ng-portal/t/68-ContextSwitching-with-Impersonation.t b/lemonldap-ng-portal/t/68-ContextSwitching-with-Impersonation.t index 969f18648..2dd8658c3 100644 --- a/lemonldap-ng-portal/t/68-ContextSwitching-with-Impersonation.t +++ b/lemonldap-ng-portal/t/68-ContextSwitching-with-Impersonation.t @@ -68,7 +68,7 @@ expectAuthenticatedAs( $res, 'dwho' ); ok( $res->[2]->[0] =~ m%contextSwitching_ON%, - 'Connected as dwho' + 'contextSwitching allowed' ) or print STDERR Dumper( $res->[2]->[0] ); count(3); diff --git a/lemonldap-ng-portal/t/68-ContextSwitching-with-Logout.t b/lemonldap-ng-portal/t/68-ContextSwitching-with-Logout.t index fa3260e47..122f5c045 100644 --- a/lemonldap-ng-portal/t/68-ContextSwitching-with-Logout.t +++ b/lemonldap-ng-portal/t/68-ContextSwitching-with-Logout.t @@ -72,7 +72,7 @@ expectAuthenticatedAs( $res, 'rtyler' ); ok( $res->[2]->[0] =~ m%contextSwitching_ON%, - 'Connected as rtyler' + 'contextSwitching allowed' ) or print STDERR Dumper( $res->[2]->[0] ); count(2); diff --git a/lemonldap-ng-portal/t/68-ContextSwitching-with-TOTP-and-Notification.t b/lemonldap-ng-portal/t/68-ContextSwitching-with-TOTP-and-Notification.t index adcec646f..84229a9bc 100644 --- a/lemonldap-ng-portal/t/68-ContextSwitching-with-TOTP-and-Notification.t +++ b/lemonldap-ng-portal/t/68-ContextSwitching-with-TOTP-and-Notification.t @@ -135,7 +135,7 @@ expectAuthenticatedAs( $res, 'rtyler' ); ok( $res->[2]->[0] =~ m%contextSwitching_ON%, - 'Connected as rtyler' + 'contextSwitching allowed' ) or print STDERR Dumper( $res->[2]->[0] ); count(3); diff --git a/lemonldap-ng-portal/t/68-ContextSwitching-with-UnrestrictedUser.t b/lemonldap-ng-portal/t/68-ContextSwitching-with-UnrestrictedUser.t index 51e26cb21..be219ed01 100644 --- a/lemonldap-ng-portal/t/68-ContextSwitching-with-UnrestrictedUser.t +++ b/lemonldap-ng-portal/t/68-ContextSwitching-with-UnrestrictedUser.t @@ -71,7 +71,7 @@ expectAuthenticatedAs( $res, 'rtyler' ); ok( $res->[2]->[0] =~ m%contextSwitching_ON%, - 'Connected as rtyler' + 'contextSwitching allowed' ) or print STDERR Dumper( $res->[2]->[0] ); count(2); diff --git a/lemonldap-ng-portal/t/68-ContextSwitching.t b/lemonldap-ng-portal/t/68-ContextSwitching.t index 95ed39d94..24ac8e683 100644 --- a/lemonldap-ng-portal/t/68-ContextSwitching.t +++ b/lemonldap-ng-portal/t/68-ContextSwitching.t @@ -113,7 +113,7 @@ expectAuthenticatedAs( $res, 'dwho' ); ok( $res->[2]->[0] =~ m%contextSwitching_ON%, - 'Connected as dwho' + 'contextSwitching allowed' ) or print STDERR Dumper( $res->[2]->[0] ); count(2); diff --git a/lemonldap-ng-portal/t/68-Impersonation-with-SFA.t b/lemonldap-ng-portal/t/68-Impersonation-with-2F.t similarity index 99% rename from lemonldap-ng-portal/t/68-Impersonation-with-SFA.t rename to lemonldap-ng-portal/t/68-Impersonation-with-2F.t index e5d233e64..d7606ce26 100644 --- a/lemonldap-ng-portal/t/68-Impersonation-with-SFA.t +++ b/lemonldap-ng-portal/t/68-Impersonation-with-2F.t @@ -29,7 +29,6 @@ SKIP: { impersonationRule => 1, totp2fSelfRegistration => 1, totp2fActivation => 1, - totp2fAuthnLevel => 8, u2fSelfRegistration => 1, u2fActivation => 1, }