mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-06 18:57:56 +01:00
org 2fa management for duo
This commit is contained in:
parent
08b2184e12
commit
24bf1363ab
@ -26,7 +26,8 @@ angular.module('bit')
|
|||||||
duo: 2,
|
duo: 2,
|
||||||
authenticator: 0,
|
authenticator: 0,
|
||||||
email: 1,
|
email: 1,
|
||||||
remember: 5
|
remember: 5,
|
||||||
|
organizationDuo: 6
|
||||||
},
|
},
|
||||||
cipherType: {
|
cipherType: {
|
||||||
login: 1,
|
login: 1,
|
||||||
@ -153,6 +154,19 @@ angular.module('bit')
|
|||||||
requiresUsb: false
|
requiresUsb: false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
orgTwoFactorProviderInfo: [
|
||||||
|
{
|
||||||
|
type: 6,
|
||||||
|
name: 'Duo',
|
||||||
|
description: 'Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.',
|
||||||
|
enabled: false,
|
||||||
|
active: true,
|
||||||
|
image: 'duo.png',
|
||||||
|
displayOrder: 1,
|
||||||
|
priority: 0,
|
||||||
|
requiresUsb: false
|
||||||
|
}
|
||||||
|
],
|
||||||
plans: {
|
plans: {
|
||||||
free: {
|
free: {
|
||||||
basePrice: 0,
|
basePrice: 0,
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
.module('bit.organization')
|
.module('bit.organization')
|
||||||
|
|
||||||
.controller('organizationSettingsController', function ($scope, $state, apiService, toastr, authService, $uibModal,
|
.controller('organizationSettingsController', function ($scope, $state, apiService, toastr, authService, $uibModal,
|
||||||
$analytics, appSettings) {
|
$analytics, appSettings, constants, $filter) {
|
||||||
$scope.selfHosted = appSettings.selfHosted;
|
$scope.selfHosted = appSettings.selfHosted;
|
||||||
$scope.model = {};
|
$scope.model = {};
|
||||||
|
$scope.twoStepProviders = constants.orgTwoFactorProviderInfo;
|
||||||
|
$scope.use2fa = false;
|
||||||
|
|
||||||
$scope.$on('$viewContentLoaded', function () {
|
$scope.$on('$viewContentLoaded', function () {
|
||||||
apiService.organizations.get({ id: $state.params.orgId }, function (org) {
|
apiService.organizations.get({ id: $state.params.orgId }).$promise.then(function (org) {
|
||||||
$scope.model = {
|
$scope.model = {
|
||||||
name: org.Name,
|
name: org.Name,
|
||||||
billingEmail: org.BillingEmail,
|
billingEmail: org.BillingEmail,
|
||||||
@ -17,6 +20,29 @@
|
|||||||
businessCountry: org.BusinessCountry,
|
businessCountry: org.BusinessCountry,
|
||||||
businessTaxNumber: org.BusinessTaxNumber
|
businessTaxNumber: org.BusinessTaxNumber
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.use2fa = org.Use2fa;
|
||||||
|
if (org.Use2fa) {
|
||||||
|
return apiService.twoFactor.listOrganization({ orgId: $state.params.orgId }).$promise;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).then(function (response) {
|
||||||
|
if (!response || !response.Data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < response.Data.length; i++) {
|
||||||
|
if (!response.Data[i].Enabled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var provider = $filter('filter')($scope.twoStepProviders, { type: response.Data[i].Type });
|
||||||
|
if (provider.length) {
|
||||||
|
provider[0].enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -56,4 +82,30 @@
|
|||||||
controller: 'organizationDeleteController'
|
controller: 'organizationDeleteController'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.edit = function (provider) {
|
||||||
|
if (provider.type === constants.twoFactorProvider.organizationDuo) {
|
||||||
|
typeName = 'Duo';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var modal = $uibModal.open({
|
||||||
|
animation: true,
|
||||||
|
templateUrl: 'app/settings/views/settingsTwoStep' + typeName + '.html',
|
||||||
|
controller: 'settingsTwoStep' + typeName + 'Controller',
|
||||||
|
resolve: {
|
||||||
|
enabled: function () { return provider.enabled; },
|
||||||
|
orgId: function () { return $state.params.orgId; }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.result.then(function (enabled) {
|
||||||
|
if (enabled || enabled === false) {
|
||||||
|
// do not adjust when undefined or null
|
||||||
|
provider.enabled = enabled;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
@ -63,6 +63,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="box box-default" ng-if="use2fa">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">Two-step Login Providers</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body no-padding">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover table-vmiddle">
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="provider in twoStepProviders | orderBy: 'displayOrder'">
|
||||||
|
<td style="width: 120px; height: 75px;" align="center">
|
||||||
|
<a href="#" stop-click ng-click="edit(provider)">
|
||||||
|
<img alt="{{::provider.name}}" ng-src="{{'images/two-factor/' + provider.image}}" />
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" stop-click ng-click="edit(provider)">{{::provider.name}}</a>
|
||||||
|
<div class="text-muted text-sm">{{::provider.description}}</div>
|
||||||
|
</td>
|
||||||
|
<td style="width: 100px;" class="text-right">
|
||||||
|
<span class="label label-full"
|
||||||
|
ng-class="{ 'label-success': provider.enabled, 'label-default': !provider.enabled }">
|
||||||
|
{{provider.enabled ? 'Enabled' : 'Disabled'}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="box box-default">
|
<div class="box box-default">
|
||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title">Import/Export</h3>
|
<h3 class="box-title">Import/Export</h3>
|
||||||
|
@ -160,9 +160,11 @@
|
|||||||
|
|
||||||
_service.twoFactor = $resource(_apiUri + '/two-factor', {}, {
|
_service.twoFactor = $resource(_apiUri + '/two-factor', {}, {
|
||||||
list: { method: 'GET', params: {} },
|
list: { method: 'GET', params: {} },
|
||||||
|
listOrganization: { url: _apiUri + '/organizations/:orgId/two-factor', method: 'GET', params: { orgId: '@orgId' } },
|
||||||
getEmail: { url: _apiUri + '/two-factor/get-email', method: 'POST', params: {} },
|
getEmail: { url: _apiUri + '/two-factor/get-email', method: 'POST', params: {} },
|
||||||
getU2f: { url: _apiUri + '/two-factor/get-u2f', method: 'POST', params: {} },
|
getU2f: { url: _apiUri + '/two-factor/get-u2f', method: 'POST', params: {} },
|
||||||
getDuo: { url: _apiUri + '/two-factor/get-duo', method: 'POST', params: {} },
|
getDuo: { url: _apiUri + '/two-factor/get-duo', method: 'POST', params: {} },
|
||||||
|
getOrganizationDuo: { url: _apiUri + '/organizations/:orgId/two-factor/get-duo', method: 'POST', params: { orgId: '@orgId' } },
|
||||||
getAuthenticator: { url: _apiUri + '/two-factor/get-authenticator', method: 'POST', params: {} },
|
getAuthenticator: { url: _apiUri + '/two-factor/get-authenticator', method: 'POST', params: {} },
|
||||||
getYubi: { url: _apiUri + '/two-factor/get-yubikey', method: 'POST', params: {} },
|
getYubi: { url: _apiUri + '/two-factor/get-yubikey', method: 'POST', params: {} },
|
||||||
sendEmail: { url: _apiUri + '/two-factor/send-email', method: 'POST', params: {} },
|
sendEmail: { url: _apiUri + '/two-factor/send-email', method: 'POST', params: {} },
|
||||||
@ -171,8 +173,10 @@
|
|||||||
putU2f: { url: _apiUri + '/two-factor/u2f', method: 'POST', params: {} },
|
putU2f: { url: _apiUri + '/two-factor/u2f', method: 'POST', params: {} },
|
||||||
putAuthenticator: { url: _apiUri + '/two-factor/authenticator', method: 'POST', params: {} },
|
putAuthenticator: { url: _apiUri + '/two-factor/authenticator', method: 'POST', params: {} },
|
||||||
putDuo: { url: _apiUri + '/two-factor/duo', method: 'POST', params: {} },
|
putDuo: { url: _apiUri + '/two-factor/duo', method: 'POST', params: {} },
|
||||||
|
putOrganizationDuo: { url: _apiUri + '/organizations/:orgId/two-factor/duo', method: 'POST', params: { orgId: '@orgId' } },
|
||||||
putYubi: { url: _apiUri + '/two-factor/yubikey', method: 'POST', params: {} },
|
putYubi: { url: _apiUri + '/two-factor/yubikey', method: 'POST', params: {} },
|
||||||
disable: { url: _apiUri + '/two-factor/disable', method: 'POST', params: {} },
|
disable: { url: _apiUri + '/two-factor/disable', method: 'POST', params: {} },
|
||||||
|
disableOrganization: { url: _apiUri + '/organizations/:orgId/two-factor/disable', method: 'POST', params: { orgId: '@orgId' } },
|
||||||
recover: { url: _apiUri + '/two-factor/recover', method: 'POST', params: {} },
|
recover: { url: _apiUri + '/two-factor/recover', method: 'POST', params: {} },
|
||||||
getRecover: { url: _apiUri + '/two-factor/get-recover', method: 'POST', params: {} }
|
getRecover: { url: _apiUri + '/two-factor/get-recover', method: 'POST', params: {} }
|
||||||
});
|
});
|
||||||
|
@ -152,6 +152,7 @@ angular
|
|||||||
useGroups: profile.Organizations[i].UseGroups,
|
useGroups: profile.Organizations[i].UseGroups,
|
||||||
useDirectory: profile.Organizations[i].UseDirectory,
|
useDirectory: profile.Organizations[i].UseDirectory,
|
||||||
useEvents: profile.Organizations[i].UseEvents,
|
useEvents: profile.Organizations[i].UseEvents,
|
||||||
|
use2fa: profile.Organizations[i].Use2fa,
|
||||||
useTotp: profile.Organizations[i].UseTotp
|
useTotp: profile.Organizations[i].UseTotp
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -187,6 +188,7 @@ angular
|
|||||||
useGroups: org.UseGroups,
|
useGroups: org.UseGroups,
|
||||||
useDirectory: org.UseDirectory,
|
useDirectory: org.UseDirectory,
|
||||||
useEvents: org.UseEvents,
|
useEvents: org.UseEvents,
|
||||||
|
use2fa: org.Use2fa,
|
||||||
useTotp: org.UseTotp
|
useTotp: org.UseTotp
|
||||||
};
|
};
|
||||||
profile.organizations[o.id] = o;
|
profile.organizations[o.id] = o;
|
||||||
|
@ -60,7 +60,8 @@
|
|||||||
templateUrl: 'app/settings/views/settingsTwoStep' + typeName + '.html',
|
templateUrl: 'app/settings/views/settingsTwoStep' + typeName + '.html',
|
||||||
controller: 'settingsTwoStep' + typeName + 'Controller',
|
controller: 'settingsTwoStep' + typeName + 'Controller',
|
||||||
resolve: {
|
resolve: {
|
||||||
enabled: function () { return provider.enabled; }
|
enabled: function () { return provider.enabled; },
|
||||||
|
orgId: function () { return null; }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
.module('bit.settings')
|
.module('bit.settings')
|
||||||
|
|
||||||
.controller('settingsTwoStepDuoController', function ($scope, apiService, $uibModalInstance, cryptoService,
|
.controller('settingsTwoStepDuoController', function ($scope, apiService, $uibModalInstance, cryptoService,
|
||||||
toastr, $analytics, constants, $timeout) {
|
toastr, $analytics, constants, $timeout, orgId) {
|
||||||
$analytics.eventTrack('settingsTwoStepDuoController', { category: 'Modal' });
|
$analytics.eventTrack('settingsTwoStepDuoController', { category: 'Modal' });
|
||||||
var _masterPasswordHash;
|
var _masterPasswordHash;
|
||||||
|
|
||||||
@ -20,9 +20,16 @@
|
|||||||
$scope.auth = function (model) {
|
$scope.auth = function (model) {
|
||||||
$scope.authPromise = cryptoService.hashPassword(model.masterPassword).then(function (hash) {
|
$scope.authPromise = cryptoService.hashPassword(model.masterPassword).then(function (hash) {
|
||||||
_masterPasswordHash = hash;
|
_masterPasswordHash = hash;
|
||||||
return apiService.twoFactor.getDuo({}, {
|
var requestModel = {
|
||||||
masterPasswordHash: _masterPasswordHash
|
masterPasswordHash: _masterPasswordHash
|
||||||
}).$promise;
|
};
|
||||||
|
|
||||||
|
if (orgId) {
|
||||||
|
return apiService.twoFactor.getOrganizationDuo({ orgId: orgId }, requestModel).$promise;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return apiService.twoFactor.getDuo({}, requestModel).$promise;
|
||||||
|
}
|
||||||
}).then(function (apiResponse) {
|
}).then(function (apiResponse) {
|
||||||
processResult(apiResponse);
|
processResult(apiResponse);
|
||||||
$scope.authed = true;
|
$scope.authed = true;
|
||||||
@ -43,6 +50,18 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (orgId) {
|
||||||
|
$scope.submitPromise = apiService.twoFactor.disableOrganization({ orgId: orgId }, {
|
||||||
|
masterPasswordHash: _masterPasswordHash,
|
||||||
|
type: constants.twoFactorProvider.organizationDuo
|
||||||
|
}, function (response) {
|
||||||
|
$analytics.eventTrack('Disabled Two-step Organization Duo');
|
||||||
|
toastr.success('Duo has been disabled.');
|
||||||
|
$scope.enabled = response.Enabled;
|
||||||
|
$scope.close();
|
||||||
|
}).$promise;
|
||||||
|
}
|
||||||
|
else {
|
||||||
$scope.submitPromise = apiService.twoFactor.disable({}, {
|
$scope.submitPromise = apiService.twoFactor.disable({}, {
|
||||||
masterPasswordHash: _masterPasswordHash,
|
masterPasswordHash: _masterPasswordHash,
|
||||||
type: constants.twoFactorProvider.duo
|
type: constants.twoFactorProvider.duo
|
||||||
@ -53,18 +72,31 @@
|
|||||||
$scope.close();
|
$scope.close();
|
||||||
}).$promise;
|
}).$promise;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function update(model) {
|
function update(model) {
|
||||||
$scope.submitPromise = apiService.twoFactor.putDuo({}, {
|
var requestModel = {
|
||||||
integrationKey: model.ikey,
|
integrationKey: model.ikey,
|
||||||
secretKey: model.skey,
|
secretKey: model.skey,
|
||||||
host: model.host,
|
host: model.host,
|
||||||
masterPasswordHash: _masterPasswordHash
|
masterPasswordHash: _masterPasswordHash
|
||||||
}, function (response) {
|
};
|
||||||
|
|
||||||
|
if (orgId) {
|
||||||
|
$scope.submitPromise = apiService.twoFactor.putOrganizationDuo({ orgId: orgId }, requestModel,
|
||||||
|
function (response) {
|
||||||
|
$analytics.eventTrack('Enabled Two-step Organization Duo');
|
||||||
|
processResult(response);
|
||||||
|
}).$promise;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$scope.submitPromise = apiService.twoFactor.putDuo({}, requestModel,
|
||||||
|
function (response) {
|
||||||
$analytics.eventTrack('Enabled Two-step Duo');
|
$analytics.eventTrack('Enabled Two-step Duo');
|
||||||
processResult(response);
|
processResult(response);
|
||||||
}).$promise;
|
}).$promise;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function processResult(response) {
|
function processResult(response) {
|
||||||
$scope.enabled = response.Enabled;
|
$scope.enabled = response.Enabled;
|
||||||
|
Loading…
Reference in New Issue
Block a user