feat(ldap): LDAP admin auto population EE-568 (#5875)

* feat(ldap): added ldap custom admin group component

* feat(ldap): added ldap custom admin group to LDAP and MS AD pages

* fix(ui): LDAP group search config label

* fix(ldap): removed testing code.

* fix(ldap): fixed default text in ldap custom admin group component
pull/5884/head
fhanportainer 2021-10-13 11:29:00 +13:00 committed by GitHub
parent 1ee363f8c9
commit 3d6c6e2604
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 189 additions and 3 deletions

View File

@ -153,5 +153,14 @@
limited-feature-id="$ctrl.limitedFeatureId" limited-feature-id="$ctrl.limitedFeatureId"
></ldap-group-search> ></ldap-group-search>
<ldap-custom-admin-group
style="margin-top: 5px;"
settings="$ctrl.settings"
on-search-click="($ctrl.onSearchAdminGroupsClick)"
selected-admin-groups="$ctrl.selectedAdminGroups"
default-admin-group-search-filter="'(objectClass=groupOfNames)'"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-custom-admin-group>
<ldap-settings-test-login settings="$ctrl.settings" limited-feature-id="$ctrl.limitedFeatureId"></ldap-settings-test-login> <ldap-settings-test-login settings="$ctrl.settings" limited-feature-id="$ctrl.limitedFeatureId"></ldap-settings-test-login>
</ng-form> </ng-form>

View File

@ -14,6 +14,7 @@ import { ldapUserSearchItem } from './ldap-user-search-item';
import { ldapSettingsDnBuilder } from './ldap-settings-dn-builder'; import { ldapSettingsDnBuilder } from './ldap-settings-dn-builder';
import { ldapSettingsGroupDnBuilder } from './ldap-settings-group-dn-builder'; import { ldapSettingsGroupDnBuilder } from './ldap-settings-group-dn-builder';
import { ldapCustomGroupSearch } from './ldap-custom-group-search'; import { ldapCustomGroupSearch } from './ldap-custom-group-search';
import { ldapCustomAdminGroup } from './ldap-custom-admin-group';
import { ldapSettingsSecurity } from './ldap-settings-security'; import { ldapSettingsSecurity } from './ldap-settings-security';
import { ldapSettingsTestLogin } from './ldap-settings-test-login'; import { ldapSettingsTestLogin } from './ldap-settings-test-login';
import { ldapCustomUserSearch } from './ldap-custom-user-search'; import { ldapCustomUserSearch } from './ldap-custom-user-search';
@ -37,6 +38,7 @@ export default angular
.component('ldapSettingsDnBuilder', ldapSettingsDnBuilder) .component('ldapSettingsDnBuilder', ldapSettingsDnBuilder)
.component('ldapSettingsGroupDnBuilder', ldapSettingsGroupDnBuilder) .component('ldapSettingsGroupDnBuilder', ldapSettingsGroupDnBuilder)
.component('ldapCustomGroupSearch', ldapCustomGroupSearch) .component('ldapCustomGroupSearch', ldapCustomGroupSearch)
.component('ldapCustomAdminGroup', ldapCustomAdminGroup)
.component('ldapSettingsOpenLdap', ldapSettingsOpenLdap) .component('ldapSettingsOpenLdap', ldapSettingsOpenLdap)
.component('ldapSettingsSecurity', ldapSettingsSecurity) .component('ldapSettingsSecurity', ldapSettingsSecurity)
.component('ldapSettingsTestLogin', ldapSettingsTestLogin) .component('ldapSettingsTestLogin', ldapSettingsTestLogin)

View File

@ -0,0 +1,13 @@
import controller from './ldap-custom-admin-group.controller';
export const ldapCustomAdminGroup = {
templateUrl: './ldap-custom-admin-group.html',
controller,
bindings: {
settings: '=',
selectedAdminGroups: '=',
defaultAdminGroupSearchFilter: '<',
onSearchClick: '<',
limitedFeatureId: '<',
},
};

View File

@ -0,0 +1,49 @@
export default class LdapCustomAdminGroupController {
/* @ngInject */
constructor($async, Notifications, LDAPService) {
Object.assign(this, { $async, Notifications, LDAPService });
this.groups = null;
this.groupstest = null;
this.enableAssignAdminGroup = false;
this.onRemoveClick = this.onRemoveClick.bind(this);
this.onAddClick = this.onAddClick.bind(this);
this.search = this.search.bind(this);
}
onAddClick() {
this.settings.AdminGroupSearchSettings.push({ GroupBaseDN: '', GroupAttribute: '', GroupFilter: '' });
}
onRemoveClick(index) {
this.settings.AdminGroupSearchSettings.splice(index, 1);
}
search() {
return this.$async(async () => {
try {
this.groups = null;
this.groups = await this.onSearchClick();
this.enableAssignAdminGroup = this.groups && this.groups.length > 0;
} catch (error) {
this.Notifications.error('Failure', error, 'Failed to search groups');
}
});
}
async $onInit() {
if (this.settings.AdminAutoPopulate && this.settings.AdminGroups && this.settings.AdminGroups.length > 0) {
const settings = {
...this.settings,
AdminGroupSearchSettings: this.settings.AdminGroupSearchSettings.map((search) => ({ ...search, GroupFilter: search.GroupFilter || this.defaultAdminGroupSearchFilter })),
};
this.groups = await this.LDAPService.adminGroups(settings);
}
if (this.groups && this.groups.length > 0) {
this.enableAssignAdminGroup = true;
}
}
}

View File

@ -0,0 +1,95 @@
<div class="col-sm-12 form-section-title" style="float: initial;">
Auto-populate team admins
</div>
<rd-widget ng-repeat="config in $ctrl.settings.AdminGroupSearchSettings | limitTo: (1 - $ctrl.settings.AdminGroupSearchSettings)" style="display: block; margin-bottom: 10px;">
<rd-widget-body>
<div class="form-group" ng-if="$index > 0" style="margin-bottom: 10px;">
<span class="col-sm-12 text-muted small">
Extra search configuration
</span>
</div>
<div class="form-group">
<label for="ldap_admin_group_basedn_{{ $index }}" class="col-sm-4 col-md-2 control-label text-left">
Group Base DN
<portainer-tooltip position="bottom" message="The distinguished name of the element from which the LDAP server will search for groups."></portainer-tooltip>
</label>
<div class="col-sm-8 col-md-4">
<input type="text" class="form-control" id="ldap_admin_group_basedn_{{ $index }}" ng-model="config.GroupBaseDN" placeholder="dc=ldap,dc=domain,dc=tld" />
</div>
<label for="ldap_admin_group_att_{{ $index }}" class="col-sm-4 col-md-2 control-label text-left">
Group Membership Attribute
<portainer-tooltip position="bottom" message="LDAP attribute which denotes the group membership."></portainer-tooltip>
</label>
<div class="col-sm-8 col-md-4">
<input type="text" class="form-control" id="ldap_admin_group_att_{{ $index }}" ng-model="config.GroupAttribute" placeholder="member" />
</div>
</div>
<div class="form-group">
<label for="ldap_admin_group_filter_{{ $index }}" class="col-sm-4 col-md-2 control-label text-left">
Group Filter
<portainer-tooltip position="bottom" message="The LDAP search filter used to select group elements, optional."></portainer-tooltip>
</label>
<div ng-class="{ 'col-sm-7 col-md-9': $index, 'col-sm-8 col-md-10': !$index }">
<input type="text" class="form-control" id="ldap_admin_group_filter_{{ $index }}" ng-model="config.GroupFilter" placeholder="(objectClass=groupOfNames)" />
</div>
<div class="col-sm-1" ng-if="$index > 0">
<button class="btn btn-sm btn-danger" type="button" ng-click="$ctrl.onRemoveClick($index)">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
</div>
</div>
</rd-widget-body>
</rd-widget>
<div class="form-group" style="margin-top: 10px;">
<div class="col-sm-12">
<button class="label label-default interactive" style="border: 0;" ng-click="$ctrl.onAddClick()">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add group search configuration
</button>
</div>
<div class="col-sm-12" style="margin-top: 10px;">
<button class="btn btm-sm btn-primary" type="button" ng-click="$ctrl.search()" limited-feature-dir="{{ $ctrl.limitedFeatureId }}" limited-feature-tabindex="-1">
Fetch Admin Group(s)
</button>
<be-feature-indicator feature="$ctrl.limitedFeatureId" class="space-left"></be-feature-indicator>
<span ng-if="$ctrl.groups && $ctrl.groups.length === 0" style="margin-left: 30px;">
<i class="fa fa-exclamation-triangle text-warning" aria-hidden="true"></i> No groups found</span
>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<label for="admin-auto-populate" class="control-label text-left text-muted" ng-class="{ 'text-muted': !$ctrl.enableAssignAdminGroup }">
Assign admin rights to group(s)
</label>
<label class="switch" style="margin-left: 20px;">
<input id="admin-auto-populate" ng-disabled="!$ctrl.enableAssignAdminGroup" name="admin-auto-populate" type="checkbox" ng-model="$ctrl.settings.AdminAutoPopulate" /><i></i>
</label>
</div>
</div>
<div class="form-group" ng-if="$ctrl.settings.AdminAutoPopulate">
<div class="col-sm-12">
<label for="group-access" class="control-label text-left">
Select Group(s)
</label>
<span
isteven-multi-select
ng-if="$ctrl.enableAssignAdminGroup"
input-model="$ctrl.groups"
output-model="$ctrl.selectedAdminGroups"
button-label="name"
item-label="name"
tick-property="selected"
helper-elements="filter"
search-property="name"
translation="{nothingSelected: 'Select one or more groups', search: 'Search...'}"
style="margin-left: 20px;"
>
</span>
</div>
</div>

View File

@ -1,5 +1,5 @@
<div class="col-sm-12 form-section-title" style="float: initial;"> <div class="col-sm-12 form-section-title" style="float: initial;">
Teams auto-population configurations Group search configurations
</div> </div>
<rd-widget ng-repeat="config in $ctrl.settings | limitTo: (1 - $ctrl.settings)" style="display: block; margin-bottom: 10px;"> <rd-widget ng-repeat="config in $ctrl.settings | limitTo: (1 - $ctrl.settings)" style="display: block; margin-bottom: 10px;">

View File

@ -1,5 +1,5 @@
<div class="col-sm-12 form-section-title" style="float: initial;"> <div class="col-sm-12 form-section-title" style="float: initial;">
Teams auto-population configurations Group search configurations
</div> </div>
<div style="margin-top: 10px;" ng-repeat="config in $ctrl.settings | limitTo: (1 - $ctrl.settings)"> <div style="margin-top: 10px;" ng-repeat="config in $ctrl.settings | limitTo: (1 - $ctrl.settings)">

View File

@ -114,6 +114,17 @@
limited-feature-id="$ctrl.limitedFeatureId" limited-feature-id="$ctrl.limitedFeatureId"
></ldap-custom-group-search> ></ldap-custom-group-search>
<div limited-feature-dir="{{ $ctrl.limitedFeatureId }}" limited-feature-class="limited-be" style="margin-bottom: 20px;">
<ldap-custom-admin-group
style="margin-top: 5px;"
settings="$ctrl.settings"
on-search-click="($ctrl.onSearchAdminGroupsClick)"
selected-admin-groups="$ctrl.selectedAdminGroups"
default-admin-group-search-filter="'(objectClass=groupOfNames)'"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-custom-admin-group>
</div>
<div limited-feature-dir="{{ $ctrl.limitedFeatureId }}" limited-feature-class="limited-be"> <div limited-feature-dir="{{ $ctrl.limitedFeatureId }}" limited-feature-class="limited-be">
<ldap-settings-test-login settings="$ctrl.settings" limited-feature-id="$ctrl.limitedFeatureId" show-be-indicator-if-needed="true"></ldap-settings-test-login> <ldap-settings-test-login settings="$ctrl.settings" limited-feature-id="$ctrl.limitedFeatureId" show-be-indicator-if-needed="true"></ldap-settings-test-login>
</div> </div>

View File

@ -23,6 +23,13 @@ export function buildLdapSettingsModel() {
GroupAttribute: '', GroupAttribute: '',
}, },
], ],
AdminGroupSearchSettings: [
{
GroupBaseDN: '',
GroupFilter: '',
GroupAttribute: '',
},
],
AutoCreateUsers: true, AutoCreateUsers: true,
}; };
} }

View File

@ -221,7 +221,7 @@ function SettingsAuthenticationController($q, $scope, $state, Notifications, Set
if (settings.LDAPSettings.ServerType === 2) { if (settings.LDAPSettings.ServerType === 2) {
$scope.formValues.ldap.adSettings = settings.LDAPSettings; $scope.formValues.ldap.adSettings = settings.LDAPSettings;
} else { } else {
$scope.formValues.ldap.ldapSettings = settings.LDAPSettings; $scope.formValues.ldap.ldapSettings = Object.assign($scope.formValues.ldap.ldapSettings, settings.LDAPSettings);
} }
if (settings.LDAPSettings.URL) { if (settings.LDAPSettings.URL) {