Add WebAuthn to manager 2FA (#1411)
This commit is contained in:
parent
ca0bc3422d
commit
38a100f6f6
|
@ -15,6 +15,7 @@ extends qw(
|
||||||
Lemonldap::NG::Common::Conf::AccessLib
|
Lemonldap::NG::Common::Conf::AccessLib
|
||||||
);
|
);
|
||||||
|
|
||||||
|
use constant _2FTYPES => [ "UBK", "U2F", "TOTP", "WebAuthn" ];
|
||||||
our $VERSION = '2.0.10';
|
our $VERSION = '2.0.10';
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
|
@ -46,7 +47,7 @@ sub init {
|
||||||
$self->{hiddenAttributes} //= "_password";
|
$self->{hiddenAttributes} //= "_password";
|
||||||
$self->{hiddenAttributes} .= ' _session_id'
|
$self->{hiddenAttributes} .= ' _session_id'
|
||||||
unless $conf->{displaySessionId};
|
unless $conf->{displaySessionId};
|
||||||
$self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = '1';
|
$self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = $self->{WebAuthnCheck} = '1';
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ sub del2F {
|
||||||
my $epoch = $params->{epoch}
|
my $epoch = $params->{epoch}
|
||||||
or return $self->sendError( $req, 'Missing "epoch" parameter', 400 );
|
or return $self->sendError( $req, 'Missing "epoch" parameter', 400 );
|
||||||
|
|
||||||
if ( $type =~ /\b(?:U2F|TOTP|UBK)\b/ ) {
|
if ( grep { $_ eq $type } @{_2FTYPES()} ) {
|
||||||
$self->logger->debug(
|
$self->logger->debug(
|
||||||
"Call procedure delete2F with type=$type and epoch=$epoch");
|
"Call procedure delete2F with type=$type and epoch=$epoch");
|
||||||
return $self->delete2F( $req, $session, $skey );
|
return $self->delete2F( $req, $session, $skey );
|
||||||
|
@ -117,7 +118,7 @@ sub sfa {
|
||||||
$moduleOptions->{backend} = $mod->{module};
|
$moduleOptions->{backend} = $mod->{module};
|
||||||
|
|
||||||
# Select 2FA sessions to display
|
# Select 2FA sessions to display
|
||||||
foreach (qw(U2F TOTP UBK)) {
|
foreach (@{_2FTYPES()}) {
|
||||||
$self->{ $_ . 'Check' } = delete $params->{ $_ . 'Check' }
|
$self->{ $_ . 'Check' } = delete $params->{ $_ . 'Check' }
|
||||||
if ( defined $params->{ $_ . 'Check' } );
|
if ( defined $params->{ $_ . 'Check' } );
|
||||||
}
|
}
|
||||||
|
@ -188,17 +189,18 @@ sub sfa {
|
||||||
# Remove sessions without at least one 2F device(s)
|
# Remove sessions without at least one 2F device(s)
|
||||||
$self->logger->debug(
|
$self->logger->debug(
|
||||||
"Removing sessions without at least one 2F device(s)...");
|
"Removing sessions without at least one 2F device(s)...");
|
||||||
|
my $_2f_types_re = join ('|', @{_2FTYPES()});
|
||||||
foreach my $session ( keys %$res ) {
|
foreach my $session ( keys %$res ) {
|
||||||
delete $res->{$session}
|
delete $res->{$session}
|
||||||
unless ( defined $res->{$session}->{_2fDevices}
|
unless ( defined $res->{$session}->{_2fDevices}
|
||||||
and $res->{$session}->{_2fDevices} =~
|
and $res->{$session}->{_2fDevices} =~
|
||||||
/"type":\s*"(?:U2F|TOTP|UBK)"/s );
|
/"type":\s*"(?:$_2f_types_re)"/s );
|
||||||
}
|
}
|
||||||
|
|
||||||
# Filter 2FA sessions if needed
|
# Filter 2FA sessions if needed
|
||||||
$self->logger->debug("Filtering 2F sessions...");
|
$self->logger->debug("Filtering 2F sessions...");
|
||||||
my $all = ( keys %$res );
|
my $all = ( keys %$res );
|
||||||
foreach (qw(U2F TOTP UBK)) {
|
foreach (@{_2FTYPES()}) {
|
||||||
if ( $self->{ $_ . 'Check' } eq '2' ) {
|
if ( $self->{ $_ . 'Check' } eq '2' ) {
|
||||||
foreach my $session ( keys %$res ) {
|
foreach my $session ( keys %$res ) {
|
||||||
delete $res->{$session}
|
delete $res->{$session}
|
||||||
|
|
|
@ -630,7 +630,7 @@ sub tests {
|
||||||
|
|
||||||
my $msg = '';
|
my $msg = '';
|
||||||
my $ok = 0;
|
my $ok = 0;
|
||||||
foreach (qw(u totp yubikey)) {
|
foreach (qw(u totp yubikey webauthn)) {
|
||||||
$ok ||= $conf->{ $_ . '2fActivation' }
|
$ok ||= $conf->{ $_ . '2fActivation' }
|
||||||
&& $conf->{ $_ . '2fSelfRegistration' };
|
&& $conf->{ $_ . '2fSelfRegistration' };
|
||||||
last if ($ok);
|
last if ($ok);
|
||||||
|
|
|
@ -73,6 +73,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
||||||
$scope.U2FCheck = "1"
|
$scope.U2FCheck = "1"
|
||||||
$scope.TOTPCheck = "1"
|
$scope.TOTPCheck = "1"
|
||||||
$scope.UBKCheck = "1"
|
$scope.UBKCheck = "1"
|
||||||
|
$scope.WebAuthnCheck = "1"
|
||||||
|
|
||||||
# Import translations functions
|
# Import translations functions
|
||||||
$scope.translateP = $translator.translateP
|
$scope.translateP = $translator.translateP
|
||||||
|
@ -201,7 +202,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
||||||
subres = []
|
subres = []
|
||||||
for attr in attrs
|
for attr in attrs
|
||||||
if session[attr]
|
if session[attr]
|
||||||
if session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK)"/)
|
if session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK|WebAuthn)"/)
|
||||||
subres.push
|
subres.push
|
||||||
title: "type"
|
title: "type"
|
||||||
value: "name"
|
value: "name"
|
||||||
|
@ -295,7 +296,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
||||||
over = 0
|
over = 0
|
||||||
|
|
||||||
# Launch HTTP query
|
# Launch HTTP query
|
||||||
$http.get("#{scriptname}sfa/#{sessionType}?#{query}&U2FCheck=#{$scope.U2FCheck}&TOTPCheck=#{$scope.TOTPCheck}&UBKCheck=#{$scope.UBKCheck}").then (response) ->
|
$http.get("#{scriptname}sfa/#{sessionType}?#{query}&U2FCheck=#{$scope.U2FCheck}&TOTPCheck=#{$scope.TOTPCheck}&UBKCheck=#{$scope.UBKCheck}&WebAuthnCheck=#{$scope.WebAuthnCheck}").then (response) ->
|
||||||
data = response.data
|
data = response.data
|
||||||
if data.result
|
if data.result
|
||||||
for n in data.values
|
for n in data.values
|
||||||
|
@ -346,7 +347,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
||||||
over = 0
|
over = 0
|
||||||
|
|
||||||
# Launch HTTP
|
# Launch HTTP
|
||||||
$http.get("#{scriptname}sfa/#{sessionType}?_session_uid=#{$scope.searchString}*&groupBy=substr(_session_uid,#{$scope.searchString.length})&U2FCheck=#{$scope.U2FCheck}&TOTPCheck=#{$scope.TOTPCheck}&UBKCheck=#{$scope.UBKCheck}").then (response) ->
|
$http.get("#{scriptname}sfa/#{sessionType}?_session_uid=#{$scope.searchString}*&groupBy=substr(_session_uid,#{$scope.searchString.length})&U2FCheck=#{$scope.U2FCheck}&TOTPCheck=#{$scope.TOTPCheck}&UBKCheck=#{$scope.UBKCheck}&WebAuthnCheck=#{$scope.WebAuthnCheck}").then (response) ->
|
||||||
data = response.data
|
data = response.data
|
||||||
if data.result
|
if data.result
|
||||||
for n in data.values
|
for n in data.values
|
||||||
|
|
|
@ -246,7 +246,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
||||||
subres = []
|
subres = []
|
||||||
for attr in attrs
|
for attr in attrs
|
||||||
if session[attr]
|
if session[attr]
|
||||||
if session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK)"/)
|
if session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK|WebAuthn)"/)
|
||||||
subres.push
|
subres.push
|
||||||
title: "type"
|
title: "type"
|
||||||
value: "name"
|
value: "name"
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
$scope.U2FCheck = "1";
|
$scope.U2FCheck = "1";
|
||||||
$scope.TOTPCheck = "1";
|
$scope.TOTPCheck = "1";
|
||||||
$scope.UBKCheck = "1";
|
$scope.UBKCheck = "1";
|
||||||
|
$scope.WebAuthnCheck = "1";
|
||||||
$scope.translateP = $translator.translateP;
|
$scope.translateP = $translator.translateP;
|
||||||
$scope.translate = $translator.translate;
|
$scope.translate = $translator.translate;
|
||||||
$scope.translateTitle = function(node) {
|
$scope.translateTitle = function(node) {
|
||||||
|
@ -205,7 +206,7 @@
|
||||||
for (i = 0, len = attrs.length; i < len; i++) {
|
for (i = 0, len = attrs.length; i < len; i++) {
|
||||||
attr = attrs[i];
|
attr = attrs[i];
|
||||||
if (session[attr]) {
|
if (session[attr]) {
|
||||||
if (session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK)"/)) {
|
if (session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK|WebAuthn)"/)) {
|
||||||
subres.push({
|
subres.push({
|
||||||
title: "type",
|
title: "type",
|
||||||
value: "name",
|
value: "name",
|
||||||
|
@ -303,7 +304,7 @@
|
||||||
} else {
|
} else {
|
||||||
over = 0;
|
over = 0;
|
||||||
}
|
}
|
||||||
return $http.get(scriptname + "sfa/" + sessionType + "?" + query + "&U2FCheck=" + $scope.U2FCheck + "&TOTPCheck=" + $scope.TOTPCheck + "&UBKCheck=" + $scope.UBKCheck).then(function(response) {
|
return $http.get(scriptname + "sfa/" + sessionType + "?" + query + "&U2FCheck=" + $scope.U2FCheck + "&TOTPCheck=" + $scope.TOTPCheck + "&UBKCheck=" + $scope.UBKCheck + "&WebAuthnCheck=" + $scope.WebAuthnCheck).then(function(response) {
|
||||||
var data, i, len, n, ref;
|
var data, i, len, n, ref;
|
||||||
data = response.data;
|
data = response.data;
|
||||||
if (data.result) {
|
if (data.result) {
|
||||||
|
@ -345,7 +346,7 @@
|
||||||
} else {
|
} else {
|
||||||
over = 0;
|
over = 0;
|
||||||
}
|
}
|
||||||
return $http.get(scriptname + "sfa/" + sessionType + "?_session_uid=" + $scope.searchString + "*&groupBy=substr(_session_uid," + $scope.searchString.length + ")&U2FCheck=" + $scope.U2FCheck + "&TOTPCheck=" + $scope.TOTPCheck + "&UBKCheck=" + $scope.UBKCheck).then(function(response) {
|
return $http.get(scriptname + "sfa/" + sessionType + "?_session_uid=" + $scope.searchString + "*&groupBy=substr(_session_uid," + $scope.searchString.length + ")&U2FCheck=" + $scope.U2FCheck + "&TOTPCheck=" + $scope.TOTPCheck + "&UBKCheck=" + $scope.UBKCheck + "&WebAuthnCheck=" + $scope.WebAuthnCheck).then(function(response) {
|
||||||
var data, i, len, n, ref;
|
var data, i, len, n, ref;
|
||||||
data = response.data;
|
data = response.data;
|
||||||
if (data.result) {
|
if (data.result) {
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -280,7 +280,7 @@
|
||||||
for (i = 0, len = attrs.length; i < len; i++) {
|
for (i = 0, len = attrs.length; i < len; i++) {
|
||||||
attr = attrs[i];
|
attr = attrs[i];
|
||||||
if (session[attr]) {
|
if (session[attr]) {
|
||||||
if (session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK)"/)) {
|
if (session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK|WebAuthn)"/)) {
|
||||||
subres.push({
|
subres.push({
|
||||||
title: "type",
|
title: "type",
|
||||||
value: "name",
|
value: "name",
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -22,6 +22,9 @@
|
||||||
&
|
&
|
||||||
<input type="checkbox" ng-model="UBKCheck" class="form-check-input" ng-true-value="2" ng-false-value="1" ng-change="search2FA()"/>
|
<input type="checkbox" ng-model="UBKCheck" class="form-check-input" ng-true-value="2" ng-false-value="1" ng-change="search2FA()"/>
|
||||||
<label class="form-check-label" for="UBKCheck">UBK</label>
|
<label class="form-check-label" for="UBKCheck">UBK</label>
|
||||||
|
&
|
||||||
|
<input type="checkbox" ng-model="WebAuthnCheck" class="form-check-input" ng-true-value="2" ng-false-value="1" ng-change="search2FA()"/>
|
||||||
|
<label class="form-check-label" for="WebAuthnCheck">WebAuthn</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -104,16 +107,16 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div ng-if="!node.nodes" >
|
<div ng-if="!node.nodes" >
|
||||||
<th class="col-md-3" ng-if="node.title!='UBK' && node.title!='TOTP' && node.title!='U2F'">{{translate(node.title)}}</th>
|
<th class="col-md-3" ng-if="node.title!='UBK' && node.title!='TOTP' && node.title!='U2F' && node.title!='WebAuthn'">{{translate(node.title)}}</th>
|
||||||
<td class="data-{{node.epoch}}" ng-if="node.title=='TOTP' || node.title=='UBK' || node.title=='U2F'" >{{node.title}}</td>
|
<td class="data-{{node.epoch}}" ng-if="node.title=='TOTP' || node.title=='UBK' || node.title=='U2F' || node.title=='WebAuthn'" >{{node.title}}</td>
|
||||||
<th class="col-md-3" ng-if="node.title=='type'">{{translate(node.value)}}</th>
|
<th class="col-md-3" ng-if="node.title=='type'">{{translate(node.value)}}</th>
|
||||||
<td class="col-md-3 data-{{node.epoch}}" ng-if="node.title!='type'" >{{node.value}}</td>
|
<td class="col-md-3 data-{{node.epoch}}" ng-if="node.title!='type'" >{{node.value}}</td>
|
||||||
<th class="col-md-3" ng-if="node.title=='type'">{{translate(node.epoch)}}</th>
|
<th class="col-md-3" ng-if="node.title=='type'">{{translate(node.epoch)}}</th>
|
||||||
<td class="col-md-3 data-{{node.epoch}}" ng-if="node.title=='TOTP' || node.title=='UBK' || node.title=='U2F'">{{localeDate(node.epoch)}}</td>
|
<td class="col-md-3 data-{{node.epoch}}" ng-if="node.title=='TOTP' || node.title=='UBK' || node.title=='U2F' || node.title=='WebAuthn'">{{localeDate(node.epoch)}}</td>
|
||||||
<td class="data-{{node.epoch}}">
|
<td class="data-{{node.epoch}}">
|
||||||
<span ng-if="node.title=='TOTP' || node.title=='UBK' || node.title=='U2F'" class="link text-danger glyphicon glyphicon-minus-sign" ng-click="delete2FA(node.title, node.epoch)"></span>
|
<span ng-if="node.title=='TOTP' || node.title=='UBK' || node.title=='U2F' || node.title=='WebAuthn'" class="link text-danger glyphicon glyphicon-minus-sign" ng-click="delete2FA(node.title, node.epoch)"></span>
|
||||||
<!--
|
<!--
|
||||||
<span ng-if="$last && ( node.title=='TOTP' || node.title=='UBK' || node.title=='U2F' )" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newRule'})"></span>
|
<span ng-if="$last && ( node.title=='TOTP' || node.title=='UBK' || node.title=='U2F' || node.title=='WebAuthn' )" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newRule'})"></span>
|
||||||
-->
|
-->
|
||||||
</td>
|
</td>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
<td class="data-{{node.epoch}}">
|
<td class="data-{{node.epoch}}">
|
||||||
<span ng-if="node.td=='2'" class="link text-danger glyphicon glyphicon-minus-sign" ng-click="deleteOIDCConsent(node.title, node.epoch)"></span>
|
<span ng-if="node.td=='2'" class="link text-danger glyphicon glyphicon-minus-sign" ng-click="deleteOIDCConsent(node.title, node.epoch)"></span>
|
||||||
<!--
|
<!--
|
||||||
<span ng-if="$last && ( node.title=='TOTP' || node.title=='UBK' || node.title=='U2F' )" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newRule'})"></span>
|
<span ng-if="$last && ( node.title=='TOTP' || node.title=='UBK' || node.title=='U2F' || node.title=='WebAuthn' )" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newRule'})"></span>
|
||||||
-->
|
-->
|
||||||
</td>
|
</td>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user