You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/07/19 12:41:51 UTC

[1/6] ambari git commit: AMBARI-20861. BE: Extend Ambari REST API to Support User Account Management Improvements (rlevas)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-20859 903cd1a06 -> 317905e40


http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderTest.java
index 4530d40..aaddda2 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderTest.java
@@ -18,14 +18,21 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.getCurrentArguments;
+import static org.easymock.EasyMock.newCapture;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -41,27 +48,46 @@ import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.AbstractRootServiceResponseFactory;
 import org.apache.ambari.server.controller.AmbariManagementController;
-import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
 import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.ResourceProviderFactory;
+import org.apache.ambari.server.controller.predicate.AndPredicate;
+import org.apache.ambari.server.controller.predicate.EqualsPredicate;
 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.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.hooks.HookContext;
 import org.apache.ambari.server.hooks.HookContextFactory;
 import org.apache.ambari.server.hooks.HookService;
 import org.apache.ambari.server.metadata.CachedRoleCommandOrderProvider;
 import org.apache.ambari.server.metadata.RoleCommandOrderProvider;
 import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.orm.dao.GroupDAO;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.orm.dao.MemberDAO;
+import org.apache.ambari.server.orm.dao.PermissionDAO;
+import org.apache.ambari.server.orm.dao.PrincipalDAO;
+import org.apache.ambari.server.orm.dao.PrincipalTypeDAO;
+import org.apache.ambari.server.orm.dao.PrivilegeDAO;
+import org.apache.ambari.server.orm.dao.ResourceDAO;
+import org.apache.ambari.server.orm.dao.UserAuthenticationDAO;
+import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.entities.MemberEntity;
+import org.apache.ambari.server.orm.entities.PermissionEntity;
+import org.apache.ambari.server.orm.entities.PrincipalEntity;
+import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
+import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.ResourceEntity;
 import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.scheduler.ExecutionScheduler;
 import org.apache.ambari.server.security.TestAuthenticationFactory;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
-import org.apache.ambari.server.security.authorization.Users;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.security.encryption.CredentialStoreService;
 import org.apache.ambari.server.security.encryption.CredentialStoreServiceImpl;
 import org.apache.ambari.server.stack.StackManagerFactory;
@@ -75,7 +101,12 @@ import org.apache.ambari.server.state.UpgradeContextFactory;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
 import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.view.ViewRegistry;
+import org.apache.commons.lang.StringUtils;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
 import org.easymock.EasyMockSupport;
+import org.easymock.IAnswer;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -87,6 +118,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
+import com.google.inject.Provider;
 import com.google.inject.assistedinject.FactoryModuleBuilder;
 
 /**
@@ -94,6 +126,8 @@ import com.google.inject.assistedinject.FactoryModuleBuilder;
  */
 public class UserResourceProviderTest extends EasyMockSupport {
 
+  private static final Date CREATE_TIME = Calendar.getInstance().getTime();
+
   @Before
   public void resetMocks() {
     resetAll();
@@ -106,107 +140,226 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
   @Test
   public void testCreateResources_Administrator() throws Exception {
-    createResourcesTest(TestAuthenticationFactory.createAdministrator("admin"));
+    Map<String, Object> resource = new HashMap<>();
+    resource.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User100");
+    resource.put(UserResourceProvider.USER_LOCAL_USERNAME_PROPERTY_ID, "user100");
+    resource.put(UserResourceProvider.USER_DISPLAY_NAME_PROPERTY_ID, "User 100");
+
+    createResourcesTest(TestAuthenticationFactory.createAdministrator(), Collections.singleton(resource));
   }
 
   @Test(expected = AuthorizationException.class)
   public void testCreateResources_NonAdministrator() throws Exception {
-    createResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L));
+    Map<String, Object> resource = new HashMap<>();
+    resource.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User100");
+    resource.put(UserResourceProvider.USER_LOCAL_USERNAME_PROPERTY_ID, "user100");
+    resource.put(UserResourceProvider.USER_DISPLAY_NAME_PROPERTY_ID, "User 100");
+
+    createResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), Collections.singleton(resource));
+  }
+
+  @Test
+  public void testCreateResources_Multiple() throws Exception {
+    Map<String, Object> resource1 = new HashMap<>();
+    resource1.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User100");
+    Map<String, Object> resource2 = new HashMap<>();
+    resource2.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User200");
+
+    HashSet<Map<String, Object>> resourceProperties = new HashSet<>();
+    resourceProperties.add(resource1);
+    resourceProperties.add(resource2);
+
+    createResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), resourceProperties);
+  }
+
+  /**
+   * Test setting a user's local password when creating the account. This is for backward compatibility
+   * to maintain the REST API V1 contract.
+   */
+  @Test
+  public void testCreateResources_SetPassword() throws Exception {
+    Map<String, Object> resource = new HashMap<>();
+    resource.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User100");
+    resource.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password100");
+
+    createResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), Collections.singleton(resource));
+  }
+
+  /**
+   * Test give a user Ambari administrative rights by assigning the user to the AMBARI.ADMINISTRATOR role
+   * when creating the account. This is for backward compatibility to maintain the REST API V1 contract.
+   */
+  @Test
+  public void testCreateResources_SetAdmin() throws Exception {
+    Map<String, Object> resource = new HashMap<>();
+    resource.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User100");
+    resource.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, true);
+
+    createResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), Collections.singleton(resource));
+  }
+
+  @Test
+  public void testCreateResources_SetInactive() throws Exception {
+    Map<String, Object> resource = new HashMap<>();
+    resource.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User100");
+    resource.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, false);
+
+    createResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), Collections.singleton(resource));
   }
 
   @Test
   public void testGetResources_Administrator() throws Exception {
-    getResourcesTest(TestAuthenticationFactory.createAdministrator("admin"));
+    getResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), null);
   }
 
   @Test
   public void testGetResources_NonAdministrator() throws Exception {
-    getResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L));
+    getResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), null);
   }
 
   @Test
   public void testGetResource_Administrator_Self() throws Exception {
-    getResourceTest(TestAuthenticationFactory.createAdministrator("admin"), "admin");
+    getResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), "admin");
   }
 
   @Test
   public void testGetResource_Administrator_Other() throws Exception {
-    getResourceTest(TestAuthenticationFactory.createAdministrator("admin"), "User1");
+    getResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), "User1");
   }
 
   @Test
   public void testGetResource_NonAdministrator_Self() throws Exception {
-    getResourceTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+    getResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
   }
 
   @Test(expected = AuthorizationException.class)
   public void testGetResource_NonAdministrator_Other() throws Exception {
-    getResourceTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+    getResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
   }
 
   @Test
-  public void testUpdateResources_SetAdmin_Administrator_Self() throws Exception {
-    updateResources_SetAdmin(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  public void testUpdateResources_UpdateAdmin_Administrator_Self() throws Exception {
+    testUpdateResources_UpdateAdmin(TestAuthenticationFactory.createAdministrator("admin"), "admin");
   }
 
   @Test
-  public void testUpdateResources_SetAdmin_Administrator_Other() throws Exception {
-    updateResources_SetAdmin(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  public void testUpdateResources_UpdateAdmin_Administrator_Other() throws Exception {
+    testUpdateResources_UpdateAdmin(TestAuthenticationFactory.createAdministrator("admin"), "User100");
   }
 
   @Test(expected = AuthorizationException.class)
-  public void testUpdateResources_SetAdmin_NonAdministrator_Self() throws Exception {
-    updateResources_SetAdmin(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+  public void testUpdateResources_UpdateAdmin_NonAdministrator_Self() throws Exception {
+    testUpdateResources_UpdateAdmin(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
   }
 
   @Test(expected = AuthorizationException.class)
-  public void testUpdateResources_SetAdmin_NonAdministrator_Other() throws Exception {
-    updateResources_SetAdmin(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+  public void testUpdateResources_UpdateAdmin_NonAdministrator_Other() throws Exception {
+    testUpdateResources_UpdateAdmin(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
   }
 
   @Test
-  public void testUpdateResources_SetActive_Administrator_Self() throws Exception {
-    updateResources_SetActive(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  public void testUpdateResources_UpdateActive_Administrator_Self() throws Exception {
+    testUpdateResources_UpdateActive(TestAuthenticationFactory.createAdministrator("admin"), "admin");
   }
 
   @Test
-  public void testUpdateResources_SetActive_Administrator_Other() throws Exception {
-    updateResources_SetActive(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  public void testUpdateResources_UpdateActive_Administrator_Other() throws Exception {
+    testUpdateResources_UpdateActive(TestAuthenticationFactory.createAdministrator("admin"), "User100");
   }
 
   @Test(expected = AuthorizationException.class)
-  public void testUpdateResources_SetActive_NonAdministrator_Self() throws Exception {
-    updateResources_SetActive(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+  public void testUpdateResources_UpdateActive_NonAdministrator_Self() throws Exception {
+    testUpdateResources_UpdateActive(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
   }
 
   @Test(expected = AuthorizationException.class)
-  public void testUpdateResources_SetActive_NonAdministrator_Other() throws Exception {
-    updateResources_SetActive(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+  public void testUpdateResources_UpdateActive_NonAdministrator_Other() throws Exception {
+    testUpdateResources_UpdateActive(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
   }
 
   @Test
-  public void testUpdateResources_SetPassword_Administrator_Self() throws Exception {
-    updateResources_SetPassword(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  public void testUpdateResources_UpdateDisplayName_Administrator_Self() throws Exception {
+    testUpdateResources_UpdateDisplayName(TestAuthenticationFactory.createAdministrator("admin"), "admin");
   }
 
   @Test
-  public void testUpdateResources_SetPassword_Administrator_Other() throws Exception {
-    updateResources_SetPassword(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  public void testUpdateResources_UpdateDisplayName_Administrator_Other() throws Exception {
+    testUpdateResources_UpdateDisplayName(TestAuthenticationFactory.createAdministrator("admin"), "User100");
   }
 
   @Test
-  public void testUpdateResources_SetPassword_NonAdministrator_Self() throws Exception {
-    updateResources_SetPassword(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+  public void testUpdateResources_UpdateDisplayName_NonAdministrator_Self() throws Exception {
+    testUpdateResources_UpdateDisplayName(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
   }
 
   @Test(expected = AuthorizationException.class)
-  public void testUpdateResources_SetPassword_NonAdministrator_Other() throws Exception {
-    updateResources_SetPassword(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+  public void testUpdateResources_UpdateDisplayName_NonAdministrator_Other() throws Exception {
+    testUpdateResources_UpdateDisplayName(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+  }
+
+  @Test
+  public void testUpdateResources_UpdateLocalUserName_Administrator_Self() throws Exception {
+    testUpdateResources_UpdateLocalUserName(TestAuthenticationFactory.createAdministrator("admin"), "admin");
+  }
+
+  @Test
+  public void testUpdateResources_UpdateLocalUserName_Administrator_Other() throws Exception {
+    testUpdateResources_UpdateLocalUserName(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_UpdateLocalUserName_NonAdministrator_Self() throws Exception {
+    testUpdateResources_UpdateLocalUserName(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_UpdateLocalUserName_NonAdministrator_Other() throws Exception {
+    testUpdateResources_UpdateLocalUserName(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+  }
+
+  @Test
+  public void testUpdateResources_UpdatePassword_Administrator_Self() throws Exception {
+    testUpdateResources_UpdatePassword(TestAuthenticationFactory.createAdministrator("admin"), "admin");
+  }
+
+  @Test
+  public void testUpdateResources_UpdatePassword_Administrator_Other() throws Exception {
+    testUpdateResources_UpdatePassword(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  }
+
+  @Test
+  public void testUpdateResources_UpdatePassword_NonAdministrator_Self() throws Exception {
+    testUpdateResources_UpdatePassword(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_UpdatePassword_NonAdministrator_Other() throws Exception {
+    testUpdateResources_UpdatePassword(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+  }
+
+  @Test
+  public void testUpdateResources_CreatePassword_Administrator_Self() throws Exception {
+    testUpdateResources_CreatePassword(TestAuthenticationFactory.createAdministrator("admin"), "admin");
+  }
+
+  @Test
+  public void testUpdateResources_CreatePassword_Administrator_Other() throws Exception {
+    testUpdateResources_CreatePassword(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_CreatePassword_NonAdministrator_Self() throws Exception {
+    testUpdateResources_CreatePassword(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_CreatePassword_NonAdministrator_Other() throws Exception {
+    testUpdateResources_CreatePassword(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
   }
 
   @Test
   public void testDeleteResource_Administrator_Self() throws Exception {
-    deleteResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+    deleteResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), "admin");
   }
 
   @Test
@@ -227,60 +380,142 @@ public class UserResourceProviderTest extends EasyMockSupport {
   private Injector createInjector() throws Exception {
     return Guice.createInjector(new AbstractModule() {
       @Override
+      protected <T> Provider<T> getProvider(Class<T> type) {
+        return super.getProvider(type);
+      }
+
+      @Override
       protected void configure() {
         install(new FactoryModuleBuilder().build(UpgradeContextFactory.class));
         install(new FactoryModuleBuilder().build(RoleGraphFactory.class));
 
-        bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
-        bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class));
-        bind(ActionDBAccessor.class).toInstance(createNiceMock(ActionDBAccessor.class));
-        bind(ExecutionScheduler.class).toInstance(createNiceMock(ExecutionScheduler.class));
-        bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
+        bind(EntityManager.class).toInstance(createMock(EntityManager.class));
+        bind(DBAccessor.class).toInstance(createMock(DBAccessor.class));
+        bind(ActionDBAccessor.class).toInstance(createMock(ActionDBAccessor.class));
+        bind(ExecutionScheduler.class).toInstance(createMock(ExecutionScheduler.class));
+        bind(OsFamily.class).toInstance(createMock(OsFamily.class));
         bind(AmbariMetaInfo.class).toInstance(createMock(AmbariMetaInfo.class));
-        bind(ActionManager.class).toInstance(createNiceMock(ActionManager.class));
-        bind(RequestFactory.class).toInstance(createNiceMock(RequestFactory.class));
-        bind(RequestExecutionFactory.class).toInstance(createNiceMock(RequestExecutionFactory.class));
-        bind(StageFactory.class).toInstance(createNiceMock(StageFactory.class));
-        bind(Clusters.class).toInstance(createNiceMock(Clusters.class));
-        bind(AbstractRootServiceResponseFactory.class).toInstance(createNiceMock(AbstractRootServiceResponseFactory.class));
-        bind(StackManagerFactory.class).toInstance(createNiceMock(StackManagerFactory.class));
-        bind(ConfigFactory.class).toInstance(createNiceMock(ConfigFactory.class));
-        bind(ConfigGroupFactory.class).toInstance(createNiceMock(ConfigGroupFactory.class));
-        bind(ServiceFactory.class).toInstance(createNiceMock(ServiceFactory.class));
-        bind(ServiceComponentFactory.class).toInstance(createNiceMock(ServiceComponentFactory.class));
-        bind(ServiceComponentHostFactory.class).toInstance(createNiceMock(ServiceComponentHostFactory.class));
-        bind(PasswordEncoder.class).toInstance(createNiceMock(PasswordEncoder.class));
-        bind(KerberosHelper.class).toInstance(createNiceMock(KerberosHelper.class));
-        bind(Users.class).toInstance(createMock(Users.class));
-        bind(AmbariManagementController.class).to(AmbariManagementControllerImpl.class);
+        bind(ActionManager.class).toInstance(createMock(ActionManager.class));
+        bind(RequestFactory.class).toInstance(createMock(RequestFactory.class));
+        bind(RequestExecutionFactory.class).toInstance(createMock(RequestExecutionFactory.class));
+        bind(StageFactory.class).toInstance(createMock(StageFactory.class));
+        bind(Clusters.class).toInstance(createMock(Clusters.class));
+        bind(AbstractRootServiceResponseFactory.class).toInstance(createMock(AbstractRootServiceResponseFactory.class));
+        bind(StackManagerFactory.class).toInstance(createMock(StackManagerFactory.class));
+        bind(ConfigFactory.class).toInstance(createMock(ConfigFactory.class));
+        bind(ConfigGroupFactory.class).toInstance(createMock(ConfigGroupFactory.class));
+        bind(ServiceFactory.class).toInstance(createMock(ServiceFactory.class));
+        bind(ServiceComponentFactory.class).toInstance(createMock(ServiceComponentFactory.class));
+        bind(ServiceComponentHostFactory.class).toInstance(createMock(ServiceComponentHostFactory.class));
+        bind(PasswordEncoder.class).toInstance(createMock(PasswordEncoder.class));
+        bind(KerberosHelper.class).toInstance(createMock(KerberosHelper.class));
+        bind(AmbariManagementController.class).toInstance(createMock(AmbariManagementController.class));
         bind(RoleCommandOrderProvider.class).to(CachedRoleCommandOrderProvider.class);
         bind(CredentialStoreService.class).to(CredentialStoreServiceImpl.class);
         bind(HostRoleCommandDAO.class).toInstance(createMock(HostRoleCommandDAO.class));
         bind(HookService.class).toInstance(createMock(HookService.class));
         bind(HookContextFactory.class).toInstance(createMock(HookContextFactory.class));
         bind(HostRoleCommandFactory.class).to(HostRoleCommandFactoryImpl.class);
+        bind(UserDAO.class).toInstance(createMock(UserDAO.class));
+
+        bind(UserAuthenticationDAO.class).toInstance(createMock(UserAuthenticationDAO.class));
+        bind(GroupDAO.class).toInstance(createMock(GroupDAO.class));
+        bind(MemberDAO.class).toInstance(createMock(MemberDAO.class));
+        bind(PrincipalDAO.class).toInstance(createMock(PrincipalDAO.class));
+        bind(PermissionDAO.class).toInstance(createMock(PermissionDAO.class));
+        bind(PrivilegeDAO.class).toInstance(createMock(PrivilegeDAO.class));
+        bind(ResourceDAO.class).toInstance(createMock(ResourceDAO.class));
+        bind(PrincipalTypeDAO.class).toInstance(createMock(PrincipalTypeDAO.class));
       }
     });
   }
 
 
-  private void createResourcesTest(Authentication authentication) throws Exception {
+  private void createResourcesTest(Authentication authentication, Set<Map<String, Object>> resourceProperties) throws Exception {
     Injector injector = createInjector();
+    UserDAO userDAO = injector.getInstance(UserDAO.class);
+    Capture<? extends UserEntity> userEntityCapture = newCapture(CaptureType.ALL);
+
+    Map<String, Map<String, Object>> expectedUsers = new HashMap<>();
+
+    for (Map<String, Object> properties : resourceProperties) {
+      String username = (String) properties.get(UserResourceProvider.USER_USERNAME_PROPERTY_ID);
+
+      if (!StringUtils.isEmpty(username)) {
+        Assert.assertFalse("User names must be unique for this test case", expectedUsers.containsKey(username.toLowerCase()));
+
+        expect(userDAO.findUserByName(username)).andReturn(null).times(2);
+        userDAO.create(capture(userEntityCapture));
+        expectLastCall().once();
+
+        PrincipalTypeEntity principalTypeEntity = createMock(PrincipalTypeEntity.class);
+
+        PrincipalTypeDAO principalTypeDAO = injector.getInstance(PrincipalTypeDAO.class);
+        expect(principalTypeDAO.findById(PrincipalTypeEntity.USER_PRINCIPAL_TYPE)).andReturn(principalTypeEntity).once();
+
+        PrincipalDAO principalDAO = injector.getInstance(PrincipalDAO.class);
+        principalDAO.create(anyObject(PrincipalEntity.class));
+        expectLastCall().andAnswer(new IAnswer<Object>() {
+          @Override
+          public Object answer() throws Throwable {
+            Object[] args = getCurrentArguments();
+
+            ((PrincipalEntity) args[0]).setId(1L);
+            return null;
+          }
+        }).once();
+
+
+        HookContextFactory hookContextFactory = injector.getInstance(HookContextFactory.class);
+        expect(hookContextFactory.createUserHookContext(username)).andReturn(null).once();
 
-    UserEntity userEntity100 = createNiceMock(UserEntity.class);
-    UserEntity userEntity200 = createNiceMock(UserEntity.class);
+        HookService hookService = injector.getInstance(HookService.class);
+        expect(hookService.execute(anyObject(HookContext.class))).andReturn(true).once();
 
-    Users users = injector.getInstance(Users.class);
-    expect(users.createUser("User100", "User100", "User100", null))
-        .andReturn(userEntity100)
-        .once();
-    expect(users.createUser("user200", "user200", "user200", null))
-        .andReturn(userEntity200)
-        .once();
 
-    users.addLocalAuthentication(userEntity100, "password100");
-    users.addLocalAuthentication(userEntity200, "password200");
-    expectLastCall().once();
+        if (properties.get(UserResourceProvider.USER_PASSWORD_PROPERTY_ID) != null) {
+          ResourceProviderFactory factory = createMock(ResourceProviderFactory.class);
+          ResourceProvider resourceProvider = createMock(ResourceProvider.class);
+          RequestStatus status = createMock(RequestStatus.class);
+          expect(resourceProvider.createResources(anyObject(Request.class))).andReturn(status).once();
+          expect(factory.getUserAuthenticationSourceResourceProvider()).andReturn(resourceProvider).once();
+
+          AbstractControllerResourceProvider.init(factory);
+        }
+
+        if (properties.get(UserResourceProvider.USER_ADMIN_PROPERTY_ID) != null) {
+          Boolean isAdmin = Boolean.TRUE.equals(properties.get(UserResourceProvider.USER_ADMIN_PROPERTY_ID));
+
+          if (isAdmin) {
+            PermissionEntity permissionEntity = createMock(PermissionEntity.class);
+            PermissionDAO permissionDAO = injector.getInstance(PermissionDAO.class);
+            expect(permissionDAO.findAmbariAdminPermission()).andReturn(permissionEntity).once();
+
+            ResourceEntity resourceEntity = createMock(ResourceEntity.class);
+            ResourceDAO resourceDAO = injector.getInstance(ResourceDAO.class);
+            expect(resourceDAO.findAmbariResource()).andReturn(resourceEntity).once();
+
+            PrivilegeDAO privilegeDAO = injector.getInstance(PrivilegeDAO.class);
+            privilegeDAO.create(anyObject(PrivilegeEntity.class));
+            expectLastCall().andAnswer(new IAnswer<Object>() {
+              @Override
+              public Object answer() throws Throwable {
+                Object[] args = getCurrentArguments();
+
+                ((PrivilegeEntity) args[0]).setId(1);
+                return null;
+              }
+            }).once();
+
+            expect(principalDAO.merge(anyObject(PrincipalEntity.class))).andReturn(null).once();
+
+            expect(userDAO.merge(anyObject(UserEntity.class))).andReturn(null).once();
+          }
+        }
+
+        expectedUsers.put(username.toLowerCase(), properties);
+      }
+    }
 
     // replay
     replayAll();
@@ -292,53 +527,73 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     ResourceProvider provider = getResourceProvider(injector);
 
-    // add the property map to a set for the request.  add more maps for multiple creates
-    Set<Map<String, Object>> propertySet = new LinkedHashSet<>();
-
-    Map<String, Object> properties;
-
-    properties = new LinkedHashMap<>();
-    properties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User100");
-    properties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password100");
-    propertySet.add(properties);
-
-    properties = new LinkedHashMap<>();
-    properties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "user200");
-    properties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password200");
-    propertySet.add(properties);
-
     // create the request
-    Request request = PropertyHelper.getCreateRequest(propertySet, null);
+    Request request = PropertyHelper.getCreateRequest(resourceProperties, null);
 
     provider.createResources(request);
 
     // verify
     verifyAll();
+
+    List<? extends UserEntity> capturedUserEntities = userEntityCapture.getValues();
+    Assert.assertEquals(expectedUsers.size(), capturedUserEntities.size());
+
+    for (UserEntity userEntity : capturedUserEntities) {
+      String userName = userEntity.getUserName();
+      Map<String, Object> userProperties = expectedUsers.get(userName);
+
+      Assert.assertNotNull(userProperties);
+
+      String username = (String) userProperties.get(UserResourceProvider.USER_USERNAME_PROPERTY_ID);
+      String displayName = (String) userProperties.get(UserResourceProvider.USER_DISPLAY_NAME_PROPERTY_ID);
+      String localUsername = (String) userProperties.get(UserResourceProvider.USER_LOCAL_USERNAME_PROPERTY_ID);
+      Boolean isActive = (userProperties.containsKey(UserResourceProvider.USER_ACTIVE_PROPERTY_ID))
+          ? !Boolean.FALSE.equals(userProperties.get(UserResourceProvider.USER_ACTIVE_PROPERTY_ID))
+          : Boolean.TRUE;
+
+      Assert.assertEquals(username.toLowerCase(), userEntity.getUserName());
+      Assert.assertEquals(StringUtils.defaultIfEmpty(localUsername, username), userEntity.getLocalUsername());
+      Assert.assertEquals(StringUtils.defaultIfEmpty(displayName, username), userEntity.getDisplayName());
+      Assert.assertEquals(isActive, userEntity.getActive());
+    }
   }
 
-  private void getResourcesTest(Authentication authentication) throws Exception {
+  private void getResourcesTest(Authentication authentication, String requestedUsername) throws Exception {
     Injector injector = createInjector();
 
-    Users users = injector.getInstance(Users.class);
+    String username = requestedUsername;
+    if (username == null) {
+      if (!"admin".equals(authentication.getName())) {
+        username = authentication.getName();
+      }
+    }
 
-    if ("admin".equals(authentication.getName())) {
+    UserDAO userDAO = injector.getInstance(UserDAO.class);
+
+    PrincipalEntity userPrincipalEntity = createMock(PrincipalEntity.class);
+    expect(userPrincipalEntity.getPrivileges()).andReturn(null).anyTimes();
+
+    if (username == null) {
       UserEntity userEntity1 = createMockUserEntity("User1");
+      expect(userEntity1.getPrincipal()).andReturn(userPrincipalEntity).once();
+
       UserEntity userEntity10 = createMockUserEntity("User10");
+      expect(userEntity10.getPrincipal()).andReturn(userPrincipalEntity).once();
+
       UserEntity userEntity100 = createMockUserEntity("User100");
+      expect(userEntity100.getPrincipal()).andReturn(userPrincipalEntity).once();
+
       UserEntity userEntityAdmin = createMockUserEntity("admin");
+      expect(userEntityAdmin.getPrincipal()).andReturn(userPrincipalEntity).once();
 
       List<UserEntity> allUsers = Arrays.asList(userEntity1, userEntity10, userEntity100, userEntityAdmin);
 
-      expect(users.getAllUserEntities()).andReturn(allUsers).once();
-      expect(users.hasAdminPrivilege(userEntity1)).andReturn(false).once();
-      expect(users.hasAdminPrivilege(userEntity10)).andReturn(false).once();
-      expect(users.hasAdminPrivilege(userEntity100)).andReturn(false).once();
-      expect(users.hasAdminPrivilege(userEntityAdmin)).andReturn(true).once();
+      expect(userDAO.findAll()).andReturn(allUsers).once();
     } else {
+      UserEntity userEntity = createMockUserEntity(username);
+      expect(userEntity.getPrincipal()).andReturn(userPrincipalEntity).once();
 
-      UserEntity userEntity = createMockUserEntity("User1");
-      expect(users.getUserEntity("User1")).andReturn(userEntity).once();
-      expect(users.hasAdminPrivilege(userEntity)).andReturn(false).once();
+      expect(userDAO.findUserByName(username)).andReturn(userEntity).once();
     }
 
     replayAll();
@@ -356,9 +611,9 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     Request request = PropertyHelper.getReadRequest(propertyIds);
 
-    Set<Resource> resources = provider.getResources(request, null);
+    Set<Resource> resources = provider.getResources(request, (requestedUsername == null) ? null : createPredicate(requestedUsername));
 
-    if ("admin".equals(authentication.getName())) {
+    if (username == null) {
       List<String> expectedList = Arrays.asList("User1", "User10", "User100", "admin");
       Assert.assertEquals(4, resources.size());
       for (Resource resource : resources) {
@@ -368,145 +623,204 @@ public class UserResourceProviderTest extends EasyMockSupport {
     } else {
       Assert.assertEquals(1, resources.size());
       for (Resource resource : resources) {
-        Assert.assertEquals("User1", resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID));
+        Assert.assertEquals(username, resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID));
       }
     }
 
     verifyAll();
   }
 
-  private void getResourceTest(Authentication authentication, String requestedUsername) throws Exception {
-    Injector injector = createInjector();
-
-    UserEntity userEntity = createMockUserEntity(requestedUsername);
-
-    Users users = injector.getInstance(Users.class);
-    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
-    expect(users.hasAdminPrivilege(userEntity)).andReturn(false).once();
-
-    replayAll();
-
-    AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
-    ambariMetaInfo.init();
+  private void testUpdateResources_UpdateAdmin(Authentication authentication, String requestedUsername) throws Exception {
+    updateResourcesTest(authentication, requestedUsername, Collections.<String, Object>singletonMap(UserResourceProvider.USER_ADMIN_PROPERTY_ID, true), false);
+  }
 
-    SecurityContextHolder.getContext().setAuthentication(authentication);
+  private void testUpdateResources_UpdateActive(Authentication authentication, String requestedUsername) throws Exception {
+    updateResourcesTest(authentication, requestedUsername, Collections.<String, Object>singletonMap(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, false), false);
+  }
 
-    ResourceProvider provider = getResourceProvider(injector);
+  private void testUpdateResources_UpdateDisplayName(Authentication authentication, String requestedUsername) throws Exception {
+    updateResourcesTest(authentication, requestedUsername, Collections.<String, Object>singletonMap(UserResourceProvider.USER_DISPLAY_NAME_PROPERTY_ID, "Updated Display Name"), false);
+  }
 
-    Set<String> propertyIds = new HashSet<>();
-    propertyIds.add(UserResourceProvider.USER_USERNAME_PROPERTY_ID);
-    propertyIds.add(UserResourceProvider.USER_PASSWORD_PROPERTY_ID);
+  private void testUpdateResources_UpdateLocalUserName(Authentication authentication, String requestedUsername) throws Exception {
+    updateResourcesTest(authentication, requestedUsername, Collections.<String, Object>singletonMap(UserResourceProvider.USER_LOCAL_USERNAME_PROPERTY_ID, "updated_username"), false);
+  }
 
-    Request request = PropertyHelper.getReadRequest(propertyIds);
+  private void testUpdateResources_UpdatePassword(Authentication authentication, String requestedUsername) throws Exception {
+    Map<String, Object> properties = new LinkedHashMap<>();
+    properties.put(UserResourceProvider.USER_OLD_PASSWORD_PROPERTY_ID, "old_password");
+    properties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "new_password");
 
-    Set<Resource> resources = provider.getResources(request, createPredicate(requestedUsername));
+    updateResourcesTest(authentication, requestedUsername, properties, true);
+  }
 
-    Assert.assertEquals(1, resources.size());
-    for (Resource resource : resources) {
-      String userName = (String) resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID);
-      Assert.assertEquals(requestedUsername, userName);
-    }
+  private void testUpdateResources_CreatePassword(Authentication authentication, String requestedUsername) throws Exception {
+    Map<String, Object> properties = new LinkedHashMap<>();
+    properties.put(UserResourceProvider.USER_OLD_PASSWORD_PROPERTY_ID, "old_password");
+    properties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "new_password");
 
-    verifyAll();
+    updateResourcesTest(authentication, requestedUsername, properties, false);
   }
 
-  private void updateResources_SetAdmin(Authentication authentication, String requestedUsername) throws Exception {
+  private void updateResourcesTest(Authentication authentication, String requestedUsername, Map<String, Object> updates, boolean passwordAlreadyExists) throws Exception {
     Injector injector = createInjector();
 
-    UserEntity userEntity = createMockUserEntity(requestedUsername);
+    Capture<Request> requestCapture = newCapture(CaptureType.FIRST);
+    Capture<Predicate> predicateCapture = newCapture(CaptureType.FIRST);
+    boolean hasUpdates = false;
 
-    Users users = injector.getInstance(Users.class);
-    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
+    ResourceProviderFactory factory = createMock(ResourceProviderFactory.class);
 
-    if ("admin".equals(authentication.getName())) {
-      users.grantAdminPrivilege(userEntity);
+    UserEntity userEntity = createMock(UserEntity.class);
+    expect(userEntity.getUserName()).andReturn(requestedUsername).anyTimes();
+    expect(userEntity.getActive()).andReturn(true).anyTimes();
+    expect(userEntity.getDisplayName()).andReturn(requestedUsername).anyTimes();
+    expect(userEntity.getLocalUsername()).andReturn(requestedUsername).anyTimes();
+
+    if (updates.containsKey(UserResourceProvider.USER_DISPLAY_NAME_PROPERTY_ID)) {
+      userEntity.setDisplayName((String) updates.get(UserResourceProvider.USER_DISPLAY_NAME_PROPERTY_ID));
       expectLastCall().once();
+      hasUpdates = true;
     }
 
-    replayAll();
-
-    AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
-    ambariMetaInfo.init();
-
-    SecurityContextHolder.getContext().setAuthentication(authentication);
-
-    ResourceProvider provider = getResourceProvider(injector);
+    if (updates.containsKey(UserResourceProvider.USER_LOCAL_USERNAME_PROPERTY_ID)) {
+      userEntity.setLocalUsername((String) updates.get(UserResourceProvider.USER_LOCAL_USERNAME_PROPERTY_ID));
+      expectLastCall().once();
+      hasUpdates = true;
+    }
 
-    // add the property map to a set for the request.
-    Map<String, Object> properties = new LinkedHashMap<>();
-    properties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, "true");
+    if (updates.containsKey(UserResourceProvider.USER_ACTIVE_PROPERTY_ID)) {
+      userEntity.setActive((Boolean) updates.get(UserResourceProvider.USER_ACTIVE_PROPERTY_ID));
+      expectLastCall().once();
+      hasUpdates = true;
+    }
 
-    // create the request
-    Request request = PropertyHelper.getUpdateRequest(properties, null);
+    UserDAO userDAO = injector.getInstance(UserDAO.class);
+    expect(userDAO.findUserByName(requestedUsername)).andReturn(userEntity).once();
 
-    provider.updateResources(request, createPredicate(requestedUsername));
+    if (hasUpdates) {
+      expect(userDAO.merge(userEntity)).andReturn(userEntity).once();
+    }
 
-    verifyAll();
-  }
+    if (updates.get(UserResourceProvider.USER_ADMIN_PROPERTY_ID) != null) {
+      Boolean isAdmin = Boolean.TRUE.equals(updates.get(UserResourceProvider.USER_ADMIN_PROPERTY_ID));
 
-  private void updateResources_SetActive(Authentication authentication, String requestedUsername) throws Exception {
-    Injector injector = createInjector();
+      if (isAdmin) {
+        PermissionEntity permissionEntity = createMock(PermissionEntity.class);
+        PermissionDAO permissionDAO = injector.getInstance(PermissionDAO.class);
+        expect(permissionDAO.findAmbariAdminPermission()).andReturn(permissionEntity).once();
 
-    UserEntity userEntity = createMockUserEntity(requestedUsername);
+        ResourceEntity resourceEntity = createMock(ResourceEntity.class);
+        ResourceDAO resourceDAO = injector.getInstance(ResourceDAO.class);
+        expect(resourceDAO.findAmbariResource()).andReturn(resourceEntity).once();
 
-    Users users = injector.getInstance(Users.class);
-    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
+        PrivilegeDAO privilegeDAO = injector.getInstance(PrivilegeDAO.class);
+        privilegeDAO.create(anyObject(PrivilegeEntity.class));
+        expectLastCall().andAnswer(new IAnswer<Object>() {
+          @Override
+          public Object answer() throws Throwable {
+            Object[] args = getCurrentArguments();
 
-    if ("admin".equals(authentication.getName())) {
-      users.setUserActive(userEntity, true);
-      expectLastCall().once();
-    }
+            ((PrivilegeEntity) args[0]).setId(1);
+            return null;
+          }
+        }).once();
 
-    replayAll();
+        PrincipalDAO principalDAO = injector.getInstance(PrincipalDAO.class);
+        expect(principalDAO.merge(anyObject(PrincipalEntity.class))).andReturn(null).once();
 
-    AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
-    ambariMetaInfo.init();
+        PrincipalEntity principalEntity = createMock(PrincipalEntity.class);
+        expect(principalEntity.getPrivileges()).andReturn(new HashSet<PrivilegeEntity>()).anyTimes();
 
-    SecurityContextHolder.getContext().setAuthentication(authentication);
+        expect(userEntity.getPrincipal()).andReturn(principalEntity).anyTimes();
 
-    ResourceProvider provider = getResourceProvider(injector);
+        expect(userDAO.merge(anyObject(UserEntity.class))).andReturn(null).once();
+      }
+    }
 
-    // add the property map to a set for the request.
-    Map<String, Object> properties = new LinkedHashMap<>();
-    properties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, "true");
+    if (updates.containsKey(UserResourceProvider.USER_PASSWORD_PROPERTY_ID)) {
+      if(passwordAlreadyExists) {
+        UserAuthenticationEntity authenticationEntity = createMock(UserAuthenticationEntity.class);
+        expect(authenticationEntity.getUserAuthenticationId()).andReturn(100L).anyTimes();
+        expect(authenticationEntity.getAuthenticationType()).andReturn(UserAuthenticationType.LOCAL).anyTimes();
 
-    Request request = PropertyHelper.getUpdateRequest(properties, null);
+        expect(userEntity.getAuthenticationEntities()).andReturn(Collections.singletonList(authenticationEntity)).once();
+      }
+      else {
+        expect(userEntity.getAuthenticationEntities()).andReturn(Collections.<UserAuthenticationEntity>emptyList()).once();
+      }
 
-    provider.updateResources(request, createPredicate(requestedUsername));
+      RequestStatus status = createMock(RequestStatus.class);
 
-    verifyAll();
-  }
+      ResourceProvider resourceProvider = createMock(ResourceProvider.class);
 
-  private void updateResources_SetPassword(Authentication authentication, String requestedUsername) throws Exception {
-    Injector injector = createInjector();
+      if(passwordAlreadyExists) {
+        expect(resourceProvider.updateResources(capture(requestCapture), capture(predicateCapture))).andReturn(status).once();
+      }
+      else {
+        expect(resourceProvider.createResources(capture(requestCapture))).andReturn(status).once();
+      }
 
-    UserEntity userEntity = createMockUserEntity(requestedUsername);
+      expect(factory.getUserAuthenticationSourceResourceProvider()).andReturn(resourceProvider).once();
+    }
 
-    Users users = injector.getInstance(Users.class);
-    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
-    users.modifyPassword(userEntity, "old_password", "new_password");
-    expectLastCall().once();
+    AmbariEventPublisher publisher = createNiceMock(AmbariEventPublisher.class);
 
     replayAll();
 
     AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
     ambariMetaInfo.init();
 
+    ViewRegistry.initInstance(new ViewRegistry(publisher));
+    AbstractControllerResourceProvider.init(factory);
     SecurityContextHolder.getContext().setAuthentication(authentication);
 
     ResourceProvider provider = getResourceProvider(injector);
 
-    // add the property map to a set for the request.
-    Map<String, Object> properties = new LinkedHashMap<>();
-    properties.put(UserResourceProvider.USER_OLD_PASSWORD_PROPERTY_ID, "old_password");
-    properties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "new_password");
-
     // create the request
-    Request request = PropertyHelper.getUpdateRequest(properties, null);
+    Request request = PropertyHelper.getUpdateRequest(updates, null);
 
     provider.updateResources(request, createPredicate(requestedUsername));
 
     verifyAll();
+
+    if (updates.containsKey(UserResourceProvider.USER_PASSWORD_PROPERTY_ID)) {
+      // Verify that the correct request was issued to update update the user's password...
+      Request capturedRequest = requestCapture.getValue();
+      Set<Map<String, Object>> capturedProperties = capturedRequest.getProperties();
+      Map<String, Object> properties = capturedProperties.iterator().next();
+      Assert.assertNotNull(capturedProperties);
+      if(passwordAlreadyExists) {
+        Assert.assertEquals(updates.get(UserResourceProvider.USER_PASSWORD_PROPERTY_ID), properties.get(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID));
+        Assert.assertEquals(updates.get(UserResourceProvider.USER_OLD_PASSWORD_PROPERTY_ID), properties.get(UserAuthenticationSourceResourceProvider.AUTHENTICATION_OLD_KEY_PROPERTY_ID));
+      }
+      else {
+        Assert.assertEquals(updates.get(UserResourceProvider.USER_PASSWORD_PROPERTY_ID), properties.get(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID));
+        Assert.assertEquals(UserAuthenticationType.LOCAL.name(), properties.get(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID));
+        Assert.assertEquals(requestedUsername, properties.get(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID));
+      }
+
+      if(passwordAlreadyExists) {
+        Predicate capturedPredicate = predicateCapture.getValue();
+        Assert.assertEquals(AndPredicate.class, capturedPredicate.getClass());
+        AndPredicate andPredicate = (AndPredicate) capturedPredicate;
+        Predicate[] predicates = andPredicate.getPredicates();
+        Assert.assertEquals(2, predicates.length);
+        for (Predicate p : predicates) {
+          Assert.assertEquals(EqualsPredicate.class, p.getClass());
+          EqualsPredicate equalsPredicate = (EqualsPredicate) p;
+
+          if (UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID.equals(equalsPredicate.getPropertyId())) {
+            Assert.assertEquals(requestedUsername, equalsPredicate.getValue());
+          } else if (UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID.equals(equalsPredicate.getPropertyId())) {
+            Assert.assertEquals(100L, equalsPredicate.getValue());
+          }
+        }
+      }
+      else {
+        Assert.assertFalse(predicateCapture.hasCaptured());
+      }
+    }
   }
 
   private void deleteResourcesTest(Authentication authentication, String requestedUsername) throws Exception {
@@ -514,11 +828,23 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     UserEntity userEntity = createMockUserEntity(requestedUsername);
 
-    Users users = injector.getInstance(Users.class);
-    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
-    users.removeUser(userEntity);
+    List<PrincipalEntity> adminPrincipals = Collections.singletonList(createMock(PrincipalEntity.class));
+
+    List<UserEntity> adminUserEntities = new ArrayList<>();
+    adminUserEntities.add(createMockUserEntity("some admin"));
+    if ("admin".equals(requestedUsername)) {
+      adminUserEntities.add(userEntity);
+    }
+
+    UserDAO userDAO = injector.getInstance(UserDAO.class);
+    expect(userDAO.findUserByName(requestedUsername)).andReturn(userEntity).once();
+    (expect(userDAO.findUsersByPrincipal(adminPrincipals))).andReturn(adminUserEntities).once();
+    userDAO.remove(userEntity);
     expectLastCall().atLeastOnce();
 
+    PrincipalDAO principalDAO = injector.getInstance(PrincipalDAO.class);
+    expect(principalDAO.findByPermissionId(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION)).andReturn(adminPrincipals).once();
+
     // replay
     replayAll();
 
@@ -547,17 +873,18 @@ public class UserResourceProviderTest extends EasyMockSupport {
     UserEntity userEntity = createMock(UserEntity.class);
     expect(userEntity.getUserId()).andReturn(username.hashCode()).anyTimes();
     expect(userEntity.getUserName()).andReturn(username).anyTimes();
+    expect(userEntity.getLocalUsername()).andReturn(username).anyTimes();
+    expect(userEntity.getDisplayName()).andReturn(username).anyTimes();
     expect(userEntity.getActive()).andReturn(true).anyTimes();
+    expect(userEntity.getCreateTime()).andReturn(CREATE_TIME).anyTimes();
+    expect(userEntity.getConsecutiveFailures()).andReturn(0).anyTimes();
     expect(userEntity.getAuthenticationEntities()).andReturn(Collections.<UserAuthenticationEntity>emptyList()).anyTimes();
     expect(userEntity.getMemberEntities()).andReturn(Collections.<MemberEntity>emptySet()).anyTimes();
     return userEntity;
   }
 
   private ResourceProvider getResourceProvider(Injector injector) {
-    UserResourceProvider resourceProvider = new UserResourceProvider(
-        PropertyHelper.getPropertyIds(Resource.Type.User),
-        PropertyHelper.getKeyPropertyIds(Resource.Type.User),
-        injector.getInstance(AmbariManagementController.class));
+    UserResourceProvider resourceProvider = new UserResourceProvider(injector.getInstance(AmbariManagementController.class));
 
     injector.injectMembers(resourceProvider);
     return resourceProvider;

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java b/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java
index 43d56cd..65ea12b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java
@@ -31,6 +31,7 @@ import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
 import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
 import org.apache.ambari.server.security.authorization.ResourceType;
 import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.ambari.server.security.authorization.UserIdAuthentication;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 
@@ -40,7 +41,7 @@ public class TestAuthenticationFactory {
   }
 
   public static Authentication createAdministrator(String name) {
-    return new TestAuthorization(name, Collections.singleton(createAdministratorGrantedAuthority()));
+    return new TestAuthorization(1, name, Collections.singleton(createAdministratorGrantedAuthority()));
   }
 
   public static Authentication createClusterAdministrator() {
@@ -52,11 +53,11 @@ public class TestAuthenticationFactory {
   }
 
   public static Authentication createClusterAdministrator(String name, Long clusterResourceId) {
-    return new TestAuthorization(name, Collections.singleton(createClusterAdministratorGrantedAuthority(clusterResourceId)));
+    return new TestAuthorization(1, name, Collections.singleton(createClusterAdministratorGrantedAuthority(clusterResourceId)));
   }
 
   public static Authentication createClusterOperator(String name, Long clusterResourceId) {
-    return new TestAuthorization(name, Collections.singleton(createClusterOperatorGrantedAuthority(clusterResourceId)));
+    return new TestAuthorization(1, name, Collections.singleton(createClusterOperatorGrantedAuthority(clusterResourceId)));
   }
 
   public static Authentication createServiceAdministrator() {
@@ -64,7 +65,7 @@ public class TestAuthenticationFactory {
   }
 
   public static Authentication createServiceAdministrator(String name, Long clusterResourceId) {
-    return new TestAuthorization(name, Collections.singleton(createServiceAdministratorGrantedAuthority(clusterResourceId)));
+    return new TestAuthorization(1, name, Collections.singleton(createServiceAdministratorGrantedAuthority(clusterResourceId)));
   }
 
   public static Authentication createServiceOperator() {
@@ -72,7 +73,7 @@ public class TestAuthenticationFactory {
   }
 
   public static Authentication createServiceOperator(String name, Long clusterResourceId) {
-    return new TestAuthorization(name, Collections.singleton(createServiceOperatorGrantedAuthority(clusterResourceId)));
+    return new TestAuthorization(1, name, Collections.singleton(createServiceOperatorGrantedAuthority(clusterResourceId)));
   }
 
   public static Authentication createClusterUser() {
@@ -80,7 +81,7 @@ public class TestAuthenticationFactory {
   }
 
   public static Authentication createClusterUser(String name, Long clusterResourceId) {
-    return new TestAuthorization(name, Collections.singleton(createClusterUserGrantedAuthority(clusterResourceId)));
+    return new TestAuthorization(1, name, Collections.singleton(createClusterUserGrantedAuthority(clusterResourceId)));
   }
 
   public static Authentication createViewUser(Long viewResourceId) {
@@ -88,7 +89,7 @@ public class TestAuthenticationFactory {
   }
 
   public static Authentication createViewUser(String name, Long viewResourceId) {
-    return new TestAuthorization(name, Collections.singleton(createViewUserGrantedAuthority(viewResourceId)));
+    return new TestAuthorization(1, name, Collections.singleton(createViewUserGrantedAuthority(viewResourceId)));
   }
 
   private static GrantedAuthority createAdministratorGrantedAuthority() {
@@ -402,11 +403,13 @@ public class TestAuthenticationFactory {
   }
 
 
-  private static class TestAuthorization implements Authentication {
+  private static class TestAuthorization implements Authentication, UserIdAuthentication {
+    private final Integer userId;
     private final String name;
     private final Collection<? extends GrantedAuthority> authorities;
 
-    private TestAuthorization(String name, Collection<? extends GrantedAuthority> authorities) {
+    private TestAuthorization(Integer userId, String name, Collection<? extends GrantedAuthority> authorities) {
+      this.userId = userId;
       this.name = name;
       this.authorities = authorities;
     }
@@ -445,5 +448,10 @@ public class TestAuthenticationFactory {
     public String getName() {
       return name;
     }
+
+    @Override
+    public Integer getUserId() {
+      return userId;
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
index e049b4e..e99bdfd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.sql.SQLException;
 import java.util.Collection;
@@ -47,12 +48,7 @@ import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
-import org.mockito.Mockito;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 
 import com.google.inject.Guice;
@@ -89,8 +85,6 @@ public class TestUsers {
     injector = Guice.createInjector(module);
     injector.getInstance(GuiceJpaInitializer.class);
     injector.injectMembers(this);
-    Authentication auth = new UsernamePasswordAuthenticationToken("admin", null);
-    SecurityContextHolder.getContext().setAuthentication(auth);
 
     // create admin permission
     ResourceTypeEntity resourceTypeEntity = new ResourceTypeEntity();
@@ -166,23 +160,56 @@ public class TestUsers {
     assertNotNull(foundUserEntity);
 
     UserAuthenticationEntity foundLocalAuthenticationEntity;
-    foundLocalAuthenticationEntity = getLocalAuthenticationEntity(foundUserEntity);
+    foundLocalAuthenticationEntity = getAuthenticationEntity(foundUserEntity, UserAuthenticationType.LOCAL);
     assertNotNull(foundLocalAuthenticationEntity);
     assertNotSame("user", foundLocalAuthenticationEntity.getAuthenticationKey());
     assertTrue(passwordEncoder.matches("user", foundLocalAuthenticationEntity.getAuthenticationKey()));
 
     foundUserEntity = userDAO.findUserByName("admin");
     assertNotNull(foundUserEntity);
-    users.modifyPassword(foundUserEntity, "admin", "user_new_password");
+    users.modifyAuthentication(foundLocalAuthenticationEntity, "user", "user_new_password", false);
 
-    foundUserEntity = userDAO.findUserByName("admin");
+    foundUserEntity = userDAO.findUserByName("user");
     assertNotNull(foundUserEntity);
-    foundLocalAuthenticationEntity = getLocalAuthenticationEntity(foundUserEntity);
+    foundLocalAuthenticationEntity = getAuthenticationEntity(foundUserEntity, UserAuthenticationType.LOCAL);
     assertNotNull(foundLocalAuthenticationEntity);
     assertTrue(passwordEncoder.matches("user_new_password", foundLocalAuthenticationEntity.getAuthenticationKey()));
   }
 
   @Test
+  public void testModifyPassword_EmptyPassword() throws Exception {
+    UserEntity userEntity;
+
+    userEntity = users.createUser("user", "user", "user");
+    users.addLocalAuthentication(userEntity, "user");
+
+    UserEntity foundUserEntity = userDAO.findUserByName("user");
+    assertNotNull(foundUserEntity);
+
+    UserAuthenticationEntity foundLocalAuthenticationEntity;
+    foundLocalAuthenticationEntity = getAuthenticationEntity(foundUserEntity, UserAuthenticationType.LOCAL);
+    assertNotNull(foundLocalAuthenticationEntity);
+    assertNotSame("user", foundLocalAuthenticationEntity.getAuthenticationKey());
+    assertTrue(passwordEncoder.matches("user", foundLocalAuthenticationEntity.getAuthenticationKey()));
+
+    try {
+      users.modifyAuthentication(foundLocalAuthenticationEntity, "user", null, false);
+      fail("Null password should not be allowed");
+    }
+    catch (AmbariException e) {
+      assertEquals("The new password does not meet the Ambari password requirements", e.getLocalizedMessage());
+    }
+
+    try {
+      users.modifyAuthentication(foundLocalAuthenticationEntity, "user", "", false);
+      fail("Empty password should not be allowed");
+    }
+    catch (AmbariException e) {
+      assertEquals("The new password does not meet the Ambari password requirements", e.getLocalizedMessage());
+    }
+  }
+
+  @Test
   public void testRevokeAdminPrivilege() throws Exception {
     final UserEntity userEntity = users.createUser("old_admin", "old_admin", "old_admin");
     users.grantAdminPrivilege(userEntity);
@@ -238,14 +265,14 @@ public class TestUsers {
     // create duplicate user
     try {
       users.createUser("user1", "user1", null);
-      Assert.fail("It shouldn't be possible to create duplicate user");
+      fail("It shouldn't be possible to create duplicate user");
     } catch (AmbariException e) {
       // This is expected
     }
 
     try {
       users.createUser("USER1", "user1", null);
-      Assert.fail("It shouldn't be possible to create duplicate user");
+      fail("It shouldn't be possible to create duplicate user");
     } catch (AmbariException e) {
       // This is expected
     }
@@ -294,7 +321,7 @@ public class TestUsers {
 
     try {
       users.setUserActive("fake user", true);
-      Assert.fail("It shouldn't be possible to call setUserActive() on non-existing user");
+      fail("It shouldn't be possible to call setUserActive() on non-existing user");
     } catch (Exception ex) {
       // This is expected
     }
@@ -315,7 +342,7 @@ public class TestUsers {
 
     try {
       users.addLdapAuthentication(users.getUserEntity("fake user"), "some other dn");
-      Assert.fail("It shouldn't be possible to call setUserLdap() on non-existing user");
+      fail("It shouldn't be possible to call setUserLdap() on non-existing user");
     } catch (AmbariException ex) {
       // This is expected
     }
@@ -331,7 +358,7 @@ public class TestUsers {
 
     try {
       users.setGroupLdap("fake group");
-      Assert.fail("It shouldn't be possible to call setGroupLdap() on non-existing group");
+      fail("It shouldn't be possible to call setGroupLdap() on non-existing group");
     } catch (AmbariException ex) {
       // This is expected
     }
@@ -379,7 +406,7 @@ public class TestUsers {
 
     try {
       users.getAllMembers("non existing");
-      Assert.fail("It shouldn't be possible to call getAllMembers() on non-existing group");
+      fail("It shouldn't be possible to call getAllMembers() on non-existing group");
     } catch (Exception ex) {
       // This is expected
     }
@@ -395,22 +422,19 @@ public class TestUsers {
 
   @Test
   public void testModifyPassword_UserByHimselfPasswordOk() throws Exception {
-    Authentication auth = new UsernamePasswordAuthenticationToken("user", null);
-    SecurityContextHolder.getContext().setAuthentication(auth);
-
     UserEntity userEntity = users.createUser("user", "user", null);
     users.addLocalAuthentication(userEntity, "user");
 
     userEntity = userDAO.findUserByName("user");
-    UserAuthenticationEntity localAuthenticationEntity = getLocalAuthenticationEntity(userEntity);
+    UserAuthenticationEntity localAuthenticationEntity = getAuthenticationEntity(userEntity, UserAuthenticationType.LOCAL);
     assertNotNull(localAuthenticationEntity);
 
     assertNotSame("user", localAuthenticationEntity.getAuthenticationKey());
     assertTrue(passwordEncoder.matches("user", localAuthenticationEntity.getAuthenticationKey()));
 
-    users.modifyPassword("user", "user", "user_new_password");
+    users.modifyAuthentication(localAuthenticationEntity, "user", "user_new_password", true);
     userEntity = userDAO.findUserByName("user");
-    localAuthenticationEntity = getLocalAuthenticationEntity(userEntity);
+    localAuthenticationEntity = getAuthenticationEntity(userEntity, UserAuthenticationType.LOCAL);
     assertNotNull(localAuthenticationEntity);
 
     assertTrue(passwordEncoder.matches("user_new_password", localAuthenticationEntity.getAuthenticationKey()));
@@ -418,66 +442,101 @@ public class TestUsers {
 
   @Test
   public void testModifyPassword_UserByHimselfPasswordNotOk() throws Exception {
-    Authentication auth = new UsernamePasswordAuthenticationToken("user", null);
-    SecurityContextHolder.getContext().setAuthentication(auth);
-
     UserEntity userEntity = users.createUser("user", "user", null);
     users.addLocalAuthentication(userEntity, "user");
 
     userEntity = userDAO.findUserByName("user");
     UserAuthenticationEntity foundLocalAuthenticationEntity;
-    foundLocalAuthenticationEntity = getLocalAuthenticationEntity(userEntity);
+    foundLocalAuthenticationEntity = getAuthenticationEntity(userEntity, UserAuthenticationType.LOCAL);
     assertNotNull(foundLocalAuthenticationEntity);
     assertNotSame("user", foundLocalAuthenticationEntity.getAuthenticationKey());
     assertTrue(passwordEncoder.matches("user", foundLocalAuthenticationEntity.getAuthenticationKey()));
 
     try {
-      users.modifyPassword("user", "admin", "user_new_password");
-      Assert.fail("Exception should be thrown here as password is incorrect");
+      users.modifyAuthentication(foundLocalAuthenticationEntity, "admin", "user_new_password", true);
+      fail("Exception should be thrown here as password is incorrect");
     } catch (AmbariException ex) {
       // This is expected
     }
   }
 
   @Test
-  public void testModifyPassword_UserByNonAdmin() throws Exception {
-    Authentication auth = new UsernamePasswordAuthenticationToken("user2", null);
-    SecurityContextHolder.getContext().setAuthentication(auth);
+  public void testAddAndRemoveAuthentication() throws Exception {
+    users.createUser("user", "user", "user");
 
-    UserEntity userEntity;
-    userEntity = users.createUser("user", "user", null);
-    users.addLocalAuthentication(userEntity, "user");
+    UserEntity userEntity = userDAO.findUserByName("user");
+    assertNotNull(userEntity);
+    assertEquals("user", userEntity.getUserName());
 
-    userEntity = users.createUser("user2", "user2", null);
-    users.addLocalAuthentication(userEntity, "user2");
+    UserEntity userEntity2 = userDAO.findUserByName("user");
+    assertNotNull(userEntity2);
+    assertEquals("user", userEntity2.getUserName());
 
-    UserAuthenticationEntity foundLocalAuthenticationEntity = getLocalAuthenticationEntity(userDAO.findUserByName("user"));
-    assertNotNull(foundLocalAuthenticationEntity);
-    assertNotSame("user", foundLocalAuthenticationEntity.getAuthenticationKey());
-    assertTrue(passwordEncoder.matches("user", foundLocalAuthenticationEntity.getAuthenticationKey()));
+    assertEquals(0, users.getUserAuthenticationEntities("user", null).size());
 
-    try {
-      users.modifyPassword("user", "user2", "user_new_password");
-      Assert.fail("Exception should be thrown here as user2 can't change password of user");
-    } catch (AuthorizationException ex) {
-      // This is expected
-    }
-  }
+    users.addAuthentication(userEntity, UserAuthenticationType.LOCAL, "local_key");
+    assertEquals(1, users.getUserAuthenticationEntities("user", null).size());
+    assertEquals(1, users.getUserAuthenticationEntities("user", UserAuthenticationType.LOCAL).size());
+    assertTrue(passwordEncoder.matches("local_key", users.getUserAuthenticationEntities("user", UserAuthenticationType.LOCAL).iterator().next().getAuthenticationKey()));
+    assertEquals(0, users.getUserAuthenticationEntities("user", UserAuthenticationType.KERBEROS).size());
 
-  @Test
-  @Ignore // TODO @Transactional annotation breaks this test
-  public void testCreateUserDefaultParams() throws Exception {
-    final Users spy = Mockito.spy(users);
-    spy.createUser("user", "user", null);
-    Mockito.verify(spy).createUser("user", "user", null);
+    users.addAuthentication(userEntity, UserAuthenticationType.PAM, "pam_key");
+    assertEquals(2, users.getUserAuthenticationEntities("user", null).size());
+    assertEquals(1, users.getUserAuthenticationEntities("user", UserAuthenticationType.PAM).size());
+    assertEquals("pam_key", users.getUserAuthenticationEntities("user", UserAuthenticationType.PAM).iterator().next().getAuthenticationKey());
+    assertEquals(0, users.getUserAuthenticationEntities("user", UserAuthenticationType.KERBEROS).size());
+
+    users.addAuthentication(userEntity, UserAuthenticationType.JWT, "jwt_key");
+    assertEquals(3, users.getUserAuthenticationEntities("user", null).size());
+    assertEquals(1, users.getUserAuthenticationEntities("user", UserAuthenticationType.JWT).size());
+    assertEquals("jwt_key", users.getUserAuthenticationEntities("user", UserAuthenticationType.JWT).iterator().next().getAuthenticationKey());
+    assertEquals(0, users.getUserAuthenticationEntities("user", UserAuthenticationType.KERBEROS).size());
+
+    users.addAuthentication(userEntity, UserAuthenticationType.LDAP, "ldap_key");
+    assertEquals(4, users.getUserAuthenticationEntities("user", null).size());
+    assertEquals(1, users.getUserAuthenticationEntities("user", UserAuthenticationType.LDAP).size());
+    assertEquals("ldap_key", users.getUserAuthenticationEntities("user", UserAuthenticationType.LDAP).iterator().next().getAuthenticationKey());
+    assertEquals(0, users.getUserAuthenticationEntities("user", UserAuthenticationType.KERBEROS).size());
+
+    users.addAuthentication(userEntity, UserAuthenticationType.KERBEROS, "kerberos_key");
+    assertEquals(5, users.getUserAuthenticationEntities("user", null).size());
+    assertEquals("kerberos_key", users.getUserAuthenticationEntities("user", UserAuthenticationType.KERBEROS).iterator().next().getAuthenticationKey());
+    assertEquals(1, users.getUserAuthenticationEntities("user", UserAuthenticationType.KERBEROS).size());
+
+    // UserEntity was updated by user.addAuthentication
+    assertEquals(5, userEntity.getAuthenticationEntities().size());
+
+    // UserEntity2 needs to be refreshed...
+    assertEquals(0, userEntity2.getAuthenticationEntities().size());
+    userEntity2 = userDAO.findUserByName("user");
+    assertEquals(5, userEntity2.getAuthenticationEntities().size());
+
+
+    // Test Remove
+    Long kerberosAuthenticationId = users.getUserAuthenticationEntities("user", UserAuthenticationType.KERBEROS).iterator().next().getUserAuthenticationId();
+    Long pamAuthenticationId = users.getUserAuthenticationEntities("user", UserAuthenticationType.PAM).iterator().next().getUserAuthenticationId();
+
+    users.removeAuthentication("user", kerberosAuthenticationId);
+    assertEquals(4, users.getUserAuthenticationEntities("user", null).size());
+
+    users.removeAuthentication(userEntity, kerberosAuthenticationId);
+    assertEquals(4, users.getUserAuthenticationEntities("user", null).size());
+
+    users.removeAuthentication(userEntity, pamAuthenticationId);
+    assertEquals(3, users.getUserAuthenticationEntities("user", null).size());
+
+    // UserEntity2 needs to be refreshed...
+    assertEquals(5, userEntity2.getAuthenticationEntities().size());
+    userEntity2 = userDAO.findUserByName("user");
+    assertEquals(3, userEntity2.getAuthenticationEntities().size());
   }
 
-  private UserAuthenticationEntity getLocalAuthenticationEntity(UserEntity userEntity) {
+    private UserAuthenticationEntity getAuthenticationEntity(UserEntity userEntity, UserAuthenticationType type) {
     assertNotNull(userEntity);
     Collection<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
     assertNotNull(authenticationEntities);
     for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
-      if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LOCAL) {
+      if (authenticationEntity.getAuthenticationType() == type) {
         return authenticationEntity;
       }
     }


[6/6] ambari git commit: AMBARI-20861. BE: Extend Ambari REST API to Support User Account Management Improvements (rlevas)

Posted by rl...@apache.org.
AMBARI-20861. BE: Extend Ambari REST API to Support User Account Management Improvements (rlevas)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 317905e40e0b4b384809ad7d900a09d97827f599
Parents: 903cd1a
Author: Robert Levas <rl...@hortonworks.com>
Authored: Wed Jul 19 08:41:36 2017 -0400
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Wed Jul 19 08:41:36 2017 -0400

----------------------------------------------------------------------
 ambari-server/docs/api/generated/index.html     | 6354 +++++++++++++-----
 ambari-server/docs/api/generated/swagger.json   |  959 ++-
 .../docs/api/v1/authentication-source-create.md |   86 +
 .../docs/api/v1/authentication-source-delete.md |   49 +
 .../docs/api/v1/authentication-source-get.md    |   93 +
 .../docs/api/v1/authentication-source-list.md   |  116 +
 .../api/v1/authentication-source-resources.md   |  117 +
 .../docs/api/v1/authentication-source-update.md |  104 +
 ambari-server/docs/api/v1/index.md              |   12 +
 ambari-server/docs/api/v1/user-create.md        |  107 +
 ambari-server/docs/api/v1/user-delete.md        |   48 +
 ambari-server/docs/api/v1/user-get.md           |   97 +
 ambari-server/docs/api/v1/user-list.md          |   98 +
 ambari-server/docs/api/v1/user-resources.md     |  175 +
 ambari-server/docs/api/v1/user-update.md        |  115 +
 .../resources/ResourceInstanceFactoryImpl.java  |    4 +
 .../api/resources/UserResourceDefinition.java   |    1 +
 .../ambari/server/api/services/BaseService.java |   70 +-
 .../users/UserAuthenticationSourceService.java  |  223 +
 .../server/api/services/users/UserService.java  |  132 +-
 .../server/controller/ControllerModule.java     |    2 +
 .../controller/ResourceProviderFactory.java     |    7 +-
 .../UserAuthenticationSourceRequest.java        |   82 +
 ...uthenticationSourceRequestCreateSwagger.java |   40 +
 ...uthenticationSourceRequestUpdateSwagger.java |   40 +
 .../UserAuthenticationSourceResponse.java       |  127 +
 .../ambari/server/controller/UserRequest.java   |   17 +-
 .../UserRequestCreateUserSwagger.java           |   49 +
 .../UserRequestCreateUsersSwagger.java          |   52 +
 .../UserRequestUpdateUserSwagger.java           |   52 +
 .../ambari/server/controller/UserResponse.java  |   76 +-
 .../AbstractControllerResourceProvider.java     |    4 +-
 ...serAuthenticationSourceResourceProvider.java |  417 ++
 .../internal/UserResourceProvider.java          |  297 +-
 .../ambari/server/controller/spi/Resource.java  |    2 +
 .../server/orm/dao/UserAuthenticationDAO.java   |    8 +
 .../orm/entities/UserAuthenticationEntity.java  |   24 +-
 .../server/security/authorization/Users.java    |  288 +-
 .../src/main/resources/properties.json          |   11 -
 .../resources/UserResourceDefinitionTest.java   |   13 +-
 .../controller/internal/RequestImplTest.java    |    7 -
 ...uthenticationSourceResourceProviderTest.java |  448 ++
 .../internal/UserResourceProviderDBTest.java    |   22 +-
 .../internal/UserResourceProviderTest.java      |  705 +-
 .../security/TestAuthenticationFactory.java     |   26 +-
 .../security/authorization/TestUsers.java       |  171 +-
 46 files changed, 9413 insertions(+), 2534 deletions(-)
----------------------------------------------------------------------



[5/6] ambari git commit: AMBARI-20861. BE: Extend Ambari REST API to Support User Account Management Improvements (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/generated/index.html
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/generated/index.html b/ambari-server/docs/api/generated/index.html
index 21e043b..5ade7a8 100644
--- a/ambari-server/docs/api/generated/index.html
+++ b/ambari-server/docs/api/generated/index.html
@@ -907,10 +907,10 @@ margin-bottom: 20px;
     "stack_version" : {
       "type" : "string"
     },
-    "stack_name" : {
+    "artifact_name" : {
       "type" : "string"
     },
-    "artifact_name" : {
+    "stack_name" : {
       "type" : "string"
     }
   }
@@ -918,15 +918,15 @@ margin-bottom: 20px;
     defs.BlueprintInfo = {
   "type" : "object",
   "properties" : {
+    "blueprint_name" : {
+      "type" : "string"
+    },
     "security" : {
       "$ref" : "#/definitions/SecurityInfo"
     },
     "stack_version" : {
       "type" : "string"
     },
-    "blueprint_name" : {
-      "type" : "string"
-    },
     "stack_name" : {
       "type" : "string"
     }
@@ -1004,25 +1004,25 @@ margin-bottom: 20px;
     defs.ClusterArtifactResponse = {
   "type" : "object",
   "properties" : {
-    "Artifacts" : {
-      "$ref" : "#/definitions/ClusterArtifactResponseInfo"
-    },
     "artifact_data" : {
       "type" : "object",
       "additionalProperties" : {
         "type" : "object",
         "properties" : { }
       }
+    },
+    "Artifacts" : {
+      "$ref" : "#/definitions/ClusterArtifactResponseInfo"
     }
   }
 };
     defs.ClusterArtifactResponseInfo = {
   "type" : "object",
   "properties" : {
-    "cluster_name" : {
+    "artifact_name" : {
       "type" : "string"
     },
-    "artifact_name" : {
+    "cluster_name" : {
       "type" : "string"
     }
   }
@@ -1214,14 +1214,14 @@ margin-bottom: 20px;
     defs.ClusterServiceArtifactResponseInfo = {
   "type" : "object",
   "properties" : {
-    "cluster_name" : {
-      "type" : "string"
-    },
     "service_name" : {
       "type" : "string"
     },
     "artifact_name" : {
       "type" : "string"
+    },
+    "cluster_name" : {
+      "type" : "string"
     }
   }
 };
@@ -1239,15 +1239,6 @@ margin-bottom: 20px;
     "scope" : {
       "type" : "string"
     },
-    "service_name" : {
-      "type" : "string"
-    },
-    "component_name" : {
-      "type" : "string"
-    },
-    "stack_version" : {
-      "type" : "string"
-    },
     "conditions" : {
       "type" : "array",
       "items" : {
@@ -1260,6 +1251,15 @@ margin-bottom: 20px;
     "dependent_service_name" : {
       "type" : "string"
     },
+    "service_name" : {
+      "type" : "string"
+    },
+    "stack_version" : {
+      "type" : "string"
+    },
+    "component_name" : {
+      "type" : "string"
+    },
     "stack_name" : {
       "type" : "string"
     }
@@ -1268,10 +1268,10 @@ margin-bottom: 20px;
     defs.ComponentInfo = {
   "type" : "object",
   "properties" : {
-    "name" : {
+    "provision_action" : {
       "type" : "string"
     },
-    "provision_action" : {
+    "name" : {
       "type" : "string"
     }
   }
@@ -1443,6 +1443,66 @@ margin-bottom: 20px;
     }
   }
 };
+    defs.CreateUserAuthenticationSourceInfo = {
+  "type" : "object",
+  "required" : [ "authentication_type", "key" ],
+  "properties" : {
+    "key" : {
+      "type" : "string"
+    },
+    "authentication_type" : {
+      "type" : "string",
+      "enum" : [ "LOCAL", "LDAP", "JWT", "PAM", "KERBEROS" ]
+    }
+  }
+};
+    defs.CreateUserInfo = {
+  "type" : "object",
+  "properties" : {
+    "display_name" : {
+      "type" : "string"
+    },
+    "active" : {
+      "type" : "boolean",
+      "default" : false
+    },
+    "password" : {
+      "type" : "string"
+    },
+    "admin" : {
+      "type" : "boolean",
+      "default" : false
+    },
+    "local_user_name" : {
+      "type" : "string"
+    }
+  }
+};
+    defs.CreateUsersInfo = {
+  "type" : "object",
+  "properties" : {
+    "display_name" : {
+      "type" : "string"
+    },
+    "active" : {
+      "type" : "boolean",
+      "default" : false
+    },
+    "user_name" : {
+      "type" : "string"
+    },
+    "password" : {
+      "type" : "string"
+    },
+    "admin" : {
+      "type" : "boolean",
+      "default" : false
+    },
+    "local_user_name" : {
+      "type" : "string"
+    }
+  }
+};
     defs.DependencyConditionInfo = {
   "type" : "object"
 };
@@ -1709,10 +1769,10 @@ margin-bottom: 20px;
     "maintenance_state" : {
       "type" : "string"
     },
-    "host_group" : {
+    "blueprint" : {
       "type" : "string"
     },
-    "blueprint" : {
+    "host_group" : {
       "type" : "string"
     },
     "public_host_name" : {
@@ -1796,10 +1856,10 @@ margin-bottom: 20px;
       "type" : "string",
       "enum" : [ "OFF", "ON", "IMPLIED_FROM_SERVICE", "IMPLIED_FROM_HOST", "IMPLIED_FROM_SERVICE_AND_HOST" ]
     },
-    "public_host_name" : {
+    "host_health_report" : {
       "type" : "string"
     },
-    "host_health_report" : {
+    "public_host_name" : {
       "type" : "string"
     }
   }
@@ -2229,20 +2289,17 @@ margin-bottom: 20px;
       "type" : "boolean",
       "default" : false
     },
-    "baseUrl" : {
+    "repoId" : {
       "type" : "string"
     },
-    "mirrorsList" : {
+    "baseUrl" : {
       "type" : "string"
     },
-    "latestUri" : {
+    "mirrorsList" : {
       "type" : "string"
     },
     "repoName" : {
       "type" : "string"
-    },
-    "repoId" : {
-      "type" : "string"
     }
   }
 };
@@ -2288,9 +2345,6 @@ margin-bottom: 20px;
     "defaultBaseUrl" : {
       "type" : "string"
     },
-    "latestBaseUrl" : {
-      "type" : "string"
-    },
     "repoSaved" : {
       "type" : "boolean",
       "default" : false
@@ -2346,6 +2400,15 @@ margin-bottom: 20px;
         "$ref" : "#/definitions/RepositoryVersionEntity"
       }
     },
+    "repositoryXml" : {
+      "$ref" : "#/definitions/VersionDefinitionXml"
+    },
+    "stackId" : {
+      "$ref" : "#/definitions/StackId"
+    },
+    "stackVersion" : {
+      "type" : "string"
+    },
     "operatingSystemsJson" : {
       "type" : "string"
     },
@@ -2353,17 +2416,8 @@ margin-bottom: 20px;
       "type" : "integer",
       "format" : "int64"
     },
-    "stackVersion" : {
-      "type" : "string"
-    },
-    "stackId" : {
-      "$ref" : "#/definitions/StackId"
-    },
     "stackName" : {
       "type" : "string"
-    },
-    "repositoryXml" : {
-      "$ref" : "#/definitions/VersionDefinitionXml"
     }
   }
 };
@@ -2389,14 +2443,14 @@ margin-bottom: 20px;
         "$ref" : "#/definitions/RepositoryInfo"
       }
     },
-    "latestURI" : {
-      "type" : "string"
-    },
     "errors" : {
       "type" : "array",
       "items" : {
         "type" : "string"
       }
+    },
+    "latestURI" : {
+      "type" : "string"
     }
   },
   "xml" : {
@@ -2406,9 +2460,6 @@ margin-bottom: 20px;
     defs.Request = {
   "type" : "object",
   "properties" : {
-    "cluster_name" : {
-      "type" : "string"
-    },
     "exclusive" : {
       "type" : "boolean",
       "default" : false
@@ -2418,6 +2469,9 @@ margin-bottom: 20px;
       "items" : {
         "$ref" : "#/definitions/RequestResourceFilter"
       }
+    },
+    "cluster_name" : {
+      "type" : "string"
     }
   }
 };
@@ -2431,14 +2485,14 @@ margin-bottom: 20px;
         "properties" : { }
       }
     },
-    "action" : {
-      "type" : "string"
+    "operation_level" : {
+      "$ref" : "#/definitions/OperationLevel"
     },
     "command" : {
       "type" : "string"
     },
-    "operation_level" : {
-      "$ref" : "#/definitions/OperationLevel"
+    "action" : {
+      "type" : "string"
     }
   }
 };
@@ -2495,16 +2549,16 @@ margin-bottom: 20px;
     defs.RequestResourceFilter = {
   "type" : "object",
   "properties" : {
-    "service_name" : {
+    "hosts_predicate" : {
       "type" : "string"
     },
-    "component_name" : {
+    "hosts" : {
       "type" : "string"
     },
-    "hosts_predicate" : {
+    "service_name" : {
       "type" : "string"
     },
-    "hosts" : {
+    "component_name" : {
       "type" : "string"
     }
   }
@@ -2526,29 +2580,23 @@ margin-bottom: 20px;
     "start_time" : {
       "type" : "string"
     },
-    "request_context" : {
-      "type" : "string"
-    },
     "request_status" : {
       "type" : "string"
     },
-    "cluster_name" : {
+    "request_context" : {
       "type" : "string"
     },
-    "request_schedule" : {
-      "type" : "string"
+    "task_count" : {
+      "type" : "integer",
+      "format" : "int32"
     },
-    "id" : {
+    "completed_task_count" : {
       "type" : "string"
     },
     "aborted_task_count" : {
       "type" : "integer",
       "format" : "int32"
     },
-    "create_time" : {
-      "type" : "integer",
-      "format" : "int64"
-    },
     "end_time" : {
       "type" : "string"
     },
@@ -2560,9 +2608,6 @@ margin-bottom: 20px;
       "type" : "integer",
       "format" : "int32"
     },
-    "inputs" : {
-      "type" : "string"
-    },
     "operation_level" : {
       "type" : "string"
     },
@@ -2570,6 +2615,9 @@ margin-bottom: 20px;
       "type" : "number",
       "format" : "double"
     },
+    "id" : {
+      "type" : "string"
+    },
     "queued_task_count" : {
       "type" : "integer",
       "format" : "int32"
@@ -2584,11 +2632,17 @@ margin-bottom: 20px;
         "$ref" : "#/definitions/RequestResourceFilter"
       }
     },
-    "task_count" : {
+    "create_time" : {
       "type" : "integer",
-      "format" : "int32"
+      "format" : "int64"
     },
-    "completed_task_count" : {
+    "inputs" : {
+      "type" : "string"
+    },
+    "cluster_name" : {
+      "type" : "string"
+    },
+    "request_schedule" : {
       "type" : "string"
     }
   }
@@ -2745,19 +2799,19 @@ margin-bottom: 20px;
     defs.SecurityInfo = {
   "type" : "object",
   "properties" : {
+    "kerberos_descriptor_reference" : {
+      "type" : "string"
+    },
+    "security_type" : {
+      "type" : "string",
+      "enum" : [ "NONE", "KERBEROS" ]
+    },
     "kerberos_descriptor" : {
       "type" : "object",
       "additionalProperties" : {
         "type" : "object",
         "properties" : { }
       }
-    },
-    "security_type" : {
-      "type" : "string",
-      "enum" : [ "NONE", "KERBEROS" ]
-    },
-    "kerberos_descriptor_reference" : {
-      "type" : "string"
     }
   }
 };
@@ -3518,11 +3572,11 @@ margin-bottom: 20px;
     "stack_version" : {
       "type" : "string"
     },
-    "stack_name" : {
-      "type" : "string"
-    },
     "theme_data" : {
       "$ref" : "#/definitions/Theme"
+    },
+    "stack_name" : {
+      "type" : "string"
     }
   }
 };
@@ -3542,6 +3596,95 @@ margin-bottom: 20px;
     }
   }
 };
+    defs.UpdateUserInfo = {
+  "type" : "object",
+  "properties" : {
+    "display_name" : {
+      "type" : "string"
+    },
+    "active" : {
+      "type" : "boolean",
+      "default" : false
+    },
+    "password" : {
+      "type" : "string"
+    },
+    "admin" : {
+      "type" : "boolean",
+      "default" : false
+    },
+    "local_user_name" : {
+      "type" : "string"
+    },
+    "old_password" : {
+      "type" : "string"
+    }
+  }
+};
+    defs.UserAuthenticationSourceRequestCreateSwagger = {
+  "type" : "object",
+  "properties" : {
+    "AuthenticationSourceInfo" : {
+      "$ref" : "#/definitions/CreateUserAuthenticationSourceInfo"
+    }
+  }
+};
+    defs.UserAuthenticationSourceRequestUpdateInfo = {
+  "type" : "object",
+  "required" : [ "key" ],
+  "properties" : {
+    "key" : {
+      "type" : "string"
+    },
+    "old_key" : {
+      "type" : "string"
+    }
+  }
+};
+    defs.UserAuthenticationSourceRequestUpdateSwagger = {
+  "type" : "object",
+  "properties" : {
+    "AuthenticationSourceInfo" : {
+      "$ref" : "#/definitions/UserAuthenticationSourceRequestUpdateInfo"
+    }
+  }
+};
+    defs.UserAuthenticationSourceResponse = {
+  "type" : "object",
+  "required" : [ "authentication_type", "source_id", "user_name" ],
+  "properties" : {
+    "user_name" : {
+      "type" : "string"
+    },
+    "source_id" : {
+      "type" : "integer",
+      "format" : "int64"
+    },
+    "authentication_type" : {
+      "type" : "string",
+      "enum" : [ "LOCAL", "LDAP", "JWT", "PAM", "KERBEROS" ]
+    },
+    "key" : {
+      "type" : "string"
+    },
+    "created" : {
+      "type" : "string",
+      "format" : "date-time"
+    },
+    "updated" : {
+      "type" : "string",
+      "format" : "date-time"
+    }
+  }
+};
+    defs.UserAuthenticationSourceResponseSwagger = {
+  "type" : "object",
+  "properties" : {
+    "AuthenticationSourceInfo" : {
+      "$ref" : "#/definitions/UserAuthenticationSourceResponse"
+    }
+  }
+};
     defs.UserAuthorizationResponse = {
   "type" : "object",
   "required" : [ "AuthorizationInfo/user_name" ],
@@ -3625,72 +3768,92 @@ margin-bottom: 20px;
     }
   }
 };
-    defs.UserRequest = {
+    defs.UserRequestCreateUserSwagger = {
   "type" : "object",
   "properties" : {
-    "Users/password" : {
-      "type" : "string"
-    },
-    "Users/old_password" : {
-      "type" : "string"
-    },
-    "Users/active" : {
-      "type" : "boolean",
-      "default" : false
-    },
-    "Users/admin" : {
-      "type" : "boolean",
-      "default" : false
-    },
-    "Users/display_name" : {
-      "type" : "string"
-    },
-    "Users/local_user_name" : {
-      "type" : "string"
+    "Users" : {
+      "$ref" : "#/definitions/CreateUserInfo"
+    }
+  }
+};
+    defs.UserRequestCreateUsersSwagger = {
+  "type" : "object",
+  "properties" : {
+    "Users" : {
+      "$ref" : "#/definitions/CreateUsersInfo"
+    }
+  }
+};
+    defs.UserRequestUpdateUserSwagger = {
+  "type" : "object",
+  "properties" : {
+    "Users" : {
+      "$ref" : "#/definitions/UpdateUserInfo"
     }
   }
 };
     defs.UserResponse = {
   "type" : "object",
-  "required" : [ "Users/user_name" ],
   "properties" : {
-    "Users/authentication_type" : {
+    "display_name" : {
+      "type" : "string"
+    },
+    "user_type" : {
       "type" : "string",
       "enum" : [ "LOCAL", "LDAP", "JWT", "PAM", "KERBEROS" ]
     },
-    "Users/groups" : {
+    "groups" : {
       "type" : "array",
       "uniqueItems" : true,
       "items" : {
         "type" : "string"
       }
     },
-    "Users/active" : {
+    "created" : {
+      "type" : "string",
+      "format" : "date-time"
+    },
+    "consecutive_failures" : {
+      "type" : "integer",
+      "format" : "int32"
+    },
+    "active" : {
       "type" : "boolean",
       "default" : false
     },
-    "Users/user_name" : {
+    "user_name" : {
       "type" : "string"
     },
-    "Users/admin" : {
+    "admin" : {
       "type" : "boolean",
       "default" : false
     },
-    "Users/ldap_user" : {
+    "ldap_user" : {
       "type" : "boolean",
       "default" : false
+    },
+    "local_user_name" : {
+      "type" : "string"
+    }
+  }
+};
+    defs.UserResponseSwagger = {
+  "type" : "object",
+  "properties" : {
+    "Users" : {
+      "$ref" : "#/definitions/UserResponse"
     }
   }
 };
     defs.ValidationResult = {
   "type" : "object",
   "properties" : {
-    "detail" : {
-      "type" : "string"
-    },
     "valid" : {
       "type" : "boolean",
       "default" : false
+    },
+    "detail" : {
+      "type" : "string"
     }
   }
 };
@@ -4537,6 +4700,22 @@ margin-bottom: 20px;
                     <li data-group="Stacks" data-name="stacksServiceGetStacks" class="">
                       <a href="#api-Stacks-stacksServiceGetStacks">stacksServiceGetStacks</a>
                     </li>
+                  <li class="nav-header" data-group="UserAuthenticationSources"><a href="#api-UserAuthenticationSources">API Methods - UserAuthenticationSources</a></li>
+                    <li data-group="UserAuthenticationSources" data-name="createAuthenticationSources" class="">
+                      <a href="#api-UserAuthenticationSources-createAuthenticationSources">createAuthenticationSources</a>
+                    </li>
+                    <li data-group="UserAuthenticationSources" data-name="deleteAuthenticationSource" class="">
+                      <a href="#api-UserAuthenticationSources-deleteAuthenticationSource">deleteAuthenticationSource</a>
+                    </li>
+                    <li data-group="UserAuthenticationSources" data-name="getAuthenticationSource" class="">
+                      <a href="#api-UserAuthenticationSources-getAuthenticationSource">getAuthenticationSource</a>
+                    </li>
+                    <li data-group="UserAuthenticationSources" data-name="getAuthenticationSources" class="">
+                      <a href="#api-UserAuthenticationSources-getAuthenticationSources">getAuthenticationSources</a>
+                    </li>
+                    <li data-group="UserAuthenticationSources" data-name="updateAuthenticationSource" class="">
+                      <a href="#api-UserAuthenticationSources-updateAuthenticationSource">updateAuthenticationSource</a>
+                    </li>
                   <li class="nav-header" data-group="Users"><a href="#api-Users">API Methods - Users</a></li>
                     <li data-group="Users" data-name="activeWidgetLayoutServiceGetServices" class="">
                       <a href="#api-Users-activeWidgetLayoutServiceGetServices">activeWidgetLayoutServiceGetServices</a>
@@ -4544,6 +4723,24 @@ margin-bottom: 20px;
                     <li data-group="Users" data-name="activeWidgetLayoutServiceUpdateServices" class="">
                       <a href="#api-Users-activeWidgetLayoutServiceUpdateServices">activeWidgetLayoutServiceUpdateServices</a>
                     </li>
+                    <li data-group="Users" data-name="createUser" class="">
+                      <a href="#api-Users-createUser">createUser</a>
+                    </li>
+                    <li data-group="Users" data-name="createUsers" class="">
+                      <a href="#api-Users-createUsers">createUsers</a>
+                    </li>
+                    <li data-group="Users" data-name="deleteUser" class="">
+                      <a href="#api-Users-deleteUser">deleteUser</a>
+                    </li>
+                    <li data-group="Users" data-name="getUser" class="">
+                      <a href="#api-Users-getUser">getUser</a>
+                    </li>
+                    <li data-group="Users" data-name="getUsers" class="">
+                      <a href="#api-Users-getUsers">getUsers</a>
+                    </li>
+                    <li data-group="Users" data-name="updateUser" class="">
+                      <a href="#api-Users-updateUser">updateUser</a>
+                    </li>
                     <li data-group="Users" data-name="userAuthorizationServiceGetAuthorization" class="">
                       <a href="#api-Users-userAuthorizationServiceGetAuthorization">userAuthorizationServiceGetAuthorization</a>
                     </li>
@@ -4556,21 +4753,6 @@ margin-bottom: 20px;
                     <li data-group="Users" data-name="userPrivilegeServiceGetPrivileges" class="">
                       <a href="#api-Users-userPrivilegeServiceGetPrivileges">userPrivilegeServiceGetPrivileges</a>
                     </li>
-                    <li data-group="Users" data-name="userServiceCreateUser" class="">
-                      <a href="#api-Users-userServiceCreateUser">userServiceCreateUser</a>
-                    </li>
-                    <li data-group="Users" data-name="userServiceDeleteUser" class="">
-                      <a href="#api-Users-userServiceDeleteUser">userServiceDeleteUser</a>
-                    </li>
-                    <li data-group="Users" data-name="userServiceGetUser" class="">
-                      <a href="#api-Users-userServiceGetUser">userServiceGetUser</a>
-                    </li>
-                    <li data-group="Users" data-name="userServiceGetUsers" class="">
-                      <a href="#api-Users-userServiceGetUsers">userServiceGetUsers</a>
-                    </li>
-                    <li data-group="Users" data-name="userServiceUpdateUser" class="">
-                      <a href="#api-Users-userServiceUpdateUser">userServiceUpdateUser</a>
-                    </li>
                   <li class="nav-header" data-group="Views"><a href="#api-Views">API Methods - Views</a></li>
                     <li data-group="Views" data-name="viewDataMigrationServiceMigrateData" class="">
                       <a href="#api-Views-viewDataMigrationServiceMigrateData">viewDataMigrationServiceMigrateData</a>
@@ -45153,121 +45335,100 @@ except ApiException as e:
                       </div>
                       <hr>
                   </section>
-                <section id="api-Users">
-                  <h1>Users</h1>
-                    <div id="api-Users-activeWidgetLayoutServiceGetServices">
-                      <article id="api-Users-activeWidgetLayoutServiceGetServices-0" data-group="User" data-name="activeWidgetLayoutServiceGetServices" data-version="0">
+                <section id="api-UserAuthenticationSources">
+                  <h1>UserAuthenticationSources</h1>
+                    <div id="api-UserAuthenticationSources-createAuthenticationSources">
+                      <article id="api-UserAuthenticationSources-createAuthenticationSources-0" data-group="User" data-name="createAuthenticationSources" data-version="0">
                         <div class="pull-left">
-                          <h1>activeWidgetLayoutServiceGetServices</h1>
-                          <p>Get user widget layouts</p>
+                          <h1>createAuthenticationSources</h1>
+                          <p>Create one or more new authentication sources for a user</p>
                         </div>
                         <div class="pull-right"></div>
                         <div class="clearfix"></div>
                         <p></p>
-                        <p class="marked">Returns all active widget layouts for user.</p>
+                        <p class="marked"></p>
                         <p></p>
                         <br />
-                        <pre class="prettyprint language-html prettyprinted" data-type="get"><code><span class="pln">/users/{userName}/activeWidgetLayouts</span></code></pre>
+                        <pre class="prettyprint language-html prettyprinted" data-type="post"><code><span class="pln">/users/{userName}/sources</span></code></pre>
                         <p>
                           <h3>Usage and SDK Samples</h3>
                         </p>
                         <ul class="nav nav-tabs nav-tabs-examples">
-                          <li class="active"><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-curl">Curl</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-java">Java</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-android">Android</a></li>
-                          <!--<li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-groovy">Groovy</a></li>-->
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-objc">Obj-C</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-javascript">JavaScript</a></li>
-                          <!--<li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-angular">Angular</a></li>-->
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-csharp">C#</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-php">PHP</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-perl">Perl</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceGetServices-0-python">Python</a></li>
+                          <li class="active"><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-curl">Curl</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-java">Java</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-android">Android</a></li>
+                          <!--<li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-groovy">Groovy</a></li>-->
+                          <li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-objc">Obj-C</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-javascript">JavaScript</a></li>
+                          <!--<li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-angular">Angular</a></li>-->
+                          <li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-csharp">C#</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-php">PHP</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-perl">Perl</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-createAuthenticationSources-0-python">Python</a></li>
                         </ul>
 
                         <div class="tab-content">
-                          <div class="tab-pane active" id="examples-Users-activeWidgetLayoutServiceGetServices-0-curl">
-                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">get</span> "http://localhost/api/v1/users/{userName}/activeWidgetLayouts?fields=&sortBy=&pageSize=&from=&to="</code></pre>
+                          <div class="tab-pane active" id="examples-UserAuthenticationSources-createAuthenticationSources-0-curl">
+                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">post</span> "http://localhost/api/v1/users/{userName}/sources"</code></pre>
                           </div>
-                          <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-java">
+                          <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-java">
                             <pre class="prettyprint"><code class="language-java">import io.swagger.client.*;
 import io.swagger.client.auth.*;
 import io.swagger.client.model.*;
-import io.swagger.client.api.UsersApi;
+import io.swagger.client.api.UserAuthenticationSourcesApi;
 
 import java.io.File;
 import java.util.*;
 
-public class UsersApiExample {
+public class UserAuthenticationSourcesApiExample {
 
     public static void main(String[] args) {
         
-        UsersApi apiInstance = new UsersApi();
+        UserAuthenticationSourcesApi apiInstance = new UserAuthenticationSourcesApi();
         String userName = userName_example; // String | user name
-        String fields = fields_example; // String | Filter user layout details
-        String sortBy = sortBy_example; // String | Sort layouts (asc | desc)
-        Integer pageSize = 56; // Integer | The number of resources to be returned for the paged response.
-        String from = from_example; // String | The starting page resource (inclusive). Valid values are :offset | "start"
-        String to = to_example; // String | The ending page resource (inclusive). Valid values are :offset | "end"
+        UserAuthenticationSourceRequestCreateSwagger body = ; // UserAuthenticationSourceRequestCreateSwagger | 
         try {
-            array[ActiveWidgetLayoutResponse] result = apiInstance.activeWidgetLayoutServiceGetServices(userName, fields, sortBy, pageSize, from, to);
-            System.out.println(result);
+            apiInstance.createAuthenticationSources(userName, body);
         } catch (ApiException e) {
-            System.err.println("Exception when calling UsersApi#activeWidgetLayoutServiceGetServices");
+            System.err.println("Exception when calling UserAuthenticationSourcesApi#createAuthenticationSources");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
 
-                          <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-android">
-                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.UsersApi;
+                          <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-android">
+                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.UserAuthenticationSourcesApi;
 
-public class UsersApiExample {
+public class UserAuthenticationSourcesApiExample {
 
     public static void main(String[] args) {
-        UsersApi apiInstance = new UsersApi();
+        UserAuthenticationSourcesApi apiInstance = new UserAuthenticationSourcesApi();
         String userName = userName_example; // String | user name
-        String fields = fields_example; // String | Filter user layout details
-        String sortBy = sortBy_example; // String | Sort layouts (asc | desc)
-        Integer pageSize = 56; // Integer | The number of resources to be returned for the paged response.
-        String from = from_example; // String | The starting page resource (inclusive). Valid values are :offset | "start"
-        String to = to_example; // String | The ending page resource (inclusive). Valid values are :offset | "end"
+        UserAuthenticationSourceRequestCreateSwagger body = ; // UserAuthenticationSourceRequestCreateSwagger | 
         try {
-            array[ActiveWidgetLayoutResponse] result = apiInstance.activeWidgetLayoutServiceGetServices(userName, fields, sortBy, pageSize, from, to);
-            System.out.println(result);
+            apiInstance.createAuthenticationSources(userName, body);
         } catch (ApiException e) {
-            System.err.println("Exception when calling UsersApi#activeWidgetLayoutServiceGetServices");
+            System.err.println("Exception when calling UserAuthenticationSourcesApi#createAuthenticationSources");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
   <!--
-  <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-groovy">
+  <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-groovy">
   <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
   </div> -->
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-objc">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-objc">
                               <pre class="prettyprint"><code class="language-cpp">String *userName = userName_example; // user name
-String *fields = fields_example; // Filter user layout details (optional) (default to WidgetLayoutInfo/*)
-String *sortBy = sortBy_example; // Sort layouts (asc | desc) (optional) (default to WidgetLayoutInfo/user_name.asc)
-Integer *pageSize = 56; // The number of resources to be returned for the paged response. (optional) (default to 10)
-String *from = from_example; // The starting page resource (inclusive). Valid values are :offset | "start" (optional) (default to 0)
-String *to = to_example; // The ending page resource (inclusive). Valid values are :offset | "end" (optional)
+UserAuthenticationSourceRequestCreateSwagger *body = ; //  (optional)
 
-UsersApi *apiInstance = [[UsersApi alloc] init];
+UserAuthenticationSourcesApi *apiInstance = [[UserAuthenticationSourcesApi alloc] init];
 
-// Get user widget layouts
-[apiInstance activeWidgetLayoutServiceGetServicesWith:userName
-    fields:fields
-    sortBy:sortBy
-    pageSize:pageSize
-    from:from
-    to:to
-              completionHandler: ^(array[ActiveWidgetLayoutResponse] output, NSError* error) {
-                            if (output) {
-                                NSLog(@"%@", output);
-                            }
+// Create one or more new authentication sources for a user
+[apiInstance createAuthenticationSourcesWith:userName
+    body:body
+              completionHandler: ^(NSError* error) {
                             if (error) {
                                 NSLog(@"Error: %@", error);
                             }
@@ -45275,36 +45436,32 @@ UsersApi *apiInstance = [[UsersApi alloc] init];
 </code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-javascript">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-javascript">
                               <pre class="prettyprint"><code class="language-js">var SwaggerSpecForAmbariRestApi = require('swagger_spec_for_ambari_rest_api');
 
-var api = new SwaggerSpecForAmbariRestApi.UsersApi()
+var api = new SwaggerSpecForAmbariRestApi.UserAuthenticationSourcesApi()
 
 var userName = userName_example; // {String} user name
 
 var opts = { 
-  'fields': fields_example, // {String} Filter user layout details
-  'sortBy': sortBy_example, // {String} Sort layouts (asc | desc)
-  'pageSize': 56, // {Integer} The number of resources to be returned for the paged response.
-  'from': from_example, // {String} The starting page resource (inclusive). Valid values are :offset | "start"
-  'to': to_example // {String} The ending page resource (inclusive). Valid values are :offset | "end"
+  'body':  // {UserAuthenticationSourceRequestCreateSwagger} 
 };
 
 var callback = function(error, data, response) {
   if (error) {
     console.error(error);
   } else {
-    console.log('API called successfully. Returned data: ' + data);
+    console.log('API called successfully.');
   }
 };
-api.activeWidgetLayoutServiceGetServices(userName, opts, callback);
+api.createAuthenticationSources(userName, opts, callback);
 </code></pre>
                             </div>
 
-                            <!--<div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-angular">
+                            <!--<div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-angular">
               <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
             </div>-->
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-csharp">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-csharp">
                               <pre class="prettyprint"><code class="language-cs">using System;
 using System.Diagnostics;
 using IO.Swagger.Api;
@@ -45313,78 +45470,63 @@ using IO.Swagger.Model;
 
 namespace Example
 {
-    public class activeWidgetLayoutServiceGetServicesExample
+    public class createAuthenticationSourcesExample
     {
         public void main()
         {
             
-            var apiInstance = new UsersApi();
+            var apiInstance = new UserAuthenticationSourcesApi();
             var userName = userName_example;  // String | user name
-            var fields = fields_example;  // String | Filter user layout details (optional)  (default to WidgetLayoutInfo/*)
-            var sortBy = sortBy_example;  // String | Sort layouts (asc | desc) (optional)  (default to WidgetLayoutInfo/user_name.asc)
-            var pageSize = 56;  // Integer | The number of resources to be returned for the paged response. (optional)  (default to 10)
-            var from = from_example;  // String | The starting page resource (inclusive). Valid values are :offset | "start" (optional)  (default to 0)
-            var to = to_example;  // String | The ending page resource (inclusive). Valid values are :offset | "end" (optional) 
+            var body = new UserAuthenticationSourceRequestCreateSwagger(); // UserAuthenticationSourceRequestCreateSwagger |  (optional) 
 
             try
             {
-                // Get user widget layouts
-                array[ActiveWidgetLayoutResponse] result = apiInstance.activeWidgetLayoutServiceGetServices(userName, fields, sortBy, pageSize, from, to);
-                Debug.WriteLine(result);
+                // Create one or more new authentication sources for a user
+                apiInstance.createAuthenticationSources(userName, body);
             }
             catch (Exception e)
             {
-                Debug.Print("Exception when calling UsersApi.activeWidgetLayoutServiceGetServices: " + e.Message );
+                Debug.Print("Exception when calling UserAuthenticationSourcesApi.createAuthenticationSources: " + e.Message );
             }
         }
     }
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-php">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-php">
                               <pre class="prettyprint"><code class="language-php"><&#63;php
 require_once(__DIR__ . '/vendor/autoload.php');
 
-$api_instance = new Swagger\Client\Api\UsersApi();
+$api_instance = new Swagger\Client\Api\UserAuthenticationSourcesApi();
 $userName = userName_example; // String | user name
-$fields = fields_example; // String | Filter user layout details
-$sortBy = sortBy_example; // String | Sort layouts (asc | desc)
-$pageSize = 56; // Integer | The number of resources to be returned for the paged response.
-$from = from_example; // String | The starting page resource (inclusive). Valid values are :offset | "start"
-$to = to_example; // String | The ending page resource (inclusive). Valid values are :offset | "end"
+$body = ; // UserAuthenticationSourceRequestCreateSwagger | 
 
 try {
-    $result = $api_instance->activeWidgetLayoutServiceGetServices($userName, $fields, $sortBy, $pageSize, $from, $to);
-    print_r($result);
+    $api_instance->createAuthenticationSources($userName, $body);
 } catch (Exception $e) {
-    echo 'Exception when calling UsersApi->activeWidgetLayoutServiceGetServices: ', $e->getMessage(), PHP_EOL;
+    echo 'Exception when calling UserAuthenticationSourcesApi->createAuthenticationSources: ', $e->getMessage(), PHP_EOL;
 }
 ?></code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-perl">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-perl">
                               <pre class="prettyprint"><code class="language-perl">use Data::Dumper;
 use WWW::SwaggerClient::Configuration;
-use WWW::SwaggerClient::UsersApi;
+use WWW::SwaggerClient::UserAuthenticationSourcesApi;
 
-my $api_instance = WWW::SwaggerClient::UsersApi->new();
+my $api_instance = WWW::SwaggerClient::UserAuthenticationSourcesApi->new();
 my $userName = userName_example; # String | user name
-my $fields = fields_example; # String | Filter user layout details
-my $sortBy = sortBy_example; # String | Sort layouts (asc | desc)
-my $pageSize = 56; # Integer | The number of resources to be returned for the paged response.
-my $from = from_example; # String | The starting page resource (inclusive). Valid values are :offset | "start"
-my $to = to_example; # String | The ending page resource (inclusive). Valid values are :offset | "end"
+my $body = WWW::SwaggerClient::Object::UserAuthenticationSourceRequestCreateSwagger->new(); # UserAuthenticationSourceRequestCreateSwagger | 
 
 eval { 
-    my $result = $api_instance->activeWidgetLayoutServiceGetServices(userName => $userName, fields => $fields, sortBy => $sortBy, pageSize => $pageSize, from => $from, to => $to);
-    print Dumper($result);
+    $api_instance->createAuthenticationSources(userName => $userName, body => $body);
 };
 if ($@) {
-    warn "Exception when calling UsersApi->activeWidgetLayoutServiceGetServices: $@\n";
+    warn "Exception when calling UserAuthenticationSourcesApi->createAuthenticationSources: $@\n";
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceGetServices-0-python">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-createAuthenticationSources-0-python">
                               <pre class="prettyprint"><code class="language-python">from __future__ import print_statement
 import time
 import swagger_client
@@ -45392,20 +45534,15 @@ from swagger_client.rest import ApiException
 from pprint import pprint
 
 # create an instance of the API class
-api_instance = swagger_client.UsersApi()
+api_instance = swagger_client.UserAuthenticationSourcesApi()
 userName = userName_example # String | user name
-fields = fields_example # String | Filter user layout details (optional) (default to WidgetLayoutInfo/*)
-sortBy = sortBy_example # String | Sort layouts (asc | desc) (optional) (default to WidgetLayoutInfo/user_name.asc)
-pageSize = 56 # Integer | The number of resources to be returned for the paged response. (optional) (default to 10)
-from = from_example # String | The starting page resource (inclusive). Valid values are :offset | "start" (optional) (default to 0)
-to = to_example # String | The ending page resource (inclusive). Valid values are :offset | "end" (optional)
+body =  # UserAuthenticationSourceRequestCreateSwagger |  (optional)
 
 try: 
-    # Get user widget layouts
-    api_response = api_instance.activeWidgetLayoutServiceGetServices(userName, fields=fields, sortBy=sortBy, pageSize=pageSize, from=from, to=to)
-    pprint(api_response)
+    # Create one or more new authentication sources for a user
+    api_instance.createAuthenticationSources(userName, body=body)
 except ApiException as e:
-    print("Exception when calling UsersApi->activeWidgetLayoutServiceGetServices: %s\n" % e)</code></pre>
+    print("Exception when calling UserAuthenticationSourcesApi->createAuthenticationSources: %s\n" % e)</code></pre>
                             </div>
                           </div>
 
@@ -45436,7 +45573,7 @@ except ApiException as e:
 
 
 													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_activeWidgetLayoutServiceGetServices_userName');
+													var result = $('#d2e199_createAuthenticationSources_userName');
 													result.empty();
 													result.append(view.render());
 
@@ -45446,332 +45583,225 @@ except ApiException as e:
 
 												});
 												</script>
-												<div id="d2e199_activeWidgetLayoutServiceGetServices_userName"></div>
+												<div id="d2e199_createAuthenticationSources_userName"></div>
 </td>
 </tr>
 
                             </table>
 
 
-
-
-                            <div class="methodsubtabletitle">Query parameters</div>
+                            <div class="methodsubtabletitle">Body parameters</div>
                             <table id="methodsubtable">
                               <tr>
                                 <th width="150px">Name</th>
                                 <th>Description</th>
                               </tr>
-                                <tr><td style="width:150px;">fields</td>
-<td>
-
-
-<script>
-												$(document).ready(function() {
-													var schemaWrapper = {
-  "name" : "fields",
-  "in" : "query",
-  "description" : "Filter user layout details",
-  "required" : false,
-  "type" : "string",
-  "default" : "WidgetLayoutInfo/*"
-};
-													var schema = schemaWrapper;
-
-
-
-
-													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_activeWidgetLayoutServiceGetServices_fields');
-													result.empty();
-													result.append(view.render());
-
-
-
-
-
-												});
-												</script>
-												<div id="d2e199_activeWidgetLayoutServiceGetServices_fields"></div>
-</td>
-</tr>
-
-                                <tr><td style="width:150px;">sortBy</td>
+                                <tr><td style="width:150px;">body </td>
 <td>
 
 
 <script>
 												$(document).ready(function() {
 													var schemaWrapper = {
-  "name" : "sortBy",
-  "in" : "query",
-  "description" : "Sort layouts (asc | desc)",
+  "in" : "body",
+  "name" : "body",
   "required" : false,
-  "type" : "string",
-  "default" : "WidgetLayoutInfo/user_name.asc"
+  "schema" : {
+    "$ref" : "#/definitions/UserAuthenticationSourceRequestCreateSwagger"
+  }
 };
-													var schema = schemaWrapper;
-
-
-
+													
+														var schema = schemaWrapper.schema;
+														schemaWrapper.definitions = defs;
+														JsonRefs.resolveRefs(schemaWrapper, {"depth":3, "resolveRemoteRefs":false,"resolveFileRefs":false },function (err, resolved, metadata) {
+														
 
-													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_activeWidgetLayoutServiceGetServices_sortBy');
+														
+													var view = new JSONSchemaView(resolved.schema,2,{isBodyParam: true});
+													 
+													var result = $('#d2e199_createAuthenticationSources_body');
 													result.empty();
 													result.append(view.render());
+													
 
-
-
+													
+    											
+													
 
 
 												});
-												</script>
-												<div id="d2e199_activeWidgetLayoutServiceGetServices_sortBy"></div>
-</td>
-</tr>
-
-                                <tr><td style="width:150px;">page_size</td>
-<td>
-
-
-<script>
-												$(document).ready(function() {
-													var schemaWrapper = {
-  "name" : "page_size",
-  "in" : "query",
-  "description" : "The number of resources to be returned for the paged response.",
-  "required" : false,
-  "type" : "integer",
-  "default" : 10
-};
-													var schema = schemaWrapper;
-
-
-
-
-													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_activeWidgetLayoutServiceGetServices_pageSize');
-													result.empty();
-													result.append(view.render());
-
-
 
 
 
 												});
 												</script>
-												<div id="d2e199_activeWidgetLayoutServiceGetServices_pageSize"></div>
+												<div id="d2e199_createAuthenticationSources_body"></div>
 </td>
 </tr>
 
-                                <tr><td style="width:150px;">from</td>
-<td>
-
+                            </table>
 
-<script>
-												$(document).ready(function() {
-													var schemaWrapper = {
-  "name" : "from",
-  "in" : "query",
-  "description" : "The starting page resource (inclusive). Valid values are :offset | \"start\"",
-  "required" : false,
-  "type" : "string",
-  "default" : "0"
-};
-													var schema = schemaWrapper;
 
 
+                          <h2>Responses</h2>
+                            <h3> Status: 201 - Successful operation </h3>
 
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
 
-													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_activeWidgetLayoutServiceGetServices_from');
-													result.empty();
-													result.append(view.render());
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
 
+                            <h3> Status: 202 - Request is accepted, but not completely processed yet </h3>
 
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
 
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
 
+                            <h3> Status: 400 - Invalid arguments </h3>
 
-												});
-												</script>
-												<div id="d2e199_activeWidgetLayoutServiceGetServices_from"></div>
-</td>
-</tr>
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
 
-                                <tr><td style="width:150px;">to</td>
-<td>
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
 
+                            <h3> Status: 401 - Not authenticated </h3>
 
-<script>
-												$(document).ready(function() {
-													var schemaWrapper = {
-  "name" : "to",
-  "in" : "query",
-  "description" : "The ending page resource (inclusive). Valid values are :offset | \"end\"",
-  "required" : false,
-  "type" : "string"
-};
-													var schema = schemaWrapper;
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
 
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
 
+                            <h3> Status: 403 - Not permitted to perform the operation </h3>
 
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
 
-													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_activeWidgetLayoutServiceGetServices_to');
-													result.empty();
-													result.append(view.render());
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
 
+                            <h3> Status: 404 - The requested resource doesn&#39;t exist. </h3>
 
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
 
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
 
+                            <h3> Status: 409 - The requested resource already exists. </h3>
 
-												});
-												</script>
-												<div id="d2e199_activeWidgetLayoutServiceGetServices_to"></div>
-</td>
-</tr>
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
 
-                            </table>
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
 
-                          <h2>Responses</h2>
-                            <h3> Status: 200 - successful operation </h3>
+                            <h3> Status: 500 - Internal server error </h3>
 
                             <ul class="nav nav-tabs nav-tabs-examples" >
-                                <li class="active">
-                                  <a data-toggle="tab" href="#responses-activeWidgetLayoutServiceGetServices-200-schema">Schema</a>
-                                </li>
-
                             </ul>
 
                             <div class="tab-content" style='margin-bottom: 10px;'>
-                                <div class="tab-pane active" id="responses-activeWidgetLayoutServiceGetServices-200-schema">
-                                  <div id='responses-activeWidgetLayoutServiceGetServices-200-schema-200' style="padding: 30px; border-left: 1px solid #eee; border-right: 1px solid #eee; border-bottom: 1px solid #eee;">
-                                                               <script>
-                                      $(document).ready(function() {
-                                        var schemaWrapper = {
-  "description" : "successful operation",
-  "schema" : {
-    "type" : "array",
-    "items" : {
-      "$ref" : "#/definitions/ActiveWidgetLayoutResponse"
-    }
-  }
-};
-                                        var schema = schemaWrapper.schema;
-                                        schemaWrapper.definitions = defs;
-                                        //console.log(JSON.stringify(schema))
-                                        JsonRefs.resolveRefs(schemaWrapper, {
-                                            "depth": 3,
-                                            "resolveRemoteRefs": false,
-                                            "resolveFileRefs": false
-                                        }, function(err, resolved, metadata) {
-                                          //console.log(JSON.stringify(resolved));
-                                          var view = new JSONSchemaView(resolved.schema, 3);
-                                          $('#responses-activeWidgetLayoutServiceGetServices-200-schema-data').val(JSON.stringify(resolved.schema));
-                                          var result = $('#responses-activeWidgetLayoutServiceGetServices-200-schema-200');
-                                          result.empty();
-                                          result.append(view.render());
-                                        });
-                                      });
-                                    </script>
-                                  </div>
-                                  <input id='responses-activeWidgetLayoutServiceGetServices-200-schema-data' type='hidden' value=''></input>
-                                </div>
                             </div>
 
                         </article>
                       </div>
                       <hr>
-                    <div id="api-Users-activeWidgetLayoutServiceUpdateServices">
-                      <article id="api-Users-activeWidgetLayoutServiceUpdateServices-0" data-group="User" data-name="activeWidgetLayoutServiceUpdateServices" data-version="0">
+                    <div id="api-UserAuthenticationSources-deleteAuthenticationSource">
+                      <article id="api-UserAuthenticationSources-deleteAuthenticationSource-0" data-group="User" data-name="deleteAuthenticationSource" data-version="0">
                         <div class="pull-left">
-                          <h1>activeWidgetLayoutServiceUpdateServices</h1>
-                          <p>Update user widget layouts</p>
+                          <h1>deleteAuthenticationSource</h1>
+                          <p>Deletes an existing authentication source</p>
                         </div>
                         <div class="pull-right"></div>
                         <div class="clearfix"></div>
                         <p></p>
-                        <p class="marked">Updates user widget layout.</p>
+                        <p class="marked"></p>
                         <p></p>
                         <br />
-                        <pre class="prettyprint language-html prettyprinted" data-type="put"><code><span class="pln">/users/{userName}/activeWidgetLayouts</span></code></pre>
+                        <pre class="prettyprint language-html prettyprinted" data-type="delete"><code><span class="pln">/users/{userName}/sources/{sourceId}</span></code></pre>
                         <p>
                           <h3>Usage and SDK Samples</h3>
                         </p>
                         <ul class="nav nav-tabs nav-tabs-examples">
-                          <li class="active"><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-curl">Curl</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-java">Java</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-android">Android</a></li>
-                          <!--<li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-groovy">Groovy</a></li>-->
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-objc">Obj-C</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-javascript">JavaScript</a></li>
-                          <!--<li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-angular">Angular</a></li>-->
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-csharp">C#</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-php">PHP</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-perl">Perl</a></li>
-                          <li class=""><a href="#examples-Users-activeWidgetLayoutServiceUpdateServices-0-python">Python</a></li>
+                          <li class="active"><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-curl">Curl</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-java">Java</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-android">Android</a></li>
+                          <!--<li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-groovy">Groovy</a></li>-->
+                          <li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-objc">Obj-C</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-javascript">JavaScript</a></li>
+                          <!--<li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-angular">Angular</a></li>-->
+                          <li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-csharp">C#</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-php">PHP</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-perl">Perl</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-deleteAuthenticationSource-0-python">Python</a></li>
                         </ul>
 
                         <div class="tab-content">
-                          <div class="tab-pane active" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-curl">
-                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">put</span> "http://localhost/api/v1/users/{userName}/activeWidgetLayouts"</code></pre>
+                          <div class="tab-pane active" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-curl">
+                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">delete</span> "http://localhost/api/v1/users/{userName}/sources/{sourceId}"</code></pre>
                           </div>
-                          <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-java">
+                          <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-java">
                             <pre class="prettyprint"><code class="language-java">import io.swagger.client.*;
 import io.swagger.client.auth.*;
 import io.swagger.client.model.*;
-import io.swagger.client.api.UsersApi;
+import io.swagger.client.api.UserAuthenticationSourcesApi;
 
 import java.io.File;
 import java.util.*;
 
-public class UsersApiExample {
+public class UserAuthenticationSourcesApiExample {
 
     public static void main(String[] args) {
         
-        UsersApi apiInstance = new UsersApi();
+        UserAuthenticationSourcesApi apiInstance = new UserAuthenticationSourcesApi();
         String userName = userName_example; // String | user name
-        ActiveWidgetLayoutRequest body = ; // ActiveWidgetLayoutRequest | input parameters in json form
+        String sourceId = sourceId_example; // String | source id
         try {
-            apiInstance.activeWidgetLayoutServiceUpdateServices(userName, body);
+            apiInstance.deleteAuthenticationSource(userName, sourceId);
         } catch (ApiException e) {
-            System.err.println("Exception when calling UsersApi#activeWidgetLayoutServiceUpdateServices");
+            System.err.println("Exception when calling UserAuthenticationSourcesApi#deleteAuthenticationSource");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
 
-                          <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-android">
-                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.UsersApi;
+                          <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-android">
+                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.UserAuthenticationSourcesApi;
 
-public class UsersApiExample {
+public class UserAuthenticationSourcesApiExample {
 
     public static void main(String[] args) {
-        UsersApi apiInstance = new UsersApi();
+        UserAuthenticationSourcesApi apiInstance = new UserAuthenticationSourcesApi();
         String userName = userName_example; // String | user name
-        ActiveWidgetLayoutRequest body = ; // ActiveWidgetLayoutRequest | input parameters in json form
+        String sourceId = sourceId_example; // String | source id
         try {
-            apiInstance.activeWidgetLayoutServiceUpdateServices(userName, body);
+            apiInstance.deleteAuthenticationSource(userName, sourceId);
         } catch (ApiException e) {
-            System.err.println("Exception when calling UsersApi#activeWidgetLayoutServiceUpdateServices");
+            System.err.println("Exception when calling UserAuthenticationSourcesApi#deleteAuthenticationSource");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
   <!--
-  <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-groovy">
+  <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-groovy">
   <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
   </div> -->
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-objc">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-objc">
                               <pre class="prettyprint"><code class="language-cpp">String *userName = userName_example; // user name
-ActiveWidgetLayoutRequest *body = ; // input parameters in json form
+String *sourceId = sourceId_example; // source id
 
-UsersApi *apiInstance = [[UsersApi alloc] init];
+UserAuthenticationSourcesApi *apiInstance = [[UserAuthenticationSourcesApi alloc] init];
 
-// Update user widget layouts
-[apiInstance activeWidgetLayoutServiceUpdateServicesWith:userName
-    body:body
+// Deletes an existing authentication source
+[apiInstance deleteAuthenticationSourceWith:userName
+    sourceId:sourceId
               completionHandler: ^(NSError* error) {
                             if (error) {
                                 NSLog(@"Error: %@", error);
@@ -45780,14 +45810,14 @@ UsersApi *apiInstance = [[UsersApi alloc] init];
 </code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-javascript">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-javascript">
                               <pre class="prettyprint"><code class="language-js">var SwaggerSpecForAmbariRestApi = require('swagger_spec_for_ambari_rest_api');
 
-var api = new SwaggerSpecForAmbariRestApi.UsersApi()
+var api = new SwaggerSpecForAmbariRestApi.UserAuthenticationSourcesApi()
 
 var userName = userName_example; // {String} user name
 
-var body = ; // {ActiveWidgetLayoutRequest} input parameters in json form
+var sourceId = sourceId_example; // {String} source id
 
 
 var callback = function(error, data, response) {
@@ -45797,14 +45827,14 @@ var callback = function(error, data, response) {
     console.log('API called successfully.');
   }
 };
-api.activeWidgetLayoutServiceUpdateServices(userName, body, callback);
+api.deleteAuthenticationSource(userName, sourceId, callback);
 </code></pre>
                             </div>
 
-                            <!--<div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-angular">
+                            <!--<div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-angular">
               <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
             </div>-->
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-csharp">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-csharp">
                               <pre class="prettyprint"><code class="language-cs">using System;
 using System.Diagnostics;
 using IO.Swagger.Api;
@@ -45813,63 +45843,63 @@ using IO.Swagger.Model;
 
 namespace Example
 {
-    public class activeWidgetLayoutServiceUpdateServicesExample
+    public class deleteAuthenticationSourceExample
     {
         public void main()
         {
             
-            var apiInstance = new UsersApi();
+            var apiInstance = new UserAuthenticationSourcesApi();
             var userName = userName_example;  // String | user name
-            var body = new ActiveWidgetLayoutRequest(); // ActiveWidgetLayoutRequest | input parameters in json form
+            var sourceId = sourceId_example;  // String | source id
 
             try
             {
-                // Update user widget layouts
-                apiInstance.activeWidgetLayoutServiceUpdateServices(userName, body);
+                // Deletes an existing authentication source
+                apiInstance.deleteAuthenticationSource(userName, sourceId);
             }
             catch (Exception e)
             {
-                Debug.Print("Exception when calling UsersApi.activeWidgetLayoutServiceUpdateServices: " + e.Message );
+                Debug.Print("Exception when calling UserAuthenticationSourcesApi.deleteAuthenticationSource: " + e.Message );
             }
         }
     }
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-php">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-php">
                               <pre class="prettyprint"><code class="language-php"><&#63;php
 require_once(__DIR__ . '/vendor/autoload.php');
 
-$api_instance = new Swagger\Client\Api\UsersApi();
+$api_instance = new Swagger\Client\Api\UserAuthenticationSourcesApi();
 $userName = userName_example; // String | user name
-$body = ; // ActiveWidgetLayoutRequest | input parameters in json form
+$sourceId = sourceId_example; // String | source id
 
 try {
-    $api_instance->activeWidgetLayoutServiceUpdateServices($userName, $body);
+    $api_instance->deleteAuthenticationSource($userName, $sourceId);
 } catch (Exception $e) {
-    echo 'Exception when calling UsersApi->activeWidgetLayoutServiceUpdateServices: ', $e->getMessage(), PHP_EOL;
+    echo 'Exception when calling UserAuthenticationSourcesApi->deleteAuthenticationSource: ', $e->getMessage(), PHP_EOL;
 }
 ?></code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-perl">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-perl">
                               <pre class="prettyprint"><code class="language-perl">use Data::Dumper;
 use WWW::SwaggerClient::Configuration;
-use WWW::SwaggerClient::UsersApi;
+use WWW::SwaggerClient::UserAuthenticationSourcesApi;
 
-my $api_instance = WWW::SwaggerClient::UsersApi->new();
+my $api_instance = WWW::SwaggerClient::UserAuthenticationSourcesApi->new();
 my $userName = userName_example; # String | user name
-my $body = WWW::SwaggerClient::Object::ActiveWidgetLayoutRequest->new(); # ActiveWidgetLayoutRequest | input parameters in json form
+my $sourceId = sourceId_example; # String | source id
 
 eval { 
-    $api_instance->activeWidgetLayoutServiceUpdateServices(userName => $userName, body => $body);
+    $api_instance->deleteAuthenticationSource(userName => $userName, sourceId => $sourceId);
 };
 if ($@) {
-    warn "Exception when calling UsersApi->activeWidgetLayoutServiceUpdateServices: $@\n";
+    warn "Exception when calling UserAuthenticationSourcesApi->deleteAuthenticationSource: $@\n";
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-activeWidgetLayoutServiceUpdateServices-0-python">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-deleteAuthenticationSource-0-python">
                               <pre class="prettyprint"><code class="language-python">from __future__ import print_statement
 import time
 import swagger_client
@@ -45877,15 +45907,15 @@ from swagger_client.rest import ApiException
 from pprint import pprint
 
 # create an instance of the API class
-api_instance = swagger_client.UsersApi()
+api_instance = swagger_client.UserAuthenticationSourcesApi()
 userName = userName_example # String | user name
-body =  # ActiveWidgetLayoutRequest | input parameters in json form
+sourceId = sourceId_example # String | source id
 
 try: 
-    # Update user widget layouts
-    api_instance.activeWidgetLayoutServiceUpdateServices(userName, body)
+    # Deletes an existing authentication source
+    api_instance.deleteAuthenticationSource(userName, sourceId)
 except ApiException as e:
-    print("Exception when calling UsersApi->activeWidgetLayoutServiceUpdateServices: %s\n" % e)</code></pre>
+    print("Exception when calling UserAuthenticationSourcesApi->deleteAuthenticationSource: %s\n" % e)</code></pre>
                             </div>
                           </div>
 
@@ -45916,7 +45946,7 @@ except ApiException as e:
 
 
 													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_activeWidgetLayoutServiceUpdateServices_userName');
+													var result = $('#d2e199_deleteAuthenticationSource_userName');
 													result.empty();
 													result.append(view.render());
 
@@ -45926,60 +45956,40 @@ except ApiException as e:
 
 												});
 												</script>
-												<div id="d2e199_activeWidgetLayoutServiceUpdateServices_userName"></div>
+												<div id="d2e199_deleteAuthenticationSource_userName"></div>
 </td>
 </tr>
 
-                            </table>
-
-
-                            <div class="methodsubtabletitle">Body parameters</div>
-                            <table id="methodsubtable">
-                              <tr>
-                                <th width="150px">Name</th>
-                                <th>Description</th>
-                              </tr>
-                                <tr><td style="width:150px;">body <span style="color:red;">*</span></td>
+                                  <tr><td style="width:150px;">sourceId*</td>
 <td>
 
 
 <script>
 												$(document).ready(function() {
 													var schemaWrapper = {
-  "in" : "body",
-  "name" : "body",
-  "description" : "input parameters in json form",
+  "name" : "sourceId",
+  "in" : "path",
+  "description" : "source id",
   "required" : true,
-  "schema" : {
-    "$ref" : "#/definitions/ActiveWidgetLayoutRequest"
-  }
+  "type" : "string"
 };
-													
-														var schema = schemaWrapper.schema;
-														schemaWrapper.definitions = defs;
-														JsonRefs.resolveRefs(schemaWrapper, {"depth":3, "resolveRemoteRefs":false,"resolveFileRefs":false },function (err, resolved, metadata) {
-														
+													var schema = schemaWrapper;
 
-														
-													var view = new JSONSchemaView(resolved.schema,2,{isBodyParam: true});
-													 
-													var result = $('#d2e199_activeWidgetLayoutServiceUpdateServices_body');
+
+
+
+													var view = new JSONSchemaView(schema,1);
+													var result = $('#d2e199_deleteAuthenticationSource_sourceId');
 													result.empty();
 													result.append(view.render());
-													
-
-													
-    											
-													
 
 
-												});
 
 
 
 												});
 												</script>
-												<div id="d2e199_activeWidgetLayoutServiceUpdateServices_body"></div>
+												<div id="d2e199_deleteAuthenticationSource_sourceId"></div>
 </td>
 </tr>
 
@@ -45987,6 +45997,8 @@ except ApiException as e:
 
 
 
+
+
                           <h2>Responses</h2>
                             <h3> Status: 200 - Successful operation </h3>
 
@@ -45996,7 +46008,31 @@ except ApiException as e:
                             <div class="tab-content" style='margin-bottom: 10px;'>
                             </div>
 
-                            <h3> Status: 500 - Server Error </h3>
+                            <h3> Status: 401 - Not authenticated </h3>
+
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
+
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
+
+                            <h3> Status: 403 - Not permitted to perform the operation </h3>
+
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
+
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
+
+                            <h3> Status: 404 - The requested resource doesn&#39;t exist. </h3>
+
+                            <ul class="nav nav-tabs nav-tabs-examples" >
+                            </ul>
+
+                            <div class="tab-content" style='margin-bottom: 10px;'>
+                            </div>
+
+                            <h3> Status: 500 - Internal server error </h3>
 
                             <ul class="nav nav-tabs nav-tabs-examples" >
                             </ul>
@@ -46007,104 +46043,104 @@ except ApiException as e:
                         </article>
                       </div>
                       <hr>
-                    <div id="api-Users-userAuthorizationServiceGetAuthorization">
-                      <article id="api-Users-userAuthorizationServiceGetAuthorization-0" data-group="User" data-name="userAuthorizationServiceGetAuthorization" data-version="0">
+                    <div id="api-UserAuthenticationSources-getAuthenticationSource">
+                      <article id="api-UserAuthenticationSources-getAuthenticationSource-0" data-group="User" data-name="getAuthenticationSource" data-version="0">
                         <div class="pull-left">
-                          <h1>userAuthorizationServiceGetAuthorization</h1>
-                          <p>Get user authorization</p>
+                          <h1>getAuthenticationSource</h1>
+                          <p>Get user authentication source</p>
                         </div>
                         <div class="pull-right"></div>
                         <div class="clearfix"></div>
                         <p></p>
-                        <p class="marked">Returns user authorization details.</p>
+                        <p class="marked"></p>
                         <p></p>
                         <br />
-                        <pre class="prettyprint language-html prettyprinted" data-type="get"><code><span class="pln">/users/{userName}/authorizations/{authorization_id}</span></code></pre>
+                        <pre class="prettyprint language-html prettyprinted" data-type="get"><code><span class="pln">/users/{userName}/sources/{sourceId}</span></code></pre>
                         <p>
                           <h3>Usage and SDK Samples</h3>
                         </p>
                         <ul class="nav nav-tabs nav-tabs-examples">
-                          <li class="active"><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-curl">Curl</a></li>
-                          <li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-java">Java</a></li>
-                          <li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-android">Android</a></li>
-                          <!--<li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-groovy">Groovy</a></li>-->
-                          <li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-objc">Obj-C</a></li>
-                          <li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-javascript">JavaScript</a></li>
-                          <!--<li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-angular">Angular</a></li>-->
-                          <li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-csharp">C#</a></li>
-                          <li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-php">PHP</a></li>
-                          <li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-perl">Perl</a></li>
-                          <li class=""><a href="#examples-Users-userAuthorizationServiceGetAuthorization-0-python">Python</a></li>
+                          <li class="active"><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-curl">Curl</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-java">Java</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-android">Android</a></li>
+                          <!--<li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-groovy">Groovy</a></li>-->
+                          <li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-objc">Obj-C</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-javascript">JavaScript</a></li>
+                          <!--<li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-angular">Angular</a></li>-->
+                          <li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-csharp">C#</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-php">PHP</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-perl">Perl</a></li>
+                          <li class=""><a href="#examples-UserAuthenticationSources-getAuthenticationSource-0-python">Python</a></li>
                         </ul>
 
                         <div class="tab-content">
-                          <div class="tab-pane active" id="examples-Users-userAuthorizationServiceGetAuthorization-0-curl">
-                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">get</span> "http://localhost/api/v1/users/{userName}/authorizations/{authorization_id}?fields="</code></pre>
+                          <div class="tab-pane active" id="examples-UserAuthenticationSources-getAuthenticationSource-0-curl">
+                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">get</span> "http://localhost/api/v1/users/{userName}/sources/{sourceId}?fields="</code></pre>
                           </div>
-                          <div class="tab-pane" id="examples-Users-userAuthorizationServiceGetAuthorization-0-java">
+                          <div class="tab-pane" id="examples-UserAuthenticationSources-getAuthenticationSource-0-java">
                             <pre class="prettyprint"><code class="language-java">import io.swagger.client.*;
 import io.swagger.client.auth.*;
 import io.swagger.client.model.*;
-import io.swagger.client.api.UsersApi;
+import io.swagger.client.api.UserAuthenticationSourcesApi;
 
 import java.io.File;
 import java.util.*;
 
-public class UsersApiExample {
+public class UserAuthenticationSourcesApiExample {
 
     public static void main(String[] args) {
         
-        UsersApi apiInstance = new UsersApi();
+        UserAuthenticationSourcesApi apiInstance = new UserAuthenticationSourcesApi();
         String userName = userName_example; // String | user name
-        String authorizationId = authorizationId_example; // String | Authorization Id
-        String fields = fields_example; // String | Filter user authorization details
+        String sourceId = sourceId_example; // String | source id
+        String fields = fields_example; // String | Filter fields in the response (identifier fields are mandatory)
         try {
-            UserAuthorizationResponse result = apiInstance.userAuthorizationServiceGetAuthorization(userName, authorizationId, fields);
+            UserAuthenticationSourceResponseSwagger result = apiInstance.getAuthenticationSource(userName, sourceId, fields);
             System.out.println(result);
         } catch (ApiException e) {
-            System.err.println("Exception when calling UsersApi#userAuthorizationServiceGetAuthorization");
+            System.err.println("Exception when calling UserAuthenticationSourcesApi#getAuthenticationSource");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
 
-                          <div class="tab-pane" id="examples-Users-userAuthorizationServiceGetAuthorization-0-android">
-                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.UsersApi;
+                          <div class="tab-pane" id="examples-UserAuthenticationSources-getAuthenticationSource-0-android">
+                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.UserAuthenticationSourcesApi;
 
-public class UsersApiExample {
+public class UserAuthenticationSourcesApiExample {
 
     public static void main(String[] args) {
-        UsersApi apiInstance = new UsersApi();
+        UserAuthenticationSourcesApi apiInstance = new UserAuthenticationSourcesApi();
         String userName = userName_example; // String | user name
-        String authorizationId = authorizationId_example; // String | Authorization Id
-        String fields = fields_example; // String | Filter user authorization details
+        String sourceId = sourceId_example; // String | source id
+        String fields = fields_example; // String | Filter fields in the response (identifier fields are mandatory)
         try {
-            UserAuthorizationResponse result = apiInstance.userAuthorizationServiceGetAuthorization(userName, authorizationId, fields);
+            UserAuthenticationSourceResponseSwagger result = apiInstance.getAuthenticationSource(userName, sourceId, fields);
             System.out.println(result);
         } catch (ApiException e) {
-            System.err.println("Exception when calling UsersApi#userAuthorizationServiceGetAuthorization");
+            System.err.println("Exception when calling UserAuthenticationSourcesApi#getAuthenticationSource");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
   <!--
-  <div class="tab-pane" id="examples-Users-userAuthorizationServiceGetAuthorization-0-groovy">
+  <div class="tab-pane" id="examples-UserAuthenticationSources-getAuthenticationSource-0-groovy">
   <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
   </div> -->
-                            <div class="tab-pane" id="examples-Users-userAuthorizationServiceGetAuthorization-0-objc">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-getAuthenticationSource-0-objc">
                               <pre class="prettyprint"><code class="language-cpp">String *userName = userName_example; // user name
-String *authorizationId = authorizationId_example; // Authorization Id
-String *fields = fields_example; // Filter user authorization details (optional) (default to AuthorizationInfo/*)
+String *sourceId = sourceId_example; // source id
+String *fields = fields_example; // Filter fields in the response (identifier fields are mandatory) (optional) (default to AuthenticationSourceInfo/*)
 
-UsersApi *apiInstance = [[UsersApi alloc] init];
+UserAuthenticationSourcesApi *apiInstance = [[UserAuthenticationSourcesApi alloc] init];
 
-// Get user authorization
-[apiInstance userAuthorizationServiceGetAuthorizationWith:userName
-    authorizationId:authorizationId
+// Get user authentication source
+[apiInstance getAuthenticationSourceWith:userName
+    sourceId:sourceId
     fields:fields
-              completionHandler: ^(UserAuthorizationResponse output, NSError* error) {
+              completionHandler: ^(UserAuthenticationSourceResponseSwagger output, NSError* error) {
                             if (output) {
                                 NSLog(@"%@", output);
                             }
@@ -46115,17 +46151,17 @@ UsersApi *apiInstance = [[UsersApi alloc] init];
 </code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Users-userAuthorizationServiceGetAuthorization-0-javascript">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-getAuthenticationSource-0-javascript">
                               <pre class="prettyprint"><code class="language-js">var SwaggerSpecForAmbariRestApi = require('swagger_spec_for_ambari_rest_api');
 
-var api = new SwaggerSpecForAmbariRestApi.UsersApi()
+var api = new SwaggerSpecForAmbariRestApi.UserAuthenticationSourcesApi()
 
 var userName = userName_example; // {String} user name
 
-var authorizationId = authorizationId_example; // {String} Authorization Id
+var sourceId = sourceId_example; // {String} source id
 
 var opts = { 
-  'fields': fields_example // {String} Filter user authorization details
+  'fields': fields_example // {String} Filter fields in the response (identifier fields are mandatory)
 };
 
 var callback = function(error, data, response) {
@@ -46135,14 +46171,14 @@ var callback = function(error, data, response) {
     console.log('API called successfully. Returned data: ' + data);
   }
 };
-api.userAuthorizationServiceGetAuthorization(userName, authorizationId, opts, callback);
+api.getAuthenticationSource(userName, sourceId, opts, callback);
 </code></pre>
                             </div>
 
-                            <!--<div class="tab-pane" id="examples-Users-userAuthorizationServiceGetAuthorization-0-angular">
+                            <!--<div class="tab-pane" id="examples-UserAuthenticationSources-getAuthenticationSource-0-angular">
               <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
             </div>-->
-                            <div class="tab-pane" id="examples-Users-userAuthorizationServiceGetAuthorization-0-csharp">
+                            <div class="tab-pane" id="examples-UserAuthenticationSources-getAuthenticationSource-0-csharp">
                               <pre class="prettyprint"><code class="language-cs">using System;
 using System.Diagnostics;
 using IO.Swagger.Api;
@@ -46151,69 +46187,69 @@ using IO.Swagger.Model;
 
 namespace Example
 {
-    public class userAuthorizationServiceGetAuthorizationExample
+    public class getAuthenticationSourceExample
     {
         public void main()
         {
             
-            

<TRUNCATED>

[2/6] ambari git commit: AMBARI-20861. BE: Extend Ambari REST API to Support User Account Management Improvements (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
index 45b733b..a2d9917 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
@@ -17,9 +17,9 @@
  */
 package org.apache.ambari.server.controller.internal;
 
-import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -29,6 +29,7 @@ import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.UserRequest;
 import org.apache.ambari.server.controller.UserResponse;
+import org.apache.ambari.server.controller.predicate.AndPredicate;
 import org.apache.ambari.server.controller.predicate.EqualsPredicate;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
@@ -38,8 +39,10 @@ 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.ResourcePredicateEvaluator;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.entities.MemberEntity;
 import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
@@ -52,6 +55,8 @@ import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.commons.lang.StringUtils;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
@@ -63,21 +68,70 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
 
   // ----- Property ID constants ---------------------------------------------
 
+  public static final String USER_RESOURCE_CATEGORY = "Users";
+
   // Users
-  public static final String USER_USERNAME_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "user_name");
-  public static final String USER_PASSWORD_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "password");
-  public static final String USER_OLD_PASSWORD_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "old_password");
+  public static final String USERNAME_PROPERTY_ID = "user_name";
+  public static final String DISPLAY_NAME_PROPERTY_ID = "display_name";
+  public static final String LOCAL_USERNAME_PROPERTY_ID = "local_user_name";
+  public static final String ACTIVE_PROPERTY_ID = "active";
+  public static final String CREATE_TIME_PROPERTY_ID = "created";
+  public static final String CONSECUTIVE_FAILURES_PROPERTY_ID = "consecutive_failures";
+  public static final String ADMIN_PROPERTY_ID = "admin";
+  public static final String GROUPS_PROPERTY_ID = "groups";
+
+  public static final String USER_USERNAME_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + USERNAME_PROPERTY_ID;
+  public static final String USER_DISPLAY_NAME_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + DISPLAY_NAME_PROPERTY_ID;
+  public static final String USER_LOCAL_USERNAME_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + LOCAL_USERNAME_PROPERTY_ID;
+  public static final String USER_ACTIVE_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + ACTIVE_PROPERTY_ID;
+  public static final String USER_CREATE_TIME_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + CREATE_TIME_PROPERTY_ID;
+  public static final String USER_CONSECUTIVE_FAILURES_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + CONSECUTIVE_FAILURES_PROPERTY_ID;
+  public static final String USER_ADMIN_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + ADMIN_PROPERTY_ID;
+  public static final String USER_GROUPS_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + GROUPS_PROPERTY_ID;
+
+  /* *******************************************************
+   * Deprecated properties, kept for backwards compatibility and to maintain API V1 contract.
+   * These properties are related to a user's authentication resource.
+   * ******************************************************* */
+  @Deprecated
+  public static final String PASSWORD_PROPERTY_ID = "password";
   @Deprecated
-  public static final String USER_LDAP_USER_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "ldap_user");
+  public static final String OLD_PASSWORD_PROPERTY_ID = "old_password";
   @Deprecated
-  public static final String USER_TYPE_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "user_type");
-  public static final String USER_ACTIVE_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "active");
-  public static final String USER_GROUPS_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "groups");
-  public static final String USER_ADMIN_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "admin");
+  public static final String LDAP_USER_PROPERTY_ID = "ldap_user";
+  @Deprecated
+  public static final String USER_TYPE_PROPERTY_ID = "user_type";
 
-  private static Set<String> pkPropertyIds =
-      new HashSet<>(Arrays.asList(new String[]{
-          USER_USERNAME_PROPERTY_ID}));
+  @Deprecated
+  public static final String USER_PASSWORD_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + PASSWORD_PROPERTY_ID;
+  @Deprecated
+  public static final String USER_OLD_PASSWORD_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + OLD_PASSWORD_PROPERTY_ID;
+  @Deprecated
+  public static final String USER_LDAP_USER_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + LDAP_USER_PROPERTY_ID;
+  @Deprecated
+  public static final String USER_USER_TYPE_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + USER_TYPE_PROPERTY_ID;
+  /* ******************************************************* */
+
+  private static final Set<String> PK_PROPERTY_IDS = ImmutableSet.of(
+      USER_USERNAME_PROPERTY_ID
+  );
+  private static final Set<String> PROPERTY_IDS = ImmutableSet.of(
+      USER_USERNAME_PROPERTY_ID,
+      USER_DISPLAY_NAME_PROPERTY_ID,
+      USER_LOCAL_USERNAME_PROPERTY_ID,
+      USER_ACTIVE_PROPERTY_ID,
+      USER_CREATE_TIME_PROPERTY_ID,
+      USER_CONSECUTIVE_FAILURES_PROPERTY_ID,
+      USER_GROUPS_PROPERTY_ID,
+      USER_PASSWORD_PROPERTY_ID,
+      USER_OLD_PASSWORD_PROPERTY_ID,
+      USER_LDAP_USER_PROPERTY_ID,
+      USER_USER_TYPE_PROPERTY_ID,
+      USER_ADMIN_PROPERTY_ID
+  );
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = ImmutableMap.of(
+      Resource.Type.User, USER_USERNAME_PROPERTY_ID
+  );
 
   @Inject
   private Users users;
@@ -86,10 +140,8 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
    * Create a new resource provider for the given management controller.
    */
   @AssistedInject
-  UserResourceProvider(@Assisted Set<String> propertyIds,
-                       @Assisted Map<Resource.Type, String> keyPropertyIds,
-                       @Assisted AmbariManagementController managementController) {
-    super(propertyIds, keyPropertyIds, managementController);
+  UserResourceProvider(@Assisted AmbariManagementController managementController) {
+    super(Resource.Type.User, PROPERTY_IDS, KEY_PROPERTY_IDS, managementController);
 
     setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_USERS));
     setRequiredDeleteAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_USERS));
@@ -109,7 +161,11 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
     createResources(new Command<Void>() {
       @Override
       public Void invoke() throws AmbariException {
-        createUsers(requests);
+        try {
+          createUsers(requests);
+        } catch (ResourceAlreadyExistsException | AuthorizationException e) {
+          throw new AmbariException(e.getMessage(), e);
+        }
         return null;
       }
     });
@@ -151,12 +207,18 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
       setResourceProperty(resource, USER_USERNAME_PROPERTY_ID,
           userResponse.getUsername(), requestedIds);
 
+      setResourceProperty(resource, USER_DISPLAY_NAME_PROPERTY_ID,
+          userResponse.getDisplayName(), requestedIds);
+
+      setResourceProperty(resource, USER_LOCAL_USERNAME_PROPERTY_ID,
+          userResponse.getLocalUsername(), requestedIds);
+
       // This is deprecated but here for backwards compatibility
       setResourceProperty(resource, USER_LDAP_USER_PROPERTY_ID,
           userResponse.isLdapUser(), requestedIds);
 
       // This is deprecated but here for backwards compatibility
-      setResourceProperty(resource, USER_TYPE_PROPERTY_ID,
+      setResourceProperty(resource, USER_USER_TYPE_PROPERTY_ID,
           userResponse.getAuthenticationType(), requestedIds);
 
       setResourceProperty(resource, USER_ACTIVE_PROPERTY_ID,
@@ -168,6 +230,12 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
       setResourceProperty(resource, USER_ADMIN_PROPERTY_ID,
           userResponse.isAdmin(), requestedIds);
 
+      setResourceProperty(resource, USER_CONSECUTIVE_FAILURES_PROPERTY_ID,
+          userResponse.getConsecutiveFailures(), requestedIds);
+
+      setResourceProperty(resource, USER_CREATE_TIME_PROPERTY_ID,
+          userResponse.getCreateTime(), requestedIds);
+
       resources.add(resource);
     }
 
@@ -241,7 +309,7 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
 
   @Override
   protected Set<String> getPKPropertyIds() {
-    return pkPropertyIds;
+    return PK_PROPERTY_IDS;
   }
 
   private UserRequest getRequest(Map<String, Object> properties) {
@@ -251,6 +319,9 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
 
     UserRequest request = new UserRequest((String) properties.get(USER_USERNAME_PROPERTY_ID));
 
+    request.setDisplayName((String) properties.get(USER_DISPLAY_NAME_PROPERTY_ID));
+    request.setLocalUserName((String) properties.get(USER_LOCAL_USERNAME_PROPERTY_ID));
+
     request.setPassword((String) properties.get(USER_PASSWORD_PROPERTY_ID));
     request.setOldPassword((String) properties.get(USER_OLD_PASSWORD_PROPERTY_ID));
 
@@ -272,25 +343,45 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
    * @param requests the request objects which define the user.
    * @throws AmbariException when the user cannot be created.
    */
-  private void createUsers(Set<UserRequest> requests) throws AmbariException {
+  private void createUsers(Set<UserRequest> requests) throws AmbariException, ResourceAlreadyExistsException, AuthorizationException {
+    // First check for obvious issues... then try to create the accounts.  This will help to avoid
+    // some accounts being created and some not due to an issue with one or more of the users.
     for (UserRequest request : requests) {
       String username = request.getUsername();
-      String password = request.getPassword();
 
-      if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
-        throw new AmbariException("Username and password must be supplied.");
+      if (StringUtils.isEmpty(username)) {
+        throw new AmbariException("Username must be supplied.");
       }
 
+      if (users.getUser(username) != null) {
+        String message;
+        if (requests.size() == 1) {
+          message = "The requested username already exists.";
+        } else {
+          message = "One or more of the requested usernames already exists.";
+        }
+        throw new ResourceAlreadyExistsException(message);
+      }
+    }
+
+    for (UserRequest request : requests) {
+      String username = request.getUsername();
       String displayName = StringUtils.defaultIfEmpty(request.getDisplayName(), username);
       String localUserName = StringUtils.defaultIfEmpty(request.getLocalUserName(), username);
 
       UserEntity userEntity = users.createUser(username, localUserName, displayName, request.isActive());
       if (userEntity != null) {
-        users.addLocalAuthentication(userEntity, password);
-
         if (Boolean.TRUE.equals(request.isAdmin())) {
           users.grantAdminPrivilege(userEntity);
         }
+
+        // Setting a user's the password here is to allow for backward compatibility with pre-Ambari-3.0
+        // versions so that the contract for REST API V1 is maintained.
+        if (!StringUtils.isEmpty(request.getPassword())) {
+          // This is performed as a user administrator since the  authorization check was done prior
+          // to executing #createResourcesAuthorized.
+          addOrUpdateLocalAuthenticationSource(true, userEntity, request.getPassword(), null);
+        }
       }
     }
   }
@@ -304,37 +395,73 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
    *                                  the requested properties
    */
   private void updateUsers(Set<UserRequest> requests) throws AmbariException, AuthorizationException {
-    boolean isUserAdministrator = AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null,
+    boolean asUserAdministrator = AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null,
         RoleAuthorization.AMBARI_MANAGE_USERS);
     String authenticatedUsername = AuthorizationHelper.getAuthenticatedName();
 
-    for (UserRequest request : requests) {
+    for (final UserRequest request : requests) {
       String requestedUsername = request.getUsername();
 
       // An administrator can modify any user, else a user can only modify themself.
-      if (!isUserAdministrator && (!authenticatedUsername.equalsIgnoreCase(requestedUsername))) {
+      if (!asUserAdministrator && (!authenticatedUsername.equalsIgnoreCase(requestedUsername))) {
         throw new AuthorizationException();
       }
 
       UserEntity userEntity = users.getUserEntity(requestedUsername);
-      if (null == userEntity) {
+      if (null == userEntity) {// Only an user with the privs to manage users can update a user's active status
         continue;
       }
 
-      if (null != request.isActive()) {
+      boolean hasUpdates = false;
+      if (isValueChanged(request.isActive(), userEntity.getActive())) {
         // If this value is being set, make sure the authenticated user is an administrator before
         // allowing to change it. Only administrators should be able to change a user's active state
-        if (!isUserAdministrator) {
-          throw new AuthorizationException("The authenticated user is not authorized to update the requested resource property");
+        if (!asUserAdministrator) {
+          throw new AuthorizationException("The authenticated user is not authorized to update the requested user's active property");
+        }
+
+        hasUpdates = true;
+      }
+
+      // Only an user with the privs to manage users can update a user's local username
+      if (isValueChanged(request.getLocalUserName(), userEntity.getLocalUsername())) {
+        // If this value is being set, make sure the authenticated user is an administrator before
+        // allowing to change it. Only administrators should be able to change a user's active state
+        if (!asUserAdministrator) {
+          throw new AuthorizationException("The authenticated user is not authorized to update the requested user's local username property");
         }
-        users.setUserActive(userEntity, request.isActive());
+
+        hasUpdates = true;
+      }
+
+      hasUpdates = hasUpdates || isValueChanged(request.getDisplayName(), userEntity.getDisplayName());
+
+      if (hasUpdates) {
+        users.safelyUpdateUserEntity(userEntity,
+            new Users.Command() {
+              @Override
+              public void perform(UserEntity userEntity) {
+                if (isValueChanged(request.isActive(), userEntity.getActive())) {
+                  userEntity.setActive(request.isActive());
+                }
+
+                if (isValueChanged(request.getLocalUserName(), userEntity.getLocalUsername())) {
+                  userEntity.setLocalUsername(request.getLocalUserName());
+                }
+
+                if (isValueChanged(request.getDisplayName(), userEntity.getDisplayName())) {
+                  userEntity.setDisplayName(request.getDisplayName());
+                }
+              }
+            });
       }
 
+      // Only an user with the privs to manage users can update a user's roles
       if (null != request.isAdmin()) {
         // If this value is being set, make sure the authenticated user is an administrator before
         // allowing to change it. Only administrators should be able to change a user's administrative
         // privileges
-        if (!isUserAdministrator) {
+        if (!asUserAdministrator) {
           throw new AuthorizationException("The authenticated user is not authorized to update the requested resource property");
         }
 
@@ -345,13 +472,87 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
         }
       }
 
-      if (null != request.getOldPassword() && null != request.getPassword()) {
-        users.modifyPassword(userEntity, request.getOldPassword(), request.getPassword());
+      // Setting/Changing a user's password here is for backward compatibility to maintain API V1 contract
+      if (request.getPassword() != null) {
+        addOrUpdateLocalAuthenticationSource(asUserAdministrator, userEntity, request.getPassword(), request.getOldPassword());
       }
     }
   }
 
   /**
+   * Adds to updates a user's local authentication source by issuing a call to the {@link UserAuthenticationSourceResourceProvider}.
+   * <p>
+   * This is for backward compatibility to maintain the contract for Ambari's REST API version V1.
+   *
+   * @param asUserAdministrator true if the authenticated user have privs to manage user; false otherwise
+   * @param subjectUserEntity   the user to update
+   * @param password            the password to set, it is expected that this value is not <code>null</code>
+   * @param oldPassword         the old/current password to use for verification is needed, this value may be <code>null</code>
+   */
+  private void addOrUpdateLocalAuthenticationSource(boolean asUserAdministrator, UserEntity subjectUserEntity, String password, String oldPassword)
+      throws AuthorizationException, AmbariException {
+    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(Resource.Type.UserAuthenticationSource,
+        PropertyHelper.getPropertyIds(Resource.Type.UserAuthenticationSource),
+        PropertyHelper.getKeyPropertyIds(Resource.Type.UserAuthenticationSource),
+        getManagementController());
+
+    if (provider != null) {
+      // Determine if the user already has an LOCAL authentication source setup...
+      UserAuthenticationEntity userAuthenticationEntity = null;
+      List<UserAuthenticationEntity> authenticationEntities = subjectUserEntity.getAuthenticationEntities();
+      for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+        if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LOCAL) {
+          userAuthenticationEntity = authenticationEntity;
+          break;
+        }
+      }
+      if (userAuthenticationEntity == null) {
+        // a new authentication source needs to be create... only a privileged user can do this...
+        if (!asUserAdministrator) {
+          throw new AuthorizationException("The authenticated user is not authorized to create a local authentication source.");
+        } else {
+          Set<Map<String, Object>> propertiesSet = new HashSet<>();
+          Map<String, Object> properties;
+          properties = new LinkedHashMap<>();
+          properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID, subjectUserEntity.getUserName());
+          properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID, UserAuthenticationType.LOCAL.name());
+          properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID, password);
+          propertiesSet.add(properties);
+
+          try {
+            provider.createResources(PropertyHelper.getCreateRequest(propertiesSet, null));
+          } catch (Exception e) {
+            throw new AmbariException(e.getMessage(), e);
+          }
+        }
+      } else {
+        Map<String, Object> properties = new LinkedHashMap<>();
+        properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_OLD_KEY_PROPERTY_ID, oldPassword);
+        properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID, password);
+
+        Predicate predicate1 = new PredicateBuilder()
+            .property(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID)
+            .equals(subjectUserEntity.getUserName())
+            .toPredicate();
+        Predicate predicate2 = new PredicateBuilder()
+            .property(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID)
+            .equals(userAuthenticationEntity.getUserAuthenticationId())
+            .toPredicate();
+
+        try {
+          provider.updateResources(PropertyHelper.getUpdateRequest(properties, null), new AndPredicate(predicate1, predicate2));
+        } catch (Exception e) {
+          throw new AmbariException(e.getMessage(), e);
+        }
+      }
+    }
+  }
+
+  private boolean isValueChanged(Object newValue, Object currentValue) {
+    return (newValue != null) && !newValue.equals(currentValue);
+  }
+
+  /**
    * Deletes the users specified.
    *
    * @param requests the users to delete
@@ -436,13 +637,13 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
     boolean isLdapUser = false;
     UserAuthenticationType userType = UserAuthenticationType.LOCAL;
 
-      for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
-        if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LDAP) {
-          isLdapUser = true;
-          userType = UserAuthenticationType.LDAP;
-        } else if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.PAM) {
-          userType = UserAuthenticationType.PAM;
-        }
+    for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+      if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LDAP) {
+        isLdapUser = true;
+        userType = UserAuthenticationType.LDAP;
+      } else if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.PAM) {
+        userType = UserAuthenticationType.PAM;
+      }
     }
 
     Set<String> groups = new HashSet<>();
@@ -452,7 +653,15 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
 
     boolean isAdmin = users.hasAdminPrivilege(userEntity);
 
-    UserResponse userResponse = new UserResponse(userEntity.getUserName(), userType, isLdapUser, userEntity.getActive(), isAdmin);
+    UserResponse userResponse = new UserResponse(userEntity.getUserName(),
+        userEntity.getDisplayName(),
+        userEntity.getLocalUsername(),
+        userType,
+        isLdapUser,
+        userEntity.getActive(),
+        isAdmin,
+        userEntity.getConsecutiveFailures(),
+        userEntity.getCreateTime());
     userResponse.setGroups(groups);
     return userResponse;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/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 362b4e6..d1be8a4 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
@@ -134,6 +134,7 @@ public interface Resource {
     StackLevelConfiguration,
     LdapSyncEvent,
     UserPrivilege,
+    UserAuthenticationSource,
     GroupPrivilege,
     RepositoryVersion,
     CompatibleRepositoryVersion,
@@ -255,6 +256,7 @@ public interface Resource {
     public static final Type StackLevelConfiguration = InternalType.StackLevelConfiguration.getType();
     public static final Type LdapSyncEvent = InternalType.LdapSyncEvent.getType();
     public static final Type UserPrivilege = InternalType.UserPrivilege.getType();
+    public static final Type UserAuthenticationSource = InternalType.UserAuthenticationSource.getType();
     public static final Type GroupPrivilege = InternalType.GroupPrivilege.getType();
     public static final Type RepositoryVersion = InternalType.RepositoryVersion.getType();
     public static final Type CompatibleRepositoryVersion = InternalType.CompatibleRepositoryVersion.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserAuthenticationDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserAuthenticationDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserAuthenticationDAO.java
index 5ecff52..c4e5cce 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserAuthenticationDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserAuthenticationDAO.java
@@ -25,6 +25,7 @@ import javax.persistence.TypedQuery;
 
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -50,6 +51,13 @@ public class UserAuthenticationDAO {
     return daoUtils.selectList(query);
   }
 
+  @RequiresSession
+  public List<UserAuthenticationEntity> findByType(UserAuthenticationType authenticationType) {
+    TypedQuery<UserAuthenticationEntity> query = entityManagerProvider.get().createNamedQuery("UserAuthenticationEntity.findByType", UserAuthenticationEntity.class);
+    query.setParameter("authenticationType", authenticationType.name());
+    return daoUtils.selectList(query);
+  }
+
   @Transactional
   public void create(UserAuthenticationEntity entity) {
     entityManagerProvider.get().persist(entity);

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserAuthenticationEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserAuthenticationEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserAuthenticationEntity.java
index ffb8e6d..fb78629 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserAuthenticationEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserAuthenticationEntity.java
@@ -33,6 +33,8 @@ import javax.persistence.Lob;
 import javax.persistence.ManyToOne;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
+import javax.persistence.PrePersist;
+import javax.persistence.PreUpdate;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 import javax.persistence.Temporal;
@@ -45,13 +47,15 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
 @Table(name = "user_authentication")
 @Entity
 @NamedQueries({
-    @NamedQuery(name = "UserAuthenticationEntity.findAll", query = "SELECT entity FROM UserAuthenticationEntity entity")
+    @NamedQuery(name = "UserAuthenticationEntity.findAll",
+        query = "SELECT entity FROM UserAuthenticationEntity entity"),
+    @NamedQuery(name = "UserAuthenticationEntity.findByType",
+        query = "SELECT entity FROM UserAuthenticationEntity entity where lower(entity.authenticationType)=lower(:authenticationType)")
 })
 @TableGenerator(name = "user_authentication_id_generator",
     table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value"
     , pkColumnValue = "user_authentication_id_seq"
     , initialValue = 2
-    , allocationSize = 500
 )
 public class UserAuthenticationEntity {
 
@@ -134,6 +138,22 @@ public class UserAuthenticationEntity {
     this.user = user;
   }
 
+  /**
+   * Ensure the create time and update time are set properly when the record is created.
+   */
+  @PrePersist
+  protected void onCreate() {
+    createTime = new Date();
+    updateTime = new Date();
+  }
+
+  /**
+   * Ensure the update time is set properly when the record is updated.
+   */
+  @PreUpdate
+  protected void onUpdate() {
+    updateTime = new Date();
+  }
 
   @Override
   public boolean equals(Object o) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/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 de12a16..d4eae9d 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
@@ -152,76 +152,6 @@ public class Users {
   }
 
   /**
-   * Modifies password of local user
-   *
-   * @throws AmbariException
-   */
-  public synchronized void modifyPassword(String userName, String currentUserPassword, String newPassword) throws AmbariException, AuthorizationException {
-    UserEntity userEntity = userDAO.findUserByName(userName);
-    modifyPassword(userEntity, currentUserPassword, newPassword);
-  }
-
-  /**
-   * Modifies password of local user
-   *
-   * @throws AmbariException
-   */
-  public synchronized void modifyPassword(UserEntity userEntity, String currentUserPassword, String newPassword) throws AmbariException, AuthorizationException {
-
-    String authenticatedUserName = AuthorizationHelper.getAuthenticatedName();
-    if (authenticatedUserName == null) {
-      throw new AmbariException("Authentication required. Please sign in.");
-    }
-
-    if (userEntity != null) {
-    /* **************************************************
-     * Ensure that the authenticated user can change the password for the subject user. at least one
-     * of the following must be true
-     *  * The authenticate user is requesting to change his/her own password
-     *  * The authenticated user has permissions to manage users
-     *  ************************************************** */
-      boolean isSelf = userEntity.getUserName().equalsIgnoreCase(authenticatedUserName);
-      if (!isSelf && !AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.AMBARI_MANAGE_USERS)) {
-        throw new AuthorizationException("You are not authorized perform this operation");
-      }
-
-      List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
-      UserAuthenticationEntity localAuthenticationEntity = null;
-
-      // Find the authentication entity for the local authentication type - only one should exist, if one exists at all.
-      for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
-        if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LOCAL) {
-          localAuthenticationEntity = authenticationEntity;
-          break;
-        }
-      }
-
-      if (localAuthenticationEntity == null) {
-        // The user account does not have a local authentication record.  Therefore there is no local
-        // password to change...
-        throw new AmbariException("An Ambari-specific password is not set for this user. The user's password cannot be changed at this time.");
-      } else if (isSelf &&
-          (StringUtils.isEmpty(currentUserPassword) || !passwordEncoder.matches(currentUserPassword, localAuthenticationEntity.getAuthenticationKey()))) {
-        // The authenticated user is the same user as subject user and the correct current password
-        // was not supplied.
-        throw new AmbariException("Wrong current password provided");
-      }
-
-      // TODO: validate the new password...
-      if (StringUtils.isEmpty(newPassword)) {
-        throw new AmbariException("The new password does not meet the Ambari password requirements");
-      }
-
-      // If we get here the authenticated user is authorized to change the password for the subject
-      // user and the correct current password was supplied (if required).
-      localAuthenticationEntity.setAuthenticationKey(passwordEncoder.encode(newPassword));
-      userAuthenticationDAO.merge(localAuthenticationEntity);
-    } else {
-      throw new AmbariException("User not found");
-    }
-  }
-
-  /**
    * Enables/disables user.
    *
    * @param userName user name
@@ -245,7 +175,7 @@ public class Users {
    * @throws AmbariException if user does not exist
    */
   public synchronized void setUserActive(UserEntity userEntity, final boolean active) throws AmbariException {
-    if(userEntity != null) {
+    if (userEntity != null) {
       Command command = new Command() {
         @Override
         public void perform(UserEntity userEntity) {
@@ -347,7 +277,7 @@ public class Users {
   /**
    * Removes a user from the Ambari database.
    * <p>
-   * It is expected that the assoicated user authencation records are removed by this operation
+   * It is expected that the associated user authentication records are removed by this operation
    * as well.
    *
    * @param user the user to remove
@@ -366,7 +296,7 @@ public class Users {
   /**
    * Removes a user from the Ambari database.
    * <p>
-   * It is expected that the assoicated user authencation records are removed by this operation
+   * It is expected that the associated user authentication records are removed by this operation
    * as well.
    *
    * @param userEntity the user to remove
@@ -792,14 +722,14 @@ public class Users {
         List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
         boolean createNew = true;
 
-          for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
-            if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LDAP) {
-              // TODO: check for the relevant LDAP entry... for now there will be only one.
-              LOG.debug("Found existing LDAP authentication record for the user account with the username {}.", userName);
-              createNew = false;
-              break;
-            }
+        for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+          if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LDAP) {
+            // TODO: check for the relevant LDAP entry... for now there will be only one.
+            LOG.debug("Found existing LDAP authentication record for the user account with the username {}.", userName);
+            createNew = false;
+            break;
           }
+        }
 
         if (createNew) {
           LOG.debug("Creating new LDAP authentication record for the user account with the username {}.", userName);
@@ -1110,6 +1040,154 @@ public class Users {
     return implicitPrivileges;
   }
 
+
+  /**
+   * Gets the collection of {@link UserAuthenticationEntity}s for a given user.
+   *
+   * @param username           the username of a user; if null assumes all users
+   * @param authenticationType the authentication type, if null assumes all
+   * @return a collection of the requested {@link UserAuthenticationEntity}s
+   */
+  public Collection<UserAuthenticationEntity> getUserAuthenticationEntities(String username, UserAuthenticationType authenticationType) {
+    if (StringUtils.isEmpty(username)) {
+      if (authenticationType == null) {
+        // Get all
+        return userAuthenticationDAO.findAll();
+      } else {
+        // Get for the specified type
+        return userAuthenticationDAO.findByType(authenticationType);
+      }
+    } else {
+      UserEntity entity = userDAO.findUserByName(username);
+
+      if (entity == null) {
+        return null;
+      } else {
+        List<UserAuthenticationEntity> authenticationEntities = entity.getAuthenticationEntities();
+
+        if (authenticationType == null) {
+          // Get for the specified user
+          return authenticationEntities;
+        } else {
+          // Get for the specified user and type
+          List<UserAuthenticationEntity> pruned = new ArrayList<>();
+          for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+            if (authenticationEntity.getAuthenticationType() == authenticationType) {
+              pruned.add(authenticationEntity);
+            }
+          }
+
+          return pruned;
+        }
+      }
+    }
+  }
+
+  /**
+   * Modifies authentication key of an authentication source for a user
+   *
+   * @throws AmbariException
+   */
+  @Transactional
+  public synchronized void modifyAuthentication(UserAuthenticationEntity userAuthenticationEntity, String currentKey, String newKey, boolean isSelf) throws AmbariException {
+
+    if (userAuthenticationEntity != null) {
+      if (userAuthenticationEntity.getAuthenticationType() == UserAuthenticationType.LOCAL) {
+        // If the authentication record represents a local password and the authenticated user is
+        // changing the password for himself, ensure the old key value matches the current key value
+        // If the authenticated user is can manager users and is not changing his own password, there
+        // is no need to check that the authenticated user knows the current password - just update it.
+        if (isSelf &&
+            (StringUtils.isEmpty(currentKey) || !passwordEncoder.matches(currentKey, userAuthenticationEntity.getAuthenticationKey()))) {
+          // The authenticated user is the same user as subject user and the correct current password
+          // was not supplied.
+          throw new AmbariException("Wrong current password provided");
+        }
+
+        validatePassword(newKey);
+
+        // If we get here the authenticated user is authorized to change the password for the subject
+        // user and the correct current password was supplied (if required).
+        userAuthenticationEntity.setAuthenticationKey(passwordEncoder.encode(newKey));
+      } else {
+        // If we get here the authenticated user is authorized to change the key for the subject.
+        userAuthenticationEntity.setAuthenticationKey(newKey);
+      }
+
+      userAuthenticationDAO.merge(userAuthenticationEntity);
+    }
+  }
+
+  public void removeAuthentication(String username, Long authenticationId) {
+    removeAuthentication(getUserEntity(username), authenticationId);
+  }
+
+  @Transactional
+  public void removeAuthentication(UserEntity userEntity, Long authenticationId) {
+    if ((userEntity != null) && (authenticationId != null)) {
+      boolean changed = false;
+
+      // Ensure we have a latest version of an attached UserEntity...
+      userEntity = userDAO.findByPK(userEntity.getUserId());
+
+      // Find the remove the specified UserAuthenticationEntity from the user's collection of
+      // UserAuthenticationEntities
+      List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+      Iterator<UserAuthenticationEntity> iterator = authenticationEntities.iterator();
+      while (iterator.hasNext()) {
+        UserAuthenticationEntity authenticationEntity = iterator.next();
+        if (authenticationId.equals(authenticationEntity.getUserAuthenticationId())) {
+          userAuthenticationDAO.remove(authenticationEntity);
+          iterator.remove();
+          changed = true;
+          break;
+        }
+      }
+
+      if (changed) {
+        // Update the UserEntity to realize the changed set of authentication sources...
+        userDAO.merge(userEntity);
+      }
+    }
+  }
+
+
+  /**
+   * Adds a new authentication type for the given user.
+   *
+   * @param userEntity         the user
+   * @param authenticationType the authentication type
+   * @param key                the relevant key
+   * @throws AmbariException
+   * @see #addLocalAuthentication(UserEntity, String)
+   * @see #addLdapAuthentication(UserEntity, String)
+   * @see #addJWTAuthentication(UserEntity, String)
+   * @see #addKerberosAuthentication(UserEntity, String)
+   * @see #addPamAuthentication(UserEntity, String)
+   */
+  public void addAuthentication(UserEntity userEntity, UserAuthenticationType authenticationType, String key) throws AmbariException {
+    switch (authenticationType) {
+      case LOCAL:
+        addLocalAuthentication(userEntity, key);
+        break;
+      case LDAP:
+        addLdapAuthentication(userEntity, key);
+        break;
+      case JWT:
+        addJWTAuthentication(userEntity, key);
+        break;
+      case PAM:
+        addPamAuthentication(userEntity, key);
+        break;
+      case KERBEROS:
+        addKerberosAuthentication(userEntity, key);
+        break;
+      default:
+        throw new AmbariException("Unexpected user authentication type");
+    }
+  }
+
+
   /**
    * TODO: This is to be revisited for AMBARI-21217 (Update JWT Authentication process to work with improved user management facility)
    * Adds the ability for a user to authenticate using a JWT token.
@@ -1172,6 +1250,8 @@ public class Users {
    */
   public void addLocalAuthentication(UserEntity userEntity, String password) throws AmbariException {
 
+    validatePassword(password);
+
     // Encode the password..
     String encodedPassword = passwordEncoder.encode(password);
 
@@ -1341,6 +1421,22 @@ public class Users {
    * Attempts to update the specified {@link UserEntity} while handling {@link OptimisticLockException}s
    * by obtaining the latest version of the {@link UserEntity} and retrying the operation.
    *
+   * If the maximum number of retries is exceeded (see {@link #MAX_RETRIES}), then the operation
+   * will fail by rethrowing the last exception encountered.
+   *
+   *
+   * @param userEntity the user entity
+   * @param command  a command to perform on the user entity object that changes it state thus needing
+   *                 to be persisted
+   */
+  public UserEntity safelyUpdateUserEntity(UserEntity userEntity, Command command) {
+    return safelyUpdateUserEntity(userEntity, command, MAX_RETRIES);
+  }
+
+  /***
+   * Attempts to update the specified {@link UserEntity} while handling {@link OptimisticLockException}s
+   * by obtaining the latest version of the {@link UserEntity} and retrying the operation.
+   *
    * If the maximum number of retries is exceeded, then the operation will fail by rethrowing the last
    * exception encountered.
    *
@@ -1348,8 +1444,9 @@ public class Users {
    * @param userEntity the user entity
    * @param command  a command to perform on the user entity object that changes it state thus needing
    *                 to be persisted
+   * @param maxRetries the maximum number of reties to peform before failing
    */
-  private UserEntity safelyUpdateUserEntity(UserEntity userEntity, Command command, int maxRetries) {
+  public UserEntity safelyUpdateUserEntity(UserEntity userEntity, Command command, int maxRetries) {
     int retriesLeft = maxRetries;
 
     do {
@@ -1361,6 +1458,7 @@ public class Users {
         return userEntity;
       } catch (Throwable t) {
         Throwable cause = t;
+        int failSafe = 50; // counter to ensure the following do/while loop does not loop indefinitely
 
         do {
           if (cause instanceof OptimisticLockException) {
@@ -1393,7 +1491,14 @@ public class Users {
             // Get the cause to see if it is an OptimisticLockException
             cause = cause.getCause();
           }
-        } while ((cause != null) && (cause != t)); // We are out of causes
+
+          // decrement the failsafe counter to ensure we do not get stuck in an infinite loop.
+          failSafe--;
+        } while ((cause != null) && (cause != t) && (failSafe > 0)); // We are out of causes
+
+        if ((cause == null) || (cause == t) || failSafe == 0) {
+          throw t;
+        }
       }
     } while (retriesLeft > 0); // We are out of retries
 
@@ -1401,6 +1506,23 @@ public class Users {
   }
 
   /**
+   * Validates the password meets configured requirements.
+   * <p>
+   * In the future this may be configurable. For now just make sure the password is not empty.
+   *
+   * @param password the password
+   * @return true if the password is valid; false otherwise
+   */
+  public boolean validatePassword(String password) throws AmbariException {
+    // TODO: validate the new password...
+    if (StringUtils.isEmpty(password)) {
+      throw new AmbariException("The new password does not meet the Ambari password requirements");
+    }
+
+    return true;
+  }
+
+  /**
    * Validator is an interface to be implemented by authentication type specific validators to ensure
    * new user authentication records meet the specific requirements for the relative authentication
    * type.
@@ -1423,7 +1545,7 @@ public class Users {
    *
    * @see #safelyUpdateUserEntity(UserEntity, Command, int)
    */
-  private interface Command {
+  public interface Command {
     void perform(UserEntity userEntity);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/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 11ca7f6..d0a7c88 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -139,17 +139,6 @@
         "Tasks/ops_display_name",
         "_"
     ],
-    "User":[
-        "Users/user_name",
-        "Users/password",
-        "Users/old_password",
-        "Users/ldap_user",
-        "Users/user_type",
-        "Users/active",
-        "Users/groups",
-        "Users/admin",
-        "_"
-    ],
     "Group":[
         "Groups/group_name",
         "Groups/ldap_group",

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/test/java/org/apache/ambari/server/api/resources/UserResourceDefinitionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/UserResourceDefinitionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/UserResourceDefinitionTest.java
index 024b118..36e5cbf 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/resources/UserResourceDefinitionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/resources/UserResourceDefinitionTest.java
@@ -18,8 +18,10 @@
 
 package org.apache.ambari.server.api.resources;
 
+import java.util.HashSet;
 import java.util.Set;
 
+import org.apache.ambari.server.controller.spi.Resource;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -41,8 +43,17 @@ public class UserResourceDefinitionTest {
 
   @Test
   public void testGetSubResourceDefinitions() throws Exception {
+    Set<Resource.Type> expectedSubResourceDefinitionTypes = new HashSet<>();
+    expectedSubResourceDefinitionTypes.add(Resource.Type.UserAuthenticationSource);
+    expectedSubResourceDefinitionTypes.add(Resource.Type.UserPrivilege);
+    expectedSubResourceDefinitionTypes.add(Resource.Type.ActiveWidgetLayout);
+
     final UserResourceDefinition userResourceDefinition = new UserResourceDefinition();
     Set<SubResourceDefinition> subResourceDefinitions = userResourceDefinition.getSubResourceDefinitions();
-    Assert.assertEquals(2, subResourceDefinitions.size());
+    Assert.assertEquals(expectedSubResourceDefinitionTypes.size(), subResourceDefinitions.size());
+
+    for(SubResourceDefinition subResourceDefinition : subResourceDefinitions) {
+      Assert.assertTrue(expectedSubResourceDefinitionTypes.contains(subResourceDefinition.getType()));
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestImplTest.java
index 3becc02..d70fed1 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestImplTest.java
@@ -199,13 +199,6 @@ public class RequestImplTest {
     request = PropertyHelper.getReadRequest(PropertyHelper.getPropertyIds(Resource.Type.User));
     validPropertyIds = request.getPropertyIds();
 
-    //User resource properties
-    Assert.assertFalse(validPropertyIds.contains("Users/unsupported_property_id"));
-    Assert.assertTrue(validPropertyIds.contains("Users/user_name"));
-    Assert.assertTrue(validPropertyIds.contains("Users/password"));
-    Assert.assertTrue(validPropertyIds.contains("Users/old_password"));
-    Assert.assertTrue(validPropertyIds.contains("Users/ldap_user"));
-
     request = PropertyHelper.getReadRequest(PropertyHelper.getPropertyIds(Resource.Type.Stack));
     validPropertyIds = request.getPropertyIds();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserAuthenticationSourceResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserAuthenticationSourceResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserAuthenticationSourceResourceProviderTest.java
new file mode 100644
index 0000000..f109c68
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserAuthenticationSourceResourceProviderTest.java
@@ -0,0 +1,448 @@
+/*
+ * 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 static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.predicate.AndPredicate;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.hooks.HookContextFactory;
+import org.apache.ambari.server.hooks.HookService;
+import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.TestAuthenticationFactory;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
+import org.apache.ambari.server.security.authorization.UserIdAuthentication;
+import org.apache.ambari.server.security.authorization.Users;
+import org.apache.ambari.server.stack.StackManagerFactory;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.easymock.EasyMockSupport;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * UserAuthenticationSourceResourceProviderTest tests.
+ */
+public class UserAuthenticationSourceResourceProviderTest extends EasyMockSupport {
+
+  private static final Date CREATE_TIME = Calendar.getInstance().getTime();
+  private static final Date UPDATE_TIME = Calendar.getInstance().getTime();
+
+  @Before
+  public void resetMocks() {
+    resetAll();
+  }
+
+  @After
+  public void clearAuthentication() {
+    SecurityContextHolder.getContext().setAuthentication(null);
+  }
+
+  @Test
+  public void testCreateResources_Administrator() throws Exception {
+    createResourcesTest(TestAuthenticationFactory.createAdministrator("admin"));
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResources_NonAdministrator() throws Exception {
+    createResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L));
+  }
+
+  @Test
+  public void testGetResources_Administrator() throws Exception {
+    getResourcesTest(TestAuthenticationFactory.createAdministrator("admin"));
+  }
+
+  @Test
+  public void testGetResources_NonAdministrator() throws Exception {
+    getResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L));
+  }
+
+  @Test
+  public void testGetResource_Administrator_Self() throws Exception {
+    getResourceTest(TestAuthenticationFactory.createAdministrator("admin"), "admin");
+  }
+
+  @Test
+  public void testGetResource_Administrator_Other() throws Exception {
+    getResourceTest(TestAuthenticationFactory.createAdministrator("admin"), "User1");
+  }
+
+  @Test
+  public void testGetResource_NonAdministrator_Self() throws Exception {
+    getResourceTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testGetResource_NonAdministrator_Other() throws Exception {
+    getResourceTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+  }
+
+  @Test
+  public void testUpdateResources_SetPassword_Administrator_Self() throws Exception {
+    updateResources_SetAuthenticationKey(TestAuthenticationFactory.createAdministrator("admin"), "User100", null);
+  }
+
+  @Test
+  public void testUpdateResources_SetPassword_Administrator_Other() throws Exception {
+    updateResources_SetAuthenticationKey(TestAuthenticationFactory.createAdministrator("admin"), "User100", null);
+  }
+
+  @Test
+  public void testUpdateResources_SetPassword_NonAdministrator_Self() throws Exception {
+    updateResources_SetAuthenticationKey(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1", null);
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_SetPassword_NonAdministrator_Other() throws Exception {
+    updateResources_SetAuthenticationKey(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100", null);
+  }
+
+  @Test
+  public void testUpdateResources_SetPassword_VerifyLocal_Success() throws Exception {
+    updateResources_SetAuthenticationKey(TestAuthenticationFactory.createAdministrator(), "User100", "local");
+  }
+
+  @Test(expected = ResourceNotFoundException.class)
+  public void testUpdateResources_SetPassword_VerifyLocal_Fail() throws Exception {
+    updateResources_SetAuthenticationKey(TestAuthenticationFactory.createAdministrator(), "User100", "KERBEROS");
+  }
+
+  @Test
+  public void testDeleteResource_Administrator_Self() throws Exception {
+    deleteResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), "admin");
+  }
+
+  @Test
+  public void testDeleteResource_Administrator_Other() throws Exception {
+    deleteResourcesTest(TestAuthenticationFactory.createAdministrator("admin"), "User100");
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testDeleteResource_NonAdministrator_Self() throws Exception {
+    deleteResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User1");
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testDeleteResource_NonAdministrator_Other() throws Exception {
+    deleteResourcesTest(TestAuthenticationFactory.createClusterAdministrator("User1", 2L), "User100");
+  }
+
+  private Injector createInjector() throws Exception {
+    return Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
+        bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class));
+        bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
+        bind(AmbariMetaInfo.class).toInstance(createMock(AmbariMetaInfo.class));
+        bind(Clusters.class).toInstance(createNiceMock(Clusters.class));
+        bind(StackManagerFactory.class).toInstance(createNiceMock(StackManagerFactory.class));
+        bind(PasswordEncoder.class).toInstance(createNiceMock(PasswordEncoder.class));
+        bind(Users.class).toInstance(createMock(Users.class));
+        bind(HookService.class).toInstance(createMock(HookService.class));
+        bind(HookContextFactory.class).toInstance(createMock(HookContextFactory.class));
+      }
+    });
+  }
+
+
+  private void createResourcesTest(Authentication authentication) throws Exception {
+    Injector injector = createInjector();
+
+    UserEntity userEntity100 = createNiceMock(UserEntity.class);
+    UserEntity userEntity200 = createNiceMock(UserEntity.class);
+
+    Users users = injector.getInstance(Users.class);
+    expect(users.getUserEntity("User100")).andReturn(userEntity100).once();
+    expect(users.getUserEntity("User200")).andReturn(userEntity200).once();
+    users.addAuthentication(userEntity100, UserAuthenticationType.LOCAL, "my_password_100_1234");
+    expectLastCall().once();
+    users.addAuthentication(userEntity200, UserAuthenticationType.LOCAL, "my_password_200_1234");
+    expectLastCall().once();
+
+    // replay
+    replayAll();
+
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
+    ambariMetaInfo.init();
+
+    ResourceProvider provider = getResourceProvider(injector);
+
+    // add the property map to a set for the request.  add more maps for multiple creates
+    Set<Map<String, Object>> propertySet = new LinkedHashSet<>();
+
+    Map<String, Object> properties;
+
+    properties = new LinkedHashMap<>();
+    properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID, "User100");
+    properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID, "local");
+    properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID, "my_password_100_1234");
+    propertySet.add(properties);
+
+    properties = new LinkedHashMap<>();
+    properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID, "User200");
+    properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID, "local");
+    properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID, "my_password_200_1234");
+    propertySet.add(properties);
+
+    // create the request
+    Request request = PropertyHelper.getCreateRequest(propertySet, null);
+
+    provider.createResources(request);
+
+    // verify
+    verifyAll();
+  }
+
+  private void getResourcesTest(Authentication authentication) throws Exception {
+    Injector injector = createInjector();
+
+    Users users = injector.getInstance(Users.class);
+    Map<String, UserAuthenticationEntity> entities = new HashMap<>();
+
+    entities.put("User1", createMockUserAuthenticationEntity("User1"));
+
+    if ("admin".equals(authentication.getName())) {
+      entities.put("User10", createMockUserAuthenticationEntity("User10"));
+      entities.put("User100", createMockUserAuthenticationEntity("User100"));
+      entities.put("admin", createMockUserAuthenticationEntity("admin"));
+
+      expect(users.getUserAuthenticationEntities(null, null)).andReturn(entities.values()).once();
+    } else {
+      expect(users.getUserAuthenticationEntities("User1", null)).andReturn(entities.values()).once();
+    }
+
+    replayAll();
+
+    AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
+    ambariMetaInfo.init();
+
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    ResourceProvider provider = getResourceProvider(injector);
+
+    Set<String> propertyIds = new HashSet<>();
+    propertyIds.add(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID);
+    propertyIds.add(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID);
+    propertyIds.add(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID);
+    propertyIds.add(UserAuthenticationSourceResourceProvider.AUTHENTICATION_CREATED_PROPERTY_ID);
+    propertyIds.add(UserAuthenticationSourceResourceProvider.AUTHENTICATION_UPDATED_PROPERTY_ID);
+
+    Request request = PropertyHelper.getReadRequest(propertyIds);
+
+    Set<Resource> resources = provider.getResources(request, null);
+
+    Assert.assertEquals(entities.size(), resources.size());
+    for (Resource resource : resources) {
+      String userName = (String) resource.getPropertyValue(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID);
+      Assert.assertTrue(entities.containsKey(userName));
+
+      // This value should never come back...
+      Assert.assertNull(resource.getPropertyValue(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID));
+    }
+
+    verifyAll();
+  }
+
+  private void getResourceTest(Authentication authentication, String requestedUsername) throws Exception {
+    Injector injector = createInjector();
+
+    List<UserAuthenticationEntity> entities = new ArrayList<>();
+    entities.add(createMockUserAuthenticationEntity(requestedUsername));
+
+    Users users = injector.getInstance(Users.class);
+    expect(users.getUserAuthenticationEntities(requestedUsername, null)).andReturn(entities).once();
+
+    replayAll();
+
+    AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
+    ambariMetaInfo.init();
+
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    ResourceProvider provider = getResourceProvider(injector);
+
+    Set<String> propertyIds = new HashSet<>();
+    propertyIds.add(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID);
+    propertyIds.add(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID);
+
+    Request request = PropertyHelper.getReadRequest(propertyIds);
+
+    Set<Resource> resources = provider.getResources(request, createPredicate(requestedUsername, null));
+
+    Assert.assertEquals(1, resources.size());
+    for (Resource resource : resources) {
+      String userName = (String) resource.getPropertyValue(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID);
+      Assert.assertEquals(requestedUsername, userName);
+
+      // This value should never come back...
+      Assert.assertNull(resource.getPropertyValue(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID));
+    }
+
+    verifyAll();
+  }
+
+  private void updateResources_SetAuthenticationKey(Authentication authentication, String requestedUsername, String authenticationType) throws Exception {
+    Injector injector = createInjector();
+
+    UserAuthenticationEntity userAuthenticationEntity = createMockUserAuthenticationEntity(requestedUsername);
+
+    boolean isSelf = authentication.getName().equalsIgnoreCase(requestedUsername);
+
+    List<UserAuthenticationEntity> userAuthenticationEntities = new ArrayList<>();
+    userAuthenticationEntities.add(userAuthenticationEntity);
+
+    UserEntity userEntity = createMock(UserEntity.class);
+    expect(userEntity.getAuthenticationEntities()).andReturn(userAuthenticationEntities).once();
+    if (isSelf) {
+      expect(userEntity.getUserId()).andReturn(((UserIdAuthentication) authentication).getUserId()).once();
+    } else {
+      expect(userEntity.getUserId()).andReturn(AuthorizationHelper.getAuthenticatedId() + 100).once();
+    }
+
+    Users users = injector.getInstance(Users.class);
+    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
+    users.modifyAuthentication(userAuthenticationEntity, "old_password", "new_password", isSelf);
+    expectLastCall().once();
+
+    replayAll();
+
+    AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
+    ambariMetaInfo.init();
+
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    ResourceProvider provider = getResourceProvider(injector);
+
+    // add the property map to a set for the request.
+    Map<String, Object> properties = new LinkedHashMap<>();
+    properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_OLD_KEY_PROPERTY_ID, "old_password");
+    properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID, "new_password");
+
+    if(authenticationType != null) {
+      properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID, authenticationType);
+    }
+
+    // create the request
+    Request request = PropertyHelper.getUpdateRequest(properties, null);
+
+    provider.updateResources(request, createPredicate(requestedUsername, userAuthenticationEntity.getUserAuthenticationId()));
+
+    verifyAll();
+  }
+
+  private void deleteResourcesTest(Authentication authentication, String requestedUsername) throws Exception {
+    Injector injector = createInjector();
+
+    Users users = injector.getInstance(Users.class);
+    users.removeAuthentication(requestedUsername, 1L);
+    expectLastCall().atLeastOnce();
+
+    // replay
+    replayAll();
+
+    AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
+    ambariMetaInfo.init();
+
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    ResourceProvider provider = getResourceProvider(injector);
+
+    provider.deleteResources(new RequestImpl(null, null, null, null), createPredicate(requestedUsername, 1L));
+
+    // verify
+    verifyAll();
+  }
+
+
+  private Predicate createPredicate(String requestedUsername, Long sourceId) {
+    Predicate predicate1 = new PredicateBuilder()
+        .property(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID)
+        .equals(requestedUsername)
+        .toPredicate();
+
+    if (sourceId == null) {
+      return predicate1;
+    } else {
+      Predicate predicate2 = new PredicateBuilder()
+          .property(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID)
+          .equals(sourceId.toString())
+          .toPredicate();
+      return new AndPredicate(predicate1, predicate2);
+    }
+  }
+
+  private UserAuthenticationEntity createMockUserAuthenticationEntity(String username) {
+    UserAuthenticationEntity entity = createMock(UserAuthenticationEntity.class);
+    UserEntity userEntity = createMock(UserEntity.class);
+    expect(entity.getAuthenticationType()).andReturn(UserAuthenticationType.LOCAL).anyTimes();
+    expect(entity.getAuthenticationKey()).andReturn("this is a secret").anyTimes();
+    expect(entity.getCreateTime()).andReturn(CREATE_TIME).anyTimes();
+    expect(entity.getUpdateTime()).andReturn(UPDATE_TIME).anyTimes();
+    expect(entity.getUserAuthenticationId()).andReturn(100L).anyTimes();
+    expect(entity.getUser()).andReturn(userEntity).anyTimes();
+
+    expect(userEntity.getUserName()).andReturn(username).anyTimes();
+    return entity;
+  }
+
+  private ResourceProvider getResourceProvider(Injector injector) {
+    UserAuthenticationSourceResourceProvider resourceProvider = new UserAuthenticationSourceResourceProvider();
+
+    injector.injectMembers(resourceProvider);
+    return resourceProvider;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderDBTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderDBTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderDBTest.java
index db7548f..6c20eb0 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderDBTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserResourceProviderDBTest.java
@@ -18,9 +18,12 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import static org.easymock.EasyMock.expect;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.powermock.api.easymock.PowerMock.createMock;
+import static org.powermock.api.easymock.PowerMock.replay;
 
 import java.sql.SQLException;
 import java.util.ArrayList;
@@ -37,6 +40,7 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.H2DatabaseCleaner;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ResourceProviderFactory;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.RequestStatus;
@@ -68,6 +72,7 @@ public class UserResourceProviderDBTest {
   private static AmbariManagementController amc;
   private static Resource.Type userType = Resource.Type.User;
   private static UserResourceProvider userResourceProvider;
+  private static UserAuthenticationSourceResourceProvider userAuthenticationSourceResourceProvider;
   private static String JDBC_IN_MEMORY_URL_CREATE =
       String.format("jdbc:derby:memory:myDB/%s;create=true", Configuration.DEFAULT_DERBY_SCHEMA);
   private static String JDBC_IN_MEMORY_URL_DROP =
@@ -89,11 +94,18 @@ public class UserResourceProviderDBTest {
 
     amc = injector.getInstance(AmbariManagementController.class);
 
-    Set<String> propertyIds = PropertyHelper.getPropertyIds(userType);
-    Map<Resource.Type, String> keyPropertyIds = PropertyHelper.getKeyPropertyIds(userType);
-
-    userResourceProvider = new UserResourceProvider(propertyIds, keyPropertyIds, amc);
+    userResourceProvider = new UserResourceProvider(amc);
     injector.injectMembers(userResourceProvider);
+
+    userAuthenticationSourceResourceProvider = new UserAuthenticationSourceResourceProvider();
+    injector.injectMembers(userAuthenticationSourceResourceProvider);
+
+
+    ResourceProviderFactory factory = createMock(ResourceProviderFactory.class);
+    expect(factory.getUserAuthenticationSourceResourceProvider()).andReturn(userAuthenticationSourceResourceProvider).anyTimes();
+    replay(factory);
+    AbstractControllerResourceProvider.init(factory);
+
   }
 
   /**
@@ -177,7 +189,7 @@ public class UserResourceProviderDBTest {
       requestStatus = userResourceProvider.createResources(request);
       assertTrue("Should fail with user exists", false);
     } catch (Exception ex) {
-      assertTrue(ex.getMessage().contains("User already exists"));
+      assertTrue(ex.getMessage().contains("already exists"));
     }
 
     // delete the created username


[3/6] ambari git commit: AMBARI-20861. BE: Extend Ambari REST API to Support User Account Management Improvements (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
index d24780b..d9b8577 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
@@ -49,46 +49,46 @@ import org.slf4j.LoggerFactory;
 public abstract class BaseService {
   public final static MediaType MEDIA_TYPE_TEXT_CSV_TYPE = new MediaType("text", "csv");
 
-  static final String MSG_SUCCESSFUL_OPERATION = "Successful operation";
-  static final String MSG_REQUEST_ACCEPTED = "Request is accepted, but not completely processed yet";
-  static final String MSG_INVALID_ARGUMENTS = "Invalid arguments";
-  static final String MSG_INVALID_REQUEST = "Invalid request";
-  static final String MSG_CLUSTER_NOT_FOUND = "Cluster not found";
-  static final String MSG_CLUSTER_OR_HOST_NOT_FOUND = "Cluster or host not found";
-  static final String MSG_NOT_AUTHENTICATED = "Not authenticated";
-  static final String MSG_PERMISSION_DENIED = "Not permitted to perform the operation";
-  static final String MSG_SERVER_ERROR = "Internal server error";
-  static final String MSG_RESOURCE_ALREADY_EXISTS = "The requested resource already exists.";
-  static final String MSG_RESOURCE_NOT_FOUND = "The requested resource doesn't exist.";
-
-  static final String QUERY_FIELDS = "fields";
-  static final String QUERY_FILTER_DESCRIPTION = "Filter fields in the response (identifier fields are mandatory)";
-  static final String QUERY_SORT = "sortBy";
-  static final String QUERY_SORT_DESCRIPTION = "Sort resources in result by (asc | desc)";
-  static final String QUERY_PAGE_SIZE = "page_size";
-  static final String QUERY_PAGE_SIZE_DESCRIPTION = "The number of resources to be returned for the paged response.";
-  static final String DEFAULT_PAGE_SIZE = "10";
-  static final String QUERY_FROM = "from";
-  static final String QUERY_FROM_DESCRIPTION = "The starting page resource (inclusive).  \"start\" is also accepted.";
-  static final String QUERY_FROM_VALUES = "range[0, infinity]";
-  static final String DEFAULT_FROM = "0";
-  static final String QUERY_TO = "to";
-  static final String QUERY_TO_DESCRIPTION = "The ending page resource (inclusive).  \"end\" is also accepted.";
-  static final String QUERY_TO_TYPE = "integer";
-  static final String QUERY_TO_VALUES = "range[1, infinity]";
-  static final String QUERY_PREDICATE = "{predicate}";
-  static final String QUERY_PREDICATE_DESCRIPTION = "The predicate to filter resources by. Omitting the predicate will " +
+  public static final String MSG_SUCCESSFUL_OPERATION = "Successful operation";
+  public static final String MSG_REQUEST_ACCEPTED = "Request is accepted, but not completely processed yet";
+  public static final String MSG_INVALID_ARGUMENTS = "Invalid arguments";
+  public static final String MSG_INVALID_REQUEST = "Invalid request";
+  public static final String MSG_CLUSTER_NOT_FOUND = "Cluster not found";
+  public static final String MSG_CLUSTER_OR_HOST_NOT_FOUND = "Cluster or host not found";
+  public static final String MSG_NOT_AUTHENTICATED = "Not authenticated";
+  public static final String MSG_PERMISSION_DENIED = "Not permitted to perform the operation";
+  public static final String MSG_SERVER_ERROR = "Internal server error";
+  public static final String MSG_RESOURCE_ALREADY_EXISTS = "The requested resource already exists.";
+  public static final String MSG_RESOURCE_NOT_FOUND = "The requested resource doesn't exist.";
+
+  public static final String QUERY_FIELDS = "fields";
+  public static final String QUERY_FILTER_DESCRIPTION = "Filter fields in the response (identifier fields are mandatory)";
+  public static final String QUERY_SORT = "sortBy";
+  public static final String QUERY_SORT_DESCRIPTION = "Sort resources in result by (asc | desc)";
+  public static final String QUERY_PAGE_SIZE = "page_size";
+  public static final String QUERY_PAGE_SIZE_DESCRIPTION = "The number of resources to be returned for the paged response.";
+  public static final String DEFAULT_PAGE_SIZE = "10";
+  public static final String QUERY_FROM = "from";
+  public static final String QUERY_FROM_DESCRIPTION = "The starting page resource (inclusive).  \"start\" is also accepted.";
+  public static final String QUERY_FROM_VALUES = "range[0, infinity]";
+  public static final String DEFAULT_FROM = "0";
+  public static final String QUERY_TO = "to";
+  public static final String QUERY_TO_DESCRIPTION = "The ending page resource (inclusive).  \"end\" is also accepted.";
+  public static final String QUERY_TO_TYPE = "integer";
+  public static final String QUERY_TO_VALUES = "range[1, infinity]";
+  public static final String QUERY_PREDICATE = "{predicate}";
+  public static final String QUERY_PREDICATE_DESCRIPTION = "The predicate to filter resources by. Omitting the predicate will " +
       "match all resources.";
 
-  static final String RESPONSE_CONTAINER_LIST = "List";
+  public static final String RESPONSE_CONTAINER_LIST = "List";
 
-  static final String DATA_TYPE_INT = "integer";
-  static final String DATA_TYPE_STRING = "string";
+  public static final String DATA_TYPE_INT = "integer";
+  public static final String DATA_TYPE_STRING = "string";
 
-  static final String PARAM_TYPE_QUERY = "query";
-  static final String PARAM_TYPE_BODY = "body";
+  public static final String PARAM_TYPE_QUERY = "query";
+  public static final String PARAM_TYPE_BODY = "body";
 
-  static final String FIELDS_SEPARATOR = ", ";
+  public static final String FIELDS_SEPARATOR = ", ";
 
   /**
    * Logger instance.

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserAuthenticationSourceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserAuthenticationSourceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserAuthenticationSourceService.java
new file mode 100644
index 0000000..8600bbf
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserAuthenticationSourceService.java
@@ -0,0 +1,223 @@
+/*
+ * 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.users;
+
+import static org.apache.ambari.server.controller.internal.UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID;
+import static org.apache.ambari.server.controller.internal.UserAuthenticationSourceResourceProvider.AUTHENTICATION_SOURCE_RESOURCE_CATEGORY;
+import static org.apache.ambari.server.controller.internal.UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+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.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.UserAuthenticationSourceResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpStatus;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * Service responsible for user authentication source resource requests.
+ */
+@Path("/users/{userName}/sources")
+@Api(value = "User Authentication Sources", description = "Endpoint for user specific authentication source operations")
+public class UserAuthenticationSourceService extends BaseService {
+
+  private static final String CREATE_REQUEST_TYPE = "org.apache.ambari.server.controller.UserAuthenticationSourceRequestCreateSwagger";
+  private static final String UPDATE_REQUEST_TYPE = "org.apache.ambari.server.controller.UserAuthenticationSourceRequestUpdateSwagger";
+  private static final String AUTHENTICATION_SOURCE_DEFAULT_SORT = AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID + ".asc";
+
+  /**
+   * Handles: GET  /users/{userName}/sources
+   * Get all authentication sources for the user.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param userName user name
+   * @return user resource instance representation
+   */
+  @GET
+  @Produces("text/plain")
+  @ApiOperation(value = "Get all authentication sources", response = UserAuthenticationSourceResponse.UserAuthenticationSourceResponseSwagger.class, responseContainer = "List")
+  @ApiImplicitParams({
+      @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY, defaultValue = AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID + "," + AUTHENTICATION_USER_NAME_PROPERTY_ID),
+      @ApiImplicitParam(name = QUERY_SORT, value = QUERY_SORT_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY, defaultValue = AUTHENTICATION_SOURCE_DEFAULT_SORT),
+      @ApiImplicitParam(name = QUERY_PAGE_SIZE, value = QUERY_PAGE_SIZE_DESCRIPTION, defaultValue = DEFAULT_PAGE_SIZE, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+      @ApiImplicitParam(name = QUERY_FROM, value = QUERY_FROM_DESCRIPTION, allowableValues = QUERY_FROM_VALUES, defaultValue = DEFAULT_FROM, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+      @ApiImplicitParam(name = QUERY_TO, value = QUERY_TO_DESCRIPTION, allowableValues = QUERY_TO_VALUES, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
+  })
+  public Response getAuthenticationSources(@Context HttpHeaders headers, @Context UriInfo ui,
+                                           @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createResource(userName, null));
+  }
+
+  /**
+   * Handles: GET /users/{userName}/sources/{sourceID}
+   * Get a specific authentication source.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param userName user name
+   * @param sourceId authentication source id
+   * @return authentication source instance representation
+   */
+  @GET
+  @Path("{sourceId}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Get user authentication source", response = UserAuthenticationSourceResponse.UserAuthenticationSourceResponseSwagger.class)
+  @ApiImplicitParams({
+      @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY, defaultValue = AUTHENTICATION_SOURCE_RESOURCE_CATEGORY + "/*"),
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
+  })
+  public Response getAuthenticationSource(@Context HttpHeaders headers, @Context UriInfo ui,
+                                          @ApiParam(value = "user name", required = true) @PathParam("userName") String userName,
+                                          @ApiParam(value = "source id", required = true) @PathParam("sourceId") String sourceId) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createResource(userName, sourceId));
+  }
+
+  /**
+   * Creates an authentication source.
+   * Handles: POST /users/{userName}/sources
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param userName user name
+   * @return information regarding the created user
+   */
+  @POST
+  @Produces("text/plain")
+  @ApiOperation(value = "Create one or more new authentication sources for a user")
+  @ApiImplicitParams({
+      @ApiImplicitParam(dataType = CREATE_REQUEST_TYPE, paramType = PARAM_TYPE_BODY, allowMultiple = true)
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_CREATED, message = MSG_SUCCESSFUL_OPERATION),
+      @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED),
+      @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_CONFLICT, message = MSG_RESOURCE_ALREADY_EXISTS),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
+  })
+  public Response createAuthenticationSources(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                              @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
+    return handleRequest(headers, body, ui, Request.Type.POST, createResource(userName, null));
+  }
+
+  /**
+   * Creates an authentication source.
+   * Handles: PUT /users/{userName}/sources/{sourceId}
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param userName user name
+   * @param sourceId authentication source id
+   * @return information regarding the created user
+   */
+  @PUT
+  @Path("{sourceId}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Updates an existing authentication source")
+  @ApiImplicitParams({
+      @ApiImplicitParam(dataType = UPDATE_REQUEST_TYPE, paramType = PARAM_TYPE_BODY)
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED),
+      @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_CONFLICT, message = MSG_RESOURCE_ALREADY_EXISTS),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
+  })
+  public Response updateAuthenticationSource(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                             @ApiParam(value = "user name", required = true) @PathParam("userName") String userName,
+                                             @ApiParam(value = "source id", required = true) @PathParam("sourceId") String sourceId) {
+    return handleRequest(headers, body, ui, Request.Type.PUT, createResource(userName, sourceId));
+  }
+
+  /**
+   * Delete an authentication source.
+   * Handles: DELETE /users/{userName}/sources/{sourceId}
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param userName user name
+   * @param sourceId authentication source id
+   * @return information regarding the created user
+   */
+  @DELETE
+  @Path("{sourceId}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Deletes an existing authentication source")
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
+  })
+  public Response deleteAuthenticationSource(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                             @ApiParam(value = "user name", required = true) @PathParam("userName") String userName,
+                                             @ApiParam(value = "source id", required = true) @PathParam("sourceId") String sourceId) {
+    return handleRequest(headers, body, ui, Request.Type.DELETE, createResource(userName, sourceId));
+  }
+
+  protected ResourceInstance createResource(String userName, String sourceId) {
+    final Map<Resource.Type, String> mapIds = new HashMap<>();
+    mapIds.put(Resource.Type.User, StringUtils.lowerCase(userName));
+    mapIds.put(Resource.Type.UserAuthenticationSource, sourceId);
+    return createResource(Resource.Type.UserAuthenticationSource, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java
index a69ed4e..4eb8587 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java
@@ -17,6 +17,9 @@
  */
 package org.apache.ambari.server.api.services.users;
 
+import static org.apache.ambari.server.controller.internal.UserResourceProvider.USER_RESOURCE_CATEGORY;
+import static org.apache.ambari.server.controller.internal.UserResourceProvider.USER_USERNAME_PROPERTY_ID;
+
 import java.util.Collections;
 
 import javax.ws.rs.DELETE;
@@ -31,12 +34,12 @@ import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
-import org.apache.ambari.annotations.ApiIgnore;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.BaseService;
 import org.apache.ambari.server.api.services.Request;
 import org.apache.ambari.server.controller.UserResponse;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.http.HttpStatus;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
@@ -53,23 +56,32 @@ import io.swagger.annotations.ApiResponses;
 @Api(value = "Users", description = "Endpoint for user specific operations")
 public class UserService extends BaseService {
 
+  private static final String UPDATE_USER_REQUEST_TYPE = "org.apache.ambari.server.controller.UserRequestUpdateUserSwagger";
+  private static final String CREATE_USER_REQUEST_TYPE = "org.apache.ambari.server.controller.UserRequestCreateUserSwagger";
+  private static final String CREATE_USERS_REQUEST_TYPE = "org.apache.ambari.server.controller.UserRequestCreateUsersSwagger";;
+  private static final String USER_DEFAULT_SORT = USER_USERNAME_PROPERTY_ID + ".asc";
+
   /**
    * Gets all users.
    * Handles: GET /users requests.
    */
   @GET
   @Produces("text/plain")
-  @ApiOperation(value = "Get all users", nickname = "UserService#getUsers", notes = "Returns details of all users.", response = UserResponse.class, responseContainer = "List")
+  @ApiOperation(value = "Get all users", response = UserResponse.UserResponseSwagger.class, responseContainer = "List")
   @ApiImplicitParams({
-    @ApiImplicitParam(name = "fields", value = "Filter user details", defaultValue = "Users/*", dataType = "string", paramType = "query"),
-    @ApiImplicitParam(name = "sortBy", value = "Sort users (asc | desc)", defaultValue = "Users/user_name.asc", dataType = "string", paramType = "query"),
-    @ApiImplicitParam(name = "page_size", value = "The number of resources to be returned for the paged response.", defaultValue = "10", dataType = "integer", paramType = "query"),
-    @ApiImplicitParam(name = "from", value = "The starting page resource (inclusive). Valid values are :offset | \"start\"", defaultValue = "0", dataType = "string", paramType = "query"),
-    @ApiImplicitParam(name = "to", value = "The ending page resource (inclusive). Valid values are :offset | \"end\"", dataType = "string", paramType = "query")
+      @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY, defaultValue = USER_USERNAME_PROPERTY_ID),
+      @ApiImplicitParam(name = QUERY_SORT, value = QUERY_SORT_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY, defaultValue = USER_DEFAULT_SORT),
+      @ApiImplicitParam(name = QUERY_PAGE_SIZE, value = QUERY_PAGE_SIZE_DESCRIPTION, defaultValue = DEFAULT_PAGE_SIZE, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+      @ApiImplicitParam(name = QUERY_FROM, value = QUERY_FROM_DESCRIPTION, allowableValues = QUERY_FROM_VALUES, defaultValue = DEFAULT_FROM, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+      @ApiImplicitParam(name = QUERY_TO, value = QUERY_TO_DESCRIPTION, allowableValues = QUERY_TO_VALUES, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
   })
-  @ApiResponses(value = {
-    @ApiResponse(code = 200, message = "Successful operation", response = UserResponse.class, responseContainer = "List")}
-  )
   public Response getUsers(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
     return handleRequest(headers, body, ui, Request.Type.GET, createUserResource(null));
   }
@@ -78,23 +90,27 @@ public class UserService extends BaseService {
    * Gets a single user.
    * Handles: GET /users/{username} requests
    *
-   * @param headers     http headers
-   * @param ui          uri info
-   * @param userName    the username
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param userName the username
    * @return information regarding the created user
    */
   @GET
   @Path("{userName}")
   @Produces("text/plain")
-  @ApiOperation(value = "Get single user", nickname = "UserService#getUser", notes = "Returns user details.", response = UserResponse.class)
+  @ApiOperation(value = "Get single user", response = UserResponse.UserResponseSwagger.class)
   @ApiImplicitParams({
-    @ApiImplicitParam(name = "fields", value = "Filter user details", defaultValue = "Users", dataType = "string", paramType = "query")
+      @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY, defaultValue = USER_RESOURCE_CATEGORY + "/*"),
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
   })
-  @ApiResponses(value = {
-    @ApiResponse(code = 200, message = "Successful operation", response = UserResponse.class)}
-  )
   public Response getUser(String body, @Context HttpHeaders headers, @Context UriInfo ui,
-                          @ApiParam(value = "user name", required = true, defaultValue = "admin") @PathParam("userName") String userName) {
+                          @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
     return handleRequest(headers, body, ui, Request.Type.GET, createUserResource(userName));
   }
 
@@ -102,13 +118,27 @@ public class UserService extends BaseService {
    * Creates a user.
    * Handles: POST /users
    *
-   * @param headers     http headers
-   * @param ui          uri info
+   * @param headers http headers
+   * @param ui      uri info
    * @return information regarding the created user
    */
-  @POST @ApiIgnore // until documented
+  @POST
   @Produces("text/plain")
-  public Response createUser(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+  @ApiOperation(value = "Creates one or more users in a single request")
+  @ApiImplicitParams({
+      @ApiImplicitParam(dataType = CREATE_USERS_REQUEST_TYPE, paramType = PARAM_TYPE_BODY, allowMultiple = true)
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_CREATED, message = MSG_SUCCESSFUL_OPERATION),
+      @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED),
+      @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_CONFLICT, message = MSG_RESOURCE_ALREADY_EXISTS),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
+  })
+  public Response createUsers(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
     return handleRequest(headers, body, ui, Request.Type.POST, createUserResource(null));
   }
 
@@ -116,22 +146,28 @@ public class UserService extends BaseService {
    * Creates a user.
    * Handles: POST /users/{username}
    *
-   * @param headers     http headers
-   * @param ui          uri info
-   * @param userName    the username
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param userName the username
    * @return information regarding the created user
    */
   @POST
   @Path("{userName}")
   @Produces("text/plain")
-  @ApiOperation(value = "Create new user", nickname = "UserService#createUser", notes = "Creates user resource.")
+  @ApiOperation(value = "Create new user")
   @ApiImplicitParams({
-    @ApiImplicitParam(name = "body", value = "input parameters in json form", required = true, dataType = "org.apache.ambari.server.controller.UserRequest", paramType = "body")
+      @ApiImplicitParam(dataType = CREATE_USER_REQUEST_TYPE, paramType = PARAM_TYPE_BODY)
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_CREATED, message = MSG_SUCCESSFUL_OPERATION),
+      @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED),
+      @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_CONFLICT, message = MSG_RESOURCE_ALREADY_EXISTS),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
   })
-  @ApiResponses(value = {
-    @ApiResponse(code = 200, message = "Successful operation"),
-    @ApiResponse(code = 500, message = "Server Error")}
-  )
   public Response createUser(String body, @Context HttpHeaders headers, @Context UriInfo ui,
                              @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
     return handleRequest(headers, body, ui, Request.Type.POST, createUserResource(userName));
@@ -141,22 +177,27 @@ public class UserService extends BaseService {
    * Updates a specific user.
    * Handles: PUT /users/{userName}
    *
-   * @param headers     http headers
-   * @param ui          uri info
-   * @param userName   the username
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param userName the username
    * @return information regarding the updated user
    */
   @PUT
   @Path("{userName}")
   @Produces("text/plain")
-  @ApiOperation(value = "Update user detail", nickname = "UserService#updateUser", notes = "Updates user resource.")
+  @ApiOperation(value = "Update user details")
   @ApiImplicitParams({
-    @ApiImplicitParam(name = "body", value = "input parameters in json form", required = true, dataType = "org.apache.ambari.server.controller.UserRequest", paramType = "body")
+      @ApiImplicitParam(dataType = UPDATE_USER_REQUEST_TYPE, paramType = PARAM_TYPE_BODY)
+  })
+  @ApiResponses({
+      @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED),
+      @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS),
+      @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+      @ApiResponse(code = HttpStatus.SC_CONFLICT, message = MSG_RESOURCE_ALREADY_EXISTS),
+      @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+      @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+      @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
   })
-  @ApiResponses(value = {
-    @ApiResponse(code = 200, message = "Successful operation"),
-    @ApiResponse(code = 500, message = "Server Error")}
-  )
   public Response updateUser(String body, @Context HttpHeaders headers, @Context UriInfo ui,
                              @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
 
@@ -170,10 +211,10 @@ public class UserService extends BaseService {
   @DELETE
   @Path("{userName}")
   @Produces("text/plain")
-  @ApiOperation(value = "Delete single user", nickname = "UserService#deleteUser", notes = "Delete user resource.")
+  @ApiOperation(value = "Delete single user")
   @ApiResponses(value = {
-    @ApiResponse(code = 200, message = "Successful operation"),
-    @ApiResponse(code = 500, message = "Server Error")}
+      @ApiResponse(code = 200, message = "Successful operation"),
+      @ApiResponse(code = 500, message = "Server Error")}
   )
   public Response deleteUser(@Context HttpHeaders headers, @Context UriInfo ui,
                              @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
@@ -183,8 +224,7 @@ public class UserService extends BaseService {
   /**
    * Create a user resource instance.
    *
-   * @param userName  user name
-   *
+   * @param userName user name
    * @return a user resource instance
    */
   private ResourceInstance createUserResource(String userName) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 25d12c7..f2fba6c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -72,6 +72,7 @@ import org.apache.ambari.server.controller.internal.MemberResourceProvider;
 import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
 import org.apache.ambari.server.controller.internal.UpgradeResourceProvider;
+import org.apache.ambari.server.controller.internal.UserAuthenticationSourceResourceProvider;
 import org.apache.ambari.server.controller.internal.UserResourceProvider;
 import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactory;
 import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactoryImpl;
@@ -466,6 +467,7 @@ public class ControllerModule extends AbstractModule {
         .implement(ResourceProvider.class, Names.named("repositoryVersion"), RepositoryVersionResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("hostKerberosIdentity"), HostKerberosIdentityResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("user"), UserResourceProvider.class)
+        .implement(ResourceProvider.class, Names.named("userAuthenticationSource"), UserAuthenticationSourceResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("credential"), CredentialResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("kerberosDescriptor"), KerberosDescriptorResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("upgrade"), UpgradeResourceProvider.class)

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
index 2454bf7..d5bebf0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
@@ -52,9 +52,10 @@ public interface ResourceProviderFactory {
       AmbariManagementController managementController);
 
   @Named("user")
-  ResourceProvider getUserResourceProvider(Set<String> propertyIds,
-                                           Map<Type, String> keyPropertyIds,
-                                           AmbariManagementController managementController);
+  ResourceProvider getUserResourceProvider(AmbariManagementController managementController);
+
+  @Named("userAuthenticationSource")
+  ResourceProvider getUserAuthenticationSourceResourceProvider();
 
   @Named("hostKerberosIdentity")
   ResourceProvider getHostKerberosIdentityResourceProvider(AmbariManagementController managementController);

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequest.java
new file mode 100644
index 0000000..17297be
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequest.java
@@ -0,0 +1,82 @@
+/*
+ * 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 org.apache.ambari.server.controller.internal.UserAuthenticationSourceResourceProvider;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Represents a user authentication source request.
+ */
+@ApiModel
+public class UserAuthenticationSourceRequest {
+  private final String username;
+  private final Long sourceId;
+  private final UserAuthenticationType authenticationType;
+  private final String key;
+  private final String oldKey;
+
+  public UserAuthenticationSourceRequest(String username, Long sourceId) {
+    this(username, sourceId, null, null);
+
+  }
+
+  public UserAuthenticationSourceRequest(String username, Long sourceId, UserAuthenticationType authenticationType) {
+    this(username, sourceId, authenticationType, null);
+  }
+
+  public UserAuthenticationSourceRequest(String username, Long sourceId, UserAuthenticationType authenticationType, String key) {
+    this(username, sourceId, authenticationType, key, null);
+  }
+
+  public UserAuthenticationSourceRequest(String username, Long sourceId, UserAuthenticationType authenticationType, String key, String oldKey) {
+    this.username = username;
+    this.sourceId = sourceId;
+    this.authenticationType = authenticationType;
+    this.key = key;
+    this.oldKey = oldKey;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.USER_NAME_PROPERTY_ID, hidden = true)
+  public String getUsername() {
+    return username;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.AUTHENTICATION_SOURCE_ID_PROPERTY_ID)
+  public Long getSourceId() {
+    return sourceId;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.AUTHENTICATION_TYPE_PROPERTY_ID)
+  public UserAuthenticationType getAuthenticationType() {
+    return authenticationType;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.KEY_PROPERTY_ID)
+  public String getKey() {
+    return key;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.OLD_KEY_PROPERTY_ID)
+  public String getOldKey() {
+    return oldKey;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequestCreateSwagger.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequestCreateSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequestCreateSwagger.java
new file mode 100644
index 0000000..72f010a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequestCreateSwagger.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.ambari.server.controller.internal.UserAuthenticationSourceResourceProvider;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Interface to help correct Swagger documentation generation
+ */
+public interface UserAuthenticationSourceRequestCreateSwagger extends ApiModel {
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.AUTHENTICATION_SOURCE_RESOURCE_CATEGORY)
+  CreateUserAuthenticationSourceInfo getCreateUserAuthenticationSourceRequest();
+
+  interface CreateUserAuthenticationSourceInfo {
+    @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.AUTHENTICATION_TYPE_PROPERTY_ID, required = true)
+    public UserAuthenticationType getAuthenticationType();
+
+    @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.KEY_PROPERTY_ID, required = true)
+    public String getKey();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequestUpdateSwagger.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequestUpdateSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequestUpdateSwagger.java
new file mode 100644
index 0000000..3e1aa8c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceRequestUpdateSwagger.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.ambari.server.controller.internal.UserAuthenticationSourceResourceProvider;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Interface to help correct Swagger documentation generation
+ */
+public interface UserAuthenticationSourceRequestUpdateSwagger extends ApiModel {
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.AUTHENTICATION_SOURCE_RESOURCE_CATEGORY)
+  UserAuthenticationSourceRequestUpdateInfo getUpdateUserAuthenticationSourceRequest();
+
+  interface UserAuthenticationSourceRequestUpdateInfo {
+
+    @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.KEY_PROPERTY_ID, required = true)
+    public String getKey();
+
+    @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.OLD_KEY_PROPERTY_ID, required = false)
+    public String getOldKey();
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceResponse.java
new file mode 100644
index 0000000..6717ad6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserAuthenticationSourceResponse.java
@@ -0,0 +1,127 @@
+/*
+ * 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.Date;
+
+import org.apache.ambari.server.controller.internal.UserAuthenticationSourceResourceProvider;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Represents a user authentication source.
+ */
+public class UserAuthenticationSourceResponse implements ApiModel {
+
+  private final String userName;
+  private final Long sourceId;
+  private final UserAuthenticationType authenticationType;
+  private final String key;
+
+  private final Date createTime;
+  private final Date updateTime;
+
+  public UserAuthenticationSourceResponse(String userName, Long sourceId, UserAuthenticationType authenticationType, String key, Date createTime, Date updateTime) {
+    this.userName = userName;
+    this.sourceId = sourceId;
+    this.authenticationType = authenticationType;
+    this.key = key;
+    this.createTime = createTime;
+    this.updateTime = updateTime;
+  }
+
+  /**
+   * Returns user name
+   *
+   * @return user name
+   */
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.USER_NAME_PROPERTY_ID, required = true)
+  public String getUserName() {
+    return userName;
+  }
+
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.AUTHENTICATION_SOURCE_ID_PROPERTY_ID, required = true)
+  public Long getSourceId() {
+    return sourceId;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.AUTHENTICATION_TYPE_PROPERTY_ID, required = true)
+  public UserAuthenticationType getAuthenticationType() {
+    return authenticationType;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.KEY_PROPERTY_ID)
+  public String getKey() {
+    return key;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.CREATED_PROPERTY_ID)
+  public Date getCreateTime() {
+    return createTime;
+  }
+
+  @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.UPDATED_PROPERTY_ID)
+  public Date getUpdateTime() {
+    return updateTime;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    } else if (o == null || getClass() != o.getClass()) {
+      return false;
+    } else {
+      UserAuthenticationSourceResponse that = (UserAuthenticationSourceResponse) o;
+
+      EqualsBuilder equalsBuilder = new EqualsBuilder();
+      equalsBuilder.append(userName, that.userName);
+      equalsBuilder.append(sourceId, that.sourceId);
+      equalsBuilder.append(authenticationType, that.authenticationType);
+      equalsBuilder.append(key, that.key);
+      equalsBuilder.append(createTime, that.createTime);
+      equalsBuilder.append(updateTime, that.updateTime);
+      return equalsBuilder.isEquals();
+    }
+  }
+
+  @Override
+  public int hashCode() {
+    HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
+    hashCodeBuilder.append(userName);
+    hashCodeBuilder.append(sourceId);
+    hashCodeBuilder.append(authenticationType);
+    hashCodeBuilder.append(key);
+    hashCodeBuilder.append(createTime);
+    hashCodeBuilder.append(updateTime);
+    return hashCodeBuilder.toHashCode();
+  }
+
+  /**
+   * Interface to help correct Swagger documentation generation
+   */
+  public interface UserAuthenticationSourceResponseSwagger {
+    @ApiModelProperty(name = UserAuthenticationSourceResourceProvider.AUTHENTICATION_SOURCE_RESOURCE_CATEGORY)
+    @SuppressWarnings("unused")
+    UserAuthenticationSourceResponse getUserAuthenticationSourceResponse();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequest.java
index 3011d01..d0836a9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequest.java
@@ -17,6 +17,8 @@
  */
 package org.apache.ambari.server.controller;
 
+import org.apache.ambari.server.controller.internal.UserResourceProvider;
+
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -38,12 +40,12 @@ public class UserRequest {
     this.userName = name;
   }
 
-  @ApiModelProperty(name = "Users/user_name",hidden = true)
+  @ApiModelProperty(name = UserResourceProvider.USERNAME_PROPERTY_ID)
   public String getUsername() {
     return userName;
   }
 
-  @ApiModelProperty(name = "Users/password")
+  @ApiModelProperty(name = UserResourceProvider.PASSWORD_PROPERTY_ID)
   public String getPassword() {
     return password;
   }
@@ -52,7 +54,7 @@ public class UserRequest {
     password = userPass;
   }
 
-  @ApiModelProperty(name = "Users/old_password")
+  @ApiModelProperty(name = UserResourceProvider.OLD_PASSWORD_PROPERTY_ID)
   public String getOldPassword() {
     return oldPassword;
   }
@@ -61,7 +63,7 @@ public class UserRequest {
     oldPassword = oldUserPass;
   }
 
-  @ApiModelProperty(name = "Users/active")
+  @ApiModelProperty(name = UserResourceProvider.ACTIVE_PROPERTY_ID)
   public Boolean isActive() {
     return active;
   }
@@ -70,7 +72,7 @@ public class UserRequest {
     this.active = active;
   }
 
-  @ApiModelProperty(name = "Users/admin")
+  @ApiModelProperty(name = UserResourceProvider.ADMIN_PROPERTY_ID)
   public Boolean isAdmin() {
     return admin;
   }
@@ -79,7 +81,7 @@ public class UserRequest {
     this.admin = admin;
   }
 
-  @ApiModelProperty(name = "Users/display_name")
+  @ApiModelProperty(name = UserResourceProvider.DISPLAY_NAME_PROPERTY_ID)
   public String getDisplayName() {
     return displayName;
   }
@@ -88,7 +90,7 @@ public class UserRequest {
     this.displayName = displayName;
   }
 
-  @ApiModelProperty(name = "Users/local_user_name")
+  @ApiModelProperty(name = UserResourceProvider.LOCAL_USERNAME_PROPERTY_ID)
   public String getLocalUserName() {
     return localUserName;
   }
@@ -103,5 +105,4 @@ public class UserRequest {
     sb.append("User, username=").append(userName);
     return sb.toString();
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestCreateUserSwagger.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestCreateUserSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestCreateUserSwagger.java
new file mode 100644
index 0000000..44b6410
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestCreateUserSwagger.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.apache.ambari.server.controller.internal.UserResourceProvider;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Interface to help correct Swagger documentation generation
+ */
+public interface UserRequestCreateUserSwagger extends ApiModel {
+
+  @ApiModelProperty(name = UserResourceProvider.USER_RESOURCE_CATEGORY)
+  CreateUserInfo getCreateUserRequest();
+
+  interface CreateUserInfo {
+    @ApiModelProperty(name = UserResourceProvider.PASSWORD_PROPERTY_ID)
+    String getPassword();
+
+    @ApiModelProperty(name = UserResourceProvider.ACTIVE_PROPERTY_ID)
+    Boolean isActive();
+
+    @ApiModelProperty(name = UserResourceProvider.ADMIN_PROPERTY_ID)
+    Boolean isAdmin();
+
+    @ApiModelProperty(name = UserResourceProvider.DISPLAY_NAME_PROPERTY_ID)
+    String getDisplayName();
+
+    @ApiModelProperty(name = UserResourceProvider.LOCAL_USERNAME_PROPERTY_ID)
+    String getLocalUserName();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestCreateUsersSwagger.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestCreateUsersSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestCreateUsersSwagger.java
new file mode 100644
index 0000000..f26ae14
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestCreateUsersSwagger.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.ambari.server.controller.internal.UserResourceProvider;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Interface to help correct Swagger documentation generation
+ */
+public interface UserRequestCreateUsersSwagger extends ApiModel {
+
+  @ApiModelProperty(name = UserResourceProvider.USER_RESOURCE_CATEGORY)
+  CreateUsersInfo getCreateUsersRequest();
+
+  interface CreateUsersInfo {
+    @ApiModelProperty(name = UserResourceProvider.USERNAME_PROPERTY_ID )
+    String getUsername();
+
+    @ApiModelProperty(name = UserResourceProvider.PASSWORD_PROPERTY_ID)
+    String getPassword();
+
+    @ApiModelProperty(name = UserResourceProvider.ACTIVE_PROPERTY_ID)
+    Boolean isActive();
+
+    @ApiModelProperty(name = UserResourceProvider.ADMIN_PROPERTY_ID)
+    Boolean isAdmin();
+
+    @ApiModelProperty(name = UserResourceProvider.DISPLAY_NAME_PROPERTY_ID)
+    String getDisplayName();
+
+    @ApiModelProperty(name = UserResourceProvider.LOCAL_USERNAME_PROPERTY_ID)
+    String getLocalUserName();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestUpdateUserSwagger.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestUpdateUserSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestUpdateUserSwagger.java
new file mode 100644
index 0000000..f2b2d84
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserRequestUpdateUserSwagger.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.ambari.server.controller.internal.UserResourceProvider;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Interface to help correct Swagger documentation generation
+ */
+public interface UserRequestUpdateUserSwagger extends ApiModel {
+
+  @ApiModelProperty(name = UserResourceProvider.USER_RESOURCE_CATEGORY)
+  UpdateUserInfo getUpdateUserRequest();
+
+  interface UpdateUserInfo {
+    @ApiModelProperty(name = UserResourceProvider.OLD_PASSWORD_PROPERTY_ID)
+    String getOldPassword();
+
+    @ApiModelProperty(name = UserResourceProvider.PASSWORD_PROPERTY_ID)
+    String getPassword();
+
+    @ApiModelProperty(name = UserResourceProvider.ACTIVE_PROPERTY_ID)
+    Boolean isActive();
+
+    @ApiModelProperty(name = UserResourceProvider.ADMIN_PROPERTY_ID)
+    Boolean isAdmin();
+
+    @ApiModelProperty(name = UserResourceProvider.DISPLAY_NAME_PROPERTY_ID)
+    String getDisplayName();
+
+    @ApiModelProperty(name = UserResourceProvider.LOCAL_USERNAME_PROPERTY_ID)
+    String getLocalUserName();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java
index bcb3aaf..6204aac 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UserResponse.java
@@ -18,8 +18,10 @@
 package org.apache.ambari.server.controller;
 
 import java.util.Collections;
+import java.util.Date;
 import java.util.Set;
 
+import org.apache.ambari.server.controller.internal.UserResourceProvider;
 import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 
 import io.swagger.annotations.ApiModelProperty;
@@ -27,38 +29,48 @@ import io.swagger.annotations.ApiModelProperty;
 /**
  * Represents a user maintenance request.
  */
-public class
-UserResponse implements ApiModel {
+public class UserResponse implements ApiModel {
 
   private final String userName;
+  private final String displayName;
+  private final String localUserName;
   private final UserAuthenticationType authenticationType;
   private final boolean isLdapUser;
   private final boolean isActive;
   private final boolean isAdmin;
   private Set<String> groups = Collections.emptySet();
 
-  public UserResponse(String userName, UserAuthenticationType userType, boolean isLdapUser, boolean isActive, boolean isAdmin) {
+  private final Date createTime;
+  private final Integer consecutiveFailures;
+
+  public UserResponse(String userName, String displayName, String localUserName, UserAuthenticationType userType, boolean isLdapUser, boolean isActive, boolean isAdmin, Integer consecutiveFailures, Date createTime) {
     this.userName = userName;
+    this.displayName = displayName;
+    this.localUserName = localUserName;
     this.authenticationType = userType;
     this.isLdapUser = isLdapUser;
     this.isActive = isActive;
     this.isAdmin = isAdmin;
+    this.consecutiveFailures = consecutiveFailures;
+    this.createTime = createTime;
   }
 
-  public UserResponse(String name, boolean isLdapUser, boolean isActive, boolean isAdmin) {
-    this.userName = name;
-    this.isLdapUser = isLdapUser;
-    this.isActive = isActive;
-    this.isAdmin = isAdmin;
-    this.authenticationType = UserAuthenticationType.LOCAL;
-  }
-
-  @ApiModelProperty(name = "Users/user_name",required = true)
+  @ApiModelProperty(name = UserResourceProvider.USERNAME_PROPERTY_ID)
   public String getUsername() {
     return userName;
   }
 
-  @ApiModelProperty(name = "Users/groups")
+  @ApiModelProperty(name = UserResourceProvider.DISPLAY_NAME_PROPERTY_ID)
+  public String getDisplayName() {
+    return displayName;
+  }
+
+  @ApiModelProperty(name = UserResourceProvider.LOCAL_USERNAME_PROPERTY_ID)
+  public String getLocalUsername() {
+    return localUserName;
+  }
+
+  @ApiModelProperty(name = UserResourceProvider.GROUPS_PROPERTY_ID)
   public Set<String> getGroups() {
     return groups;
   }
@@ -70,34 +82,50 @@ UserResponse implements ApiModel {
   /**
    * @return the isLdapUser
    */
-  @ApiModelProperty(name = "Users/ldap_user")
+  @ApiModelProperty(name = UserResourceProvider.LDAP_USER_PROPERTY_ID)
   public boolean isLdapUser() {
     return isLdapUser;
   }
 
-  @ApiModelProperty(name = "Users/active")
+  @ApiModelProperty(name = UserResourceProvider.ACTIVE_PROPERTY_ID)
   public boolean isActive() {
     return isActive;
   }
 
-  @ApiModelProperty(name = "Users/admin")
+  @ApiModelProperty(name = UserResourceProvider.ADMIN_PROPERTY_ID)
   public boolean isAdmin() {
     return isAdmin;
   }
 
-  @ApiModelProperty(name = "Users/authentication_type")
+  @ApiModelProperty(name = UserResourceProvider.USER_TYPE_PROPERTY_ID)
   public UserAuthenticationType getAuthenticationType() {
     return authenticationType;
   }
 
+  @ApiModelProperty(name = UserResourceProvider.CONSECUTIVE_FAILURES_PROPERTY_ID)
+  public Integer getConsecutiveFailures() {
+    return consecutiveFailures;
+  }
+
+  @ApiModelProperty(name = UserResourceProvider.CREATE_TIME_PROPERTY_ID)
+  public Date getCreateTime() {
+    return createTime;
+  }
+
   @Override
   public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
 
     UserResponse that = (UserResponse) o;
 
-    if (userName != null ? !userName.equals(that.userName) : that.userName != null) return false;
+    if (userName != null ? !userName.equals(that.userName) : that.userName != null) {
+      return false;
+    }
     return authenticationType == that.authenticationType;
 
   }
@@ -108,4 +136,12 @@ UserResponse implements ApiModel {
     result = 31 * result + (authenticationType != null ? authenticationType.hashCode() : 0);
     return result;
   }
+
+  /**
+   * Interface to help correct Swagger documentation generation
+   */
+  public interface UserResponseSwagger {
+    @ApiModelProperty(name = UserResourceProvider.USER_RESOURCE_CATEGORY)
+    UserResponse getUserResponse();
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/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 595b7f9..af2c0e8 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
@@ -171,7 +171,9 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
       case Task:
         return new TaskResourceProvider(propertyIds, keyPropertyIds, managementController);
       case User:
-        return resourceProviderFactory.getUserResourceProvider(propertyIds, keyPropertyIds, managementController);
+        return resourceProviderFactory.getUserResourceProvider(managementController);
+      case UserAuthenticationSource:
+        return resourceProviderFactory.getUserAuthenticationSourceResourceProvider();
       case Group:
         return new GroupResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Member:

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserAuthenticationSourceResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserAuthenticationSourceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserAuthenticationSourceResourceProvider.java
new file mode 100644
index 0000000..6a5f528
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserAuthenticationSourceResourceProvider.java
@@ -0,0 +1,417 @@
+/*
+ * 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.Collection;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.PrivilegeResponse;
+import org.apache.ambari.server.controller.UserAuthenticationSourceRequest;
+import org.apache.ambari.server.controller.UserAuthenticationSourceResponse;
+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.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.ResourceType;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
+import org.apache.ambari.server.security.authorization.Users;
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.exception.ResourceNotFoundException;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Inject;
+
+/**
+ * Resource provider for user authentication source resources.
+ */
+public class UserAuthenticationSourceResourceProvider extends AbstractAuthorizedResourceProvider {
+
+  public static final String AUTHENTICATION_SOURCE_RESOURCE_CATEGORY = "AuthenticationSourceInfo";
+
+  public static final String AUTHENTICATION_SOURCE_ID_PROPERTY_ID = "source_id";
+  public static final String USER_NAME_PROPERTY_ID = "user_name";
+  public static final String AUTHENTICATION_TYPE_PROPERTY_ID = "authentication_type";
+  public static final String KEY_PROPERTY_ID = "key";
+  public static final String OLD_KEY_PROPERTY_ID = "old_key";
+  public static final String CREATED_PROPERTY_ID = "created";
+  public static final String UPDATED_PROPERTY_ID = "updated";
+
+  public static final String AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID = AUTHENTICATION_SOURCE_RESOURCE_CATEGORY + "/" + AUTHENTICATION_SOURCE_ID_PROPERTY_ID;
+  public static final String AUTHENTICATION_USER_NAME_PROPERTY_ID = AUTHENTICATION_SOURCE_RESOURCE_CATEGORY + "/" + USER_NAME_PROPERTY_ID;
+  public static final String AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID = AUTHENTICATION_SOURCE_RESOURCE_CATEGORY + "/" + AUTHENTICATION_TYPE_PROPERTY_ID;
+  public static final String AUTHENTICATION_KEY_PROPERTY_ID = AUTHENTICATION_SOURCE_RESOURCE_CATEGORY + "/" + KEY_PROPERTY_ID;
+  public static final String AUTHENTICATION_OLD_KEY_PROPERTY_ID = AUTHENTICATION_SOURCE_RESOURCE_CATEGORY + "/" + OLD_KEY_PROPERTY_ID;
+  public static final String AUTHENTICATION_CREATED_PROPERTY_ID = AUTHENTICATION_SOURCE_RESOURCE_CATEGORY + "/" + CREATED_PROPERTY_ID;
+  public static final String AUTHENTICATION_UPDATED_PROPERTY_ID = AUTHENTICATION_SOURCE_RESOURCE_CATEGORY + "/" + UPDATED_PROPERTY_ID;
+
+  private static final Set<String> PK_PROPERTY_IDS = ImmutableSet.of(
+      AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID
+  );
+  private static final Set<String> PROPERTY_IDS = ImmutableSet.of(
+      AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID,
+      AUTHENTICATION_USER_NAME_PROPERTY_ID,
+      AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID,
+      AUTHENTICATION_KEY_PROPERTY_ID,
+      AUTHENTICATION_OLD_KEY_PROPERTY_ID,
+      AUTHENTICATION_CREATED_PROPERTY_ID,
+      AUTHENTICATION_UPDATED_PROPERTY_ID
+  );
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = ImmutableMap.of(
+      Resource.Type.User, AUTHENTICATION_USER_NAME_PROPERTY_ID,
+      Resource.Type.UserAuthenticationSource, AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID
+  );
+
+  @Inject
+  private Users users;
+
+  /**
+   * Constructor.
+   */
+  public UserAuthenticationSourceResourceProvider() {
+    super(Resource.Type.UserAuthenticationSource, PROPERTY_IDS, KEY_PROPERTY_IDS);
+
+    EnumSet<RoleAuthorization> requiredAuthorizations = EnumSet.of(RoleAuthorization.AMBARI_MANAGE_USERS);
+    setRequiredCreateAuthorizations(requiredAuthorizations);
+    setRequiredDeleteAuthorizations(requiredAuthorizations);
+    setRequiredGetAuthorizations(requiredAuthorizations);
+    setRequiredUpdateAuthorizations(requiredAuthorizations);
+  }
+
+  // ----- PrivilegeResourceProvider -----------------------------------------
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return PK_PROPERTY_IDS;
+  }
+
+  @Override
+  public RequestStatus createResourcesAuthorized(Request request)
+      throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException {
+    final Set<UserAuthenticationSourceRequest> requests = new HashSet<>();
+    for (Map<String, Object> propertyMap : request.getProperties()) {
+      requests.add(getRequest(propertyMap));
+    }
+
+    createResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        createUserAuthenticationSources(requests);
+        return null;
+      }
+    });
+
+    return getRequestStatus(null);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<UserAuthenticationSourceRequest> requests = new HashSet<>();
+    if (predicate == null) {
+      requests.add(getRequest(null));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<UserAuthenticationSourceResponse> responses = getResources(new Command<Set<UserAuthenticationSourceResponse>>() {
+      @Override
+      public Set<UserAuthenticationSourceResponse> invoke() throws AmbariException, AuthorizationException {
+        return getUserAuthenticationSources(requests);
+      }
+    });
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+    Set<Resource> resources = new HashSet<>();
+
+    for (UserAuthenticationSourceResponse response : responses) {
+      resources.add(toResource(response, requestedIds));
+    }
+
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    final Set<UserAuthenticationSourceRequest> requests = new HashSet<>();
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(request.getProperties().iterator().next(), predicate)) {
+      requests.add(getRequest(propertyMap));
+    }
+
+    modifyResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException, AuthorizationException {
+        updateUserAuthenticationSources(requests);
+        return null;
+      }
+    });
+
+    return getRequestStatus(null);
+  }
+
+  @Override
+  public RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    final Set<UserAuthenticationSourceRequest> requests = new HashSet<>();
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      requests.add(getRequest(propertyMap));
+    }
+
+    modifyResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException, AuthorizationException {
+        deleteUserAuthenticationSources(requests);
+        return null;
+      }
+    });
+
+    return getRequestStatus(null);
+  }
+
+  private UserAuthenticationSourceRequest getRequest(Map<String, Object> properties) {
+    String username;
+    Long sourceId;
+    UserAuthenticationType authenticationType;
+    String key;
+    String oldKey;
+
+    if (properties == null) {
+      username = null;
+      sourceId = null;
+      authenticationType = null;
+      key = null;
+      oldKey = null;
+    } else {
+      String tmp;
+
+      username = (String) properties.get(AUTHENTICATION_USER_NAME_PROPERTY_ID);
+      key = (String) properties.get(AUTHENTICATION_KEY_PROPERTY_ID);
+      oldKey = (String) properties.get(AUTHENTICATION_OLD_KEY_PROPERTY_ID);
+
+      tmp = (String) properties.get(AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID);
+
+      if (StringUtils.isEmpty(tmp)) {
+        sourceId = null;
+      } else {
+        sourceId = Long.parseLong(tmp);
+      }
+
+      tmp = (String) properties.get(AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID);
+      if (StringUtils.isEmpty(tmp)) {
+        authenticationType = null;
+      } else {
+        authenticationType = UserAuthenticationType.valueOf(tmp.trim().toUpperCase());
+      }
+    }
+
+    return new UserAuthenticationSourceRequest(username, sourceId, authenticationType, key, oldKey);
+  }
+
+  /**
+   * Creates user authentication sources.
+   *
+   * @param requests the request objects which define the user authentication source.
+   * @throws AmbariException when the user authentication source cannot be created.
+   */
+  private void createUserAuthenticationSources(Set<UserAuthenticationSourceRequest> requests) throws AmbariException {
+    for (UserAuthenticationSourceRequest request : requests) {
+      String username = request.getUsername();
+      if (StringUtils.isEmpty(username)) {
+        throw new AmbariException("Username must be supplied.");
+      }
+
+      UserAuthenticationType authenticationType = request.getAuthenticationType();
+      if (authenticationType == null) {
+        throw new AmbariException("A value authentication type must be supplied.");
+      }
+
+      UserEntity userEntity = users.getUserEntity(username);
+      if (userEntity == null) {
+        throw new AmbariException("There is no user with the supplied username");
+      }
+
+      users.addAuthentication(userEntity, authenticationType, request.getKey());
+    }
+  }
+
+  /**
+   * Gets the users authentication sources identified by the given request objects.
+   *
+   * @param requests the request objects
+   * @return a set of user responses
+   * @throws AmbariException if the user authentication sources could not be read
+   */
+  private Set<UserAuthenticationSourceResponse> getUserAuthenticationSources(Set<UserAuthenticationSourceRequest> requests)
+      throws AmbariException, AuthorizationException {
+
+    Set<UserAuthenticationSourceResponse> responses = new HashSet<>();
+
+    for (UserAuthenticationSourceRequest request : requests) {
+
+      String requestedUsername = request.getUsername();
+      String authenticatedUsername = AuthorizationHelper.getAuthenticatedName();
+
+      // A user authentication source resource may be retrieved by an administrator or the same user.
+      if (!AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.AMBARI_MANAGE_USERS)) {
+        if (null == requestedUsername) {
+          // Since the authenticated user is not the administrator, force only that user's resource
+          // to be returned
+          requestedUsername = authenticatedUsername;
+        } else if (!requestedUsername.equalsIgnoreCase(authenticatedUsername)) {
+          // Since the authenticated user is not the administrator and is asking for a different user,
+          // throw an AuthorizationException
+          throw new AuthorizationException();
+        }
+      }
+
+      Collection<UserAuthenticationEntity> authenticationEntities = users.getUserAuthenticationEntities(requestedUsername, request.getAuthenticationType());
+      if (authenticationEntities != null) {
+        for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+          responses.add(createUserAuthenticationSourceResponse(authenticationEntity));
+        }
+      }
+    }
+
+    return responses;
+  }
+
+  /**
+   * Delete the users authentication sources identified by the given request objects.
+   * <p>
+   * It ia assumed that the user has previously been authorized to perform this operation.
+   *
+   * @param requests the request objects
+   * @throws AmbariException if the user authentication sources could not be read
+   */
+  private void deleteUserAuthenticationSources(Set<UserAuthenticationSourceRequest> requests)
+      throws AmbariException, AuthorizationException {
+
+    for (UserAuthenticationSourceRequest r : requests) {
+      String username = r.getUsername();
+      Long sourceId = r.getSourceId();
+      if (!StringUtils.isEmpty(username) && (sourceId != null)) {
+        users.removeAuthentication(username, sourceId);
+      }
+    }
+  }
+
+  private void updateUserAuthenticationSources(Set<UserAuthenticationSourceRequest> requests) throws AuthorizationException, AmbariException {
+
+    Integer authenticatedUserId = AuthorizationHelper.getAuthenticatedId();
+
+
+    for (UserAuthenticationSourceRequest request : requests) {
+      String requestedUsername = request.getUsername();
+
+      UserEntity userEntity = users.getUserEntity(requestedUsername);
+      if (null == userEntity) {
+        continue;
+      }
+
+      boolean isSelf = authenticatedUserId.equals(userEntity.getUserId());
+      /* **************************************************
+       * Ensure that the authenticated user can change the password for the subject user. At least one
+       * of the following must be true
+       *  * The authenticate user is requesting to change his/her own password for a local authentication source
+       *  * The authenticated user has permissions to manage users
+       *  ************************************************** */
+      if (!isSelf && !AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.AMBARI_MANAGE_USERS)) {
+        throw new AuthorizationException("You are not authorized perform this operation");
+      }
+
+      UserAuthenticationEntity userAuthenticationEntity = null;
+      Long sourceId = request.getSourceId();
+
+      if (sourceId != null) {
+        List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+        // Find the relevant authentication entity...
+        for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+          if (sourceId.equals(authenticationEntity.getUserAuthenticationId())) {
+            userAuthenticationEntity = authenticationEntity;
+            break;
+          }
+        }
+      }
+
+      if (userAuthenticationEntity == null) {
+        // The requested authentication record was not found....
+        throw new ResourceNotFoundException("The requested authentication source was not found.");
+      }
+
+      // If the authentication_type is set, use it to verify that the found authentication source matches it...
+      if ((request.getAuthenticationType() != null) && (request.getAuthenticationType() != userAuthenticationEntity.getAuthenticationType())) {
+        throw new ResourceNotFoundException("The requested authentication source was not found - mismatch on authentication type");
+      }
+
+      users.modifyAuthentication(userAuthenticationEntity, request.getOldKey(), request.getKey(), isSelf);
+    }
+  }
+
+  private UserAuthenticationSourceResponse createUserAuthenticationSourceResponse(UserAuthenticationEntity entity) {
+    return new UserAuthenticationSourceResponse(entity.getUser().getUserName(),
+        entity.getUserAuthenticationId(),
+        entity.getAuthenticationType(),
+        entity.getAuthenticationKey(),
+        entity.getCreateTime(),
+        entity.getUpdateTime());
+  }
+
+
+  /**
+   * Translate the Response into a Resource
+   *
+   * @param response     {@link PrivilegeResponse}
+   * @param requestedIds the relevant request ids
+   * @return a resource
+   */
+  private Resource toResource(UserAuthenticationSourceResponse response, Set<String> requestedIds) {
+    final ResourceImpl resource = new ResourceImpl(Resource.Type.UserAuthenticationSource);
+
+    setResourceProperty(resource, AUTHENTICATION_USER_NAME_PROPERTY_ID, response.getUserName(), requestedIds);
+    setResourceProperty(resource, AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID, response.getSourceId(), requestedIds);
+    setResourceProperty(resource, AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID, response.getAuthenticationType().name(), requestedIds);
+    setResourceProperty(resource, AUTHENTICATION_CREATED_PROPERTY_ID, response.getCreateTime(), requestedIds);
+    setResourceProperty(resource, AUTHENTICATION_UPDATED_PROPERTY_ID, response.getUpdateTime(), requestedIds);
+
+    // NOTE, AUTHENTICATION_KEY_PROPERTY_ID is not being returned here since we don't want to return
+    // any sensitive information.  Once set that data should stay internal to Ambari.
+
+    return resource;
+  }
+}
\ No newline at end of file


[4/6] ambari git commit: AMBARI-20861. BE: Extend Ambari REST API to Support User Account Management Improvements (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/generated/swagger.json
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/generated/swagger.json b/ambari-server/docs/api/generated/swagger.json
index 6347bfa..7baaa6a 100644
--- a/ambari-server/docs/api/generated/swagger.json
+++ b/ambari-server/docs/api/generated/swagger.json
@@ -29,8 +29,11 @@
     "name" : "Stacks",
     "description" : "Endpoint for stack specific operations"
   }, {
+    "name" : "User Authentication Sources",
+    "description" : "Endpoint for user specific authentication source operations"
+  }, {
     "name" : "Users",
-    "description" : "Endpoint for user specific operations"
+    "description" : "Endpoint for User specific operations"
   }, {
     "name" : "Views"
   }, {
@@ -4681,20 +4684,20 @@
       "get" : {
         "tags" : [ "Users" ],
         "summary" : "Get all users",
-        "description" : "Returns details of all users.",
-        "operationId" : "UserService#getUsers",
+        "description" : "",
+        "operationId" : "getUsers",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter user details",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Users/*"
+          "default" : "Users/user_name"
         }, {
           "name" : "sortBy",
           "in" : "query",
-          "description" : "Sort users (asc | desc)",
+          "description" : "Sort resources in result by (asc | desc)",
           "required" : false,
           "type" : "string",
           "default" : "Users/user_name.asc"
@@ -4708,16 +4711,18 @@
         }, {
           "name" : "from",
           "in" : "query",
-          "description" : "The starting page resource (inclusive). Valid values are :offset | \"start\"",
+          "description" : "The starting page resource (inclusive).  \"start\" is also accepted.",
           "required" : false,
-          "type" : "string",
-          "default" : "0"
+          "type" : "integer",
+          "default" : 0,
+          "minimum" : 0.0
         }, {
           "name" : "to",
           "in" : "query",
-          "description" : "The ending page resource (inclusive). Valid values are :offset | \"end\"",
+          "description" : "The ending page resource (inclusive).  \"end\" is also accepted.",
           "required" : false,
-          "type" : "string"
+          "type" : "integer",
+          "minimum" : 1.0
         } ],
         "responses" : {
           "200" : {
@@ -4725,9 +4730,62 @@
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/UserResponse"
+                "$ref" : "#/definitions/UserResponseSwagger"
               }
             }
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "500" : {
+            "description" : "Internal server error"
+          }
+        }
+      },
+      "post" : {
+        "tags" : [ "Users" ],
+        "summary" : "Creates one or more users in a single request",
+        "description" : "",
+        "operationId" : "createUsers",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "in" : "body",
+          "name" : "body",
+          "required" : false,
+          "schema" : {
+            "$ref" : "#/definitions/UserRequestCreateUsersSwagger"
+          }
+        } ],
+        "responses" : {
+          "201" : {
+            "description" : "Successful operation"
+          },
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet"
+          },
+          "400" : {
+            "description" : "Invalid arguments"
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "409" : {
+            "description" : "The requested resource already exists."
+          },
+          "500" : {
+            "description" : "Internal server error"
           }
         }
       }
@@ -4736,38 +4794,49 @@
       "get" : {
         "tags" : [ "Users" ],
         "summary" : "Get single user",
-        "description" : "Returns user details.",
-        "operationId" : "UserService#getUser",
+        "description" : "",
+        "operationId" : "getUser",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
           "name" : "userName",
           "in" : "path",
           "description" : "user name",
           "required" : true,
-          "type" : "string",
-          "default" : "admin"
+          "type" : "string"
         }, {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter user details",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Users"
+          "default" : "Users/*"
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation",
             "schema" : {
-              "$ref" : "#/definitions/UserResponse"
+              "$ref" : "#/definitions/UserResponseSwagger"
             }
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "500" : {
+            "description" : "Internal server error"
           }
         }
       },
       "post" : {
         "tags" : [ "Users" ],
         "summary" : "Create new user",
-        "description" : "Creates user resource.",
-        "operationId" : "UserService#createUser",
+        "description" : "",
+        "operationId" : "createUser",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
           "name" : "userName",
@@ -4778,26 +4847,43 @@
         }, {
           "in" : "body",
           "name" : "body",
-          "description" : "input parameters in json form",
-          "required" : true,
+          "required" : false,
           "schema" : {
-            "$ref" : "#/definitions/UserRequest"
+            "$ref" : "#/definitions/UserRequestCreateUserSwagger"
           }
         } ],
         "responses" : {
-          "200" : {
+          "201" : {
             "description" : "Successful operation"
           },
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet"
+          },
+          "400" : {
+            "description" : "Invalid arguments"
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "409" : {
+            "description" : "The requested resource already exists."
+          },
           "500" : {
-            "description" : "Server Error"
+            "description" : "Internal server error"
           }
         }
       },
       "put" : {
         "tags" : [ "Users" ],
-        "summary" : "Update user detail",
-        "description" : "Updates user resource.",
-        "operationId" : "UserService#updateUser",
+        "summary" : "Update user details",
+        "description" : "",
+        "operationId" : "updateUser",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
           "name" : "userName",
@@ -4808,26 +4894,40 @@
         }, {
           "in" : "body",
           "name" : "body",
-          "description" : "input parameters in json form",
-          "required" : true,
+          "required" : false,
           "schema" : {
-            "$ref" : "#/definitions/UserRequest"
+            "$ref" : "#/definitions/UserRequestUpdateUserSwagger"
           }
         } ],
         "responses" : {
-          "200" : {
-            "description" : "Successful operation"
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet"
+          },
+          "400" : {
+            "description" : "Invalid arguments"
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "409" : {
+            "description" : "The requested resource already exists."
           },
           "500" : {
-            "description" : "Server Error"
+            "description" : "Internal server error"
           }
         }
       },
       "delete" : {
         "tags" : [ "Users" ],
         "summary" : "Delete single user",
-        "description" : "Delete user resource.",
-        "operationId" : "UserService#deleteUser",
+        "description" : "",
+        "operationId" : "deleteUser",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
           "name" : "userName",
@@ -5134,27 +5234,33 @@
         }
       }
     },
-    "/views" : {
+    "/users/{userName}/sources" : {
       "get" : {
-        "tags" : [ "Views" ],
-        "summary" : "Get all views",
-        "description" : "Returns details of all views.",
-        "operationId" : "ViewService#getViews",
+        "tags" : [ "User Authentication Sources" ],
+        "summary" : "Get all authentication sources",
+        "description" : "",
+        "operationId" : "getAuthenticationSources",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
+          "name" : "userName",
+          "in" : "path",
+          "description" : "user name",
+          "required" : true,
+          "type" : "string"
+        }, {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter view details",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "ViewInfo/*"
+          "default" : "AuthenticationSourceInfo/source_id,AuthenticationSourceInfo/user_name"
         }, {
           "name" : "sortBy",
           "in" : "query",
-          "description" : "Sort users (asc | desc)",
+          "description" : "Sort resources in result by (asc | desc)",
           "required" : false,
           "type" : "string",
-          "default" : "ViewInfo/view_name.asc"
+          "default" : "AuthenticationSourceInfo/source_id.asc"
         }, {
           "name" : "page_size",
           "in" : "query",
@@ -5165,16 +5271,18 @@
         }, {
           "name" : "from",
           "in" : "query",
-          "description" : "The starting page resource (inclusive). Valid values are :offset | \"start\"",
+          "description" : "The starting page resource (inclusive).  \"start\" is also accepted.",
           "required" : false,
-          "type" : "string",
-          "default" : "0"
+          "type" : "integer",
+          "default" : 0,
+          "minimum" : 0.0
         }, {
           "name" : "to",
           "in" : "query",
-          "description" : "The ending page resource (inclusive). Valid values are :offset | \"end\"",
+          "description" : "The ending page resource (inclusive).  \"end\" is also accepted.",
           "required" : false,
-          "type" : "string"
+          "type" : "integer",
+          "minimum" : 1.0
         } ],
         "responses" : {
           "200" : {
@@ -5182,68 +5290,318 @@
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/ViewResponse"
+                "$ref" : "#/definitions/UserAuthenticationSourceResponseSwagger"
               }
             }
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "500" : {
+            "description" : "Internal server error"
           }
         }
-      }
-    },
-    "/views/{viewName}" : {
-      "get" : {
-        "tags" : [ "Views" ],
-        "summary" : "Get single view",
-        "description" : "Returns view details.",
-        "operationId" : "ViewService#getView",
+      },
+      "post" : {
+        "tags" : [ "User Authentication Sources" ],
+        "summary" : "Create one or more new authentication sources for a user",
+        "description" : "",
+        "operationId" : "createAuthenticationSources",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "viewName",
+          "name" : "userName",
           "in" : "path",
-          "description" : "view name",
+          "description" : "user name",
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter view details",
+          "in" : "body",
+          "name" : "body",
           "required" : false,
-          "type" : "string",
-          "default" : "ViewInfo"
+          "schema" : {
+            "$ref" : "#/definitions/UserAuthenticationSourceRequestCreateSwagger"
+          }
         } ],
         "responses" : {
-          "200" : {
-            "description" : "Successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/ViewResponse"
-            }
+          "201" : {
+            "description" : "Successful operation"
+          },
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet"
+          },
+          "400" : {
+            "description" : "Invalid arguments"
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "409" : {
+            "description" : "The requested resource already exists."
+          },
+          "500" : {
+            "description" : "Internal server error"
           }
         }
       }
     },
-    "/views/{viewName}/versions" : {
+    "/users/{userName}/sources/{sourceId}" : {
       "get" : {
-        "tags" : [ "Views" ],
-        "summary" : "Get all versions for a view",
-        "description" : "Returns details of all versions for a view.",
-        "operationId" : "ViewVersionService#getVersions",
+        "tags" : [ "User Authentication Sources" ],
+        "summary" : "Get user authentication source",
+        "description" : "",
+        "operationId" : "getAuthenticationSource",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "viewName",
+          "name" : "userName",
           "in" : "path",
-          "description" : "view name",
+          "description" : "user name",
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter view version details",
-          "required" : false,
-          "type" : "string",
-          "default" : "ViewVersionInfo/*"
+          "name" : "sourceId",
+          "in" : "path",
+          "description" : "source id",
+          "required" : true,
+          "type" : "string"
         }, {
-          "name" : "sortBy",
+          "name" : "fields",
           "in" : "query",
-          "description" : "Sort users (asc | desc)",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "required" : false,
+          "type" : "string",
+          "default" : "AuthenticationSourceInfo/*"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation",
+            "schema" : {
+              "$ref" : "#/definitions/UserAuthenticationSourceResponseSwagger"
+            }
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "500" : {
+            "description" : "Internal server error"
+          }
+        }
+      },
+      "put" : {
+        "tags" : [ "User Authentication Sources" ],
+        "summary" : "Updates an existing authentication source",
+        "description" : "",
+        "operationId" : "updateAuthenticationSource",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "userName",
+          "in" : "path",
+          "description" : "user name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "sourceId",
+          "in" : "path",
+          "description" : "source id",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "in" : "body",
+          "name" : "body",
+          "required" : false,
+          "schema" : {
+            "$ref" : "#/definitions/UserAuthenticationSourceRequestUpdateSwagger"
+          }
+        } ],
+        "responses" : {
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet"
+          },
+          "400" : {
+            "description" : "Invalid arguments"
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "409" : {
+            "description" : "The requested resource already exists."
+          },
+          "500" : {
+            "description" : "Internal server error"
+          }
+        }
+      },
+      "delete" : {
+        "tags" : [ "User Authentication Sources" ],
+        "summary" : "Deletes an existing authentication source",
+        "description" : "",
+        "operationId" : "deleteAuthenticationSource",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "userName",
+          "in" : "path",
+          "description" : "user name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "sourceId",
+          "in" : "path",
+          "description" : "source id",
+          "required" : true,
+          "type" : "string"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation"
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "500" : {
+            "description" : "Internal server error"
+          }
+        }
+      }
+    },
+    "/views" : {
+      "get" : {
+        "tags" : [ "Views" ],
+        "summary" : "Get all views",
+        "description" : "Returns details of all views.",
+        "operationId" : "ViewService#getViews",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter view details",
+          "required" : false,
+          "type" : "string",
+          "default" : "ViewInfo/*"
+        }, {
+          "name" : "sortBy",
+          "in" : "query",
+          "description" : "Sort users (asc | desc)",
+          "required" : false,
+          "type" : "string",
+          "default" : "ViewInfo/view_name.asc"
+        }, {
+          "name" : "page_size",
+          "in" : "query",
+          "description" : "The number of resources to be returned for the paged response.",
+          "required" : false,
+          "type" : "integer",
+          "default" : 10
+        }, {
+          "name" : "from",
+          "in" : "query",
+          "description" : "The starting page resource (inclusive). Valid values are :offset | \"start\"",
+          "required" : false,
+          "type" : "string",
+          "default" : "0"
+        }, {
+          "name" : "to",
+          "in" : "query",
+          "description" : "The ending page resource (inclusive). Valid values are :offset | \"end\"",
+          "required" : false,
+          "type" : "string"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation",
+            "schema" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/definitions/ViewResponse"
+              }
+            }
+          }
+        }
+      }
+    },
+    "/views/{viewName}" : {
+      "get" : {
+        "tags" : [ "Views" ],
+        "summary" : "Get single view",
+        "description" : "Returns view details.",
+        "operationId" : "ViewService#getView",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "viewName",
+          "in" : "path",
+          "description" : "view name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter view details",
+          "required" : false,
+          "type" : "string",
+          "default" : "ViewInfo"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation",
+            "schema" : {
+              "$ref" : "#/definitions/ViewResponse"
+            }
+          }
+        }
+      }
+    },
+    "/views/{viewName}/versions" : {
+      "get" : {
+        "tags" : [ "Views" ],
+        "summary" : "Get all versions for a view",
+        "description" : "Returns details of all versions for a view.",
+        "operationId" : "ViewVersionService#getVersions",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "viewName",
+          "in" : "path",
+          "description" : "view name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter view version details",
+          "required" : false,
+          "type" : "string",
+          "default" : "ViewVersionInfo/*"
+        }, {
+          "name" : "sortBy",
+          "in" : "query",
+          "description" : "Sort users (asc | desc)",
           "required" : false,
           "type" : "string",
           "default" : "ViewVersionInfo/version.desc"
@@ -6086,13 +6444,13 @@
     "Artifacts" : {
       "type" : "object",
       "properties" : {
-        "service_name" : {
+        "stack_name" : {
           "type" : "string"
         },
-        "stack_version" : {
+        "service_name" : {
           "type" : "string"
         },
-        "stack_name" : {
+        "stack_version" : {
           "type" : "string"
         },
         "artifact_name" : {
@@ -6103,6 +6461,9 @@
     "BlueprintInfo" : {
       "type" : "object",
       "properties" : {
+        "stack_name" : {
+          "type" : "string"
+        },
         "security" : {
           "$ref" : "#/definitions/SecurityInfo"
         },
@@ -6111,9 +6472,6 @@
         },
         "blueprint_name" : {
           "type" : "string"
-        },
-        "stack_name" : {
-          "type" : "string"
         }
       }
     },
@@ -6187,14 +6545,14 @@
     "ClusterArtifactResponse" : {
       "type" : "object",
       "properties" : {
-        "Artifacts" : {
-          "$ref" : "#/definitions/ClusterArtifactResponseInfo"
-        },
         "artifact_data" : {
           "type" : "object",
           "additionalProperties" : {
             "type" : "object"
           }
+        },
+        "Artifacts" : {
+          "$ref" : "#/definitions/ClusterArtifactResponseInfo"
         }
       }
     },
@@ -6380,14 +6738,14 @@
     "ClusterServiceArtifactResponse" : {
       "type" : "object",
       "properties" : {
+        "Artifacts" : {
+          "$ref" : "#/definitions/ClusterServiceArtifactResponseInfo"
+        },
         "artifact_data" : {
           "type" : "object",
           "additionalProperties" : {
             "type" : "object"
           }
-        },
-        "Artifacts" : {
-          "$ref" : "#/definitions/ClusterServiceArtifactResponseInfo"
         }
       }
     },
@@ -6419,15 +6777,18 @@
         "scope" : {
           "type" : "string"
         },
-        "service_name" : {
+        "stack_name" : {
           "type" : "string"
         },
-        "component_name" : {
+        "service_name" : {
           "type" : "string"
         },
         "stack_version" : {
           "type" : "string"
         },
+        "component_name" : {
+          "type" : "string"
+        },
         "conditions" : {
           "type" : "array",
           "items" : {
@@ -6439,9 +6800,6 @@
         },
         "dependent_service_name" : {
           "type" : "string"
-        },
-        "stack_name" : {
-          "type" : "string"
         }
       }
     },
@@ -6596,30 +6954,90 @@
             "format" : "int64"
           }
         },
-        "configs" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "string"
-          }
+        "configs" : {
+          "type" : "object",
+          "additionalProperties" : {
+            "type" : "string"
+          }
+        },
+        "configAttributes" : {
+          "type" : "object",
+          "additionalProperties" : {
+            "type" : "object",
+            "additionalProperties" : {
+              "type" : "string"
+            }
+          }
+        },
+        "propertiesTypes" : {
+          "type" : "object",
+          "additionalProperties" : {
+            "type" : "array",
+            "uniqueItems" : true,
+            "items" : {
+              "type" : "string"
+            }
+          }
+        }
+      }
+    },
+    "CreateUserAuthenticationSourceInfo" : {
+      "type" : "object",
+      "required" : [ "authentication_type", "key" ],
+      "properties" : {
+        "key" : {
+          "type" : "string"
+        },
+        "authentication_type" : {
+          "type" : "string",
+          "enum" : [ "LOCAL", "LDAP", "JWT", "PAM", "KERBEROS" ]
+        }
+      }
+    },
+    "CreateUserInfo" : {
+      "type" : "object",
+      "properties" : {
+        "display_name" : {
+          "type" : "string"
+        },
+        "active" : {
+          "type" : "boolean",
+          "default" : false
+        },
+        "password" : {
+          "type" : "string"
+        },
+        "admin" : {
+          "type" : "boolean",
+          "default" : false
+        },
+        "local_user_name" : {
+          "type" : "string"
+        }
+      }
+    },
+    "CreateUsersInfo" : {
+      "type" : "object",
+      "properties" : {
+        "display_name" : {
+          "type" : "string"
+        },
+        "active" : {
+          "type" : "boolean",
+          "default" : false
+        },
+        "user_name" : {
+          "type" : "string"
         },
-        "configAttributes" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "object",
-            "additionalProperties" : {
-              "type" : "string"
-            }
-          }
+        "password" : {
+          "type" : "string"
         },
-        "propertiesTypes" : {
-          "type" : "object",
-          "additionalProperties" : {
-            "type" : "array",
-            "uniqueItems" : true,
-            "items" : {
-              "type" : "string"
-            }
-          }
+        "admin" : {
+          "type" : "boolean",
+          "default" : false
+        },
+        "local_user_name" : {
+          "type" : "string"
         }
       }
     },
@@ -6825,12 +7243,12 @@
             "$ref" : "#/definitions/ComponentInfo"
           }
         },
-        "name" : {
-          "type" : "string"
-        },
         "cardinality" : {
           "type" : "integer",
           "format" : "int32"
+        },
+        "name" : {
+          "type" : "string"
         }
       }
     },
@@ -6888,13 +7306,13 @@
         "maintenance_state" : {
           "type" : "string"
         },
-        "host_group" : {
+        "public_host_name" : {
           "type" : "string"
         },
         "blueprint" : {
           "type" : "string"
         },
-        "public_host_name" : {
+        "host_group" : {
           "type" : "string"
         }
       }
@@ -6975,10 +7393,10 @@
           "type" : "string",
           "enum" : [ "OFF", "ON", "IMPLIED_FROM_SERVICE", "IMPLIED_FROM_HOST", "IMPLIED_FROM_SERVICE_AND_HOST" ]
         },
-        "public_host_name" : {
+        "host_health_report" : {
           "type" : "string"
         },
-        "host_health_report" : {
+        "public_host_name" : {
           "type" : "string"
         }
       }
@@ -7331,16 +7749,16 @@
         "file_name" : {
           "type" : "string"
         },
-        "service_name" : {
+        "stack_name" : {
           "type" : "string"
         },
         "quicklink_data" : {
           "$ref" : "#/definitions/QuickLinksConfiguration"
         },
-        "stack_version" : {
+        "service_name" : {
           "type" : "string"
         },
-        "stack_name" : {
+        "stack_version" : {
           "type" : "string"
         }
       }
@@ -7408,16 +7826,13 @@
           "type" : "boolean",
           "default" : false
         },
-        "baseUrl" : {
-          "type" : "string"
-        },
-        "mirrorsList" : {
+        "repoName" : {
           "type" : "string"
         },
-        "latestUri" : {
+        "baseUrl" : {
           "type" : "string"
         },
-        "repoName" : {
+        "mirrorsList" : {
           "type" : "string"
         },
         "repoId" : {
@@ -7467,9 +7882,6 @@
         "defaultBaseUrl" : {
           "type" : "string"
         },
-        "latestBaseUrl" : {
-          "type" : "string"
-        },
         "repoSaved" : {
           "type" : "boolean",
           "default" : false
@@ -7525,6 +7937,15 @@
             "$ref" : "#/definitions/RepositoryVersionEntity"
           }
         },
+        "stackId" : {
+          "$ref" : "#/definitions/StackId"
+        },
+        "repositoryXml" : {
+          "$ref" : "#/definitions/VersionDefinitionXml"
+        },
+        "stackName" : {
+          "type" : "string"
+        },
         "operatingSystemsJson" : {
           "type" : "string"
         },
@@ -7534,15 +7955,6 @@
         },
         "stackVersion" : {
           "type" : "string"
-        },
-        "stackId" : {
-          "$ref" : "#/definitions/StackId"
-        },
-        "stackName" : {
-          "type" : "string"
-        },
-        "repositoryXml" : {
-          "$ref" : "#/definitions/VersionDefinitionXml"
         }
       }
     },
@@ -7568,14 +7980,14 @@
             "$ref" : "#/definitions/RepositoryInfo"
           }
         },
-        "latestURI" : {
-          "type" : "string"
-        },
         "errors" : {
           "type" : "array",
           "items" : {
             "type" : "string"
           }
+        },
+        "latestURI" : {
+          "type" : "string"
         }
       },
       "xml" : {
@@ -7609,14 +8021,14 @@
             "type" : "object"
           }
         },
-        "action" : {
-          "type" : "string"
+        "operation_level" : {
+          "$ref" : "#/definitions/OperationLevel"
         },
         "command" : {
           "type" : "string"
         },
-        "operation_level" : {
-          "$ref" : "#/definitions/OperationLevel"
+        "action" : {
+          "type" : "string"
         }
       }
     },
@@ -7673,6 +8085,9 @@
     "RequestResourceFilter" : {
       "type" : "object",
       "properties" : {
+        "hosts" : {
+          "type" : "string"
+        },
         "service_name" : {
           "type" : "string"
         },
@@ -7681,9 +8096,6 @@
         },
         "hosts_predicate" : {
           "type" : "string"
-        },
-        "hosts" : {
-          "type" : "string"
         }
       }
     },
@@ -7701,19 +8113,27 @@
         "type" : {
           "type" : "string"
         },
-        "start_time" : {
-          "type" : "string"
+        "create_time" : {
+          "type" : "integer",
+          "format" : "int64"
         },
         "request_context" : {
           "type" : "string"
         },
-        "request_status" : {
+        "task_count" : {
+          "type" : "integer",
+          "format" : "int32"
+        },
+        "completed_task_count" : {
           "type" : "string"
         },
-        "cluster_name" : {
+        "start_time" : {
           "type" : "string"
         },
-        "request_schedule" : {
+        "request_status" : {
+          "type" : "string"
+        },
+        "cluster_name" : {
           "type" : "string"
         },
         "id" : {
@@ -7723,10 +8143,6 @@
           "type" : "integer",
           "format" : "int32"
         },
-        "create_time" : {
-          "type" : "integer",
-          "format" : "int64"
-        },
         "end_time" : {
           "type" : "string"
         },
@@ -7738,9 +8154,6 @@
           "type" : "integer",
           "format" : "int32"
         },
-        "inputs" : {
-          "type" : "string"
-        },
         "operation_level" : {
           "type" : "string"
         },
@@ -7762,11 +8175,10 @@
             "$ref" : "#/definitions/RequestResourceFilter"
           }
         },
-        "task_count" : {
-          "type" : "integer",
-          "format" : "int32"
+        "request_schedule" : {
+          "type" : "string"
         },
-        "completed_task_count" : {
+        "inputs" : {
           "type" : "string"
         }
       }
@@ -8172,14 +8584,14 @@
     "StackArtifactResponse" : {
       "type" : "object",
       "properties" : {
-        "Artifacts" : {
-          "$ref" : "#/definitions/Artifacts"
-        },
         "artifact_data" : {
           "type" : "object",
           "additionalProperties" : {
             "type" : "object"
           }
+        },
+        "Artifacts" : {
+          "$ref" : "#/definitions/Artifacts"
         }
       }
     },
@@ -8317,14 +8729,14 @@
     "StackServiceArtifactResponse" : {
       "type" : "object",
       "properties" : {
-        "Artifacts" : {
-          "$ref" : "#/definitions/Artifacts"
-        },
         "artifact_data" : {
           "type" : "object",
           "additionalProperties" : {
             "type" : "object"
           }
+        },
+        "Artifacts" : {
+          "$ref" : "#/definitions/Artifacts"
         }
       }
     },
@@ -8687,17 +9099,17 @@
         "file_name" : {
           "type" : "string"
         },
-        "service_name" : {
-          "type" : "string"
+        "theme_data" : {
+          "$ref" : "#/definitions/Theme"
         },
-        "stack_version" : {
+        "stack_name" : {
           "type" : "string"
         },
-        "stack_name" : {
+        "service_name" : {
           "type" : "string"
         },
-        "theme_data" : {
-          "$ref" : "#/definitions/Theme"
+        "stack_version" : {
+          "type" : "string"
         }
       }
     },
@@ -8717,6 +9129,95 @@
         }
       }
     },
+    "UpdateUserInfo" : {
+      "type" : "object",
+      "properties" : {
+        "display_name" : {
+          "type" : "string"
+        },
+        "active" : {
+          "type" : "boolean",
+          "default" : false
+        },
+        "password" : {
+          "type" : "string"
+        },
+        "admin" : {
+          "type" : "boolean",
+          "default" : false
+        },
+        "local_user_name" : {
+          "type" : "string"
+        },
+        "old_password" : {
+          "type" : "string"
+        }
+      }
+    },
+    "UserAuthenticationSourceRequestCreateSwagger" : {
+      "type" : "object",
+      "properties" : {
+        "AuthenticationSourceInfo" : {
+          "$ref" : "#/definitions/CreateUserAuthenticationSourceInfo"
+        }
+      }
+    },
+    "UserAuthenticationSourceRequestUpdateInfo" : {
+      "type" : "object",
+      "required" : [ "key" ],
+      "properties" : {
+        "key" : {
+          "type" : "string"
+        },
+        "old_key" : {
+          "type" : "string"
+        }
+      }
+    },
+    "UserAuthenticationSourceRequestUpdateSwagger" : {
+      "type" : "object",
+      "properties" : {
+        "AuthenticationSourceInfo" : {
+          "$ref" : "#/definitions/UserAuthenticationSourceRequestUpdateInfo"
+        }
+      }
+    },
+    "UserAuthenticationSourceResponse" : {
+      "type" : "object",
+      "required" : [ "authentication_type", "source_id", "user_name" ],
+      "properties" : {
+        "user_name" : {
+          "type" : "string"
+        },
+        "source_id" : {
+          "type" : "integer",
+          "format" : "int64"
+        },
+        "authentication_type" : {
+          "type" : "string",
+          "enum" : [ "LOCAL", "LDAP", "JWT", "PAM", "KERBEROS" ]
+        },
+        "key" : {
+          "type" : "string"
+        },
+        "created" : {
+          "type" : "string",
+          "format" : "date-time"
+        },
+        "updated" : {
+          "type" : "string",
+          "format" : "date-time"
+        }
+      }
+    },
+    "UserAuthenticationSourceResponseSwagger" : {
+      "type" : "object",
+      "properties" : {
+        "AuthenticationSourceInfo" : {
+          "$ref" : "#/definitions/UserAuthenticationSourceResponse"
+        }
+      }
+    },
     "UserAuthorizationResponse" : {
       "type" : "object",
       "required" : [ "AuthorizationInfo/user_name" ],
@@ -8800,60 +9301,80 @@
         }
       }
     },
-    "UserRequest" : {
+    "UserRequestCreateUserSwagger" : {
       "type" : "object",
       "properties" : {
-        "Users/password" : {
-          "type" : "string"
-        },
-        "Users/old_password" : {
-          "type" : "string"
-        },
-        "Users/active" : {
-          "type" : "boolean",
-          "default" : false
-        },
-        "Users/admin" : {
-          "type" : "boolean",
-          "default" : false
-        },
-        "Users/display_name" : {
-          "type" : "string"
-        },
-        "Users/local_user_name" : {
-          "type" : "string"
+        "Users" : {
+          "$ref" : "#/definitions/CreateUserInfo"
+        }
+      }
+    },
+    "UserRequestCreateUsersSwagger" : {
+      "type" : "object",
+      "properties" : {
+        "Users" : {
+          "$ref" : "#/definitions/CreateUsersInfo"
+        }
+      }
+    },
+    "UserRequestUpdateUserSwagger" : {
+      "type" : "object",
+      "properties" : {
+        "Users" : {
+          "$ref" : "#/definitions/UpdateUserInfo"
         }
       }
     },
     "UserResponse" : {
       "type" : "object",
-      "required" : [ "Users/user_name" ],
       "properties" : {
-        "Users/authentication_type" : {
+        "display_name" : {
+          "type" : "string"
+        },
+        "user_type" : {
           "type" : "string",
           "enum" : [ "LOCAL", "LDAP", "JWT", "PAM", "KERBEROS" ]
         },
-        "Users/groups" : {
+        "groups" : {
           "type" : "array",
           "uniqueItems" : true,
           "items" : {
             "type" : "string"
           }
         },
-        "Users/active" : {
+        "created" : {
+          "type" : "string",
+          "format" : "date-time"
+        },
+        "consecutive_failures" : {
+          "type" : "integer",
+          "format" : "int32"
+        },
+        "active" : {
           "type" : "boolean",
           "default" : false
         },
-        "Users/user_name" : {
+        "user_name" : {
           "type" : "string"
         },
-        "Users/admin" : {
+        "admin" : {
           "type" : "boolean",
           "default" : false
         },
-        "Users/ldap_user" : {
+        "ldap_user" : {
           "type" : "boolean",
           "default" : false
+        },
+        "local_user_name" : {
+          "type" : "string"
+        }
+      }
+    },
+    "UserResponseSwagger" : {
+      "type" : "object",
+      "properties" : {
+        "Users" : {
+          "$ref" : "#/definitions/UserResponse"
         }
       }
     },

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/authentication-source-create.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/authentication-source-create.md b/ambari-server/docs/api/v1/authentication-source-create.md
new file mode 100644
index 0000000..89f74c7
--- /dev/null
+++ b/ambari-server/docs/api/v1/authentication-source-create.md
@@ -0,0 +1,86 @@
+
+<!---
+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.
+-->
+
+Create Authentication Source
+=====
+
+[Back to Authentication Source Resources](authentication-source-resources.md)
+
+**Summary**
+
+Create a new authentication source resource as a child to a user identified by <code>:user_name</code>. 
+<p/><p/>
+Only users with the <code>AMBARI.MANAGE_USERS</code> privilege (currently, Ambari Administrators)
+may perform this operation.
+
+    POST /users/:user_name/sources
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>Forbidden</td>  
+  </tr>
+</table>
+
+
+**Examples*
+    
+Create a LOCAL authentication source for the user with a username of "jdoe".
+    
+    POST /users/jdoe/sources
+    
+    {
+      "AuthenticationSourceInfo": {
+        "authentication_type": "LDAP",
+        "key": "some dn"
+      }
+    }
+
+    201 Created
+    
+
+Create multiple authentication sources for the user with a username of "jdoe".
+    
+    POST /users/jdoe/sources
+    
+    [
+      {
+        "AuthenticationSourceInfo": {
+          "authentication_type": "PAM",
+          "key": "pam_key"
+        }
+      },
+      {
+        "AuthenticationSourceInfo": {
+          "authentication_type": "LDAP",
+          "key": "ldap_key"
+        }
+      }
+    ]
+    
+    201 Created

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/authentication-source-delete.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/authentication-source-delete.md b/ambari-server/docs/api/v1/authentication-source-delete.md
new file mode 100644
index 0000000..845b6f5
--- /dev/null
+++ b/ambari-server/docs/api/v1/authentication-source-delete.md
@@ -0,0 +1,49 @@
+
+<!---
+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.
+-->
+
+Delete Authentication Source
+=====
+
+[Back to Authentication Source Resources](authentication-source-resources.md)
+
+**Summary**
+
+Removes an existing authentication source resource identified by <code>:source_id</code> for a user
+identified by <code>:user_name</code>. 
+<p/><p/>
+Only users with the <code>AMBARI.MANAGE_USERS</code> privilege (currently, Ambari Administrators)
+may perform this operation.
+
+    DELETE /users/:user_name/source/:source_id
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>Forbidden</td>  
+  </tr>
+</table>

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/authentication-source-get.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/authentication-source-get.md b/ambari-server/docs/api/v1/authentication-source-get.md
new file mode 100644
index 0000000..8ff5fd1
--- /dev/null
+++ b/ambari-server/docs/api/v1/authentication-source-get.md
@@ -0,0 +1,93 @@
+
+<!---
+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.
+-->
+
+Get Authentication Source
+=====
+
+[Back to Authentication Source Resources](authentication-source-resources.md)
+
+**Summary**
+
+Gets the details about an existing authentication source identified by <code>:source_id</code> for 
+a user identified by <code>:user_name</code> 
+
+    GET /users/:user_name/sources/:source_id
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>OK</td>  
+  </tr>
+  <tr>
+    <td>400</td>
+    <td>Bad Request</td>  
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>Unauthorized</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>Forbidden</td>  
+  </tr> 
+  <tr>
+    <td>404</td>
+    <td>Not Found</td>  
+  </tr>
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+</table>
+
+**Example**
+
+Get a specific authentication source for user with the user_name of jdoe.
+
+    GET /users/jdoe/sources/1234
+
+    200 OK
+    {
+      "href" : "http://your.ambari.server/api/v1/users/userc/sources/1234",
+      "AuthenticationSourceInfo" : {
+        "source_id" : 1234,
+        "user_name" : "jdoe"
+      }
+    }     
+
+Get more details about specific authentication source for user with the user_name of jdoe.
+
+    GET /users/jdoe/sources/1234?fields=*
+
+    200 OK
+    {
+      "href" : "http://your.ambari.server/api/v1/users/userc/sources/1234",
+      "AuthenticationSourceInfo" : {
+        "authentication_type" : "LOCAL",
+        "created" : 1498844132119,
+        "source_id" : 1234,
+        "updated" : 1498844157794,
+        "user_name" : "jdoe"
+      }
+    }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/authentication-source-list.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/authentication-source-list.md b/ambari-server/docs/api/v1/authentication-source-list.md
new file mode 100644
index 0000000..6a7c574
--- /dev/null
+++ b/ambari-server/docs/api/v1/authentication-source-list.md
@@ -0,0 +1,116 @@
+
+<!---
+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.
+-->
+
+List Authentication Sources
+=====
+
+[Back to Authentication Source Resources](authentication-source-resources.md)
+
+**Summary**
+
+Returns a collection of the existing authentication sources for a given user, identified by 
+<code>:user_name</code>.
+
+    GET /users/:user_name/sources
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>OK</td>  
+  </tr>
+  <tr>
+    <td>400</td>
+    <td>Bad Request</td>  
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>Unauthorized</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>Forbidden</td>  
+  </tr> 
+  <tr>
+    <td>404</td>
+    <td>Not Found</td>  
+  </tr>
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+</table>
+
+**Example**
+
+Get the collection of all authentication sources for user with username jdoe.
+
+    GET /users/jdoe/sources
+
+    200 OK
+    {
+      "href" : "http://your.ambari.server/api/v1/users/jdoe/sources?fields=*",
+      "items" : [
+        {
+          "href" : "http://your.ambari.server/api/v1/users/jdoe/sources/1004",
+          "AuthenticationSourceInfo" : {
+            "authentication_type" : "LOCAL",
+            "created" : 1497472842579,
+            "source_id" : 1004,
+            "updated" : 1497472842579,
+            "user_name" : "jdoe"
+          }
+        },
+        {
+          "href" : "http://your.ambari.server/api/v1/users/jdoe/sources/3653",
+          "AuthenticationSourceInfo" : {
+            "authentication_type" : "LDAP",
+            "created" : 1499372841818,
+            "source_id" : 3653,
+            "updated" : 1499372841818,
+            "user_name" : "jdoe"
+          }
+        },
+        {
+          "href" : "http://your.ambari.server/api/v1/users/jdoe/sources/3654",
+          "AuthenticationSourceInfo" : {
+            "authentication_type" : "LDAP",
+            "created" : 1499373089670,
+            "source_id" : 3654,
+            "updated" : 1499373089670,
+            "user_name" : "jdoe"
+          }
+        },
+        {
+          "href" : "http://your.ambari.server/api/v1/users/jdoe/sources/3655",
+          "AuthenticationSourceInfo" : {
+            "authentication_type" : "PAM",
+            "created" : 1499373089677,
+            "source_id" : 3655,
+            "updated" : 1499373089677,
+            "user_name" : "jdoe"
+          }
+        }
+      ]
+    }
+    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/authentication-source-resources.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/authentication-source-resources.md b/ambari-server/docs/api/v1/authentication-source-resources.md
new file mode 100644
index 0000000..417d2ca
--- /dev/null
+++ b/ambari-server/docs/api/v1/authentication-source-resources.md
@@ -0,0 +1,117 @@
+<!---
+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.
+-->
+
+# Authentication Source Resources
+Authentication Source resources represent authentication sources that a user may use to authenticate
+so they may login to Ambari.  Each user account may have multiple authentication sources of various 
+types (LOCAL, LDAP, JWT, KERBEROS, PAM, etc...). Each authentication source type has its own 
+requirements.  For example, a user may have only one LOCAL authentication source.
+<p/>
+Users with the <code>AMBARI.MANAGE_USERS</code> privilege (currently, Ambari Administrators) can 
+view and update all authentication source resources.  Any other user can only view and (partially) 
+update their own authentication source resources. For example a user may change their own password
+by updating the relevant authentication source resource.  
+
+###API Summary
+
+- [List authentication sources](authentication-source-list.md)
+- [Get authentication source](authentication-source-get.md)
+- [Create authentication source](authentication-source-create.md)
+- [Update authentication source](authentication-source-update.md)
+- [Delete authentication source](authenticationsource-delete.md)
+
+###Properties
+
+<table>
+  <tr>
+    <th>Property</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>AuthenticationSourceInfo/source_id</td>
+    <td>
+      The authentication source's unique id - this value may be used to uniquely identify an 
+      authentication source. 
+      <p/><p/>
+      The value is generated internally and is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>AuthenticationSourceInfo/user_name</td>
+    <td>
+      The parent resource's user name.
+      <p/><p/>
+      The value is read-only.
+     </td>  
+  </tr>
+  <tr>
+    <td>AuthenticationSourceInfo/authentication_type</td>
+    <td>
+      The type of authentication source. Possible values include:
+      <ul>
+        <li>LOCAL - the user has an Ambari-local password</li>
+        <li>LDAP - the user authenticates using an LDAP server</li>
+        <li>KERBEROS - the user authenticates using a Kerberos token</li>
+        <li>PAM - the user authenticates using PAM</li>
+        <li>JWT - the user authenticates using a JWT token from Knox</li>
+      </ul>
+      <p/><p/>
+      The value must be set when creating the resource; otherwise it is read-only. 
+    </td>  
+  </tr>
+  <tr>
+    <td>AuthenticationSourceInfo/key</td>
+    <td>
+      The authencation type-specific key.  For example, if the authentcation type is LOCAL, than
+      the authentication key is the password.
+      <p/><p/>
+      The value is settable by an Ambari administrator and potentially the parent user (depending 
+      on authentication type); otherwise it not returned in queries to .
+    </td>  
+  </tr>
+  <tr>
+    <td>AuthenticationSourceInfo/old_key</td>
+    <td>       
+      This propery may be set when updating an authentication source resource if verification of the
+      current key is needed before being allowed to set a new one.  For eample if setting a new 
+      password for an authentication source of type LOCAL, this value is required when a user is 
+      updating the value.  It is not used when an Ambari user administrator is updating a user's 
+      password.  The need for this property is specific to the requirments of the authentication 
+      source type.
+      <p/><p/>
+      The value is write-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>AuthenticationSourceInfo/created</td>
+    <td>
+      The timestamp indicating when the authentcation source resource was created.
+      <p/><p/>
+      The value is generated internally and is read-only.
+     </td>  
+  </tr>
+  <tr>
+    <td>AuthenticationSourceInfo/updated</td>
+    <td>
+      The timestamp indicating when the authentcation source resource was updated.
+      <p/><p/>
+      The value is generated internally and is read-only.
+     </td>  
+  </tr>
+  </tr>
+</table>
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/authentication-source-update.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/authentication-source-update.md b/ambari-server/docs/api/v1/authentication-source-update.md
new file mode 100644
index 0000000..be2c2a9
--- /dev/null
+++ b/ambari-server/docs/api/v1/authentication-source-update.md
@@ -0,0 +1,104 @@
+
+<!---
+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.
+-->
+
+Modify Authentication Source
+=====
+
+[Back to Authentication Source Resources](authentication-source-resources.md)
+
+**Summary**
+
+Update an existing authentication source identified by <code>:source_id</code> for a user identified
+by <code>:user_name</code>.  If the <code>AuthenticationSourceInfo/authentication_type</code> is set
+the found authentication source resource is tested to ensure it matches the expected value.  
+
+    PUT /user/:user_name/sources/:source_id
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>OK</td>  
+  </tr>
+  <tr>
+    <td>400</td>
+    <td>Bad Request</td>  
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>Unauthorized</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>Forbidden</td>  
+  </tr>
+  <tr>
+    <td>404</td>
+    <td>Not Found</td>  
+  </tr> 
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+</table>
+
+**Examples**
+
+Update an authentication source for user jdoe when authenticated as a user administrator.
+
+    PUT /users/jdoe/sources/1234
+
+    {
+      "AuthenticationSourceInfo": {
+        "key": "new_secret"
+      }
+    }
+
+    200 OK
+
+Update an authentication source for user jdoe when authenticated as a user administrator, verifying 
+that the authentication source resource is a LOCAL authentication source.
+
+    PUT /users/jdoe/sources/1234
+
+    {
+      "AuthenticationSourceInfo": {
+        "authentication_type": "LOCAL",
+        "key": "new_secret"
+      }
+    }
+
+    200 OK
+
+Update an authentication source for user jdoe when authenticated as jdoe.
+
+    PUT /users/jdoe/sources/1234
+
+    {
+      "AuthenticationSourceInfo": {
+        "old_key": "secret",
+        "key": "new_secret"
+      }
+    }
+
+    200 OK

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/index.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/index.md b/ambari-server/docs/api/v1/index.md
index da05d75..d69b214 100644
--- a/ambari-server/docs/api/v1/index.md
+++ b/ambari-server/docs/api/v1/index.md
@@ -372,6 +372,18 @@ Permission resources are used to help determine authorization rights for a user.
 
 [Permission Resources](permission-resources.md)
 
+#### users
+User resources represent users that may use Ambari. A user is given permissions to perform tasks within Ambari.  
+
+[User Resources](user-resources.md)
+
+#### authentication sources
+Authentication source resources are child resources of [user resources](#users). Each source represent an authentication 
+source that a user may use to login into Ambari.  There are different types of authentication sources
+such as (but not limited to) local, LDAP, JWT, and Kerberos.
+
+[Authentication Source Resources](authentication-source-resources.md)
+
 Partial Response
 ----
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/user-create.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/user-create.md b/ambari-server/docs/api/v1/user-create.md
new file mode 100644
index 0000000..47524de
--- /dev/null
+++ b/ambari-server/docs/api/v1/user-create.md
@@ -0,0 +1,107 @@
+
+<!---
+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.
+-->
+
+Create User
+=====
+
+[Back to User Resources](user-resources.md)
+
+**Summary**
+
+Create a new user resource identified by <code>:user_name</code>. 
+<p/><p/>
+Only users with the <code>AMBARI.MANAGE_USERS</code> privilege (currently, Ambari Administrators)
+may perform this operation.
+
+    POST /users/:user_name
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>The authenticated user does not have authorization to create/store user persisted data.</td>  
+  </tr>
+</table>
+
+
+**Examples*
+    
+Create a user with a username of "jdoe".
+    
+    POST /users/jdoe
+    
+    {
+      "Users": {
+        "local_user_name": "jdoe",
+        "display_name": "Jane Doe",
+        "admin" : false
+      }
+    }
+
+    201 Created
+    
+
+Create multiple users.
+    
+    POST /users
+    
+    [
+      {
+        "Users": {
+          "user_name": "UserA",
+          "admin": "true"
+        }
+      },
+      {
+        "Users": {
+          "user_name": "userb",
+          "active": "false"
+        }
+      },
+      {
+        "Users": {
+          "user_name": "userc",
+          "local_user_name": "UserC"
+        }
+      },
+      {
+        "Users": {
+          "user_name": "userd",
+          "local_user_name": "userD",
+          "display_name": "User D"
+        }
+      },
+      {
+        "Users": {
+          "user_name": "usere",
+          "password": "hadoop"
+        }
+      }
+    ]
+    
+    201 Created
+        
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/user-delete.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/user-delete.md b/ambari-server/docs/api/v1/user-delete.md
new file mode 100644
index 0000000..a8a5375
--- /dev/null
+++ b/ambari-server/docs/api/v1/user-delete.md
@@ -0,0 +1,48 @@
+
+<!---
+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.
+-->
+
+Delete User
+=====
+
+[Back to User Resources](user-resources.md)
+
+**Summary**
+
+Removes an existing user resource identified by <code>:user_name</code>. 
+<p/><p/>
+Only users with the <code>AMBARI.MANAGE_USERS</code> privilege (currently, Ambari Administrators)
+may perform this operation.
+
+    DELETE /users/:user_name
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>The authenticated user does not have the appropriate authorizations to delete the requested resource(s)</td>  
+  </tr>
+</table>

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/user-get.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/user-get.md b/ambari-server/docs/api/v1/user-get.md
new file mode 100644
index 0000000..9e8db95
--- /dev/null
+++ b/ambari-server/docs/api/v1/user-get.md
@@ -0,0 +1,97 @@
+
+<!---
+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.
+-->
+
+Get a User
+=====
+
+[Back to User Resources](user-resources.md)
+
+**Summary**
+
+Gets the details about an existing user identified by <code>:user_name</code> 
+
+    GET /users/:user_name
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>OK</td>  
+  </tr>
+  <tr>
+    <td>400</td>
+    <td>Bad Request</td>  
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>Unauthorized</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>The authenticated user is not authorized to perform the requested operation</td>  
+  </tr> 
+  <tr>
+    <td>404</td>
+    <td>Not Found</td>  
+  </tr>
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+</table>
+
+**Example**
+
+Get the user with the user_name of jdoe.
+
+    GET /users/jdoe
+
+    200 OK
+    {
+      "href" : "http://your.ambari.server/api/v1/users/jdoe",
+      "Users" : {
+        "user_id" : 100,
+        "user_name" : "jdoe",
+        "local_user_name" : "jdoe",
+        "display_name" : "Jane Doe",
+        "admin" : false,
+        "active" : true,
+        "consecutive_failures" : 0,
+        "created" : 1497472842569,
+        "groups" : [ ],
+        "ldap_user" : false,
+        "user_type" : "LOCAL"        
+      }
+      "widget_layouts" : [ ],
+      "privileges" : [ ],
+      "sources" : [
+        {
+          "href" : "http://your.ambari.server/api/v1/users/jdoe/sources/1004",
+          "AuthenticationSourceInfo" : {
+            "source_id" : 1004,
+            "user_name" : "jdoe"
+          }
+        }
+      ]
+    }
+    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/user-list.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/user-list.md b/ambari-server/docs/api/v1/user-list.md
new file mode 100644
index 0000000..ee1abbb
--- /dev/null
+++ b/ambari-server/docs/api/v1/user-list.md
@@ -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.
+-->
+
+List Users
+=====
+
+[Back to User Resources](user-resources.md)
+
+**Summary**
+
+Returns a collection of the existing Users.
+
+    GET /users
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>OK</td>  
+  </tr>
+  <tr>
+    <td>400</td>
+    <td>Bad Request</td>  
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>Unauthorized</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>Forbidden</td>  
+  </tr> 
+  <tr>
+    <td>404</td>
+    <td>Not Found</td>  
+  </tr>
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+</table>
+
+**Example**
+
+Get the collection of all currently stored users.
+
+    GET /users
+
+    200 OK
+    {
+      "href" : "http://your.ambari.server/api/v1/users",
+      "items" : [
+        {
+          "href" : "http://your.ambari.server/api/v1/users/admin",
+          "Users" : {
+            "user_name" : "admin"
+          }
+        },
+        {
+          "href" : "http://your.ambari.server/api/v1/users/jdoe",
+          "Users" : {
+            "user_name" : "jdoe"
+          }
+        },
+        {
+          "href" : "http://your.ambari.server/api/v1/users/jsmith",
+          "Users" : {
+            "user_name" : "jsmith"
+          }
+        },
+        {
+          "href" : "http://your.ambari.server/api/v1/users/jqpublic",
+          "Users" : {
+            "user_nane" : "jqpublic"
+          }
+        }
+      ]
+    }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/user-resources.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/user-resources.md b/ambari-server/docs/api/v1/user-resources.md
new file mode 100644
index 0000000..45a17d7
--- /dev/null
+++ b/ambari-server/docs/api/v1/user-resources.md
@@ -0,0 +1,175 @@
+<!---
+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.
+-->
+
+# User Resources
+User resources represent user accounts in Ambari.  Each user account has a set of authentication 
+sources and is is given permission to perform tasks within Ambari.
+<p/>
+Users with the <code>AMBARI.MANAGE_USERS</code> privilege (currently, Ambari Administrators) can 
+view and update all user resources.  Any other user can only view and (partially) update their own 
+user resource.
+
+###API Summary
+
+- [List users](user-list.md)
+- [Get user](user-get.md)
+- [Create user](user-create.md)
+- [Update user](user-update.md)
+- [Delete user](user-delete.md)
+
+###Properties
+
+<table>
+  <tr>
+    <th>Property</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>Users/user_id</td>
+    <td>
+      The user's unique id - this value may be used to uniquely identify a user. 
+      <p/><p/>
+      The value is generated internally and is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/user_name</td>
+    <td>
+      The user's unique name - this value is case-insensitive and may be used to uniquely 
+      identify a user.
+      <p/><p/>
+      The value must be set when creating the resource; otherwise it is read-only. 
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/local_user_name</td>
+    <td>
+      The user's local user name - this value is case-sensitive and used as the username to use 
+      when accessing service via Ambari Views. If not set, the username value will be used.
+      <p/><p/>
+      The value is settable by an Ambari administrator; otherwise it is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/display_name</td>
+    <td>
+      The user's local user name - this value is used for display purposes in messages and user 
+      intefaces. If not set, the username value will be used.
+      <p/><p/>
+      The value is settable by the user or an Ambari administrator.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/active</td>
+    <td>
+      The user's active/inactive status - <code>true</code> if active; <code>false</code> if 
+      inactive.
+      <p/><p/>
+      The value is settable by an Ambari administrator; otherwise it is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/consecutive_failures</td>
+    <td>
+      The number of consecutive authentication failures since the last successful authentication 
+      attempt.
+      <p/><p/>
+      The value is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/created</td>
+    <td>
+      The timestamp indicating when the user resource was created.
+      <p/><p/>
+      The value is generated internally and is read-only.
+     </td>  
+  </tr>
+  <tr>
+    <td>Users/groups</td>
+    <td>
+      The set of groups for which the user is a member.
+      <p/><p/>
+      The value is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/admin</td>
+    <td>
+      Indicates wheather the user has administrative privilieges (<code>true</code>) or not 
+      (<code>false</code>). This propery is deprecated and is provided to maintain the REST API V1 
+      contract. This information may be found by querying for the user's permissions (or roles).
+      <p/><p/>
+      The value is settable by an Ambari administrator; otherwise it is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/ldap_user</td>
+    <td>
+      Indicates wheather the user was imported from an LDAP server. This propery is deprecated 
+      and is provided to maintain the REST API V1 contract. This information may be found by querying
+      for the user's authentication sources.
+      <p/><p/>
+      The value is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/user_type</td>
+    <td>
+      The type of user account. Possible values include:
+      <ul>
+        <li>LOCAL - the user has an Ambari-local password</li>
+        <li>LDAP - the user authenticates using an LDAP server</li>
+        <li>KERBEROS - the user authenticates using a Kerberos token</li>
+        <li>PAM - the user authenticates using PAM</li>
+        <li>JWT - the user authenticates using a JWT token from Knox</li>
+      </ul>
+      This propery is deprecated and is provided to maintain the REST API V1 contract. This 
+      information may be found by querying for the user's authentication sources.  
+      <p/><p/>
+      Since this value contains a single entry, it does not properly indicate what authentication 
+      sources a user may use.  However, if the set of authentication sources contains an LDAP source,
+      this value will be set to LDAP.
+      <p/><p/>
+      The value is read-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/password</td>
+    <td>
+      This propery is deprecated and is provided to maintain the REST API V1 contract.  
+      This propery may be set when creating or updating a user resource to set it's (Ambari) local 
+      password. However, it is expected that a LOCAL authentication source resource is created and
+      updated instead.
+      <p/><p/>
+      The value is write-only.
+    </td>  
+  </tr>
+  <tr>
+    <td>Users/old_password</td>
+    <td>
+      This propery is deprecated and is provided to maintain the REST API V1 contract.  
+      This propery may be set when updating a user resource to set a new password for a (Ambari) local 
+      password. This value is required when a user is updating their own password.  It is not used
+      when an Ambari administrator is updating a user's password.  However, it is expected that a 
+      LOCAL authentication source resource is updated instead.
+      <p/><p/>
+      The value is write-only.
+    </td>  
+  </tr>
+</table>
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/docs/api/v1/user-update.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/api/v1/user-update.md b/ambari-server/docs/api/v1/user-update.md
new file mode 100644
index 0000000..e93388f
--- /dev/null
+++ b/ambari-server/docs/api/v1/user-update.md
@@ -0,0 +1,115 @@
+
+<!---
+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.
+-->
+
+Update a User
+=====
+
+[Back to User Resources](user-resources.md)
+
+**Summary**
+
+Update an existing user resource identified by <code>:user_name</code>
+
+    PUT /user/:user_name
+
+**Response**
+
+<table>
+  <tr>
+    <th>HTTP CODE</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>OK</td>  
+  </tr>
+  <tr>
+    <td>400</td>
+    <td>Bad Request</td>  
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>Unauthorized</td>  
+  </tr>
+  <tr>
+    <td>403</td>
+    <td>The authenticated user does not have authorization to create/store user persisted data.</td>  
+  </tr>
+  <tr>
+    <td>404</td>
+    <td>Not Found</td>  
+  </tr> 
+  <tr>
+    <td>500</td>
+    <td>Internal Server Error</td>  
+  </tr>
+</table>
+
+**Examples**
+
+Update a user.
+
+    PUT /users/jdoe
+
+    {
+      "User" : {
+        "display_name" : "Jane Q. Doe"
+      }
+    }
+    
+    200 OK
+
+Set (create/update) a user's password as a user administrator. Deprecated, see 
+[Source Resources](authentication-source-resources.md).
+
+    POST /users/jdoe
+
+    {
+      "User" : {
+        "password" : "secret"
+      }
+    }
+    
+    200 OK
+
+Change a user's existing password as the (non-administrative) user. Deprecated, see 
+[Source Resources](authentication-source-resources.md).
+
+    POST /users/jdoe
+
+    {
+      "User" : {
+        "password" : "secret",
+        "old_password" : "old_secret"
+      }
+    }
+    
+    200 OK
+
+Set a user to be an Ambari Administrator, as a user administrator. Deprecated, see 
+[Permission Resources](permission-resources.md).
+
+    POST /users/jdoe
+
+    {
+      "User" : {
+        "admin" : true
+      }
+    }
+    
+    200 OK

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/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 96e288f..ababe00 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
@@ -141,6 +141,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new UserResourceDefinition();
         break;
 
+      case UserAuthenticationSource:
+        resourceDefinition = new SimpleResourceDefinition(Resource.Type.UserAuthenticationSource, "source", "sources");
+        break;
+
       case Group:
         resourceDefinition = new GroupResourceDefinition();
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/317905e4/ambari-server/src/main/java/org/apache/ambari/server/api/resources/UserResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/UserResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/UserResourceDefinition.java
index b228c82..c62ca71 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/UserResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/UserResourceDefinition.java
@@ -44,6 +44,7 @@ public class UserResourceDefinition extends BaseResourceDefinition {
   @Override
   public Set<SubResourceDefinition> getSubResourceDefinitions() {
     final Set<SubResourceDefinition> subResourceDefinitions = new HashSet<>();
+    subResourceDefinitions.add(new SubResourceDefinition(Resource.Type.UserAuthenticationSource));
     subResourceDefinitions.add(new SubResourceDefinition(Resource.Type.UserPrivilege));
     subResourceDefinitions.add(new SubResourceDefinition(Resource.Type.ActiveWidgetLayout));
     return subResourceDefinitions;