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/07/31 01:46:25 UTC

git commit: Views : Admin - LDAP Support.

Repository: ambari
Updated Branches:
  refs/heads/trunk ce4020028 -> 15b54439a


Views : Admin - LDAP Support.


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/15b54439
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/15b54439
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/15b54439

Branch: refs/heads/trunk
Commit: 15b54439af4b95386fe678b97a1d88a062dc9309
Parents: ce40200
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Wed Jul 30 16:40:48 2014 -0700
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Wed Jul 30 16:40:48 2014 -0700

----------------------------------------------------------------------
 .../resources/ControllerResourceDefinition.java |  60 +++
 .../resources/ResourceInstanceFactoryImpl.java  |   8 +-
 .../server/api/services/ControllerService.java  |  98 +++++
 .../server/configuration/Configuration.java     |  52 ++-
 .../controller/AmbariManagementController.java  |  36 +-
 .../AmbariManagementControllerImpl.java         |  70 +++-
 .../ambari/server/controller/AmbariServer.java  |   3 +
 .../server/controller/ControllerRequest.java    |  41 ++
 .../server/controller/ControllerResponse.java   |  33 ++
 .../AbstractControllerResourceProvider.java     |   2 +
 .../internal/ControllerResourceProvider.java    | 243 +++++++++++
 .../controller/internal/ControllerType.java     |  65 +++
 .../ambari/server/controller/spi/Resource.java  |   4 +-
 .../apache/ambari/server/orm/dao/GroupDAO.java  |   1 -
 .../AmbariLdapAuthenticationProvider.java       |   2 +-
 .../authorization/AmbariLdapDataPopulator.java  | 419 +++++++++++++++++++
 .../authorization/LdapServerProperties.java     |  38 +-
 .../server/security/authorization/Member.java   |  53 ---
 .../server/security/authorization/User.java     |  15 +-
 .../server/security/authorization/Users.java    |  32 ++
 .../src/main/resources/key_properties.json      |   3 +
 .../src/main/resources/properties.json          |   9 +
 22 files changed, 1170 insertions(+), 117 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ControllerResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ControllerResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ControllerResourceDefinition.java
new file mode 100644
index 0000000..55e6502
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ControllerResourceDefinition.java
@@ -0,0 +1,60 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.server.api.resources;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.internal.ControllerType;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Controller Resource Definition
+ */
+public class ControllerResourceDefinition extends BaseResourceDefinition {
+
+  private final ControllerType type;
+
+  public ControllerResourceDefinition(ControllerType type) {
+    super(Resource.Type.Controller);
+    this.type = type;
+  }
+
+  @Override
+  public String getPluralName() {
+    return "controllers";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "controller";
+  }
+
+  @Override
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    final Set<SubResourceDefinition> subResourceDefinitions = new HashSet<SubResourceDefinition>();
+    if (type != null) {
+      switch (type) {
+      case LDAP:
+        break;
+      }
+    }
+    return subResourceDefinitions;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index 3d198d6..bc2e634 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.server.api.query.QueryImpl;
+import org.apache.ambari.server.controller.internal.ControllerType;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
 import org.apache.ambari.server.view.ViewRegistry;
@@ -241,7 +242,7 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
       case Permission:
         resourceDefinition = new PermissionResourceDefinition();
         break;
-        
+
       case AlertDefinition:
         resourceDefinition = new AlertDefResourceDefinition();
         break;
@@ -262,6 +263,11 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new ViewPermissionResourceDefinition();
         break;
 
+      case Controller:
+        resourceDefinition = new ControllerResourceDefinition(
+            ControllerType.getByName(mapIds.get(Resource.Type.Controller)));
+        break;
+
       default:
         throw new IllegalArgumentException("Unsupported resource type: " + type);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/api/services/ControllerService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ControllerService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ControllerService.java
new file mode 100644
index 0000000..6d20a93
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ControllerService.java
@@ -0,0 +1,98 @@
+/**
+ * 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.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import java.util.Collections;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Service responsible for controllers.
+ */
+@Path("/controllers/")
+public class ControllerService extends BaseService {
+  /**
+   * Handles: GET  /controllers
+   * Get all controllers.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return controller collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getControllers(@Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createControllerResource(null));
+  }
+
+  /**
+   * Handles: GET  /controllers/{controllerName}
+   * Get single controller.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return controller resource representation
+   */
+  @GET
+  @Path("{controllerName}")
+  @Produces("text/plain")
+  public Response getController(@Context HttpHeaders headers, @Context UriInfo ui,
+      @PathParam("controllerName") String controllerName) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createControllerResource(controllerName));
+  }
+
+  /**
+   * Handles: PUT  /controllers/{controllerName}
+   * Update data of a single controller.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return controller resource representation
+   */
+  @PUT
+  @Path("{controllerName}")
+  @Produces("text/plain")
+  public Response updateController(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+      @PathParam("controllerName") String controllerName) {
+    return handleRequest(headers, body, ui, Request.Type.PUT, createControllerResource(controllerName));
+  }
+
+  /**
+   * Create a controller resource instance.
+   *
+   * @param controllerName controller name
+   *
+   * @return a cluster resource instance
+   */
+  ResourceInstance createControllerResource(String controllerName) {
+    return createResource(Resource.Type.Controller,
+        Collections.singletonMap(Resource.Type.Controller, controllerName));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index 68df120..65cf668 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -132,6 +132,10 @@ public class Configuration {
       "authentication.ldap.managerPassword";
   public static final String LDAP_USERNAME_ATTRIBUTE_KEY =
       "authentication.ldap.usernameAttribute";
+  public static final String LDAP_USER_BASE_KEY =
+      "authentication.ldap.userBase";
+  public static final String LDAP_USER_OBJECT_CLASS_KEY =
+      "authentication.ldap.userObjectClass";
   public static final String LDAP_GROUP_BASE_KEY =
       "authorization.ldap.groupBase";
   public static final String LDAP_GROUP_OBJECT_CLASS_KEY =
@@ -268,6 +272,9 @@ public class Configuration {
   private static final String LDAP_PRIMARY_URL_DEFAULT = "localhost:33389";
   private static final String LDAP_BASE_DN_DEFAULT = "dc=ambari,dc=apache,dc=org";
   private static final String LDAP_USERNAME_ATTRIBUTE_DEFAULT = "uid";
+  private static final String LDAP_USER_BASE_DEFAULT =
+      "ou=people,dc=ambari,dc=apache,dc=org";
+  private static final String LDAP_USER_OBJECT_CLASS_DEFAULT = "person";
   private static final String LDAP_GROUP_BASE_DEFAULT =
       "ou=groups,dc=ambari,dc=apache,dc=org";
   private static final String LDAP_GROUP_OBJECT_CLASS_DEFAULT = "group";
@@ -280,23 +287,23 @@ public class Configuration {
   private static final String SERVER_PERSISTENCE_TYPE_DEFAULT = "local";
   private static final String SERVER_CONNECTION_MAX_IDLE_TIME =
       "server.connection.max.idle.millis";
-  
+
   private static final String UBUNTU_OS = "debian12";
-  
+
   /**
    * Default for repo validation suffixes.
    */
   private static final String REPO_SUFFIX_DEFAULT = "/repodata/repomd.xml";
   private static final String REPO_SUFFIX_UBUNTU = "/dists/%s/Release.gpg,/dists/%s/Release";
-  
+
   private static final String PARALLEL_STAGE_EXECUTION_DEFAULT = "true";
-  
+
   private static final String CLIENT_THREADPOOL_SIZE_KEY = "client.threadpool.size.max";
   private static final int CLIENT_THREADPOOL_SIZE_DEFAULT = 25;
   private static final String AGENT_THREADPOOL_SIZE_KEY = "agent.threadpool.size.max";
   private static final int AGENT_THREADPOOL_SIZE_DEFAULT = 25;
-  
-  
+
+
   private static final Logger LOG = LoggerFactory.getLogger(
       Configuration.class);
   private Properties properties;
@@ -776,6 +783,9 @@ public class Configuration {
     ldapServerProperties.setUsernameAttribute(properties.
         getProperty(LDAP_USERNAME_ATTRIBUTE_KEY, LDAP_USERNAME_ATTRIBUTE_DEFAULT));
 
+    ldapServerProperties.setUserBase(properties.getProperty(LDAP_USER_BASE_KEY, LDAP_USER_BASE_DEFAULT));
+    ldapServerProperties.setUserObjectClass(properties.getProperty(LDAP_USER_OBJECT_CLASS_KEY, LDAP_USER_OBJECT_CLASS_DEFAULT));
+
     ldapServerProperties.setGroupBase(properties.
         getProperty(LDAP_GROUP_BASE_KEY, LDAP_GROUP_BASE_DEFAULT));
     ldapServerProperties.setGroupObjectClass(properties.
@@ -832,11 +842,11 @@ public class Configuration {
   public String getServerDBName() {
 	return properties.getProperty(SERVER_DB_NAME_KEY, SERVER_DB_NAME_DEFAULT);
   }
-  
+
   public String getMySQLJarName() {
 	return properties.getProperty(MYSQL_JAR_NAME_KEY, MYSQL_JAR_NAME_DEFAULT);
   }
-  
+
   public JPATableGenerationStrategy getJPATableGenerationStrategy() {
     return JPATableGenerationStrategy.fromString(System.getProperty(SERVER_JDBC_GENERATE_TABLES_KEY));
   }
@@ -881,9 +891,9 @@ public class Configuration {
     if (null != customDbProperties) {
       return customDbProperties;
     }
-    
+
     customDbProperties = new HashMap<String, String>();
-    
+
     for (Entry<Object, Object> entry : properties.entrySet()) {
       String key = entry.getKey().toString();
       String val = entry.getValue().toString();
@@ -891,15 +901,15 @@ public class Configuration {
         customDbProperties.put(key.substring(SERVER_JDBC_PROPERTIES_PREFIX.length()), val);
       }
     }
-    
+
     return customDbProperties;
   }
 
   public Map<String, String> getAmbariProperties() {
-    
+
     Properties properties = readConfigFile();
     Map<String, String> ambariPropertiesMap = new HashMap<String, String>();
-    
+
     for(String key : properties.stringPropertyNames()) {
       ambariPropertiesMap.put(key, properties.getProperty(key));
     }
@@ -921,7 +931,7 @@ public class Configuration {
   }
 
   /**
-   * @return whether staleConfig's flag is cached. 
+   * @return whether staleConfig's flag is cached.
    */
   public boolean isStaleConfigCacheEnabled() {
     String stringValue =
@@ -929,21 +939,21 @@ public class Configuration {
         SERVER_STALE_CONFIG_CACHE_ENABLED_DEFAULT);
     return "true".equalsIgnoreCase(stringValue);
   }
-  
+
   /**
    * @return a string array of suffixes used to validate repo URLs.
    */
   public String[] getRepoValidationSuffixes(String osFamily) {
     String repoSuffixes;
-    
+
     if(osFamily.equals(UBUNTU_OS)) {
-      repoSuffixes = properties.getProperty(REPO_SUFFIX_KEY_UBUNTU, 
+      repoSuffixes = properties.getProperty(REPO_SUFFIX_KEY_UBUNTU,
           REPO_SUFFIX_UBUNTU);
     } else {
-      repoSuffixes = properties.getProperty(REPO_SUFFIX_KEY_DEFAULT, 
+      repoSuffixes = properties.getProperty(REPO_SUFFIX_KEY_DEFAULT,
           REPO_SUFFIX_DEFAULT);
     }
-    
+
     return repoSuffixes.split(",");
   }
 
@@ -1014,12 +1024,12 @@ public class Configuration {
     return Integer.parseInt(properties.getProperty(
         CLIENT_THREADPOOL_SIZE_KEY, String.valueOf(CLIENT_THREADPOOL_SIZE_DEFAULT)));
   }
-  
+
   /**
    * @return max thread pool size for agents, default 25
    */
   public int getAgentThreadPoolSize() {
     return Integer.parseInt(properties.getProperty(
         AGENT_THREADPOOL_SIZE_KEY, String.valueOf(AGENT_THREADPOOL_SIZE_DEFAULT)));
-  }  
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/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 ab03b30..4c41d90 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
@@ -36,7 +36,6 @@ import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
-
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -666,8 +665,43 @@ public interface AmbariManagementController {
       throws AmbariException;
 
   /**
+<<<<<<< HEAD
    * Get Role Command Order
    */
   public RoleCommandOrder getRoleCommandOrder(Cluster cluster);
+
+  /**
+=======
+>>>>>>> a96596eb4c0e9551156585a67181b64df75e335a
+   * Performs a test if LDAP server is reachable.
+   *
+   * @return true if connection to LDAP was established
+   */
+  public boolean checkLdapConfigured();
+
+  /**
+   * Retrieves users from external LDAP.
+   *
+   * @return key-value pairs UserName-Synced
+   * @throws AmbariException if LDAP is configured incorrectly
+   */
+  public Map<String, Boolean> getLdapUsersSyncInfo() throws AmbariException;
+
+  /**
+   * Retrieves groups from external LDAP.
+   *
+   * @return key-value pairs GroupName-Synced
+   * @throws AmbariException if LDAP is configured incorrectly
+   */
+  public Map<String, Boolean> getLdapGroupsSyncInfo() throws AmbariException;
+
+  /**
+   * Synchronizes local users and groups with given data.
+   *
+   * @param users users to be synchronized
+   * @param groups groups to be synchronized
+   * @throws AmbariException if synchronization data was invalid
+   */
+  public void synchronizeLdapUsersAndGroups(Set<String> users, Set<String> groups) throws AmbariException;
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/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 ef031e6..7f53ded 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
@@ -18,6 +18,29 @@
 
 package org.apache.ambari.server.controller;
 
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_DRIVER;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_PASSWORD;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_URL;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_USERNAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMMAND_TIMEOUT;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JAVA_HOME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JCE_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MYSQL_JDBC_URL;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.ORACLE_JDBC_URL;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.PACKAGE_LIST;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.REPO_INFO;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TYPE;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_REPO_INFO;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
+import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
+
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.google.gson.Gson;
@@ -55,29 +78,6 @@ import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.agent.ExecutionCommand;
 
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_DRIVER;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_PASSWORD;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_URL;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AMBARI_DB_RCA_USERNAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMMAND_TIMEOUT;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JAVA_HOME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JCE_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MYSQL_JDBC_URL;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.ORACLE_JDBC_URL;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.PACKAGE_LIST;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.REPO_INFO;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TYPE;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_REPO_INFO;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
-import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
-
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.internal.RequestOperationLevel;
@@ -88,6 +88,7 @@ import org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.metadata.ActionMetadata;
 import org.apache.ambari.server.metadata.RoleCommandOrder;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
+import org.apache.ambari.server.security.authorization.AmbariLdapDataPopulator;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 import org.apache.ambari.server.security.authorization.Group;
 import org.apache.ambari.server.security.authorization.User;
@@ -189,6 +190,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   private RequestExecutionFactory requestExecutionFactory;
   @Inject
   private ExecutionScheduleManager executionScheduleManager;
+  @Inject
+  private AmbariLdapDataPopulator ldapDataPopulator;
 
   private MaintenanceStateHelper maintenanceStateHelper;
 
@@ -3482,4 +3485,25 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     return rcaParameters;
   }
 
+  @Override
+  public boolean checkLdapConfigured() {
+    return ldapDataPopulator.isLdapEnabled();
+  }
+
+  @Override
+  public Map<String, Boolean> getLdapUsersSyncInfo() throws AmbariException {
+    return ldapDataPopulator.getLdapUsersSyncInfo();
+  }
+
+  @Override
+  public Map<String, Boolean> getLdapGroupsSyncInfo() throws AmbariException {
+    return ldapDataPopulator.getLdapGroupsSyncInfo();
+  }
+
+  @Override
+  public synchronized void synchronizeLdapUsersAndGroups(Set<String> users,
+      Set<String> groups) throws AmbariException {
+    ldapDataPopulator.synchronizeLdapUsersAndGroups(users, groups);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index eb34a77..77d2a77 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -78,6 +78,7 @@ import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
 import org.apache.ambari.server.security.CertificateManager;
 import org.apache.ambari.server.security.SecurityFilter;
 import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider;
+import org.apache.ambari.server.security.authorization.AmbariLdapDataPopulator;
 import org.apache.ambari.server.security.authorization.AmbariLocalUserDetailsService;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.security.authorization.internal.AmbariInternalAuthenticationProvider;
@@ -181,6 +182,8 @@ public class AmbariServer {
           injector.getInstance(AmbariLocalUserDetailsService.class));
       factory.registerSingleton("ambariLdapAuthenticationProvider",
           injector.getInstance(AmbariLdapAuthenticationProvider.class));
+      factory.registerSingleton("ambariLdapDataPopulator",
+          injector.getInstance(AmbariLdapDataPopulator.class));
       factory.registerSingleton("internalTokenAuthenticationFilter",
           injector.getInstance(InternalTokenAuthenticationFilter.class));
       factory.registerSingleton("ambariInternalAuthenticationProvider",

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerRequest.java
new file mode 100644
index 0000000..49121d3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerRequest.java
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.server.controller;
+
+import java.util.Map;
+
+/**
+ * Represents a controller maintenance request.
+ */
+public class ControllerRequest {
+  private final String name;
+  private final Map<String, Object> propertyMap;
+
+  public ControllerRequest(String name, Map<String, Object> propertyMap) {
+    this.name = name;
+    this.propertyMap = propertyMap;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public Map<String, Object> getPropertyMap() {
+    return propertyMap;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerResponse.java
new file mode 100644
index 0000000..c75e153
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerResponse.java
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.server.controller;
+
+/**
+ * Represents a controller maintenance response.
+ */
+public class ControllerResponse {
+  private final String name;
+
+  public ControllerResponse(String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index 7224d7a..6c33bdf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -150,6 +150,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return new RecommendationResourceProvider(propertyIds, keyPropertyIds, managementController);
       case AlertDefinition:
         return new AlertDefinitionResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case Controller:
+        return new ControllerResourceProvider(propertyIds, keyPropertyIds, managementController);
       default:
         throw new IllegalArgumentException("Unknown type " + type);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/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
new file mode 100644
index 0000000..9434026
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerResourceProvider.java
@@ -0,0 +1,243 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ControllerRequest;
+import org.apache.ambari.server.controller.ControllerResponse;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+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.commons.lang.StringUtils;
+
+/**
+ * Resource provider for controller resource.
+ */
+class ControllerResourceProvider extends AbstractControllerResourceProvider {
+
+  // ----- Property ID constants ---------------------------------------------
+
+  protected static final String CONTROLLER_NAME_PROPERTY_ID               = PropertyHelper.getPropertyId("Controllers", "name");
+  protected static final String CONTROLLER_LDAP_CONFIGURED_PROPERTY_ID    = PropertyHelper.getPropertyId("LDAP", "configured");
+  protected static final String CONTROLLER_LDAP_USERS_PROPERTY_ID         = PropertyHelper.getPropertyId("LDAP", "users");
+  protected static final String CONTROLLER_LDAP_GROUPS_PROPERTY_ID        = PropertyHelper.getPropertyId("LDAP", "groups");
+  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");
+
+  private static Set<String> pkPropertyIds = new HashSet<String>(
+      Arrays.asList(new String[] { CONTROLLER_NAME_PROPERTY_ID }));
+
+  private static Map<String, ControllerResponse> controllers = new HashMap<String, ControllerResponse>() {
+    {
+      for (ControllerType type: ControllerType.values()) {
+        put(type.getName(), new ControllerResponse(type.getName()));
+      }
+    }
+  };
+
+  /**
+   * Create a new resource provider for the given management controller.
+   *
+   * @param propertyIds           the property ids
+   * @param keyPropertyIds        the key property ids
+   * @param managementController  the management controller
+   */
+  ControllerResourceProvider(Set<String> propertyIds,
+                       Map<Resource.Type, String> keyPropertyIds,
+                       AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public RequestStatus createResources(Request request)
+      throws SystemException,
+      UnsupportedPropertyException,
+      ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+    // controllers can't be dynamically created
+    return getRequestStatus(null);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ControllerRequest> requests = new HashSet<ControllerRequest>();
+
+    if (predicate == null) {
+      requests.add(getRequest(null));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<ControllerResponse> responses = getResources(new Command<Set<ControllerResponse>>() {
+      @Override
+      public Set<ControllerResponse> invoke() throws AmbariException {
+        final Set<ControllerResponse> responses = new HashSet<ControllerResponse>();
+        for (ControllerRequest request: requests) {
+          if (request.getName() == null) {
+            responses.addAll(controllers.values());
+          } else {
+            if (controllers.containsKey(request.getName())) {
+              responses.add(controllers.get(request.getName()));
+            }
+          }
+        }
+        return responses;
+      }
+    });
+
+    Set<String>   requestedIds = getRequestPropertyIds(request, predicate);
+    Set<Resource> resources    = new HashSet<Resource>();
+
+    for (ControllerResponse controllerResponse : responses) {
+      ResourceImpl resource = new ResourceImpl(Resource.Type.Controller);
+
+      setResourceProperty(resource, CONTROLLER_NAME_PROPERTY_ID,
+          controllerResponse.getName(), requestedIds);
+
+      switch (ControllerType.getByName(controllerResponse.getName())) {
+      case LDAP:
+        final boolean ldapConfigured = getManagementController().checkLdapConfigured();
+        setResourceProperty(resource, CONTROLLER_LDAP_CONFIGURED_PROPERTY_ID,
+            ldapConfigured, requestedIds);
+        if (ldapConfigured) {
+          try {
+            final List<String> allUsers = new ArrayList<String>();
+            final List<String> syncedUsers = new ArrayList<String>();
+            for (Entry<String, Boolean> user : getManagementController().getLdapUsersSyncInfo().entrySet()) {
+              allUsers.add(user.getKey());
+              if (user.getValue()) {
+                syncedUsers.add(user.getKey());
+              }
+            }
+            setResourceProperty(resource, CONTROLLER_LDAP_USERS_PROPERTY_ID,
+                allUsers, requestedIds);
+            setResourceProperty(resource, CONTROLLER_LDAP_SYNCED_USERS_PROPERTY_ID,
+                syncedUsers, requestedIds);
+            final List<String> allGroups = new ArrayList<String>();
+            final List<String> syncedGroups = new ArrayList<String>();
+            for (Entry<String, Boolean> group : getManagementController().getLdapGroupsSyncInfo().entrySet()) {
+              allGroups.add(group.getKey());
+              if (group.getValue()) {
+                syncedGroups.add(group.getKey());
+              }
+            }
+            setResourceProperty(resource, CONTROLLER_LDAP_GROUPS_PROPERTY_ID,
+                allGroups, requestedIds);
+            setResourceProperty(resource, CONTROLLER_LDAP_SYNCED_GROUPS_PROPERTY_ID,
+                syncedGroups, requestedIds);
+          } catch (AmbariException ex) {
+            throw new SystemException("Can't retrieve data from external LDAP server", ex);
+          }
+        }
+        break;
+      }
+
+      resources.add(resource);
+    }
+
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+    throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ControllerRequest> requests = new HashSet<ControllerRequest>();
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(request.getProperties().iterator().next(), predicate)) {
+      final ControllerRequest req = getRequest(propertyMap);
+      requests.add(req);
+    }
+
+    // one request per each controller
+    for (final ControllerRequest controllerRequest: requests) {
+      modifyResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          switch (ControllerType.getByName(controllerRequest.getName())) {
+          case LDAP:
+            Set<String> users = new HashSet<String>();
+            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());
+                }
+              }
+            }
+            Set<String> groups = new HashSet<String>();
+            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());
+                }
+              }
+            }
+            getManagementController().synchronizeLdapUsersAndGroups(users, groups);
+            break;
+          }
+          return null;
+        }
+      });
+    }
+
+    return getRequestStatus(null);
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    // controllers can't be removed
+    return getRequestStatus(null);
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  private ControllerRequest getRequest(Map<String, Object> properties) {
+    if (properties == null) {
+      return new ControllerRequest(null, properties);
+    }
+    final ControllerRequest request = new ControllerRequest((String) properties.get(CONTROLLER_NAME_PROPERTY_ID), properties);
+    return request;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerType.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerType.java
new file mode 100644
index 0000000..82b6eac
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ControllerType.java
@@ -0,0 +1,65 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Enumeration of internal controllers used via API.
+ */
+public enum ControllerType {
+  LDAP("ldap");
+
+  /**
+   * Controller name.
+   */
+  private String name;
+
+  /**
+   * Constructor.
+   *
+   * @param name controller name
+   */
+  private ControllerType(String name) {
+    this.name = name;
+  }
+
+  /**
+   * Getter.
+   *
+   * @return controller name
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Returns corresponding controller type to given name.
+   *
+   * @param name controller name
+   * @return null if controller type was not found
+   */
+  public static ControllerType getByName(String name) {
+    for (ControllerType type : ControllerType.values()) {
+      if (StringUtils.equals(type.getName(), name)) {
+        return type;
+      }
+    }
+    return null;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 51a3086..41b38fa 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -117,7 +117,8 @@ public interface Resource {
     AmbariPrivilege,
     ClusterPrivilege,
     ViewPrivilege,
-    ViewPermission;
+    ViewPermission,
+    Controller;
 
     /**
      * Get the {@link Type} that corresponds to this InternalType.
@@ -196,6 +197,7 @@ public interface Resource {
     public static final Type ClusterPrivilege = InternalType.ClusterPrivilege.getType();
     public static final Type ViewPrivilege = InternalType.ViewPrivilege.getType();
     public static final Type ViewPermission = InternalType.ViewPermission.getType();
+    public static final Type Controller = InternalType.Controller.getType();
 
     /**
      * The type name.

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java
index bedf24a..b918454 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java
@@ -26,7 +26,6 @@ import javax.persistence.TypedQuery;
 
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.GroupEntity;
-
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
index 20cf2fd..3818e37 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
@@ -110,7 +110,7 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
       }
 
       //TODO change properties
-      String userSearchBase = ldapServerProperties.get().getUserSearchBase();
+      String userSearchBase = ldapServerProperties.get().getUserBase();
       String userSearchFilter = ldapServerProperties.get().getUserSearchFilter();
 
       FilterBasedLdapUserSearch userSearch = new FilterBasedLdapUserSearch(userSearchBase, userSearchFilter, springSecurityContextSource);

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulator.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulator.java
new file mode 100644
index 0000000..c4a6eaa
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapDataPopulator.java
@@ -0,0 +1,419 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.server.security.authorization;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.ldap.core.AttributesMapper;
+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.security.core.userdetails.UsernameNotFoundException;
+
+import com.google.inject.Inject;
+
+/**
+ * Provides users, groups and membership population from LDAP catalog.
+ */
+public class AmbariLdapDataPopulator {
+  /**
+   * Log.
+   */
+  private static final Log LOG = LogFactory.getLog(AmbariLdapDataPopulator.class);
+
+  /**
+   * Ambari configuration.
+   */
+  private Configuration configuration;
+
+  /**
+   * Highlevel facade for management of users and groups.
+   */
+  private Users users;
+
+  /**
+   * LDAP specific properties.
+   */
+  private LdapServerProperties ldapServerProperties;
+
+  /**
+   * LDAP template for making search queries.
+   */
+  private LdapTemplate ldapTemplate;
+
+  @Inject
+  public AmbariLdapDataPopulator(Configuration configuration, Users users) {
+    this.configuration = configuration;
+    this.users = users;
+  }
+
+  /**
+   * Check if LDAP is enabled in server properties.
+   *
+   * @return true if enabled
+   */
+  public boolean isLdapEnabled() {
+    try {
+      final LdapTemplate ldapTemplate = loadLdapTemplate();
+      ldapTemplate.search(ldapServerProperties.getBaseDN(),
+          "(objectclass=person)", new AttributesMapper() {
+
+            public Object mapFromAttributes(Attributes attributes)
+                throws NamingException {
+              return attributes.get("uid").get();
+            }
+          });
+      return true;
+    } catch (Exception ex) {
+      LOG.error("Could not connect to LDAP server", ex);
+      return false;
+    }
+  }
+
+  /**
+   * Retrieves a key-value map of all LDAP groups.
+   *
+   * @return map of GroupName-Synced pairs
+   */
+  public Map<String, Boolean> getLdapGroupsSyncInfo() {
+    final Map<String, Boolean> ldapGroups = new HashMap<String, Boolean>();
+    final Map<String, Group> internalGroupsMap = getInternalGroups();
+    final Set<String> externalGroups = getExternalLdapGroupNames();
+    for (String externalGroup : externalGroups) {
+      if (internalGroupsMap.containsKey(externalGroup)
+          && internalGroupsMap.get(externalGroup).isLdapGroup()) {
+        ldapGroups.put(externalGroup, true);
+      } else {
+        ldapGroups.put(externalGroup, false);
+      }
+    }
+
+    return ldapGroups;
+  }
+
+  /**
+   * Retrieves a key-value map of all LDAP users.
+   *
+   * @return map of UserName-Synced pairs.
+   */
+  public Map<String, Boolean> getLdapUsersSyncInfo() {
+    final Map<String, Boolean> ldapUsers = new HashMap<String, Boolean>();
+    final List<User> internalUsers = users.getAllUsers();
+    final Map<String, User> internalUsersMap = new HashMap<String, User>();
+    for (User user : internalUsers) {
+      internalUsersMap.put(user.getUserName(), user);
+    }
+    final Set<String> externalUsers = getExternalLdapUserNames();
+    for (String externalUser : externalUsers) {
+      if (internalUsersMap.containsKey(externalUser)
+          && internalUsersMap.get(externalUser).isLdapUser()) {
+        ldapUsers.put(externalUser, true);
+      } else {
+        ldapUsers.put(externalUser, false);
+      }
+    }
+
+    return ldapUsers;
+  }
+
+  /**
+   * Performs synchronization of given sets of usernames and groupnames.
+   *
+   * @param users set of users to synchronize
+   * @param groups set of groups to synchronize
+   * @throws AmbariException if synchronization failed for any reason
+   */
+  public void synchronizeLdapUsersAndGroups(Set<String> users,
+      Set<String> groups) throws AmbariException {
+    // validate request
+    final Set<String> externalUsers = getExternalLdapUserNames();
+    for (String user : users) {
+      if (!externalUsers.contains(user)) {
+        throw new AmbariException("Couldn't sync LDAP user " + user
+            + ", it doesn't exist");
+      }
+    }
+    final Set<String> externalGroups = getExternalLdapGroupNames();
+    for (String group : groups) {
+      if (!externalGroups.contains(group)) {
+        throw new AmbariException("Couldn't sync LDAP group " + group
+            + ", it doesn't exist");
+      }
+    }
+
+    // processing groups
+    final Map<String, Group> internalGroupsMap = getInternalGroups();
+    for (String groupName : groups) {
+      if (internalGroupsMap.containsKey(groupName)) {
+        final Group group = internalGroupsMap.get(groupName);
+        if (!group.isLdapGroup()) {
+          this.users.setGroupLdap(groupName);
+        }
+      } else {
+        this.users.createGroup(groupName);
+        this.users.setGroupLdap(groupName);
+      }
+      refreshGroupMembers(groupName);
+      internalGroupsMap.remove(groupName);
+    }
+    for (Entry<String, Group> internalGroup : internalGroupsMap.entrySet()) {
+      if (internalGroup.getValue().isLdapGroup()) {
+        this.users.removeGroup(internalGroup.getValue());
+      }
+    }
+
+    cleanUpLdapUsersWithoutGroup();
+
+    // processing users
+    final Map<String, User> internalUsersMap = getInternalUsers();
+    for (String userName : users) {
+      if (internalUsersMap.containsKey(userName)) {
+        final User user = internalUsersMap.get(userName);
+        if (!user.isLdapUser()) {
+          this.users.setUserLdap(userName);
+        }
+      } else {
+        this.users.createUser(userName, "");
+        this.users.setUserLdap(userName);
+      }
+    }
+
+  }
+
+  /**
+   * Check group members of the synced group: add missing ones and remove the ones absent in external LDAP.
+   *
+   * @param groupName group name
+   * @throws AmbariException if group refresh failed
+   */
+  private void refreshGroupMembers(String groupName) throws AmbariException {
+    final Set<String> externalMembers = getExternalLdapGroupMembers(groupName);
+    final Map<String, User> internalUsers = getInternalUsers();
+    final Map<String, User> internalMembers = getInternalMembers(groupName);
+    for (String externalMember: externalMembers) {
+      if (internalUsers.containsKey(externalMember)) {
+        final User user = internalUsers.get(externalMember);
+        if (!user.isLdapUser()) {
+          users.setUserLdap(externalMember);
+        }
+        internalUsers.remove(externalMember);
+        internalMembers.remove(externalMember);
+      } else {
+        users.createUser(externalMember, "");
+        users.setUserLdap(externalMember);
+      }
+      users.addMemberToGroup(groupName, externalMember);
+    }
+    for (Entry<String, User> userToBeUnsynced: internalMembers.entrySet()) {
+      final User user = userToBeUnsynced.getValue();
+      users.removeMemberFromGroup(groupName, user.getUserName());
+    }
+  }
+
+  /**
+   * Removes synced users which are not present in any of group.
+   *
+   * @throws AmbariException
+   */
+  private void cleanUpLdapUsersWithoutGroup() throws AmbariException {
+    final List<User> allUsers = users.getAllUsers();
+    for (User user: allUsers) {
+      if (user.isLdapUser() && user.getGroups().isEmpty()) {
+        users.removeUser(user);
+      }
+    }
+  }
+
+  // Utility methods
+
+  /**
+   * Retrieves groups from external LDAP server.
+   *
+   * @return set of user names
+   */
+  private Set<String> getExternalLdapGroupNames() {
+    final Set<String> groups = new HashSet<String>();
+    final LdapTemplate ldapTemplate = loadLdapTemplate();
+    final EqualsFilter equalsFilter = new EqualsFilter("objectClass",
+        ldapServerProperties.getGroupObjectClass());
+    String baseDn = ldapServerProperties.getGroupBase();
+    if (baseDn == null) {
+      baseDn = ldapServerProperties.getBaseDN();
+    }
+    ldapTemplate.search(baseDn, equalsFilter.encode(), new AttributesMapper() {
+
+      public Object mapFromAttributes(Attributes attributes)
+          throws NamingException {
+        groups.add(attributes.get(ldapServerProperties.getGroupNamingAttr())
+            .get().toString().toLowerCase());
+        return null;
+      }
+    });
+    return groups;
+  }
+
+  /**
+   * Retrieves users from external LDAP server.
+   *
+   * @return set of user names
+   */
+  private Set<String> getExternalLdapUserNames() {
+    final Set<String> users = new HashSet<String>();
+    final LdapTemplate ldapTemplate = loadLdapTemplate();
+    final EqualsFilter equalsFilter = new EqualsFilter("objectClass",
+        ldapServerProperties.getUserObjectClass());
+    String baseDn = ldapServerProperties.getUserBase();
+    if (baseDn == null) {
+      baseDn = ldapServerProperties.getBaseDN();
+    }
+    ldapTemplate.search(baseDn, equalsFilter.encode(), new AttributesMapper() {
+
+      public Object mapFromAttributes(Attributes attributes)
+          throws NamingException {
+        users.add(attributes.get(ldapServerProperties.getUsernameAttribute())
+            .get().toString().toLowerCase());
+        return null;
+      }
+    });
+    return users;
+  }
+
+  /**
+   * Retrieves members of the specified group from external LDAP server.
+   *
+   * @param groupName group name
+   * @return set of group names
+   */
+  private Set<String> getExternalLdapGroupMembers(String groupName) {
+    final Set<String> members = new HashSet<String>();
+    final LdapTemplate ldapTemplate = loadLdapTemplate();
+    final AndFilter andFilter = new AndFilter();
+    andFilter.and(new EqualsFilter("objectClass", ldapServerProperties.getGroupObjectClass()));
+    andFilter.and(new EqualsFilter(ldapServerProperties.getGroupNamingAttr(), groupName));
+    String baseDn = ldapServerProperties.getGroupBase();
+    if (baseDn == null) {
+      baseDn = ldapServerProperties.getBaseDN();
+    }
+    ldapTemplate.search(baseDn, andFilter.encode(), new ContextMapper() {
+
+      public Object mapFromContext(Object ctx) {
+        final DirContextAdapter adapter  = (DirContextAdapter) ctx;
+        for (String uniqueMember: adapter.getStringAttributes(ldapServerProperties.getGroupMembershipAttr())) {
+          final DirContextAdapter userAdapter = (DirContextAdapter) ldapTemplate.lookup(uniqueMember);
+          members.add(userAdapter.getStringAttribute(ldapServerProperties.getUsernameAttribute().toLowerCase()));
+        }
+        return null;
+      }
+    });
+    return members;
+  }
+
+  /**
+   * Creates a map of internal groups.
+   *
+   * @return map of GroupName-Group pairs
+   */
+  private Map<String, Group> getInternalGroups() {
+    final List<Group> internalGroups = users.getAllGroups();
+    final Map<String, Group> internalGroupsMap = new HashMap<String, Group>();
+    for (Group group : internalGroups) {
+      internalGroupsMap.put(group.getGroupName(), group);
+    }
+    return internalGroupsMap;
+  }
+
+  /**
+   * Creates a map of internal users.
+   *
+   * @return map of UserName-User pairs
+   */
+  private Map<String, User> getInternalUsers() {
+    final List<User> internalUsers = users.getAllUsers();
+    final Map<String, User> internalUsersMap = new HashMap<String, User>();
+    for (User user : internalUsers) {
+      internalUsersMap.put(user.getUserName(), user);
+    }
+    return internalUsersMap;
+  }
+
+  /**
+   * Creates a map of internal users present in specified group.
+   *
+   * @param groupName group name
+   * @return map of UserName-User pairs
+   */
+  private Map<String, User> getInternalMembers(String groupName) {
+    final Collection<User> internalMembers = users.getGroupMembers(groupName);
+    final Map<String, User> internalMembersMap = new HashMap<String, User>();
+    for (User user : internalMembers) {
+      internalMembersMap.put(user.getUserName(), user);
+    }
+    return internalMembersMap;
+  }
+
+  /**
+   * Checks LDAP configuration for changes and reloads LDAP template if they occured.
+   *
+   * @return LdapTemplate instance
+   */
+  private LdapTemplate loadLdapTemplate() {
+    final LdapServerProperties properties = configuration
+        .getLdapServerProperties();
+    if (ldapTemplate == null || !properties.equals(ldapServerProperties)) {
+      LOG.info("Reloading properties");
+      ldapServerProperties = properties;
+
+      final LdapContextSource ldapContextSource = new LdapContextSource();
+      final List<String> ldapUrls = ldapServerProperties.getLdapUrls();
+      ldapContextSource.setUrls(ldapUrls.toArray(new String[ldapUrls.size()]));
+
+      if (!ldapServerProperties.isAnonymousBind()) {
+        ldapContextSource.setUserDn(ldapServerProperties.getManagerDn());
+        ldapContextSource
+            .setPassword(ldapServerProperties.getManagerPassword());
+      }
+
+      try {
+        ldapContextSource.afterPropertiesSet();
+      } catch (Exception e) {
+        LOG.error("LDAP Context Source not loaded ", e);
+        throw new UsernameNotFoundException("LDAP Context Source not loaded", e);
+      }
+
+      ldapTemplate = new LdapTemplate(ldapContextSource);
+    }
+    return ldapTemplate;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
index 8f9eb81..e13f131 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/LdapServerProperties.java
@@ -35,8 +35,6 @@ public class LdapServerProperties {
   private String managerDn;
   private String managerPassword;
   private String baseDN;
-  private String userSearchBase = "";
-  private String usernameAttribute;
 
   //LDAP group properties
   private String groupBase;
@@ -46,6 +44,11 @@ public class LdapServerProperties {
   private String adminGroupMappingRules;
   private boolean groupMappingEnabled;
 
+  //LDAP user properties
+  private String userBase;
+  private String userObjectClass;
+  private String usernameAttribute;
+
   private String groupSearchFilter;
   private static final String userSearchFilter = "({attribute}={0})";
 
@@ -120,14 +123,6 @@ public class LdapServerProperties {
     this.baseDN = baseDN;
   }
 
-  public String getUserSearchBase() {
-    return userSearchBase;
-  }
-
-  public void setUserSearchBase(String userSearchBase) {
-    this.userSearchBase = userSearchBase;
-  }
-
   public String getUserSearchFilter() {
     return userSearchFilter.replace("{attribute}", usernameAttribute);
   }
@@ -196,6 +191,22 @@ public class LdapServerProperties {
     this.groupMappingEnabled = groupMappingEnabled;
   }
 
+  public void setUserBase(String userBase) {
+    this.userBase = userBase;
+  }
+
+  public void setUserObjectClass(String userObjectClass) {
+    this.userObjectClass = userObjectClass;
+  }
+
+  public String getUserBase() {
+    return userBase;
+  }
+
+  public String getUserObjectClass() {
+    return userObjectClass;
+  }
+
   @Override
   public boolean equals(Object obj) {
     if (this == obj) return true;
@@ -211,7 +222,9 @@ public class LdapServerProperties {
     if (managerPassword != null ? !managerPassword.equals(that.managerPassword) : that.managerPassword != null)
       return false;
     if (baseDN != null ? !baseDN.equals(that.baseDN) : that.baseDN != null) return false;
-    if (userSearchBase != null ? !userSearchBase.equals(that.userSearchBase) : that.userSearchBase != null)
+    if (userBase != null ? !userBase.equals(that.userBase) : that.userBase != null)
+      return false;
+    if (userObjectClass != null ? !userObjectClass.equals(that.userObjectClass) : that.userObjectClass != null)
       return false;
     if (usernameAttribute != null ? !usernameAttribute.equals(that.usernameAttribute) : that.usernameAttribute != null)
       return false;
@@ -240,7 +253,8 @@ public class LdapServerProperties {
     result = 31 * result + (managerDn != null ? managerDn.hashCode() : 0);
     result = 31 * result + (managerPassword != null ? managerPassword.hashCode() : 0);
     result = 31 * result + (baseDN != null ? baseDN.hashCode() : 0);
-    result = 31 * result + (userSearchBase != null ? userSearchBase.hashCode() : 0);
+    result = 31 * result + (userBase != null ? userBase.hashCode() : 0);
+    result = 31 * result + (userObjectClass != null ? userObjectClass.hashCode() : 0);
     result = 31 * result + (usernameAttribute != null ? usernameAttribute.hashCode() : 0);
     result = 31 * result + (groupBase != null ? groupBase.hashCode() : 0);
     result = 31 * result + (groupObjectClass != null ? groupObjectClass.hashCode() : 0);

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Member.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Member.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Member.java
deleted file mode 100644
index da4732a..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Member.java
+++ /dev/null
@@ -1,53 +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.
- */
-package org.apache.ambari.server.security.authorization;
-
-import org.apache.ambari.server.orm.entities.GroupEntity;
-
-/**
- * Describes group of users of web-service.
- */
-public class Member {
-  private final int groupId;
-  private final String groupName;
-  private final boolean ldapGroup;
-
-  Member(GroupEntity groupEntity) {
-    this.groupId = groupEntity.getGroupId();
-    this.groupName = groupEntity.getGroupName();
-    this.ldapGroup = groupEntity.getLdapGroup();
-  }
-
-  public int getGroupId() {
-    return groupId;
-  }
-
-  public String getGroupName() {
-    return groupName;
-  }
-
-  public boolean isLdapGroup() {
-    return ldapGroup;
-  }
-
-  @Override
-  public String toString() {
-    return "Group [groupId=" + groupId + ", groupName=" + groupName
-        + ", ldapGroup=" + ldapGroup + "]";
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
index f9f8e21..e0e84c2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
@@ -17,13 +17,14 @@
  */
 package org.apache.ambari.server.security.authorization;
 
-import org.apache.ambari.server.orm.entities.RoleEntity;
-import org.apache.ambari.server.orm.entities.UserEntity;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 
+import org.apache.ambari.server.orm.entities.MemberEntity;
+import org.apache.ambari.server.orm.entities.RoleEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
+
 /**
  * Describes user of web-services
  */
@@ -34,6 +35,7 @@ public class User {
   final Date createTime;
   final boolean active;
   final Collection<String> roles = new ArrayList<String>();
+  final Collection<String> groups = new ArrayList<String>();
 
   User(UserEntity userEntity) {
     userId = userEntity.getUserId();
@@ -44,6 +46,9 @@ public class User {
     for (RoleEntity roleEntity : userEntity.getRoleEntities()) {
       roles.add(roleEntity.getRoleName());
     }
+    for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
+      groups.add(memberEntity.getGroup().getGroupName());
+    }
   }
 
   public int getUserId() {
@@ -70,6 +75,10 @@ public class User {
     return roles;
   }
 
+  public Collection<String> getGroups() {
+    return groups;
+  }
+
   @Override
   public String toString() {
     return (ldapUser ? "[LDAP]" : "[LOCAL]") + userName;

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/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 f3050ce..cbafb16 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
@@ -185,6 +185,38 @@ public class Users {
   }
 
   /**
+   * Converts user to LDAP user.
+   *
+   * @param userName user name
+   * @throws AmbariException if user does not exist
+   */
+  public synchronized void setUserLdap(String userName) throws AmbariException {
+    UserEntity userEntity = userDAO.findLocalUserByName(userName);
+    if (userEntity != null) {
+      userEntity.setLdapUser(true);
+      userDAO.merge(userEntity);
+    } else {
+      throw new AmbariException("User " + userName + " doesn't exist or is already an LDAP user");
+    }
+  }
+
+  /**
+   * Converts group to LDAP group.
+   *
+   * @param groupName group name
+   * @throws AmbariException if group does not exist
+   */
+  public synchronized void setGroupLdap(String groupName) throws AmbariException {
+    GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
+    if (groupEntity != null) {
+      groupEntity.setLdapGroup(true);
+      groupDAO.merge(groupEntity);
+    } else {
+      throw new AmbariException("Group " + groupName + " doesn't exist");
+    }
+  }
+
+  /**
    * Creates new local user with provided userName and password
    */
   @Transactional

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/resources/key_properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/key_properties.json b/ambari-server/src/main/resources/key_properties.json
index 3c63ccb..b693dec 100644
--- a/ambari-server/src/main/resources/key_properties.json
+++ b/ambari-server/src/main/resources/key_properties.json
@@ -143,5 +143,8 @@
   "AlertDefinition": {
     "Cluster": "AlertDefinition/cluster_name",
     "AlertDefinition": "AlertDefinition/id"
+  },
+  "Controller": {
+    "Controller": "Controllers/name"
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/15b54439/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index 697a44c..1716973 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -397,5 +397,14 @@
       "AlertDefinition/enabled",
       "AlertDefinition/scope",
       "AlertDefinition/source"
+    ],      
+    "Controller":[
+        "Controllers/name",
+        "LDAP/configured",
+        "LDAP/users",
+        "LDAP/groups",
+        "LDAP/synced_users",
+        "LDAP/synced_groups",
+        "_"
     ]
 }