You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sw...@apache.org on 2014/09/19 20:24:51 UTC
[2/2] git commit: AMBARI-7417. Admin Views: Remove SYNC LDAP from the
UI and create commandline ambari-server sync-ldap to call the API for
syncing.
AMBARI-7417. Admin Views: Remove SYNC LDAP from the UI and create commandline ambari-server sync-ldap to call the API for syncing.
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/21d784b6
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/21d784b6
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/21d784b6
Branch: refs/heads/trunk
Commit: 21d784b68764899c8aa7262ba4b9a447911ddc22
Parents: d018aa6
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Fri Sep 19 11:21:04 2014 -0700
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Fri Sep 19 11:24:05 2014 -0700
----------------------------------------------------------------------
.../main/resources/ui/admin-web/app/index.html | 1 -
.../app/scripts/controllers/NavbarCtrl.js | 22 +-
.../ui/admin-web/app/scripts/services/ldap.js | 60 -
.../resources/ui/admin-web/app/styles/main.css | 10 +-
.../ui/admin-web/app/views/leftNavbar.html | 9 -
ambari-server/sbin/ambari-server | 4 +
.../controller/AmbariManagementController.java | 10 +-
.../AmbariManagementControllerImpl.java | 31 +-
.../internal/ControllerResourceProvider.java | 53 +-
.../server/security/authorization/Users.java | 17 +-
.../security/ldap/AmbariLdapDataPopulator.java | 268 +++-
ambari-server/src/main/python/ambari-server.py | 74 +
.../ldap/AmbariLdapDataPopulatorTest.java | 1329 +++++++++++++++++-
.../security/ldap/LdapPerformanceTest.java | 10 +-
14 files changed, 1673 insertions(+), 225 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-admin/src/main/resources/ui/admin-web/app/index.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/index.html b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
index 7ff0638..2fb9fce 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/index.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
@@ -134,7 +134,6 @@
<script src="scripts/services/User.js"></script>
<script src="scripts/services/Group.js"></script>
<script src="scripts/services/View.js"></script>
- <script src="scripts/services/ldap.js"></script>
<script src="scripts/services/Cluster.js"></script>
<script src="scripts/services/uiAlert.js"></script>
<script src="scripts/services/PermissionLoader.js"></script>
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
index 9434cff..130d6fc 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
@@ -18,7 +18,7 @@
'use strict';
angular.module('ambariAdminConsole')
-.controller('NavbarCtrl',['$scope', 'Cluster', '$location', 'uiAlert', 'ROUTES', 'LDAP', 'ConfirmationModal', '$rootScope', function($scope, Cluster, $location, uiAlert, ROUTES, LDAP, ConfirmationModal, $rootScope) {
+.controller('NavbarCtrl',['$scope', 'Cluster', '$location', 'uiAlert', 'ROUTES', 'ConfirmationModal', '$rootScope', function($scope, Cluster, $location, uiAlert, ROUTES, ConfirmationModal, $rootScope) {
$scope.cluster = null;
$scope.editCluster = {
name : '',
@@ -73,24 +73,4 @@ angular.module('ambariAdminConsole')
var r = new RegExp( route.url.replace(/(:\w+)/, '\\w+'));
return r.test($location.path());
};
-
- $scope.isLDAPConfigured = false;
- $scope.ldapData = {};
- LDAP.get().then(function(data) {
- $scope.ldapData = data.data;
- $scope.isLDAPConfigured = data.data['LDAP']['configured'];
- });
-
- $scope.syncLDAP = function() {
- ConfirmationModal.show('Sync LDAP', 'Are you sure you want to sync LDAP?').then(function() {
- LDAP.sync($scope.ldapData['LDAP'].groups, $scope.ldapData['LDAP'].users).then(function() {
- uiAlert.success('LDAP synced successful');
- $rootScope.$evalAsync(function() {
- $rootScope.LDAPSynced = true;
- });
- }).catch(function(data) {
- uiAlert.danger(data.data.status, data.data.message);
- });
- });
- };
}]);
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ldap.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ldap.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ldap.js
deleted file mode 100644
index a911ec2..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ldap.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-'use strict';
-
-angular.module('ambariAdminConsole')
-.factory('LDAP', ['$http', '$q', 'Settings', function($http, $q, Settings) {
-
-
- return {
- get: function() {
- return $http({
- method: 'GET',
- url: '/api/v1/controllers/ldap'
- });
- },
- sync: function(groupsList, usersList) {
- groupsList = Array.isArray(groupsList) ? groupsList : [];
- usersList = Array.isArray(usersList) ? usersList : [];
- return $http({
- method: 'PUT',
- url: Settings.baseUrl + '/controllers/ldap',
- data:[{
- LDAP:{
- "synced_groups": groupsList.join(','),
- "synced_users": usersList.join(',')
- }
- }]
- });
- },
- syncResource: function(resourceType, items) {
- var items = items.map(function(item) {
- var name = 'LDAP/synced_' + resourceType;
- var obj = {};
- obj['LDAP/synced_' + resourceType] = item;
- return obj;
- });
-
- return $http({
- method: 'POST',
- url: '/api/v1/controllers/ldap',
- data: items
- });
- }
- };
-}]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
index 4d6d081..131f452 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
@@ -345,11 +345,6 @@
-o-transform: translateY(2px);
transform: translateY(2px);
}
-.btn.disabled.syncldapbtn{
- pointer-events: auto;
- background-color: #e6e6e6;
- cursor: not-allowed;
-}
.btn.deleteuser-btn.disabled, .btn.deleteuser-btn[disabled], .btn.btn-delete-instance.disabled{
pointer-events: auto;
cursor: not-allowed;
@@ -466,9 +461,6 @@
font-size: 13px;
color: #428bca;
}
-.left-navbar .panel-body #LDAP-button {
- padding: 5px;
-}
.left-navbar .panel-body hr{
margin-top: 5px;
margin-bottom: 5px;
@@ -1099,4 +1091,4 @@ button.btn.btn-xs{
accordion .panel-group .panel{
overflow: visible;
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
index 8119428..4680e9a 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
@@ -85,15 +85,6 @@
<li ng-class="{active: isActive('users.list')}"><link-to route="users.list" class="userslist-link">Users</link-to></li>
<li ng-class="{active: isActive('groups.list')}"><link-to route="groups.list" class="groupslist-link">Groups</link-to></li>
</ul>
- <hr>
- <div id="LDAP-button" ng-switch="isLDAPConfigured">
- <a ng-switch-when="true" href class="btn btn-primary btn-block syncldapbtn" ng-click="syncLDAP()">
- <span class="glyphicon glyphicon-transfer pulldown2"></span> Sync LDAP
- </a>
- <a ng-switch-default href class="btn btn-default btn-block syncldapbtn disabled" tooltip="LDAP is not configured. To configure LDAP, run ambari-server setup-ldap from the command line.">
- <span class="glyphicon glyphicon-transfer pulldown2"></span> Sync LDAP
- </a>
- </div>
</div>
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-server/sbin/ambari-server
----------------------------------------------------------------------
diff --git a/ambari-server/sbin/ambari-server b/ambari-server/sbin/ambari-server
index f4b66eb..027bf87 100644
--- a/ambari-server/sbin/ambari-server
+++ b/ambari-server/sbin/ambari-server
@@ -115,6 +115,10 @@ case "$1" in
echo -e "Setting up LDAP properties..."
$PYTHON /usr/sbin/ambari-server.py $@
;;
+ sync-ldap)
+ echo -e "Syncing with LDAP..."
+ $PYTHON /usr/sbin/ambari-server.py $@
+ ;;
setup-security)
echo -e "Security setup options..."
$PYTHON /usr/sbin/ambari-server.py $@
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
index 13efd32..b932cbb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
@@ -24,6 +24,7 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.controller.internal.RequestStageContainer;
import org.apache.ambari.server.metadata.RoleCommandOrder;
import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
+import org.apache.ambari.server.security.ldap.LdapBatchDto;
import org.apache.ambari.server.security.ldap.LdapSyncDto;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
@@ -705,7 +706,14 @@ public interface AmbariManagementController {
* @param groups groups to be synchronized
* @throws AmbariException if synchronization data was invalid
*/
- public void synchronizeLdapUsersAndGroups(Set<String> users, Set<String> groups) throws AmbariException;
+ public LdapBatchDto synchronizeLdapUsersAndGroups(Set<String> users, Set<String> groups) throws AmbariException;
+
+ /**
+ * Checks if LDAP sync process is running.
+ *
+ * @return true if LDAP sync is in progress
+ */
+ public boolean isLdapSyncInProgress();
/**
* Get configurations which are specific for a cluster (!not a service).
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 97137a2..8c0dfeb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -227,6 +227,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
final private String serverDB;
final private String mysqljdbcUrl;
+ private boolean ldapSyncInProgress;
+
private Cache<ClusterRequest, ClusterResponse> clusterUpdateCache =
CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build();
@@ -3675,9 +3677,30 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
}
@Override
- public synchronized void synchronizeLdapUsersAndGroups(Set<String> users,
- Set<String> groups) throws AmbariException {
- final LdapBatchDto batchInfo = ldapDataPopulator.synchronizeLdapUsersAndGroups(users, groups);
- this.users.processLdapSync(batchInfo);
+ public boolean isLdapSyncInProgress() {
+ return ldapSyncInProgress;
+ }
+
+ @Override
+ public synchronized LdapBatchDto synchronizeLdapUsersAndGroups(Set<String> users, Set<String> groups)
+ throws AmbariException {
+ ldapSyncInProgress = true;
+ try {
+ final LdapBatchDto batchInfo = new LdapBatchDto();
+ if (users != null) {
+ ldapDataPopulator.synchronizeLdapUsers(users, batchInfo);
+ } else {
+ ldapDataPopulator.synchronizeAllLdapUsers(batchInfo);
+ }
+ if (groups != null) {
+ ldapDataPopulator.synchronizeLdapGroups(groups, batchInfo);
+ } else {
+ ldapDataPopulator.synchronizeAllLdapGroups(batchInfo);
+ }
+ this.users.processLdapSync(batchInfo);
+ return batchInfo;
+ } finally {
+ ldapSyncInProgress = false;
+ }
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
index a3bd6d5..129824f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
@@ -39,6 +39,7 @@ import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.security.ldap.LdapBatchDto;
import org.apache.ambari.server.security.ldap.LdapGroupDto;
import org.apache.ambari.server.security.ldap.LdapSyncDto;
import org.apache.ambari.server.security.ldap.LdapUserDto;
@@ -58,6 +59,8 @@ class ControllerResourceProvider extends AbstractControllerResourceProvider {
protected static final String CONTROLLER_LDAP_SYNCED_USERS_PROPERTY_ID = PropertyHelper.getPropertyId("LDAP", "synced_users");
protected static final String CONTROLLER_LDAP_SYNCED_GROUPS_PROPERTY_ID = PropertyHelper.getPropertyId("LDAP", "synced_groups");
+ protected static final String ALL_ENTRIES = "*";
+
private static Set<String> pkPropertyIds = new HashSet<String>(
Arrays.asList(new String[] { CONTROLLER_NAME_PROPERTY_ID }));
@@ -190,39 +193,63 @@ class ControllerResourceProvider extends AbstractControllerResourceProvider {
}
// one request per each controller
+ Set<Resource> resources = new HashSet<Resource>();
for (final ControllerRequest controllerRequest: requests) {
- modifyResources(new Command<Void>() {
+ Resource resource = modifyResources(new Command<Resource>() {
@Override
- public Void invoke() throws AmbariException {
+ public Resource invoke() throws AmbariException {
+ Resource resource = null;
switch (ControllerType.getByName(controllerRequest.getName())) {
case LDAP:
- Set<String> users = new HashSet<String>();
+ resource = new ResourceImpl(Resource.Type.Controller);
+ Set<String> users = null;
if (controllerRequest.getPropertyMap().containsKey(CONTROLLER_LDAP_SYNCED_USERS_PROPERTY_ID)) {
final String userCsv = (String) controllerRequest.getPropertyMap().get(CONTROLLER_LDAP_SYNCED_USERS_PROPERTY_ID);
- for (String user: userCsv.split(",")) {
- if (StringUtils.isNotEmpty(user)) {
- users.add(user.toLowerCase());
+ if (!userCsv.trim().equals(ALL_ENTRIES)) {
+ users = new HashSet<String>();
+ for (String user: userCsv.split(",")) {
+ if (StringUtils.isNotEmpty(user)) {
+ users.add(user.toLowerCase());
+ }
}
}
}
- Set<String> groups = new HashSet<String>();
+ Set<String> groups = null;
if (controllerRequest.getPropertyMap().containsKey(CONTROLLER_LDAP_SYNCED_GROUPS_PROPERTY_ID)) {
final String groupCsv = (String) controllerRequest.getPropertyMap().get(CONTROLLER_LDAP_SYNCED_GROUPS_PROPERTY_ID);
- for (String group: groupCsv.split(",")) {
- if (StringUtils.isNotEmpty(group)) {
- groups.add(group.toLowerCase());
+ if (!groupCsv.trim().equals(ALL_ENTRIES)) {
+ groups = new HashSet<String>();
+ for (String group : groupCsv.split(",")) {
+ if (StringUtils.isNotEmpty(group)) {
+ groups.add(group.toLowerCase());
+ }
}
}
}
- getManagementController().synchronizeLdapUsersAndGroups(users, groups);
+ if (!getManagementController().isLdapSyncInProgress()) {
+ LdapBatchDto syncInfo = getManagementController().synchronizeLdapUsersAndGroups(users, groups);
+ resource.setProperty("Sync/status", "successful");
+ resource.setProperty("Sync/summary/Users/created", syncInfo.getUsersToBeCreated().size());
+ resource.setProperty("Sync/summary/Users/updated", syncInfo.getUsersToBecomeLdap().size());
+ resource.setProperty("Sync/summary/Users/removed", syncInfo.getUsersToBeRemoved().size());
+ resource.setProperty("Sync/summary/Groups/created", syncInfo.getGroupsToBeCreated().size());
+ resource.setProperty("Sync/summary/Groups/updated", syncInfo.getGroupsToBecomeLdap().size());
+ resource.setProperty("Sync/summary/Groups/removed", syncInfo.getGroupsToBeRemoved().size());
+ resource.setProperty("Sync/summary/Memberships/created", syncInfo.getMembershipToAdd().size());
+ resource.setProperty("Sync/summary/Memberships/removed", syncInfo.getMembershipToRemove().size());
+ } else {
+ resource.setProperty("Sync/status", "not started");
+ resource.setProperty("Sync/summary", "Another sync is already running");
+ }
break;
}
- return null;
+ return resource;
}
});
+ resources.add(resource);
}
- return getRequestStatus(null);
+ return getRequestStatus(null, resources);
}
@Override
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
index 1cd5b95..fd2f77b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
@@ -638,13 +638,6 @@ public class Users {
userDAO.create(usersToCreate);
groupDAO.create(groupsToCreate);
- // remove membership
- final Set<MemberEntity> membersToRemove = new HashSet<MemberEntity>();
- for (LdapUserGroupMemberDto member: batchInfo.getMembershipToRemove()) {
- membersToRemove.add(memberDAO.findByUserAndGroup(member.getUserName(), member.getGroupName()));
- }
- memberDAO.remove(membersToRemove);
-
// create membership
final Set<MemberEntity> membersToCreate = new HashSet<MemberEntity>();
final Set<GroupEntity> groupsToUpdate = new HashSet<GroupEntity>();
@@ -660,6 +653,16 @@ public class Users {
memberDAO.create(membersToCreate);
groupDAO.merge(groupsToUpdate); // needed for Derby DB as it doesn't fetch newly added members automatically
+ // remove membership
+ final Set<MemberEntity> membersToRemove = new HashSet<MemberEntity>();
+ for (LdapUserGroupMemberDto member: batchInfo.getMembershipToRemove()) {
+ MemberEntity memberEntity = memberDAO.findByUserAndGroup(member.getUserName(), member.getGroupName());
+ if (memberEntity != null) {
+ membersToRemove.add(memberEntity);
+ }
+ }
+ memberDAO.remove(membersToRemove);
+
// clear cached entities
entityManagerProvider.get().getEntityManagerFactory().getCache().evictAll();
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
index 2342bd4..f07c6d0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
@@ -42,7 +42,11 @@ import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
+import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
+import org.springframework.ldap.filter.Filter;
+import org.springframework.ldap.filter.LikeFilter;
+import org.springframework.ldap.filter.OrFilter;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.google.inject.Inject;
@@ -80,6 +84,7 @@ public class AmbariLdapDataPopulator {
public AmbariLdapDataPopulator(Configuration configuration, Users users) {
this.configuration = configuration;
this.users = users;
+ this.ldapServerProperties = configuration.getLdapServerProperties();
}
/**
@@ -143,69 +148,136 @@ public class AmbariLdapDataPopulator {
}
/**
- * Performs synchronization of given sets of usernames and groupnames.
+ * Performs synchronization of all groups.
*
- * @param users set of users to synchronize
- * @param groups set of groups to synchronize
* @throws AmbariException if synchronization failed for any reason
*/
- public LdapBatchDto synchronizeLdapUsersAndGroups(Set<String> users,
- Set<String> groups) throws AmbariException {
- final LdapBatchDto batchInfo = new LdapBatchDto();
+ public LdapBatchDto synchronizeAllLdapGroups(LdapBatchDto batchInfo) throws AmbariException {
- // validate request
- final Set<LdapUserDto> externalUsers = getExternalLdapUserInfo();
- final Map<String, LdapUserDto> externalUsersMap = new HashMap<String, LdapUserDto>();
- for (LdapUserDto user: externalUsers) {
- externalUsersMap.put(user.getUserName(), user);
+ Set<LdapGroupDto> externalLdapGroupInfo = getExternalLdapGroupInfo();
+
+ final Map<String, Group> internalGroupsMap = getInternalGroups();
+ final Map<String, User> internalUsersMap = getInternalUsers();
+
+ for (LdapGroupDto groupDto : externalLdapGroupInfo) {
+ String groupName = groupDto.getGroupName();
+ if (internalGroupsMap.containsKey(groupName)) {
+ final Group group = internalGroupsMap.get(groupName);
+ if (!group.isLdapGroup()) {
+ batchInfo.getGroupsToBecomeLdap().add(groupName);
+ }
+ internalGroupsMap.remove(groupName);
+ } else {
+ batchInfo.getGroupsToBeCreated().add(groupName);
+ }
+ refreshGroupMembers(batchInfo, groupDto, internalUsersMap);
}
- for (String user : users) {
- if (!externalUsersMap.containsKey(user)) {
- throw new AmbariException("Couldn't sync LDAP user " + user
- + ", it doesn't exist");
+ for (Entry<String, Group> internalGroup : internalGroupsMap.entrySet()) {
+ if (internalGroup.getValue().isLdapGroup()) {
+ batchInfo.getGroupsToBeRemoved().add(internalGroup.getValue().getGroupName());
}
}
- final Set<LdapGroupDto> externalGroups = getExternalLdapGroupInfo();
- final Map<String, LdapGroupDto> externalGroupsMap = new HashMap<String, LdapGroupDto>();
- for (LdapGroupDto group: externalGroups) {
- externalGroupsMap.put(group.getGroupName(), group);
+
+ return batchInfo;
+ }
+
+ /**
+ * Performs synchronization of given sets of all users.
+ *
+ * @throws AmbariException if synchronization failed for any reason
+ */
+ public LdapBatchDto synchronizeAllLdapUsers(LdapBatchDto batchInfo) throws AmbariException {
+
+ Set<LdapUserDto> externalLdapUserInfo = getExternalLdapUserInfo();
+ Map<String, User> internalUsersMap = getInternalUsers();
+
+ for (LdapUserDto userDto : externalLdapUserInfo) {
+ String userName = userDto.getUserName();
+ if (internalUsersMap.containsKey(userName)) {
+ final User user = internalUsersMap.get(userName);
+ if (user != null && !user.isLdapUser()) {
+ batchInfo.getUsersToBecomeLdap().add(userName);
+ }
+ internalUsersMap.remove(userName);
+ } else {
+ batchInfo.getUsersToBeCreated().add(userName);
+ }
+ }
+ for (Entry<String, User> internalUser : internalUsersMap.entrySet()) {
+ if (internalUser.getValue().isLdapUser()) {
+ batchInfo.getUsersToBeRemoved().add(internalUser.getValue().getUserName());
+ }
}
+
+ return batchInfo;
+ }
+
+ /**
+ * Performs synchronization of given set of groupnames.
+ *
+ * @param groups set of groups to synchronize
+ * @throws AmbariException if synchronization failed for any reason
+ */
+ public LdapBatchDto synchronizeLdapGroups(Set<String> groups, LdapBatchDto batchInfo) throws AmbariException {
+
+ final Set<LdapGroupDto> specifiedGroups = new HashSet<LdapGroupDto>();
for (String group : groups) {
- if (!externalGroupsMap.containsKey(group)) {
+ Set<LdapGroupDto> groupDtos = getLdapGroups(group);
+ if (groupDtos.isEmpty()) {
throw new AmbariException("Couldn't sync LDAP group " + group
+ ", it doesn't exist");
}
+ specifiedGroups.addAll(groupDtos);
}
final Map<String, Group> internalGroupsMap = getInternalGroups();
final Map<String, User> internalUsersMap = getInternalUsers();
- // processing groups
- for (String groupName : groups) {
+ for (LdapGroupDto groupDto : specifiedGroups) {
+ String groupName = groupDto.getGroupName();
if (internalGroupsMap.containsKey(groupName)) {
final Group group = internalGroupsMap.get(groupName);
if (!group.isLdapGroup()) {
batchInfo.getGroupsToBecomeLdap().add(groupName);
}
+ internalGroupsMap.remove(groupName);
} else {
batchInfo.getGroupsToBeCreated().add(groupName);
}
- refreshGroupMembers(batchInfo, externalGroupsMap.get(groupName), internalUsersMap, externalUsers);
- internalGroupsMap.remove(groupName);
+ refreshGroupMembers(batchInfo, groupDto, internalUsersMap);
}
- for (Entry<String, Group> internalGroup : internalGroupsMap.entrySet()) {
- if (internalGroup.getValue().isLdapGroup()) {
- batchInfo.getGroupsToBeRemoved().add(internalGroup.getValue().getGroupName());
+
+ return batchInfo;
+ }
+
+ /**
+ * Performs synchronization of given set of usernames.
+ *
+ * @param users set of users to synchronize
+ * @throws AmbariException if synchronization failed for any reason
+ */
+ public LdapBatchDto synchronizeLdapUsers(Set<String> users, LdapBatchDto batchInfo) throws AmbariException {
+
+ final Set<LdapUserDto> specifiedUsers = new HashSet<LdapUserDto>();
+
+ for (String user : users) {
+ Set<LdapUserDto> userDtos = getLdapUsers(user);
+ if (userDtos.isEmpty()) {
+ throw new AmbariException("Couldn't sync LDAP user " + user
+ + ", it doesn't exist");
}
+ specifiedUsers.addAll(userDtos);
}
- // processing users
- for (String userName : users) {
+ final Map<String, User> internalUsersMap = getInternalUsers();
+ for (LdapUserDto userDto : specifiedUsers) {
+ String userName = userDto.getUserName();
if (internalUsersMap.containsKey(userName)) {
final User user = internalUsersMap.get(userName);
if (user != null && !user.isLdapUser()) {
batchInfo.getUsersToBecomeLdap().add(userName);
}
+ internalUsersMap.remove(userName);
} else {
batchInfo.getUsersToBeCreated().add(userName);
}
@@ -215,32 +287,74 @@ public class AmbariLdapDataPopulator {
}
/**
+ * Performs synchronization of existent users and groups.
+ *
+ * @throws AmbariException if synchronization failed for any reason
+ */
+ public LdapBatchDto synchronizeExistingLdapGroups(LdapBatchDto batchInfo) throws AmbariException {
+ final Map<String, Group> internalGroupsMap = getInternalGroups();
+ final Map<String, User> internalUsersMap = getInternalUsers();
+
+ for (Group group : internalGroupsMap.values()) {
+ if (group.isLdapGroup()) {
+ Set<LdapGroupDto> groupDtos = getLdapGroups(group.getGroupName());
+ if (groupDtos.isEmpty()) {
+ batchInfo.getGroupsToBeRemoved().add(group.getGroupName());
+ } else {
+ LdapGroupDto groupDto = groupDtos.iterator().next();
+ refreshGroupMembers(batchInfo, groupDto, internalUsersMap);
+ }
+ }
+ }
+
+ return batchInfo;
+ }
+
+ /**
+ * Performs synchronization of existent users and groups.
+ *
+ * @throws AmbariException if synchronization failed for any reason
+ */
+ public LdapBatchDto synchronizeExistingLdapUsers(LdapBatchDto batchInfo) throws AmbariException {
+ final Map<String, User> internalUsersMap = getInternalUsers();
+
+ for (User user : internalUsersMap.values()) {
+ if (user.isLdapUser()) {
+ Set<LdapUserDto> userDtos = getLdapUsers(user.getUserName());
+ if (userDtos.isEmpty()) {
+ batchInfo.getUsersToBeRemoved().add(user.getUserName());
+ }
+ }
+ }
+
+ return batchInfo;
+ }
+
+ /**
* Check group members of the synced group: add missing ones and remove the ones absent in external LDAP.
*
- * @param groupName group name
+ * @param batchInfo batch update object
+ * @param group ldap group
* @param internalUsers map of internal users
- * @param externalUsers set of external users
* @throws AmbariException if group refresh failed
*/
- protected void refreshGroupMembers(LdapBatchDto batchInfo, LdapGroupDto group, Map<String, User> internalUsers, Set<LdapUserDto> externalUsers) throws AmbariException {
- final Set<String> externalMembers = new HashSet<String>();
+ protected void refreshGroupMembers(LdapBatchDto batchInfo, LdapGroupDto group, Map<String, User> internalUsers) throws AmbariException {
+ Set<String> externalMembers = new HashSet<String>();
for (String memberAttribute: group.getMemberAttributes()) {
- for (LdapUserDto externalUser: externalUsers) {
- // memberAttribute may be either DN or UID, check both
- if (externalUser.getDn().equals(memberAttribute) || externalUser.getUid().equals(memberAttribute)) {
- externalMembers.add(externalUser.getUserName());
- break;
- }
+ LdapUserDto groupMember = getLdapUserByMemberAttr(memberAttribute);
+ if (groupMember != null) {
+ externalMembers.add(groupMember.getUserName());
}
}
- final Map<String, User> internalMembers = getInternalMembers(group.getGroupName());
+ String groupName = group.getGroupName();
+ final Map<String, User> internalMembers = getInternalMembers(groupName);
for (String externalMember: externalMembers) {
if (internalUsers.containsKey(externalMember)) {
final User user = internalUsers.get(externalMember);
if (user == null) {
// user is fresh and is already added to batch info
if (!internalMembers.containsKey(externalMember)) {
- batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(group.getGroupName(), externalMember));
+ batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember));
}
continue;
}
@@ -248,21 +362,47 @@ public class AmbariLdapDataPopulator {
batchInfo.getUsersToBecomeLdap().add(externalMember);
}
if (!internalMembers.containsKey(externalMember)) {
- batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(group.getGroupName(), externalMember));
+ batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember));
}
internalMembers.remove(externalMember);
} else {
batchInfo.getUsersToBeCreated().add(externalMember);
- batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(group.getGroupName(), externalMember));
- internalUsers.put(externalMember, null);
+ batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember));
}
}
for (Entry<String, User> userToBeUnsynced: internalMembers.entrySet()) {
final User user = userToBeUnsynced.getValue();
- batchInfo.getMembershipToRemove().add(new LdapUserGroupMemberDto(group.getGroupName(), user.getUserName()));
+ batchInfo.getMembershipToRemove().add(new LdapUserGroupMemberDto(groupName, user.getUserName()));
}
}
+ protected Set<LdapGroupDto> getLdapGroups(String groupName) {
+ Filter groupObjectFilter = new EqualsFilter("objectClass",
+ ldapServerProperties.getGroupObjectClass());
+ Filter groupNameFilter = new LikeFilter(ldapServerProperties.getGroupNamingAttr(), groupName);
+ Set<LdapGroupDto> filteredLdapGroups = getFilteredLdapGroups(groupObjectFilter, groupNameFilter);
+ return filteredLdapGroups;
+ }
+
+ protected Set<LdapUserDto> getLdapUsers(String username) {
+ Filter userObjectFilter = new EqualsFilter("objectClass", ldapServerProperties.getUserObjectClass());
+ Filter userNameFilter = new LikeFilter(ldapServerProperties.getUsernameAttribute(), username);
+ Set<LdapUserDto> filteredLdapUsers = getFilteredLdapUsers(userObjectFilter, userNameFilter);
+ return filteredLdapUsers;
+ }
+
+ protected LdapUserDto getLdapUserByMemberAttr(String memberAttribute) {
+ // memberAttribute may be either DN or UID, check both
+ Filter userObjectFilter = new EqualsFilter("objectClass", ldapServerProperties.getUserObjectClass());
+ Filter dnFilter = new EqualsFilter("dn", memberAttribute);
+ Filter uidFilter = new EqualsFilter("uid", memberAttribute);
+ OrFilter orFilter = new OrFilter();
+ orFilter.or(dnFilter);
+ orFilter.or(uidFilter);
+ Set<LdapUserDto> filteredLdapUsers = getFilteredLdapUsers(userObjectFilter, orFilter);
+ return (filteredLdapUsers.isEmpty()) ? null : filteredLdapUsers.iterator().next();
+ }
+
/**
* Removes synced users which are not present in any of group.
*
@@ -285,12 +425,24 @@ public class AmbariLdapDataPopulator {
* @return set of info about LDAP groups
*/
protected Set<LdapGroupDto> getExternalLdapGroupInfo() {
+ EqualsFilter groupObjectFilter = new EqualsFilter("objectClass",
+ ldapServerProperties.getGroupObjectClass());
+ return getFilteredLdapGroups(groupObjectFilter);
+ }
+
+ private Set<LdapGroupDto> getFilteredLdapGroups(Filter...filters) {
+ AndFilter andFilter = new AndFilter();
+ for (Filter filter : filters) {
+ andFilter.and(filter);
+ }
+ return getFilteredLdapGroups(andFilter);
+ }
+
+ private Set<LdapGroupDto> getFilteredLdapGroups(Filter filter) {
final Set<LdapGroupDto> groups = new HashSet<LdapGroupDto>();
final LdapTemplate ldapTemplate = loadLdapTemplate();
- final EqualsFilter equalsFilter = new EqualsFilter("objectClass",
- ldapServerProperties.getGroupObjectClass());
String baseDn = ldapServerProperties.getBaseDN();
- ldapTemplate.search(baseDn, equalsFilter.encode(), new ContextMapper() {
+ ldapTemplate.search(baseDn, filter.encode(), new ContextMapper() {
@Override
public Object mapFromContext(Object ctx) {
@@ -320,12 +472,24 @@ public class AmbariLdapDataPopulator {
* @return set of info about LDAP users
*/
protected Set<LdapUserDto> getExternalLdapUserInfo() {
+ EqualsFilter userObjectFilter = new EqualsFilter("objectClass",
+ ldapServerProperties.getUserObjectClass());
+ return getFilteredLdapUsers(userObjectFilter);
+ }
+
+ private Set<LdapUserDto> getFilteredLdapUsers(Filter...filters) {
+ AndFilter andFilter = new AndFilter();
+ for (Filter filter : filters) {
+ andFilter.and(filter);
+ }
+ return getFilteredLdapUsers(andFilter);
+ }
+
+ private Set<LdapUserDto> getFilteredLdapUsers(Filter filter) {
final Set<LdapUserDto> users = new HashSet<LdapUserDto>();
final LdapTemplate ldapTemplate = loadLdapTemplate();
- final EqualsFilter equalsFilter = new EqualsFilter("objectClass",
- ldapServerProperties.getUserObjectClass());
String baseDn = ldapServerProperties.getBaseDN();
- ldapTemplate.search(baseDn, equalsFilter.encode(), new ContextMapper() {
+ ldapTemplate.search(baseDn, filter.encode(), new ContextMapper() {
@Override
public Object mapFromContext(Object ctx) {
@@ -337,11 +501,11 @@ public class AmbariLdapDataPopulator {
user.setUserName(usernameAttribute.toLowerCase());
user.setUid(uidAttribute.toLowerCase());
user.setDn(adapter.getNameInNamespace().toLowerCase());
+ users.add(user);
} else {
LOG.warn("Ignoring LDAP user " + adapter.getNameInNamespace() + " as it doesn't have required" +
" attributes uid and " + ldapServerProperties.getUsernameAttribute());
}
- users.add(user);
return null;
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/21d784b6/ambari-server/src/main/python/ambari-server.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py
index 1ad906f..5843279 100755
--- a/ambari-server/src/main/python/ambari-server.py
+++ b/ambari-server/src/main/python/ambari-server.py
@@ -41,6 +41,8 @@ import random
import pwd
from ambari_server.resourceFilesKeeper import ResourceFilesKeeper, KeeperException
import json
+import base64
+from threading import Thread
from ambari_commons import OSCheck, OSConst, Firewall
from ambari_server import utils
@@ -64,6 +66,7 @@ UPGRADE_STACK_ACTION = "upgradestack"
STATUS_ACTION = "status"
SETUP_HTTPS_ACTION = "setup-https"
LDAP_SETUP_ACTION = "setup-ldap"
+LDAP_SYNC_ACTION = "sync-ldap"
SETUP_GANGLIA_HTTPS_ACTION = "setup-ganglia-https"
SETUP_NAGIOS_HTTPS_ACTION = "setup-nagios-https"
ENCRYPT_PASSWORDS_ACTION = "encrypt-passwords"
@@ -119,6 +122,14 @@ SERVER_LOG_FILE = "/var/log/ambari-server/ambari-server.log"
BLIND_PASSWORD = "*****"
ROOT_FS_PATH = "/"
+# api properties
+SERVER_API_HOST = '127.0.0.1'
+SERVER_API_PROTOCOL = 'http'
+SERVER_API_PORT = '8080'
+SERVER_API_LDAP_URL = '/api/v1/controllers/ldap'
+SERVER_API_LOGIN = 'admin'
+SERVER_API_PASS = 'admin'
+
# terminal styles
BOLD_ON = '\033[1m'
BOLD_OFF = '\033[0m'
@@ -2994,6 +3005,67 @@ def get_prompt_default(defaultStr=None):
else:
return '(' + defaultStr + ')'
+def sync_ldap():
+ if not is_root():
+ err = 'Ambari-server sync-ldap should be run with ' \
+ 'root-level privileges'
+ raise FatalException(4, err)
+
+ server_status, pid = is_server_runing()
+ if not server_status:
+ err = 'Ambari Server is not running.'
+ raise FatalException(1, err)
+
+ ldap_configured = get_ambari_properties().get_property(IS_LDAP_CONFIGURED)
+ if ldap_configured != 'true':
+ err = "LDAP is not configured. Run 'ambari-server setup-ldap' first."
+ raise FatalException(1, err)
+
+ url = '{0}://{1}:{2!s}{3}'.format(SERVER_API_PROTOCOL, SERVER_API_HOST, SERVER_API_PORT, SERVER_API_LDAP_URL)
+ admin_auth = base64.encodestring('%s:%s' % (SERVER_API_LOGIN, SERVER_API_PASS)).replace('\n', '')
+ request = urllib2.Request(url)
+ request.add_header('Authorization', 'Basic %s' % admin_auth)
+ request.add_header('X-Requested-By', 'ambari')
+ body = [{"LDAP":{"synced_groups":"*","synced_users":"*"}}]
+ request.add_data(json.dumps(body))
+ request.get_method = lambda: 'PUT'
+ progress_message_thread = None
+ request_in_progress = True
+ def print_progress(message):
+ sys.stdout.write(message)
+ sys.stdout.flush()
+ while request_in_progress:
+ sys.stdout.write('.')
+ sys.stdout.flush()
+ time.sleep(1)
+ sys.stdout.write('\n')
+ sys.stdout.flush()
+ try:
+ progress_message_thread = Thread(target=print_progress, args=('Syncing Ambari Database for permissions for the LDAP Users and Groups..',))
+ progress_message_thread.start()
+ response = urllib2.urlopen(request)
+ except Exception as e:
+ err = 'Sync failed. Error details: %s' % e
+ raise FatalException(1, err)
+ finally:
+ request_in_progress = False
+ if progress_message_thread is not None:
+ progress_message_thread.join()
+ response_status_code = response.getcode()
+ if response_status_code != 200:
+ err = 'Error during syncing. Http status code - ' + response_status_code
+ raise FatalException(1, err)
+ response_body = json.loads(response.read())
+ sync_info = response_body['resources'][0]['Sync']
+ if sync_info['status'] != 'successful':
+ raise FatalException(1, sync_info['summary'])
+ else:
+ print 'Synced:'
+ for principal_type, summary in sync_info['summary'].iteritems():
+ print ' {0}:'.format(principal_type)
+ for action, amount in summary.iteritems():
+ print ' - {0} = {1!s}'.format(action, amount)
+ print 'Finished LDAP Sync.'
def setup_ldap():
if not is_root():
@@ -4343,6 +4415,8 @@ def main():
upgrade_stack(options, stack_id, repo_url, repo_url_os)
elif action == LDAP_SETUP_ACTION:
setup_ldap()
+ elif action == LDAP_SYNC_ACTION:
+ sync_ldap()
elif action == SETUP_SECURITY_ACTION:
need_restart = setup_security(options)
elif action == REFRESH_STACK_HASH_ACTION: