summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbeccabroek <beccabroek@gmail.com>2018-11-07 12:22:31 -0600
committerGunnar Mills <gmills@us.ibm.com>2019-09-26 20:04:56 +0000
commit5e258e43070b46b9d1ec5ec01e02b9f707cbf7b8 (patch)
treedcce595926ecd55bdb86f93800dcb95886cd06e5
parent5dac9e155e46cd8615a057ff6fe1577a9f21a0a7 (diff)
downloadphosphor-webui-5e258e43070b46b9d1ec5ec01e02b9f707cbf7b8.tar.gz
phosphor-webui-5e258e43070b46b9d1ec5ec01e02b9f707cbf7b8.zip
LDAP configuration and user groups
Adds LDAP page and ability to add and change configuration settings. Adds ability to add, remove and edit user groups for LDAP. Resolves openbmc/phosphor-webui#38 Resolves openbmc/phosphor-webui#39 Tested: Loaded on to a witherspoon and able to add initial LDAP config as well us update the configuration and role groups. Appropriate messages displayed to user when required fields are missing or in the incorrect format. Change-Id: If8a21f3f9d9334415ead73472e90b2a0823bf9ea Signed-off-by: beccabroek <beccabroek@gmail.com> Signed-off-by: Dixsie Wolmers <dixsiew@gmail.com> Signed-off-by: Derick Montague <derick.montague@ibm.com>
-rw-r--r--app/common/directives/app-navigation.html3
-rw-r--r--app/common/directives/ldap-user-roles.html185
-rw-r--r--app/common/directives/ldap-user-roles.js231
-rw-r--r--app/common/services/api-utils.js8
-rw-r--r--app/common/styles/components/form-elements.scss7
-rw-r--r--app/configuration/controllers/ldap-controller.html148
-rw-r--r--app/configuration/controllers/ldap-controller.js224
-rw-r--r--app/configuration/index.js5
-rw-r--r--app/configuration/styles/index.scss1
-rw-r--r--app/configuration/styles/ldap.scss269
-rw-r--r--app/index.js2
11 files changed, 1082 insertions, 1 deletions
diff --git a/app/common/directives/app-navigation.html b/app/common/directives/app-navigation.html
index 82a4a70..02b7194 100644
--- a/app/common/directives/app-navigation.html
+++ b/app/common/directives/app-navigation.html
@@ -100,6 +100,9 @@
<a href="#/configuration/date-time" ng-click="closeSubnav()"
tabindex="{{(showSubMenu && firstLevel == 'configuration') ? 0 : -1}}">Date and time settings</a>
</li>
+ <li ng-class="{'active': (path == '/configuration' || path == '/configuration/ldap')}">
+ <a href="#/configuration/ldap" ng-click="closeSubnav()"
+ tabindex="{{(showSubMenu && firstLevel == 'configuration') ? 0 : -1}}">LDAP settings</a></li>
</ul>
</li>
<li>
diff --git a/app/common/directives/ldap-user-roles.html b/app/common/directives/ldap-user-roles.html
new file mode 100644
index 0000000..1f509b8
--- /dev/null
+++ b/app/common/directives/ldap-user-roles.html
@@ -0,0 +1,185 @@
+<div class="row column">
+ <button type="button" ng-class="{'disabled' : roleGroupType === '' }" ng-disabled="roleGroupType === ''"
+ class="btn btn-tertiary" ng-click="addGroupFn(); $parent.newGroup={}">
+ <icon aria-hidden="true" file="icon-plus.svg"></icon>
+ <span>Add role group</span>
+ </button>
+ <button type="button" ng-disabled="roleGroupType === '' || !hasSelectedGroup" class="btn btn-tertiary"
+ ng-click="removeMultipleRoleGroupsFn() ">
+ <icon aria-hidden="true" file="icon-trashcan.svg"></icon>
+ <span>Remove role groups</span>
+ </button>
+</div>
+<div class="ldap__table">
+ <div class="table__row-header row column" ng-class="{'disabled' : !enabled }">
+ <div class="row column">
+ <div class="table__cell-select">
+ <label class="control-check" aria-label="select or deselect all groups">
+ <input type="checkbox" ng-disabled="!enabled || roleGroups.length < 1 " name="events__check"
+ ng-click="toggleAll()" ng-checked="roleGroupIsSelectedChanged()" ng-model="all" />
+ <span class="control__indicator"></span>
+ </label>
+ </div>
+ <div class="table__cell-sort">
+ <div class="column small-2 sort_button_wrapper">
+ <button class="sort-ascending" ng-click="sortBy('RemoteGroup', false)"></button>
+ <button class="sort-descending" ng-click="sortBy('RemoteGroup', true)"></button>
+ </div>
+ </div>
+ <div class="table__cell-ldap-group">
+ Group name
+ </div>
+ <div class="table__cell-sort">
+ <div class="column small-2 sort_button_wrapper">
+ <button class="sort-ascending" ng-click="sortBy('LocalRole', false)"></button>
+ <button class="sort-descending" ng-click="sortBy('LocalRole', true)"></button>
+ </div>
+ </div>
+ <div class="table__cell-ldap-role">
+ Group privilege
+ </div>
+ </div>
+ </div>
+ <div class="empty__logs" ng-if="roleGroups.length < 1 || !enabled">
+ <p ng-if="roleGroups.length < 1 && roleGroupType === 'ad' || roleGroupType === 'ldap'">
+ No role groups have been created yet.
+ </p>
+ <p ng-if=" roleGroupType === '' " ng-class="{'disabled' : !enabled }">
+ LDAP authentication must be enabled before creating role groups.
+ </p>
+ </div>
+ <div ng-repeat="group in roleGroups | orderBy:sortPropertyName:reverse track by $index ">
+ <div class="row column table__row-value" ng-if="enabled">
+ <div class="table__cell-select select-header">
+ <label class="control-check" aria-label="select or deselect group">
+ <input type="checkbox" name="events__check" ng-model="group.isSelected"
+ ng-change="roleGroupIsSelectedChanged(); optionToggled()" />
+ <span class="control__indicator"></span>
+ </label>
+ </div>
+ <div class="table__cell-ldap">
+ {{ group.RemoteGroup }}
+ </div>
+ <div class="table__cell-ldap">
+ {{ group.LocalRole }}
+ </div>
+ <div class="table__cell-buttons">
+ <button class="btn btn-tertiary" type="button" aria-label="edit selected role group"
+ ng-click="editGroupFn(group.RemoteGroup, group.LocalRole, $index); newGroup.RemoteGroup = group.RemoteGroup; newGroup.LocalRole = group.LocalRole; selectedGroupIndex = $index">
+ <icon aria-hidden="true" file="icon-edit.svg"></icon>
+ </button>
+ <button class="btn btn-tertiary" type="button" aria-label="delete selected role group"
+ ng-class="{'disabled' : roleGroups.length < 1}"
+ ng-click="removeGroupFn($index); newGroup.RemoteGroup = group.RemoteGroup; newGroup.LocalRole = group.LocalRole; selectedGroupIndex = $index">
+ <icon aria-hidden="true" file="icon-trashcan.svg"></icon>
+ </button>
+ </div>
+ </div>
+ </div>
+</div>
+<section class="modal" aria-hidden="true" role="dialog" ng-class="{'active': addGroup || editGroup}">
+ <h3 class="subhead">{{ addGroup ? "Add new role group" : "Edit group privilege" }}</h3>
+ <div class="modal__content-ldap">
+ <div ng-if="addGroup">
+ <form name="add__group__form" id="add__group__form" novalidate>
+ <div class="small-9">
+ <label for="group_name">Role group name</label>
+ <input type="text" name="group_name" id="group_name" ng-model="newGroup.RemoteGroup" required />
+ <div ng-messages="add__group__form.group_name.$error" class="form-error"
+ ng-class="{'visible' : add__group__form.group_name.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="small-9">
+ <label for="group__role">Privilege</label>
+ <select id="group__role" class="select__group-role" name="group__role" ng-model="newGroup.LocalRole" required>
+ <option class="courier-bold" ng-value="">Select an option</option>
+ <option class="courier-bold" ng-repeat="privilege in privileges">{{
+ privilege
+ }}</option>
+ </select>
+ <div ng-messages="add__group__form.group__role.$error" class="form-error"
+ ng-class="{'visible' : add__group__form.group__role.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ </form>
+ <div class="form-actions">
+ <button type="button" class="btn btn-primary" ng-class="{'disabled' : add__group__form.$invalid}"
+ ng-click="addRoleGroup(); $parent.addGroup=false; $parent.newGroup={}">
+ Save
+ </button>
+ <button type="button" class="btn btn-secondary" ng-click="$parent.addGroup=false; $parent.newGroup={}">
+ Cancel
+ </button>
+ </div>
+ </div>
+ <div ng-if="editGroup">
+ <form name="edit__group__form" id="edit__group__form" novalidate>
+ <label>Role group name</label>
+ <div class="small-9 edit-group-name" ng-model="newGroup.RemoteGroup">
+ {{ newGroup.RemoteGroup }}
+ </div>
+ <div class="small-9">
+ <label for="group__role__edit">Privilege</label>
+ <select id="group__role__edit" name="group__role__edit" ng-model="newGroup.LocalRole" required>
+ <option class="courier-bold" ng-repeat="privilege in privileges">{{
+ privilege
+ }}</option>
+ </select>
+ <div ng-messages="edit__group__form.group__role__edit.$error" class="form-error"
+ ng-class="{'visible' : edit__group__form.group__role__edit.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ </form>
+ <div class="form-actions">
+ <button type="button" class="btn btn-primary"
+ ng-click="editRoleGroup();$parent.editGroup=false; $parent.newGroup={}">
+ Save
+ </button>
+ <button type="button" class="btn btn-secondary" ng-click="$parent.editGroup=false; $parent.newGroup={}">
+ Cancel
+ </button>
+ </div>
+ </div>
+ </div>
+</section>
+<section class="modal" aria-hidden="true" role="dialog" ng-class="{'active': removeGroup}">
+ <h3 class="subhead">Remove role group</h3>
+ <div class="modal__content-ldap">
+ <p>Are you sure you want to remove "{{ newGroup.RemoteGroup }}"?</p>
+ </div>
+ <div class="form-actions">
+ <button type="button" class="btn btn-primary" ng-click="removeRoleGroup(); $parent.removeGroup=false; newGroup={}">
+ Remove
+ </button>
+ <button type="button" class="btn btn-secondary"
+ ng-click="removeGroup=false; $parent.removeGroup=false; newGroup={}">
+ Cancel
+ </button>
+ </div>
+</section>
+<section class="modal" aria-hidden="true" role="dialog" ng-class="{'active': removeMultipleGroups}">
+ <div class="page-header">
+ <h3>Remove role group</h3>
+ </div>
+ <div class="modal__content-ldap">
+ <p>
+ Are you sure you want to remove
+ <span ng-repeat="groups in roleGroups | filter:{isSelected:true}">{{ $last && !$first ? " and " : $first ? "" : ", "
+ }}{{ "'" + groups.RemoteGroup + "'" }}?</span>
+ </p>
+ </div>
+ <div class="form-actions">
+ <button type="button" class="btn btn-primary"
+ ng-click="removeMultipleRoleGroups();$parent.removeMultipleGroups=false; $parent.newGroup={}">
+ Remove
+ </button>
+ <button type="button" class="btn btn-secondary" ng-click="removeMultipleGroups = false">
+ Cancel
+ </button>
+ </div>
+</section>
+<div class="modal-overlay" tabindex="-1"
+ ng-class="{'active': addGroup || editGroup || removeGroup || removeMultipleGroups}"></div> \ No newline at end of file
diff --git a/app/common/directives/ldap-user-roles.js b/app/common/directives/ldap-user-roles.js
new file mode 100644
index 0000000..4e83606
--- /dev/null
+++ b/app/common/directives/ldap-user-roles.js
@@ -0,0 +1,231 @@
+window.angular && (function(angular) {
+ 'use strict';
+
+ angular.module('app.common.directives').directive('ldapUserRoles', [
+ 'APIUtils',
+ function(APIUtils) {
+ return {
+ restrict: 'E',
+ template: require('./ldap-user-roles.html'),
+ scope: {roleGroups: '=', enabled: '=', roleGroupType: '='},
+ controller: [
+ '$scope', 'APIUtils', 'toastService', '$q',
+ function($scope, APIUtils, toastService, $q) {
+ $scope.privileges = [];
+ $scope.loading = true;
+ $scope.newGroup = {};
+ $scope.selectedGroupIndex = '';
+ $scope.editGroup = false;
+ $scope.removeGroup = false;
+ $scope.removeMultipleGroups = false;
+ $scope.all = false;
+ $scope.sortPropertyName = 'id';
+ $scope.reverse = false;
+ $scope.addGroup = false;
+ $scope.hasSelectedGroup = false;
+
+ APIUtils.getAccountServiceRoles()
+ .then(
+ (data) => {
+ $scope.privileges = data;
+ },
+ (error) => {
+ console.log(JSON.stringify(error));
+ })
+ .finally(() => {
+ $scope.loading = false;
+ });
+
+ $scope.addGroupFn = () => {
+ $scope.addGroup = true;
+ };
+
+ $scope.addRoleGroup = () => {
+ const newGroup = {};
+ newGroup.RemoteGroup = $scope.newGroup.RemoteGroup;
+ newGroup.LocalRole = $scope.newGroup.LocalRole;
+
+ $scope.loading = true;
+ const data = {};
+
+ if ($scope.roleGroupType == 'ldap') {
+ data.LDAP = {};
+ data.LDAP.RemoteRoleMapping = $scope.roleGroups;
+ data.LDAP.RemoteRoleMapping.push(newGroup);
+ } else {
+ data.ActiveDirectory = {};
+ data.ActiveDirectory.RemoteRoleMapping = $scope.roleGroups;
+ data.ActiveDirectory.RemoteRoleMapping.push(newGroup);
+ }
+
+ APIUtils.saveLdapProperties(data)
+ .then(
+ (response) => {
+ toastService.success(
+ 'Group has been created successfully.');
+ },
+ (error) => {
+ toastService.error('Failed to create new group.');
+ })
+ .finally(() => {
+ $scope.loading = false;
+ });
+ };
+
+ $scope.editGroupFn = (group, role, index) => {
+ $scope.editGroup = true;
+ $scope.selectedGroupIndex = index;
+ $scope.newGroup.RemoteGroup = group;
+ $scope.newGroup.LocalRole = role;
+ };
+
+ $scope.editRoleGroup = () => {
+ $scope.loading = true;
+ const data = {};
+
+ if ($scope.roleGroupType == 'ldap') {
+ data.LDAP = {};
+ data.LDAP.RemoteRoleMapping = $scope.roleGroups;
+ data.LDAP.RemoteRoleMapping[$scope.selectedGroupIndex]
+ .LocalRole = $scope.newGroup.LocalRole;
+ } else {
+ data.ActiveDirectory = {};
+ data.ActiveDirectory.RemoteRoleMapping = $scope.roleGroups;
+ data.ActiveDirectory
+ .RemoteRoleMapping[$scope.selectedGroupIndex]
+ .LocalRole = $scope.newGroup.LocalRole;
+ }
+
+ APIUtils.saveLdapProperties(data)
+ .then(
+ (response) => {
+ toastService.success(
+ 'Group has been edited successfully.');
+ },
+ (error) => {
+ toastService.error('Failed to edit group.');
+ })
+ .finally(() => {
+ $scope.loading = false;
+ });
+ $scope.editGroup = false;
+ };
+
+ $scope.removeGroupFn = (index) => {
+ $scope.removeGroup = true;
+ $scope.selectedGroupIndex = index;
+ };
+
+ $scope.removeRoleGroup = () => {
+ $scope.loading = true;
+ const data = {};
+
+ if ($scope.roleGroupType == 'ldap') {
+ data.LDAP = {};
+ data.LDAP.RemoteRoleMapping = $scope.roleGroups;
+ data.LDAP.RemoteRoleMapping[$scope.selectedGroupIndex] =
+ $scope.newGroup;
+ } else {
+ data.ActiveDirectory = {};
+ data.ActiveDirectory.RemoteRoleMapping = $scope.roleGroups;
+ data.ActiveDirectory
+ .RemoteRoleMapping[$scope.selectedGroupIndex] =
+ $scope.newGroup;
+ }
+
+ $scope.roleGroups[$scope.selectedGroupIndex] = null;
+
+ APIUtils.saveLdapProperties(data)
+ .then(
+ (response) => {
+ toastService.success(
+ 'Group has been removed successfully.');
+ },
+ (error) => {
+ toastService.error('Failed to remove group.');
+ })
+ .finally(() => {
+ $scope.loading = false;
+ $scope.$parent.loadLdap();
+ });
+ $scope.removeGroup = false;
+ };
+
+ $scope.removeMultipleRoleGroupsFn = () => {
+ $scope.removeMultipleGroups = true;
+ };
+
+ $scope.roleGroupIsSelectedChanged = () => {
+ let groupSelected = false;
+ $scope.roleGroups.forEach(group => {
+ if (group['isSelected']) {
+ groupSelected = true;
+ }
+ });
+ $scope.hasSelectedGroup = groupSelected;
+ };
+
+ $scope.removeMultipleRoleGroups = () => {
+ $scope.loading = true;
+ const data = {};
+
+ if ($scope.roleGroupType == 'ldap') {
+ data.LDAP = {};
+ data.LDAP.RemoteRoleMapping = $scope.roleGroups.map((group) => {
+ if (group['isSelected']) {
+ return null;
+ } else {
+ return group;
+ }
+ });
+ } else {
+ data.ActiveDirectory = {};
+ data.ActiveDirectory.RemoteRoleMapping =
+ $scope.roleGroups.map((group) => {
+ if (group['isSelected']) {
+ return null;
+ } else {
+ return group;
+ }
+ });
+ }
+
+ APIUtils.saveLdapProperties(data)
+ .then(
+ (response) => {
+ toastService.success(
+ 'Groups has been removed successfully.');
+ },
+ (error) => {
+ toastService.error('Failed to remove groups.');
+ })
+ .finally(() => {
+ $scope.loading = false;
+ $scope.$parent.loadLdap();
+ });
+ $scope.removeMultipleGroups = false;
+ };
+
+ $scope.toggleAll = () => {
+ let toggleStatus = !$scope.all;
+ $scope.roleGroups.forEach((group) => {
+ group.isSelected = toggleStatus;
+ });
+ };
+
+ $scope.optionToggled = () => {
+ $scope.all = $scope.roleGroups.every((group) => {
+ return group.isSelected;
+ });
+ };
+
+ $scope.sortBy = (propertyName, isReverse) => {
+ $scope.reverse = isReverse;
+ $scope.sortPropertyName = propertyName;
+ };
+ }
+ ]
+ };
+ }
+ ]);
+})(window.angular);
diff --git a/app/common/services/api-utils.js b/app/common/services/api-utils.js
index 51da8bb..2b3cac9 100644
--- a/app/common/services/api-utils.js
+++ b/app/common/services/api-utils.js
@@ -604,6 +604,14 @@ window.angular && (function(angular) {
});
},
+ saveLdapProperties: function(properties) {
+ return $http({
+ method: 'PATCH',
+ url: DataService.getHost() + '/redfish/v1/AccountService',
+ withCredentials: true,
+ data: properties
+ });
+ },
createUser: function(user, passwd, role, enabled) {
var data = {};
data['UserName'] = user;
diff --git a/app/common/styles/components/form-elements.scss b/app/common/styles/components/form-elements.scss
index 61ca4d3..8ee6e66 100644
--- a/app/common/styles/components/form-elements.scss
+++ b/app/common/styles/components/form-elements.scss
@@ -78,7 +78,6 @@
// Checkbox
-
.control-check,
.control-radio {
position: relative;
@@ -106,6 +105,12 @@
font-size: 0;
}
+.control__label {
+ display: inline-block;
+ margin-left: 26px;
+ user-select: none;
+}
+
/* Hover and focus states */
.control-check:hover input ~ .control__indicator,
.control-check input:focus ~ .control__indicator {
diff --git a/app/configuration/controllers/ldap-controller.html b/app/configuration/controllers/ldap-controller.html
new file mode 100644
index 0000000..daace8e
--- /dev/null
+++ b/app/configuration/controllers/ldap-controller.html
@@ -0,0 +1,148 @@
+<loader loading="loading"></loader>
+<div class="ldap" id="configuration-ldap">
+ <div class="row column">
+ <h1>LDAP role group settings</h1>
+ </div>
+ <div class="row column">
+ <p>Configure LDAP settings and manage role groups.</p>
+ </div>
+ <div class="row column">
+ <h2 class="subhead">
+ Settings
+ </h2>
+ </div>
+ <div class="row column">
+ <label class="control-check ldap__control-check">
+ <input type="checkbox" id="enable-ldap-checkbox"
+ ng-change="updateServiceEnabled(); ldap__configuration.$setUntouched()"
+ ng-model="ldapProperties.ServiceEnabled" />
+ <span class="control__indicator"></span>
+ <span class="control__label">
+ <strong>Enable LDAP authentication</strong> <br>
+ LDAP authentication must be enabled to modify role groups.
+ </span>
+ </label>
+ </div>
+ <div class="row column">
+ <form id="ldap__configuration" name="ldap__configuration" ng-class="{'submitted': submitted}"
+ class="ldap__configuration" novalidate>
+ <fieldset ng-disabled="!ldapProperties.ServiceEnabled">
+ <div class="ldap__configure-settings row column">
+ <div class="large-3 column ldap__ssl-column">
+ <label class="control-check" ng-class="{'disabled' : certificates.length < 1}">
+ <input id="secure-ldap-ssl" type="checkbox" ng-model="ldapProperties.useSSL"
+ ng-checked="ldapProperties.useSSL" ng-disabled="certificates.length < 1" />
+ <span class="control__indicator"></span>
+ <span class="control__label">Secure LDAP using SSL</span>
+ </label>
+ <div>
+ <div class="ldap__certificate-info" ng-if="ldapProperties.ServiceEnabled">
+ <p>Client certificate valid until:</p>
+ <small>
+ {{clientCertificateExpires ? (clientCertificateExpires | localeDate) : 'none available'}}</small>
+ </div>
+ </div>
+ <div class="ldap__certificate-info" ng-if="data.ValidNotAfter='' || !ldapProperties.ServiceEnabled">
+ <span>SSL certificates must be uploaded to secure LDAP using SSL.</span>
+ </div>
+ <div class="ldap__certificate-info">
+ <a href="#/configuration/certificate">Go to SSL certificates</a>
+ </div>
+ </div>
+ <div class="large-9 columns ldap__server-info">
+ <div class="column service-type-column">
+ <fieldset class="ldap__server-info-service-type">
+ <legend class="content-label">Service Type</legend>
+ <label class="control-radio control__radio__label" for="open-ldap">Open LDAP
+ <input type="radio" name="service_enabled_type" id="open-ldap" value="ldap"
+ ng-checked="ldapProperties.LDAPServiceEnabled"
+ ng-change="ldapProperties.EnabledServiceUpdated = true" ng-model="ldapProperties.EnabledServiceType"
+ required />
+ <span class="control__indicator control__indicator-on control__indicator-service-type"></span>
+ </label>
+ <label class="control-radio control__radio__label" for="active-directory">Active directory
+ <input type="radio" name="service_enabled_type" id="active-directory"
+ ng-change="ldapProperties.EnabledServiceUpdated = true" value="ad"
+ ng-checked="ldapProperties.ADServiceEnabled" ng-model="ldapProperties.EnabledServiceType"
+ required />
+ <span class="control__indicator control__indicator-on control__indicator-service-type"></span>
+ </label>
+ </fieldset>
+ </div>
+ <div class="medium-6 large-4 columns">
+ <label for="ldap__uri">Server uri</label>
+ <input id="ldap__uri" name="ldap__uri" type="text"
+ ng-change="ldapProperties.ServiceAddressesUpdated = true" ng-model="ldapProperties.ServiceAddresses[0]"
+ required />
+ <div ng-messages="ldap__configuration.ldap__uri.$error" class="form-error"
+ ng-class="{'visible' : ldap__configuration.ldap__uri.$touched || submitted}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="medium-6 large-4 columns">
+ <label for="ldap__bind__dn">Bind DN</label>
+ <input id="ldap__bind__dn" name="ldap__bind__dn" type="text"
+ ng-change="ldapProperties.UsernameUpdated = true" ng-model="ldapProperties.Username" required />
+ <div ng-messages="ldap__configuration.ldap__bind__dn.$error" class="form-error"
+ ng-class="{'visible' : ldap__configuration.ldap__bind__dn.$touched || submitted}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="medium-6 large-4 columns">
+ <label for="ldap__bind_pw">Bind password</label>
+ <input id="ldap__bind_pw" type="{{showpassword ? 'text' : 'password'}}" name="ldap__bind_pw"
+ ng-change="ldapProperties.PasswordUpdated = true" autocomplete="off" ng-model="ldapProperties.Password"
+ required />
+ <button ng-model="showpassword" ng-class="{'disabled' : !ldap__configuration.$valid}"
+ ng-click="togglePassword = !togglePassword; showpassword = !showpassword;" class="password-toggle">
+ <span ng-hide="togglePassword">Show</span>
+ <span ng-show="togglePassword">Hide</span>
+ </button>
+ <div ng-messages="ldap__configuration.ldap__bind_pw.$error" class="form-error"
+ ng-class="{'visible' : ldap__configuration.ldap__bind_pw.$touched || submitted}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="medium-6 large-4 columns">
+ <label for="ldap__base__dn">Base DN</label>
+ <input id="ldap__base__dn" name="ldap__base__dn" type="text"
+ ng-change="ldapProperties.BaseDistinguishedNamesUpdated = true"
+ ng-model="ldapProperties.BaseDistinguishedNames[0]" required />
+ <div ng-messages="ldap__configuration.ldap__base__dn.$error" class="form-error"
+ ng-class="{'visible' : ldap__configuration.ldap__base__dn.$touched || submitted}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="medium-6 large-4 columns">
+ <label for="ldap__user_attribute">User id attribute (optional)</label>
+ <input id="ldap__user_attribute" name="ldap__user_attribute" type="text"
+ ng-change="ldapProperties.UsernameAttributeUpdated = true" ng-model="ldapProperties.UsernameAttribute"
+ class="ldap__optional-field" />
+ </div>
+ <div class="medium-6 large-4 columns">
+ <label for="ldap__group_attribute">Group id attribute (optional)</label>
+ <input id="ldap__group_attribute" name="ldap__group_attribute" type="text"
+ ng-change="ldapProperties.GroupsAttributeUpdated = true" ng-model="ldapProperties.GroupsAttribute"
+ class="ldap__optional-field" />
+ </div>
+ <div class="column ldap__configuration-buttons">
+ <button type="button" class="btn btn-primary" ng-disabled="!ldap__configuration.$valid"
+ ng-click="$parent.submitted=true; ldap__configuration.$valid && saveLdapSettings(); ldap__configuration.$setUntouched()">Save</button>
+ <button type="button" class="btn btn-secondary"
+ ng-click="loadLdap(); ldap__configuration.$setUntouched()">Reset</button>
+ </div>
+ </fieldset>
+ </form>
+ </div>
+</div>
+<div class="ldap-groups row column">
+ <h2 class="small-12 subhead">
+ Role groups
+ </h2>
+ <div class="row column">
+ <div class="small-12">
+ <ldap-user-roles role-groups="roleGroups" role-group-type="roleGroupType" enabled="ldapProperties.ServiceEnabled">
+ </ldap-user-roles>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/app/configuration/controllers/ldap-controller.js b/app/configuration/controllers/ldap-controller.js
new file mode 100644
index 0000000..129e3db
--- /dev/null
+++ b/app/configuration/controllers/ldap-controller.js
@@ -0,0 +1,224 @@
+/**
+ * Controller for LDAP
+ *
+ * @module app/configuration
+ * @exports ldapController
+ * @name ldapController
+ */
+
+window.angular && (function(angular) {
+ 'use strict';
+
+ angular.module('app.configuration').controller('ldapController', [
+ '$scope', 'APIUtils', '$q', 'toastService',
+ function($scope, APIUtils, $q, toastService) {
+ $scope.loading = false;
+ $scope.isSecure = false;
+ $scope.ldapProperties = {};
+ $scope.originalProperties = {};
+ $scope.submitted = false;
+ $scope.roleGroups = [];
+ $scope.roleGroupType = '';
+ $scope.clientCertificateExpires = '';
+
+ $scope.$on('$viewContentLoaded', function() {
+ $scope.loadLdap();
+ });
+
+ $scope.loadLdap = function() {
+ $scope.loading = true;
+ $scope.submitted = false;
+ var getLdapProperties =
+ APIUtils.getAllUserAccountProperties()
+ .then(function(data) {
+ $scope.ldapProperties = {
+ 'ServiceEnabled': data.LDAP.ServiceEnabled ?
+ data.LDAP.ServiceEnabled :
+ data.ActiveDirectory.ServiceEnabled ?
+ data.ActiveDirectory.ServiceEnabled :
+ false,
+ 'LDAPServiceEnabled': data.LDAP.ServiceEnabled,
+ 'ADServiceEnabled': data.ActiveDirectory.ServiceEnabled,
+ 'EnabledServiceType': data.LDAP.ServiceEnabled ?
+ 'ldap' :
+ data.ActiveDirectory.ServiceEnabled ? 'ad' : '',
+ 'ServiceAddresses': data.LDAP.ServiceEnabled ?
+ data.LDAP.ServiceAddresses :
+ data.ActiveDirectory.ServiceEnabled ?
+ data.ActiveDirectory.ServiceAddresses :
+ [],
+ 'useSSL': $scope.isSSL(
+ data.LDAP.ServiceEnabled ?
+ data.LDAP.ServiceAddresses[0] :
+ data.ActiveDirectory.ServiceAddresses[0]),
+ 'Username': data.LDAP.ServiceEnabled ?
+ data.LDAP.Authentication.Username :
+ data.ActiveDirectory.ServiceEnabled ?
+ data.ActiveDirectory.Authentication.Username :
+ '',
+ 'BaseDistinguishedNames': data.LDAP.ServiceEnabled ?
+ data.LDAP.LDAPService.SearchSettings
+ .BaseDistinguishedNames :
+ data.ActiveDirectory.ServiceEnabled ?
+ data.ActiveDirectory.LDAPService.SearchSettings
+ .BaseDistinguishedNames :
+ [],
+ 'GroupsAttribute': data.LDAP.ServiceEnabled ?
+ data.LDAP.LDAPService.SearchSettings.GroupsAttribute :
+ data.ActiveDirectory.ServiceEnabled ?
+ data.ActiveDirectory.LDAPService.SearchSettings
+ .GroupsAttribute :
+ '',
+ 'UsernameAttribute': data.LDAP.ServiceEnabled ?
+ data.LDAP.LDAPService.SearchSettings.UsernameAttribute :
+ data.ActiveDirectory.ServiceEnabled ?
+ data.ActiveDirectory.LDAPService.SearchSettings
+ .UsernameAttribute :
+ '',
+ 'AuthenticationType': data.LDAP.ServiceEnabled ?
+ data.LDAP.Authentication.AuthenticationType :
+ data.ActiveDirectory.Authentication.AuthenticationType,
+ };
+
+ $scope.roleGroupType =
+ $scope.ldapProperties.EnabledServiceType;
+
+ if ($scope.ldapProperties.ServiceEnabled) {
+ if ($scope.ldapProperties.LDAPServiceEnabled) {
+ $scope.roleGroups = data.LDAP.RemoteRoleMapping;
+ } else if ($scope.ldapProperties.ADServiceEnabled) {
+ $scope.roleGroups =
+ data.ActiveDirectory.RemoteRoleMapping;
+ }
+ }
+ })
+ .catch(function(error) {
+ console.log(JSON.stringify(error));
+ });
+ var getClientCertificate =
+ APIUtils
+ .getCertificate('/redfish/v1/AccountService/LDAP/Certificates')
+ .then(function(data) {
+ if (data.Members) {
+ var certificate = data.Members[0];
+ APIUtils.getCertificate(certificate['@odata.id'])
+ .then(
+ function(data) {
+ $scope.clientCertificateExpires =
+ data.ValidNotAfter;
+ },
+ function(error) {
+ console.log(JSON.stringify(error));
+ })
+ }
+ })
+ .catch(function(error) {
+ console.log(JSON.stringify(error));
+ });
+
+ var promises = [getLdapProperties, getClientCertificate];
+ $q.all(promises).finally(function() {
+ $scope.loading = false;
+ });
+ };
+
+ $scope.saveLdapSettings = function() {
+ for (var i in $scope.ldapProperties.ServiceAddresses) {
+ if ($scope.ldapProperties.useSSL !==
+ $scope.isSSL($scope.ldapProperties.ServiceAddresses[i])) {
+ toastService.error(
+ 'Server URI ' + $scope.ldapProperties.ServiceAddresses[i] +
+ ' must begin with ' +
+ ($scope.ldapProperties.useSSL ? 'ldaps:// ' : 'ldap:// ') +
+ 'when SSL is ' +
+ ($scope.ldapProperties.useSSL ? 'configured. ' :
+ 'not configured.'));
+ }
+ }
+
+ // Default LDAP and AD Attributes
+ let LDAP = {};
+
+ let ActiveDirectory = {};
+
+ // Data to pass to request
+ let data = {};
+ data.LDAP = LDAP;
+ data.ActiveDirectory = ActiveDirectory;
+
+ // Values to update the service type object
+ let Authentication = {};
+ Authentication.Username = $scope.ldapProperties.Username;
+ Authentication.Password = $scope.ldapProperties.Password;
+ Authentication.AuthenticationType =
+ $scope.ldapProperties.AuthenticationType;
+
+ let LDAPService = {};
+ LDAPService.SearchSettings = {};
+ LDAPService.SearchSettings.BaseDistinguishedNames =
+ $scope.ldapProperties.BaseDistinguishedNames;
+ LDAPService.SearchSettings.GroupsAttribute =
+ $scope.ldapProperties.GroupsAttribute;
+ LDAPService.SearchSettings.UsernameAttribute =
+ $scope.ldapProperties.UsernameAttribute;
+
+ let ServiceAddresses = $scope.ldapProperties.ServiceAddresses;
+ if ($scope.ldapProperties.EnabledServiceType == 'ldap') {
+ ActiveDirectory.ServiceEnabled = false;
+ LDAP.ServiceEnabled = true;
+ LDAP.Authentication = Authentication;
+ LDAP.LDAPService = LDAPService;
+ LDAP.ServiceAddresses = ServiceAddresses;
+ } else if ($scope.ldapProperties.EnabledServiceType == 'ad') {
+ ActiveDirectory.ServiceEnabled = true;
+ LDAP.ServiceEnabled = false;
+ ActiveDirectory.Authentication = Authentication;
+ ActiveDirectory.LDAPService = LDAPService;
+ ActiveDirectory.ServiceAddresses = ServiceAddresses;
+ }
+
+ APIUtils.saveLdapProperties(data).then(
+ function(response) {
+ if (!response.data.hasOwnProperty('error')) {
+ toastService.success('Successfully updated LDAP settings.');
+ $scope.loadLdap();
+ } else {
+ toastService.error('Unable to update LDAP settings.');
+ console.log(JSON.stringify(response.data.error.message));
+ }
+ },
+ function(error) {
+ toastService.error('Unable to update LDAP settings.');
+ console.log(JSON.stringify(error));
+ });
+ };
+
+ $scope.isSSL = function(uri) {
+ return uri.startsWith('ldaps://');
+ };
+ $scope.updateServiceEnabled = function() {
+ if (!$scope.ldapProperties.ServiceEnabled) {
+ $scope.ldapProperties.EnabledServiceType = '';
+ let data = {};
+ let LDAP = {};
+ data.LDAP = LDAP;
+ LDAP.ServiceEnabled = false;
+ let ActiveDirectory = {};
+ data.ActiveDirectory = ActiveDirectory;
+ ActiveDirectory.ServiceEnabled = false;
+
+ APIUtils.saveLdapProperties(data).then(
+ function(response) {
+ toastService.success('Successfully disabled LDAP.');
+ $scope.roleGroups = [];
+ $scope.loadLdap();
+ },
+ function(error) {
+ toastService.error('Unable to disable LDAP.');
+ console.log(JSON.stringify(error));
+ });
+ }
+ }
+ }
+ ]);
+})(angular);
diff --git a/app/configuration/index.js b/app/configuration/index.js
index e7e5369..4ad7ff9 100644
--- a/app/configuration/index.js
+++ b/app/configuration/index.js
@@ -41,6 +41,11 @@ window.angular && (function(angular) {
'controller': 'certificateController',
authenticated: true
})
+ .when('/configuration/ldap', {
+ 'template': require('./controllers/ldap-controller.html'),
+ 'controller': 'ldapController',
+ authenticated: true
+ })
.when('/configuration/firmware', {
'template': require('./controllers/firmware-controller.html'),
'controller': 'firmwareController',
diff --git a/app/configuration/styles/index.scss b/app/configuration/styles/index.scss
index 28d98de..2e70e84 100644
--- a/app/configuration/styles/index.scss
+++ b/app/configuration/styles/index.scss
@@ -3,3 +3,4 @@
@import "./date-time.scss";
@import "./firmware.scss";
@import "./certificate.scss";
+@import "./ldap.scss";
diff --git a/app/configuration/styles/ldap.scss b/app/configuration/styles/ldap.scss
new file mode 100644
index 0000000..a18ac70
--- /dev/null
+++ b/app/configuration/styles/ldap.scss
@@ -0,0 +1,269 @@
+// LDAP SCSS
+
+.ldap__optional-field {
+ margin-bottom: 1.7em;
+}
+
+.ldap__configure-settings {
+ background-color: $base-02--06;
+ padding-top: 1.5em;
+ padding-bottom: 1.5em;
+ margin-top: 1em;
+ margin-bottom: 3em;
+}
+
+.ldap__server-info {
+ @media (min-width: 1024px) {
+ border-left: 1px solid $border-color-01;
+ }
+
+ .control-radio {
+ margin-bottom: 6px;
+ display: block;
+ }
+
+ .service-type-column {
+ margin-bottom: 1.2em;
+ }
+}
+
+.ldap__ssl-column {
+ padding-left: 1.5em;
+ .control__label {
+ text-transform: none;
+ font-weight: 400;
+ font-size: 16px;
+ color: $primary-dark;
+ }
+ .control__indicator {
+ top: 5px;
+ }
+}
+
+.ldap__configuration-buttons {
+ margin-top: 1rem;
+
+ @media (min-width: 1024px) {
+ margin-top: 0;
+ }
+
+ .btn {
+ float: right;
+ margin-left: 0.5em;
+ margin-top: 0.5em;
+ }
+
+ .btn-secondary {
+ background-color: $primary-light;
+ }
+
+ .btn-secondary:disabled {
+ color: $base-02--03;
+ border-color: $border-color-02;
+ }
+}
+
+.ldap__server-info-service-type {
+ .content-label {
+ margin-bottom: 1rem;
+ }
+}
+
+.ldap__certificate-info {
+ padding-top: 0.5em;
+ small {
+ font-size: 14px;
+ }
+ p {
+ color: $base-02--02;
+ text-transform: uppercase;
+ font-weight: 700;
+ font-size: 0.75em;
+ margin-bottom: 0;
+ }
+}
+
+.control__radio__label {
+ padding: 0.2em 1em 0 2em;
+ text-transform: none;
+ font-weight: 400;
+ font-size: 16px;
+ color: $primary-dark;
+}
+
+.ldap__control-check {
+ text-transform: none;
+ font-weight: 400;
+ font-size: 16px;
+ color: $primary-dark;
+
+ .control__indicator {
+ top: 11px;
+ }
+
+ .control__label {
+ margin-left: 30px;
+ }
+}
+
+.control-radio .control__indicator-service-type {
+ width: 20px;
+ height: 20px;
+}
+
+.control-radio .control__indicator-service-type:after {
+ top: 3px;
+ left: 3px;
+ width: 10px;
+ height: 10px;
+}
+
+.control-radio input:disabled ~ .control__indicator-service-type:after {
+ top: 0;
+ left: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.password-toggle {
+ color: $base-01--03;
+ font-size: 0.8em;
+ float: right;
+ position: relative;
+ z-index: 2;
+ padding: 6px 0 0 0;
+}
+
+.password-toggle.disabled {
+ background: transparent;
+ color: $base-02--03;
+ border: none;
+}
+
+.ldap-groups {
+ .ldap__table {
+ border-left: 1px solid $border-color-01;
+ border-right: 1px solid $border-color-01;
+
+ .empty__logs {
+ margin-top: 0;
+ }
+
+ .table__row-header {
+ width: 100%;
+ border-bottom: 1px solid $border-color-01;
+ background-color: $primary-dark;
+ color: $primary-light;
+ font-weight: 700;
+ padding: 0;
+ }
+
+ .table__row-header.disabled {
+ opacity: 0.8;
+ }
+
+ .table__row-value {
+ width: 100%;
+ border-bottom: 1px solid $border-color-01;
+ }
+
+ .table__cell-ldap {
+ width: 30%;
+ padding: 1.3em 1.5em 0.8em 1.5em;
+ }
+
+ .table__cell-select {
+ width: 8%;
+ padding: 1.3em 1.5em 0.8em 1.5em;
+ .select-header {
+ padding-top: 1em;
+ }
+ }
+
+ .table__cell-sort {
+ padding: 0.4em 1em 0 0;
+ margin: 0 -25px 0 -13px;
+ }
+
+ .table__cell-ldap-group {
+ width: 29%;
+ padding: 1.2em 0.5em 0.8em 0.75em;
+ }
+
+ .table__cell-ldap-role {
+ width: 30%;
+ padding: 1.2em 0.5em 0.8em 0.75em;
+ }
+
+ .table__cell-buttons {
+ width: 32%;
+ text-align: right;
+ padding: 0.8em;
+ .btn {
+ padding-left: 0;
+ padding-right: 0;
+ }
+ }
+ }
+
+ .btn-add-group,
+ .btn-remove-group {
+ color: $base-01--03;
+ padding: 0.75em 0;
+ }
+
+ .modal__content-ldap {
+ margin-bottom: 2em;
+ margin-top: 2em;
+ input[type="text"] {
+ max-height: 2.4em;
+ }
+ select {
+ margin: 0 0 0;
+ }
+ }
+
+ .edit-group-name {
+ padding-bottom: 1em;
+ }
+
+ .form-actions {
+ width: 100%;
+ padding-top: 2em;
+ margin-top: 1.5em;
+ border-top: 1px solid $border-color-01;
+ button {
+ display: block;
+ float: right;
+ margin: 0 0 0 1em;
+ }
+ }
+
+ .sort-ascending,
+ .sort-descending {
+ display: block;
+ padding: 0;
+ color: $primary-light;
+ font-size: 1em;
+ transform: rotate(-90deg);
+
+ &:hover {
+ color: $primary-accent;
+ }
+
+ &:after {
+ content: "\276F";
+ }
+
+ &:focus {
+ outline: 0;
+ color: $primary-accent;
+ }
+ }
+
+ .sort-descending {
+ &:after {
+ content: "\276e";
+ }
+ }
+}
diff --git a/app/index.js b/app/index.js
index 918748a..3f25a72 100644
--- a/app/index.js
+++ b/app/index.js
@@ -51,6 +51,7 @@ import log_event from './common/directives/log-event.js';
import certificate from './common/directives/certificate.js';
import log_filter from './common/directives/log-filter.js';
import log_search_control from './common/directives/log-search-control.js';
+import ldap_user_roles from './common/directives/ldap-user-roles.js';
import toggle_flag from './common/directives/toggle-flag.js';
import firmware_list from './common/directives/firmware-list.js';
import file from './common/directives/file.js';
@@ -101,6 +102,7 @@ import date_time_controller from './configuration/controllers/date-time-controll
import certificate_controller from './configuration/controllers/certificate-controller.js';
import network_controller from './configuration/controllers/network-controller.js';
import snmp_controller from './configuration/controllers/snmp-controller.js';
+import ldap_controller from './configuration/controllers/ldap-controller.js';
import firmware_controller from './configuration/controllers/firmware-controller.js';
import users_index from './users/index.js';
OpenPOWER on IntegriCloud