Commit 2cce5799 authored by Yadd's avatar Yadd
Browse files

Merge branch 'manager-u2f-module' into 'master'

Manager u2f module

See merge request lemonldap-ng/lemonldap-ng!17
parents 565798b9 3ec64aca
......@@ -8,12 +8,12 @@ sub types {
'authParamsText' => {
'test' => sub {
1;
}
}
},
'blackWhiteList' => {
'test' => sub {
1;
}
}
},
'bool' => {
'msgFail' => '__notABoolean__',
......@@ -36,17 +36,17 @@ sub types {
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'catAndAppList' => {
'test' => sub {
1;
}
}
},
'file' => {
'test' => sub {
1;
}
}
},
'hostname' => {
'form' => 'text',
......@@ -80,48 +80,48 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
if $_ =~ /exportedvars$/i and defined $conf->{$_}{$val};
}
return 1, "__unknownAttrOrMacro__: $val";
}
}
},
'longtext' => {
'test' => sub {
1;
}
}
},
'menuApp' => {
'test' => sub {
1;
}
}
},
'menuCat' => {
'test' => sub {
1;
}
}
},
'oidcmetadatajson' => {
'test' => sub {
1;
}
}
},
'oidcmetadatajwks' => {
'test' => sub {
1;
}
}
},
'oidcOPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'oidcRPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'password' => {
'msgFail' => '__malformedValue__',
'test' => sub {
1;
}
}
},
'pcre' => {
'form' => 'text',
......@@ -132,7 +132,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
}
};
return $@ ? ( 0, "__badRegexp__: $@" ) : 1;
}
}
},
'PerlModule' => {
'form' => 'text',
......@@ -142,17 +142,17 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
'portalskin' => {
'test' => sub {
1;
}
}
},
'portalskinbackground' => {
'test' => sub {
1;
}
}
},
'post' => {
'test' => sub {
1;
}
}
},
'RSAPrivateKey' => {
'test' => sub {
......@@ -160,7 +160,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:RSA\s+)PRIVATE\s+KEY\s*\-+)?[\r\n]*)?$]s
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'RSAPublicKey' => {
'test' => sub {
......@@ -168,7 +168,7 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+=
m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+PUBLIC\s+KEY\s*\-+)?[\r\n]*)?$]s
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'RSAPublicKeyOrCertificate' => {
'test' => sub {
......@@ -176,37 +176,37 @@ m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\
m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+)?[\r\n]*)?$]s
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'rule' => {
'test' => sub {
1;
}
}
},
'samlAssertion' => {
'test' => sub {
1;
}
}
},
'samlAttribute' => {
'test' => sub {
1;
}
}
},
'samlIDPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'samlService' => {
'test' => sub {
1;
}
}
},
'samlSPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'select' => {
'test' => sub {
......@@ -216,19 +216,19 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\
return $test
? 1
: ( 1, "Invalid value '$_[0]' for this select" );
}
}
},
'subContainer' => {
'keyTest' => qr/\w/,
'test' => sub {
1;
}
}
},
'text' => {
'msgFail' => '__malformedValue__',
'test' => sub {
1;
}
}
},
'trool' => {
'msgFail' => '__authorizedValues__: -1, 0, 1',
......@@ -1045,7 +1045,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'type' => 'keyTextContainer'
},
......@@ -1217,7 +1217,7 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
and defined $conf->{$_}{$val};
}
return 1, "__unknownAttrOrMacro__: $val";
}
}
},
'type' => 'doubleHash'
},
......@@ -1505,7 +1505,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'type' => 'ruleContainer'
},
......@@ -3001,19 +3001,19 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => 0,
'select' => [
{
'k' => '0',
'k' => 0,
'v' => 'unsecuredCookie'
},
{
'k' => '1',
'k' => 1,
'v' => 'securedCookie'
},
{
'k' => '2',
'k' => 2,
'v' => 'doubleCookie'
},
{
'k' => '3',
'k' => 3,
'v' => 'doubleCookieForSingleSession'
}
],
......
......@@ -5,13 +5,12 @@ use utf8;
use strict;
use Mouse;
use MIME::Base64 qw(encode_base64 decode_base64);
use Crypt::U2F::Server::Simple;
#use Crypt::U2F::Server::Simple;
use Lemonldap::NG::Common::Session;
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Common::PSGI::Constants;
use Lemonldap::NG::Common::Conf::ReConstants;
#use Lemonldap::NG::Common::IPv6;
use feature 'state';
......@@ -130,12 +129,11 @@ sub u2f {
: ( $s => $params->{$_} );
} keys %$params;
$filters{_session_kind} = $type;
# $filters{_u2fKeyHandle} = '';
push @fields, keys(%filters);
{
my %seen;
@fields = grep { !$seen{$_}++ } @fields;
# @fields = grep { !/\w+/ } @fields;
}
# For now, only one argument can be passed to
......@@ -195,7 +193,7 @@ sub u2f {
}
}
# Display sessions with U2F key registered only
# Display sessions with registered U2F key only
foreach my $session ( keys %$res ) {
delete $res->{$session}
unless ( defined $res->{$session}->{_u2fKeyHandle} and length $res->{$session}->{_u2fKeyHandle} )
......
......@@ -200,7 +200,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
session[key] = '########'
res = []
# 2. Push session keys in reuslt, grouped by categories
# 2. Push session keys in result, grouped by categories
for category, attrs of categories
subres = []
for attr in attrs
......
......@@ -151,39 +151,46 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
$scope.waiting = true
$http['delete']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
$scope.currentSession = null
#$scope.currentScope.remove()
$scope.currentScope.remove()
$scope.waiting = false
, (resp) ->
$scope.currentSession = null
#$scope.currentScope.remove()
$scope.currentScope.remove()
$scope.waiting = false
$scope.showT = true
$scope.showT = false
# Add U2F key
$scope.addU2FKey = ->
$scope.waiting = true
$http['put']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
$scope.currentSession = null
#$scope.currentSession = null
#$scope.currentScope.remove()
$scope.waiting = false
, (resp) ->
$scope.currentSession = null
#$scope.currentSession = null
#$scope.currentScope.remove()
$scope.waiting = false
$scope.showT = true
$scope.showT = false
$http.get("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
$scope.currentSession = transformSession response.data
$scope.showT = false
# Verify U2F key
$scope.verifyU2FKey = ->
$scope.waiting = true
$http['post']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
$scope.currentSession = null
#$scope.currentSession = null
#$scope.currentScope.remove()
$scope.waiting = false
, (resp) ->
$scope.currentSession = null
#$scope.currentSession = null
#$scope.currentScope.remove()
$scope.waiting = false
$scope.showT = true
$http.get("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
$scope.currentSession = transformSession response.data
$scope.showT = false
# Open node
$scope.stoggle = (scope) ->
......@@ -231,8 +238,8 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
session[key] = $scope.localeDate value
else if key.match /^(_startTime|_updateTime)$/
session[key] = _stToStr value
else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/
session[key] = '########'
#else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/
# session[key] = '########'
res = []
# 2. Push session keys in result, grouped by categories
......
......@@ -178,34 +178,40 @@
$scope.waiting = true;
$http['delete'](scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false;
}, function(resp) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false;
});
return $scope.showT = true;
return $scope.showT = false;
};
$scope.addU2FKey = function() {
$scope.waiting = true;
$http['put'](scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) {
$scope.currentSession = null;
return $scope.waiting = false;
}, function(resp) {
$scope.currentSession = null;
return $scope.waiting = false;
});
return $scope.showT = true;
$scope.showT = false;
$http.get(scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) {
return $scope.currentSession = transformSession(response.data);
});
return $scope.showT = false;
};
$scope.verifyU2FKey = function() {
$scope.waiting = true;
$http['post'](scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) {
$scope.currentSession = null;
return $scope.waiting = false;
}, function(resp) {
$scope.currentSession = null;
return $scope.waiting = false;
});
return $scope.showT = true;
$scope.showT = true;
$http.get(scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) {
return $scope.currentSession = transformSession(response.data);
});
return $scope.showT = false;
};
$scope.stoggle = function(scope) {
var node;
......@@ -260,8 +266,6 @@
session[key] = $scope.localeDate(value);
} else if (key.match(/^(_startTime|_updateTime)$/)) {
session[key] = _stToStr(value);
} else if (key.match(/^(_u2fKeyHandle|_u2fUserKey)$/)) {
session[key] = '########';
}
}
}
......
(function(){var c,e,d,b,g,f,a;b=25;a={_whatToTrace:[function(i,h){return"groupBy=substr("+i+",1)"},function(i,h){return i+"="+h+"*&groupBy="+i},function(i,h){return i+"="+h}],ipAddr:[function(i,h){return"groupBy=net("+i+",16,1)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",32,2)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",48,3)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",128,4)"},function(i,h){return i+"="+h+"&groupBy=_whatToTrace"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],_startTime:[function(i,h){return"groupBy=substr("+i+",8)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",10)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",11)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",12)"},function(i,h){return i+"="+h+"*&groupBy=_whatToTrace"},function(i,h,j){console.log(i);console.log(h);console.log(j);return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],doubleIp:[function(i,h){return i},function(i,h){return"_whatToTrace="+h+"&groupBy=ipAddr"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&ipAddr="+h)}]};f={_whatToTrace:function(i,h,k,j){if(k===1){return i+"="+h+"*&groupBy=substr("+i+","+(k+j+1)+")"}else{return null}},ipAddr:function(i,h,k,j){if(k>0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={delU2FKey:[{title:"deleteU2FKey",icon:"trash"}],addU2FKey:[{title:"addU2FKey",icon:"plus"}],verifyU2FKey:[{title:"verifyU2FKey",icon:"check"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteU2FKey=function(){p.waiting=true;m["delete"](scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.addU2FKey=function(){p.waiting=true;m.put(scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.verifyU2FKey=function(){p.waiting=true;m.post(scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}else{if(O.match(/^(_u2fKeyHandle|_u2fUserKey)$/)){t[O]="########"}}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J<K;J++){E=C[J];if(t[E]){M.push({title:E,value:t[E]});delete t[E]}}if(M.length>0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;I<x;I++){F=u[I];L.push({t:F._utime,title:p.localeDate(F._utime),value:"Success (IP "+F.ipAddr+")"})}}if(t._loginHistory.failedLogin){z=t._loginHistory.failedLogin;for(H=0,w=z.length;H<w;H++){F=z[H];L.push({t:F._utime,title:p.localeDate(F._utime),value:F.error+" (IP "+F.ipAddr+")"})}}delete t._loginHistory;L.sort(function(Q,P){return Q.t-P.t});N.push({title:"__loginHistory__",nodes:L})}L=[];for(O in t){D=t[O];L.push({title:O,value:D})}L.sort(function(Q,P){if(Q.title>P.title){return 1}else{if(Q.title<P.title){return -1}else{return 0}}});N.push({title:"__attributesAndMacros__",nodes:L});return{_utime:v,id:B,nodes:N}};p.currentScope=r;s=r.$modelValue.session;m.get(scriptname+"u2f/"+o+"/"+s).then(function(t){return p.currentSession=q(t.data)});return p.showT=false};p.localeDate=function(q){var r;r=new Date(q*1000);return r.toLocaleString()};p.getLanguage=function(q){p.lang=q;p.form="white";p.init();return p.showM=false};k=function(r,q,s){var t;t=q.match(/#\/(\w+)/);o="global";if(t===null){p.type="_whatToTrace"}else{if(t[1].match(/^(persistent)$/)){o=RegExp.$1;p.type="_session_uid"}else{p.type=t[1]}}return p.init()};p.$on("$locationChangeSuccess",k);n=0;p.updateTree=function(y,s,q,v,x,u){var w,r,t;p.waiting=true;r=a[p.type]?a[p.type]:p.type==="_updateTime"?a._startTime:a._whatToTrace;w=r[q](p.type,y,x);if(u>b&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"u2f/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B<z;B++){E=C[B];n++;E.id="node"+n;if(q<r.length-1){E.nodes=[];E.level=q+1;E.query=w;E.over=v;if(p.type.match(/^(?:start|update)Time$/)){E.title=E.value.replace(/^(\d{8})(\d{2})(\d{2})$/,"$2:$3").replace(/^(\d{8})(\d{2})(\d)$/,"$2:$30").replace(/^(\d{8})(\d{2})$/,"$2h").replace(/^(\d{4})(\d{2})(\d{2})/,"$1-$2-$3")}}s.push(E)}if(y===""){p.total=D.total}}return p.waiting=false},function(z){return p.waiting=false})};p.init=function(){p.waiting=true;p.data=[];return j.all([h.init(p.lang),p.updateTree("",p.data,0,0)]).then(function(){return p.waiting=false},function(q){return p.waiting=false})};l=i.path().match(/^\/(\w+)/);return p.type=l?l[1]:"_whatToTrace"}])}).call(this);
\ No newline at end of file
(function(){var c,e,d,b,g,f,a;b=25;a={_whatToTrace:[function(i,h){return"groupBy=substr("+i+",1)"},function(i,h){return i+"="+h+"*&groupBy="+i},function(i,h){return i+"="+h}],ipAddr:[function(i,h){return"groupBy=net("+i+",16,1)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",32,2)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",48,3)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",128,4)"},function(i,h){return i+"="+h+"&groupBy=_whatToTrace"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],_startTime:[function(i,h){return"groupBy=substr("+i+",8)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",10)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",11)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",12)"},function(i,h){return i+"="+h+"*&groupBy=_whatToTrace"},function(i,h,j){console.log(i);console.log(h);console.log(j);return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],doubleIp:[function(i,h){return i},function(i,h){return"_whatToTrace="+h+"&groupBy=ipAddr"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&ipAddr="+h)}]};f={_whatToTrace:function(i,h,k,j){if(k===1){return i+"="+h+"*&groupBy=substr("+i+","+(k+j+1)+")"}else{return null}},ipAddr:function(i,h,k,j){if(k>0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={delU2FKey:[{title:"deleteU2FKey",icon:"trash"}],addU2FKey:[{title:"addU2FKey",icon:"plus"}],verifyU2FKey:[{title:"verifyU2FKey",icon:"check"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteU2FKey=function(){p.waiting=true;m["delete"](scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false},function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false});return p.showT=false};p.addU2FKey=function(){p.waiting=true;m.put(scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){return p.waiting=false},function(q){return p.waiting=false});p.showT=false;m.get(scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){return p.currentSession=transformSession(q.data)});return p.showT=false};p.verifyU2FKey=function(){p.waiting=true;m.post(scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){return p.waiting=false},function(q){return p.waiting=false});p.showT=true;m.get(scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){return p.currentSession=transformSession(q.data)});return p.showT=false};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J<K;J++){E=C[J];if(t[E]){M.push({title:E,value:t[E]});delete t[E]}}if(M.length>0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;I<x;I++){F=u[I];L.push({t:F._utime,title:p.localeDate(F._utime),value:"Success (IP "+F.ipAddr+")"})}}if(t._loginHistory.failedLogin){z=t._loginHistory.failedLogin;for(H=0,w=z.length;H<w;H++){F=z[H];L.push({t:F._utime,title:p.localeDate(F._utime),value:F.error+" (IP "+F.ipAddr+")"})}}delete t._loginHistory;L.sort(function(Q,P){return Q.t-P.t});N.push({title:"__loginHistory__",nodes:L})}L=[];for(O in t){D=t[O];L.push({title:O,value:D})}L.sort(function(Q,P){if(Q.title>P.title){return 1}else{if(Q.title<P.title){return -1}else{return 0}}});N.push({title:"__attributesAndMacros__",nodes:L});return{_utime:v,id:B,nodes:N}};p.currentScope=r;s=r.$modelValue.session;m.get(scriptname+"u2f/"+o+"/"+s).then(function(t){return p.currentSession=q(t.data)});return p.showT=false};p.localeDate=function(q){var r;r=new Date(q*1000);return r.toLocaleString()};p.getLanguage=function(q){p.lang=q;p.form="white";p.init();return p.showM=false};k=function(r,q,s){var t;t=q.match(/#\/(\w+)/);o="global";if(t===null){p.type="_whatToTrace"}else{if(t[1].match(/^(persistent)$/)){o=RegExp.$1;p.type="_session_uid"}else{p.type=t[1]}}return p.init()};p.$on("$locationChangeSuccess",k);n=0;p.updateTree=function(y,s,q,v,x,u){var w,r,t;p.waiting=true;r=a[p.type]?a[p.type]:p.type==="_updateTime"?a._startTime:a._whatToTrace;w=r[q](p.type,y,x);if(u>b&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"u2f/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B<z;B++){E=C[B];n++;E.id="node"+n;if(q<r.length-1){E.nodes=[];E.level=q+1;E.query=w;E.over=v;if(p.type.match(/^(?:start|update)Time$/)){E.title=E.value.replace(/^(\d{8})(\d{2})(\d{2})$/,"$2:$3").replace(/^(\d{8})(\d{2})(\d)$/,"$2:$30").replace(/^(\d{8})(\d{2})$/,"$2h").replace(/^(\d{4})(\d{2})(\d{2})/,"$1-$2-$3")}}s.push(E)}if(y===""){p.total=D.total}}return p.waiting=false},function(z){return p.waiting=false})};p.init=function(){p.waiting=true;p.data=[];return j.all([h.init(p.lang),p.updateTree("",p.data,0,0)]).then(function(){return p.waiting=false},function(q){return p.waiting=false})};l=i.path().match(/^\/(\w+)/);return p.type=l?l[1]:"_whatToTrace"}])}).call(this);
\ No newline at end of file
......@@ -15,7 +15,7 @@
<div class="navbar navbar-default">
<div class="navbar-collapse">
<ul class="nav navbar-nav" role="grid">
<li><a id="a-persistent" href="#/persistent" role="row"><i class="glyphicon glyphicon-exclamation-sign"></i> {{translate('u2fSessions')}}</a></li>
<li><a id="a-persistent" role="row"><i class="glyphicon glyphicon-exclamation-sign"></i> {{translate('u2fSessions')}}</a></li>
</ul>
</div>
</div>
......@@ -41,10 +41,10 @@
<div class="lmmenu navbar navbar-default" ng-class="{'hidden-xs':!showM}">
<div class="navbar-collapse" ng-class="{'collapse':!showM}" id="formmenu">
<ul class="nav navbar-nav">
<!--
<li ng-if="currentSession" ng-repeat="button in menu.addU2FKey" ng-include="'menubutton.html'"></li>
<li ng-if="currentSession" ng-repeat="button in menu.verifyU2FKey" ng-include="'menubutton.html'"></li>
-->
<li ng-if="currentSession" ng-repeat="button in menu.delU2FKey" ng-include="'menubutton.html'"></li>
<li ng-if="currentSession===null" ng-repeat="button in menu.home" ng-include="'menubutton.html'"></li>
......
......@@ -137,6 +137,24 @@ sub selfRegister {
}
);
}
# Get or generate master key
elsif ( $action eq 'unregister' ) {
$self->p->updatePersistentSession( $req,
{ _totp2fSecret => '' }
);
$self->userLogger->notice('TOTP unregistration succeed');
return [ 200, [ 'Content-Type' => 'application/json' ],
['{"result":1}'] ];
}
}
1;
......@@ -74,37 +74,18 @@ sub run {
return [ 200, [ 'Content-Type' => 'application/json' ], [$challenge] ];
}
if ( $action eq 'unregistration' ) {
my ( $resp, $challenge );
unless ($resp = $req->param('registration')
and $challenge = $req->param('challenge') )
{
return $self->p->sendError( $req, 'Missing registration parameter',
400 );
}
$self->logger->debug("Get unregistration data $resp");
$self->logger->debug("Get challenge $challenge");
eval { $challenge = JSON::from_json($challenge)->{challenge} };
if ($@) {
$self->userLogger->error("Bad challenge: $@");
return $self->p->sendError( $req, 'Bad challenge', 400 );
}
my $c = $self->crypter;
if ( $c->setChallenge