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 8537c481f..7249fce8a 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 @@ -63,9 +63,11 @@ sub run { # ($token->{_totp2fSecret}) # Now check TOTP code to verify that user has a valid TOTP app - my $code = $req->param('code'); - unless ($code) { - $self->logger->userInfo('TOTP registration: empty validation form'); + my $code = $req->param('code'); + my $TOTPName = $req->param('TOTPName'); + unless ( $code and $TOTPName ) { + $self->logger->userInfo( + 'TOTP registration: empty code or name in validation form'); return $self->p->sendError( $req, 'missingCode', 200 ); } my $r = $self->verifyCode( @@ -90,17 +92,26 @@ sub run { # Now code is verified, let's store the master key in persistent data $self->p->updatePersistentSession( $req, { _totp2fSecret => $token->{_totp2fSecret} } ); - - my $list2FDevices = eval { from_json($req->userData->{list2FDevices}, { allow_nonref => 1 } ) }; - unless ($list2FDevices) { - $self->logger->debug("No 2F Device found"); - $list2FDevices = []; - }; - push $list2FDevices, { type => 'totp', name => 'TOTP_1', _secret => $token->{_totp2fSecret}, epoch => time() }; - $self->logger->debug("Append 2F Device : { type => 'totp', name => 'TOTP1' }"); + + my $list2FDevices = eval { + from_json( $req->userData->{list2FDevices}, { allow_nonref => 1 } ); + }; + unless ($list2FDevices) { + $self->logger->debug("No 2F Device found"); + $list2FDevices = []; + } + push $list2FDevices, + { + type => 'totp', + name => $TOTPName, + _secret => $token->{_totp2fSecret}, + epoch => time() + }; + $self->logger->debug( + "Append 2F Device : { type => 'totp', name => $TOTPName }"); $self->p->updatePersistentSession( $req, - { list2FDevices => to_json($list2FDevices) } ); - + { list2FDevices => to_json($list2FDevices) } ); + $self->userLogger->notice('TOTP registration succeed'); return [ 200, [ 'Content-Type' => 'application/json' ], ['{"result":1}'] ]; 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 ef41318c9..45aa49b7f 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 @@ -5,7 +5,6 @@ use strict; use Mouse; use JSON qw(from_json to_json); - our $VERSION = '2.0.0'; extends 'Lemonldap::NG::Portal::Lib::U2F'; @@ -47,14 +46,15 @@ sub run { my ( $resp, $challenge ); $self->logger->debug('Regististration response'); unless ($resp = $req->param('registration') - and $challenge = $req->param('challenge') ) + and $challenge = $req->param('challenge') + and $req->param('keyName') ) { return $self->p->sendError( $req, 'Missing registration parameter', 400 ); } $self->logger->debug("Get registration data $resp"); $self->logger->debug("Get challenge $challenge"); - eval { $challenge = JSON::from_json($challenge)->{challenge} }; + eval { $challenge = from_json($challenge)->{challenge} }; if ($@) { $self->userLogger->error("Bad challenge: $@"); return $self->p->sendError( $req, 'Bad challenge', 400 ); @@ -63,34 +63,29 @@ sub run { if ( $c->setChallenge($challenge) ) { my ( $keyHandle, $userKey ) = $c->registrationVerify($resp); if ( $keyHandle and $userKey ) { - - my $list2FDevices = eval { from_json($req->userData->{list2FDevices}, { allow_nonref => 1 } ) }; - unless ($list2FDevices) { - $self->logger->debug("No 2F Device found"); - $list2FDevices = []; - }; - push $list2FDevices, { type => 'U2F', name => 'U2F_1', _userKey => $self->encode_base64url($userKey, ''), _keyHandle => $keyHandle, epoch => time() }; - $self->logger->debug("Append 2F Device : { type => 'U2F', name => 'U2F_1' }" ); - $self->p->updatePersistentSession( $req, - { list2FDevices => to_json($list2FDevices) } ); - - - - - - - - - - - - - - - - - - + + my $list2FDevices = eval { + from_json( $req->userData->{list2FDevices}, + { allow_nonref => 1 } ); + }; + unless ($list2FDevices) { + $self->logger->debug("No 2F Device found"); + $list2FDevices = []; + } + my $keyName = $req->param('keyName'); + push $list2FDevices, + { + type => 'U2F', + name => $keyName, + _userKey => $self->encode_base64url( $userKey, '' ), + _keyHandle => $keyHandle, + epoch => time() + }; + $self->logger->debug( + "Append 2F Device : { type => 'U2F', name => $keyName }"); + $self->p->updatePersistentSession( $req, + { list2FDevices => to_json($list2FDevices) } ); + $self->p->updatePersistentSession( $req, { 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 e09134db1..c4f1a96a2 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 @@ -32,41 +32,48 @@ sub init { sub run { my ( $self, $req, $action ) = @_; if ( $action eq 'register' ) { - my $otp = $req->param('otp'); - if ( $otp and length($otp) > $self->conf->{yubikey2fPublicIDSize} ) { + my $otp = $req->param('otp'); + my $UBKName = $req->param('UBKName'); + if ( $UBKName + and $otp + and length($otp) > $self->conf->{yubikey2fPublicIDSize} ) + { my $keys = $req->userData->{_yubikeys} || ''; $keys .= ( $keys ? ', ' : '' ) . substr( $otp, 0, $self->conf->{yubikey2fPublicIDSize} ); - - - - + my $key = substr( $otp, 0, $self->conf->{yubikey2fPublicIDSize} ); - my $list2FDevices = eval { from_json($req->userData->{list2FDevices}, { allow_nonref => 1 } ) }; - unless ($list2FDevices) { - $self->logger->debug("No 2F Device found"); - $list2FDevices = []; - }; - push $list2FDevices, { type => 'UBK', name => 'UBK_1', _yubikey => $key, epoch => time() }; - $self->logger->debug("Append 2F Device : { type => 'UBK', name => 'UBK_1' }" ); - $self->p->updatePersistentSession( $req, - { list2FDevices => to_json($list2FDevices) } ); - - - - - + my $list2FDevices = eval { + from_json( $req->userData->{list2FDevices}, + { allow_nonref => 1 } ); + }; + unless ($list2FDevices) { + $self->logger->debug("No 2F Device found"); + $list2FDevices = []; + } + push $list2FDevices, + { + type => 'UBK', + name => $UBKName, + _yubikey => $key, + epoch => time() + }; + $self->logger->debug( + "Append 2F Device : { type => 'UBK', name => $UBKName }"); + $self->p->updatePersistentSession( $req, + { list2FDevices => to_json($list2FDevices) } ); + $self->p->updatePersistentSession( $req, { _yubikeys => $keys } ); return $self->p->sendHtml( $req, 'error', params => { - RAW_ERROR => 'yourKeyIsRegistered', + RAW_ERROR => 'yourKeyIsRegistered', AUTH_ERROR_TYPE => 'positive', } ); } else { - $self->userLogger->error('Yubikey 2F: no code'); + $self->userLogger->error('Yubikey 2F: no code or name'); return $self->p->sendHtml( $req, 'error', params => { diff --git a/lemonldap-ng-portal/site/coffee/totpregistration.coffee b/lemonldap-ng-portal/site/coffee/totpregistration.coffee index 164e7f2ac..84e450032 100644 --- a/lemonldap-ng-portal/site/coffee/totpregistration.coffee +++ b/lemonldap-ng-portal/site/coffee/totpregistration.coffee @@ -66,6 +66,7 @@ verify = -> data: token: token code: val + TOTPName: $('#TOTPName').val() error: displayError success: (data) -> if data.error diff --git a/lemonldap-ng-portal/site/coffee/u2fregistration.coffee b/lemonldap-ng-portal/site/coffee/u2fregistration.coffee index 0366c9a88..d058c447a 100644 --- a/lemonldap-ng-portal/site/coffee/u2fregistration.coffee +++ b/lemonldap-ng-portal/site/coffee/u2fregistration.coffee @@ -44,9 +44,10 @@ register = -> $.ajax type: "POST" url: "#{portal}2fregisters/u/registration" - data: + data: registration: JSON.stringify data challenge: JSON.stringify ch + keyName: $('#keyName').val() dataType: 'json' success: (resp) -> if resp.error diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.js b/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.js index dddcd253f..6eb207bb4 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/totpregistration.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.9.3 /* LemonLDAP::NG TOTP registration script @@ -82,7 +82,8 @@ LemonLDAP::NG TOTP registration script dataType: 'json', data: { token: token, - code: val + code: val, + TOTPName: $('#TOTPName').val() }, error: displayError, success: function(data) { 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 6746b08b6..577bad94e 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,b,e,d,c,f;e=function(g,h){$("#msg").html(window.translate(g));$("#color").removeClass("message-positive message-warning alert-success alert-warning");$("#color").addClass("message-"+h);if(h==="positive"){h="success"}return $("#color").addClass("alert-"+h)};a=function(h,g,k){var i;console.log("Error",k);i=JSON.parse(h.responseText);if(i&&i.error){i=i.error.replace(/.* /,"");console.log("Returned error",i);return e(i,"warning")}};d="";b=function(g){return $.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",data:{newkey:g},error:a,success:function(j){var h,i;if(j.error){return e(j.error,"warning")}if(!(j.portal&&j.user&&j.secret)){return e("PE24","danger")}i="otpauth://totp/"+(escape(j.portal))+":"+(escape(j.user))+"?secret="+j.secret+"&issuer="+(escape(j.portal));if(j.digits!==6){i+="&digits="+j.digits}if(j.interval!==30){i+="&period="+j.interval}h=new QRious({element:document.getElementById("qr"),value:i,size:150});$("#serialized").text(i);if(j.newkey){e("yourNewTotpKey","warning")}else{e("yourTotpKey","success")}return d=j.token}})};f=function(){var g;g=$("#code").val();if(!g){return e("fillTheForm","warning")}else{return $.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:d,code:g},error:a,success:function(h){if(h.error){if(h.error.match(/badCode/)){return e("badCode","warning")}else{return e(h.error,"danger")}}else{return e("yourKeyIsRegistered","success")}}})}};c=function(){return $.ajax({type:"POST",url:portal+"/totpregister/unregister",data:{},dataType:"json",error:a,success:function(g){}},e("yourKeyIsUnregistered","success"))};$(document).ready(function(){b(0);$("#changekey").on("click",function(){return b(1)});$("#verify").on("click",function(){return f()});return $("#unregister").on("click",function(){return c()})})}).call(this); \ No newline at end of file +(function(){var a,b,e,d,c,f;e=function(g,h){$("#msg").html(window.translate(g));$("#color").removeClass("message-positive message-warning alert-success alert-warning");$("#color").addClass("message-"+h);if(h==="positive"){h="success"}return $("#color").addClass("alert-"+h)};a=function(h,g,k){var i;console.log("Error",k);i=JSON.parse(h.responseText);if(i&&i.error){i=i.error.replace(/.* /,"");console.log("Returned error",i);return e(i,"warning")}};d="";b=function(g){return $.ajax({type:"POST",url:portal+"/2fregisters/totp/getkey",dataType:"json",data:{newkey:g},error:a,success:function(j){var h,i;if(j.error){return e(j.error,"warning")}if(!(j.portal&&j.user&&j.secret)){return e("PE24","danger")}i="otpauth://totp/"+(escape(j.portal))+":"+(escape(j.user))+"?secret="+j.secret+"&issuer="+(escape(j.portal));if(j.digits!==6){i+="&digits="+j.digits}if(j.interval!==30){i+="&period="+j.interval}h=new QRious({element:document.getElementById("qr"),value:i,size:150});$("#serialized").text(i);if(j.newkey){e("yourNewTotpKey","warning")}else{e("yourTotpKey","success")}return d=j.token}})};f=function(){var g;g=$("#code").val();if(!g){return e("fillTheForm","warning")}else{return $.ajax({type:"POST",url:portal+"/2fregisters/totp/verify",dataType:"json",data:{token:d,code:g,TOTPName:$("#TOTPName").val()},error:a,success:function(h){if(h.error){if(h.error.match(/badCode/)){return e("badCode","warning")}else{return e(h.error,"danger")}}else{return e("yourKeyIsRegistered","success")}}})}};c=function(){return $.ajax({type:"POST",url:portal+"/totpregister/unregister",data:{},dataType:"json",error:a,success:function(g){}},e("yourKeyIsUnregistered","success"))};$(document).ready(function(){b(0);$("#changekey").on("click",function(){return b(1)});$("#verify").on("click",function(){return f()});return $("#unregister").on("click",function(){return c()})})}).call(this); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/u2fregistration.js b/lemonldap-ng-portal/site/htdocs/static/common/js/u2fregistration.js index 61e152c01..ad1ca72e3 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/u2fregistration.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/u2fregistration.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.12.7 +// Generated by CoffeeScript 1.9.3 /* LemonLDAP::NG U2F registration script @@ -55,7 +55,8 @@ LemonLDAP::NG U2F registration script url: portal + "2fregisters/u/registration", data: { registration: JSON.stringify(data), - challenge: JSON.stringify(ch) + challenge: JSON.stringify(ch), + keyName: $('#keyName').val() }, dataType: 'json', success: function(resp) { diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/u2fregistration.min.js b/lemonldap-ng-portal/site/htdocs/static/common/js/u2fregistration.min.js index 1406ce1b9..1abc16416 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/u2fregistration.min.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/u2fregistration.min.js @@ -1 +1 @@ -(function(){var a,c,d,b,e;d=function(f,g){$("#msg").html(window.translate(f));$("#color").removeClass("message-positive message-warning alert-success alert-warning");$("#color").addClass("message-"+g);if(g==="positive"){g="success"}return $("#color").addClass("alert-"+g)};a=function(g,f,i){var h;console.log("Error",i);h=JSON.parse(g.responseText);if(h&&h.error){h=h.error.replace(/.* /,"");console.log("Returned error",h);return d(h,"warning")}};c=function(){return $.ajax({type:"POST",url:portal+"2fregisters/u/register",data:{},dataType:"json",error:a,success:function(f){var g;g=[{challenge:f.challenge,version:f.version}];d("touchU2fDevice","positive");$("#u2fPermission").show();return u2f.register(f.appId,g,[],function(h){$("#u2fPermission").hide();if(h.errorCode){return d("unableToGetKey","warning")}else{return $.ajax({type:"POST",url:portal+"2fregisters/u/registration",data:{registration:JSON.stringify(h),challenge:JSON.stringify(f)},dataType:"json",success:function(i){if(i.error){return d("u2fFailed","warning")}else{if(i.result){return d("yourKeyIsRegistered","positive")}}},error:a})}})}})};b=function(){return $.ajax({type:"POST",url:portal+"2fregisters/u/unregistration",data:{},dataType:"json",error:a,success:function(f){if(f.error){return d("u2fFailed","warning")}else{if(f.result){return d("yourKeyIsUnregistered","positive")}}},error:a})};e=function(){return $.ajax({type:"POST",url:portal+"2fregisters/u/verify",data:{},dataType:"json",error:a,success:function(f){var g;g=[{keyHandle:f.keyHandle,version:f.version}];d("touchU2fDevice","positive");return u2f.sign(f.appId,f.challenge,g,function(h){if(h.errorCode){return d("unableToGetU2FKey","warning")}else{return $.ajax({type:"POST",url:portal+"2fregisters/u/signature",data:{signature:JSON.stringify(h),challenge:f.challenge},dataType:"json",success:function(i){if(i.error){return d("u2fFailed","warning")}else{if(i.result){return d("yourKeyIsVerified","positive")}}},error:function(k,i,l){return console.log("error",l)}})}})}})};$(document).ready(function(){$("#u2fPermission").hide();$("#register").on("click",c);$("#unregister").on("click",b);$("#verify").on("click",e);return $("#goback").attr("href",portal)})}).call(this); \ No newline at end of file +(function(){var a,c,d,b,e;d=function(f,g){$("#msg").html(window.translate(f));$("#color").removeClass("message-positive message-warning alert-success alert-warning");$("#color").addClass("message-"+g);if(g==="positive"){g="success"}return $("#color").addClass("alert-"+g)};a=function(g,f,i){var h;console.log("Error",i);h=JSON.parse(g.responseText);if(h&&h.error){h=h.error.replace(/.* /,"");console.log("Returned error",h);return d(h,"warning")}};c=function(){return $.ajax({type:"POST",url:portal+"2fregisters/u/register",data:{},dataType:"json",error:a,success:function(f){var g;g=[{challenge:f.challenge,version:f.version}];d("touchU2fDevice","positive");$("#u2fPermission").show();return u2f.register(f.appId,g,[],function(h){$("#u2fPermission").hide();if(h.errorCode){return d("unableToGetKey","warning")}else{return $.ajax({type:"POST",url:portal+"2fregisters/u/registration",data:{registration:JSON.stringify(h),challenge:JSON.stringify(f),keyName:$("#keyName").val()},dataType:"json",success:function(i){if(i.error){return d("u2fFailed","warning")}else{if(i.result){return d("yourKeyIsRegistered","positive")}}},error:a})}})}})};b=function(){return $.ajax({type:"POST",url:portal+"2fregisters/u/unregistration",data:{},dataType:"json",error:a,success:function(f){if(f.error){return d("u2fFailed","warning")}else{if(f.result){return d("yourKeyIsUnregistered","positive")}}},error:a})};e=function(){return $.ajax({type:"POST",url:portal+"2fregisters/u/verify",data:{},dataType:"json",error:a,success:function(f){var g;g=[{keyHandle:f.keyHandle,version:f.version}];d("touchU2fDevice","positive");return u2f.sign(f.appId,f.challenge,g,function(h){if(h.errorCode){return d("unableToGetU2FKey","warning")}else{return $.ajax({type:"POST",url:portal+"2fregisters/u/signature",data:{signature:JSON.stringify(h),challenge:f.challenge},dataType:"json",success:function(i){if(i.error){return d("u2fFailed","warning")}else{if(i.result){return d("yourKeyIsVerified","positive")}}},error:function(k,i,l){return console.log("error",l)}})}})}})};$(document).ready(function(){$("#u2fPermission").hide();$("#register").on("click",c);$("#unregister").on("click",b);$("#verify").on("click",e);return $("#goback").attr("href",portal)})}).call(this); \ No newline at end of file diff --git a/lemonldap-ng-portal/site/templates/bootstrap/totpregister.tpl b/lemonldap-ng-portal/site/templates/bootstrap/totpregister.tpl index c78c0d4c6..65f7494f7 100644 --- a/lemonldap-ng-portal/site/templates/bootstrap/totpregister.tpl +++ b/lemonldap-ng-portal/site/templates/bootstrap/totpregister.tpl @@ -13,7 +13,10 @@
- + Code :   +
+
+ Nom :  
diff --git a/lemonldap-ng-portal/site/templates/bootstrap/u2fregister.tpl b/lemonldap-ng-portal/site/templates/bootstrap/u2fregister.tpl index 05b9c1184..609fdb8cc 100644 --- a/lemonldap-ng-portal/site/templates/bootstrap/u2fregister.tpl +++ b/lemonldap-ng-portal/site/templates/bootstrap/u2fregister.tpl @@ -10,6 +10,9 @@
You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.
+ + Nom :   +          Register diff --git a/lemonldap-ng-portal/site/templates/bootstrap/yubikey2fregister.tpl b/lemonldap-ng-portal/site/templates/bootstrap/yubikey2fregister.tpl index 73a96da89..245943845 100644 --- a/lemonldap-ng-portal/site/templates/bootstrap/yubikey2fregister.tpl +++ b/lemonldap-ng-portal/site/templates/bootstrap/yubikey2fregister.tpl @@ -8,7 +8,11 @@
- + Nom : +
+
+ Id : +