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/06/15 15:06:15 UTC

[1/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-20859 d7bc588a1 -> f76c87a69


http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 e29791f..e049b4e 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
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.sql.SQLException;
+import java.util.Collection;
 import java.util.List;
 
 import org.apache.ambari.server.AmbariException;
@@ -42,6 +43,7 @@ import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
 import org.apache.ambari.server.orm.entities.ResourceEntity;
 import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.junit.After;
 import org.junit.Before;
@@ -125,65 +127,94 @@ public class TestUsers {
 
   @Test
   public void testIsUserCanBeRemoved() throws Exception {
-    users.createUser("admin", "admin", UserType.LOCAL, true, true);
-    users.createUser("admin222", "admin222", UserType.LOCAL, true, true);
+    UserEntity userEntity;
+
+    userEntity = users.createUser("admin", "admin", "admin");
+    users.grantAdminPrivilege(userEntity);
+
+    userEntity = users.createUser("admin222", "admin222", "admin22");
+    users.grantAdminPrivilege(userEntity);
 
     Assert.assertTrue(users.isUserCanBeRemoved(userDAO.findUserByName("admin")));
     Assert.assertTrue(users.isUserCanBeRemoved(userDAO.findUserByName("admin222")));
 
-    users.removeUser(users.getAnyUser("admin222"));
+    users.removeUser(users.getUser("admin222"));
 
     Assert.assertFalse(users.isUserCanBeRemoved(userDAO.findUserByName("admin")));
-    users.createUser("user", "user");
+    users.createUser("user", "user", "user");
     Assert.assertFalse(users.isUserCanBeRemoved(userDAO.findUserByName("admin")));
 
-    users.createUser("admin333", "admin333", UserType.LOCAL, true, true);
+    userEntity = users.createUser("admin333", "admin333", "admin333");
+    users.grantAdminPrivilege(userEntity);
+
     Assert.assertTrue(users.isUserCanBeRemoved(userDAO.findUserByName("admin")));
     Assert.assertTrue(users.isUserCanBeRemoved(userDAO.findUserByName("admin333")));
   }
 
   @Test
   public void testModifyPassword_UserByAdmin() throws Exception {
-    users.createUser("admin", "admin", UserType.LOCAL, true, true);
-    users.createUser("user", "user");
+    UserEntity userEntity;
+
+    userEntity = users.createUser("admin", "admin", "admin");
+    users.grantAdminPrivilege(userEntity);
+    users.addLocalAuthentication(userEntity, "admin");
 
-    UserEntity userEntity = userDAO.findUserByName("user");
+    userEntity = users.createUser("user", "user", "user");
+    users.addLocalAuthentication(userEntity, "user");
 
-    assertNotSame("user", userEntity.getUserPassword());
-    assertTrue(passwordEncoder.matches("user", userEntity.getUserPassword()));
+    UserEntity foundUserEntity = userDAO.findUserByName("user");
+    assertNotNull(foundUserEntity);
 
-    users.modifyPassword("user", "admin", "user_new_password");
-    assertTrue(passwordEncoder.matches("user_new_password", userDAO.findUserByName("user").getUserPassword()));
+    UserAuthenticationEntity foundLocalAuthenticationEntity;
+    foundLocalAuthenticationEntity = getLocalAuthenticationEntity(foundUserEntity);
+    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");
+
+    foundUserEntity = userDAO.findUserByName("admin");
+    assertNotNull(foundUserEntity);
+    foundLocalAuthenticationEntity = getLocalAuthenticationEntity(foundUserEntity);
+    assertNotNull(foundLocalAuthenticationEntity);
+    assertTrue(passwordEncoder.matches("user_new_password", foundLocalAuthenticationEntity.getAuthenticationKey()));
   }
 
   @Test
   public void testRevokeAdminPrivilege() throws Exception {
-    users.createUser("old_admin", "old_admin", UserType.LOCAL, true, true);
+    final UserEntity userEntity = users.createUser("old_admin", "old_admin", "old_admin");
+    users.grantAdminPrivilege(userEntity);
 
-    final User admin = users.getAnyUser("old_admin");
+    final User admin = users.getUser("old_admin");
     users.revokeAdminPrivilege(admin.getUserId());
 
-    Assert.assertFalse(users.getAnyUser("old_admin").isAdmin());
+    Assert.assertFalse(users.getUser("old_admin").isAdmin());
   }
 
   @Test
   public void testGrantAdminPrivilege() throws Exception {
-    users.createUser("user", "user");
+    users.createUser("user", "user", "user");
 
-    final User user = users.getAnyUser("user");
+    final User user = users.getUser("user");
     users.grantAdminPrivilege(user.getUserId());
 
-    Assert.assertTrue(users.getAnyUser("user").isAdmin());
+    Assert.assertTrue(users.getUser("user").isAdmin());
   }
 
   @Test
   public void testCreateGetRemoveUser() throws Exception {
-    users.createUser("user1", "user1");
-    users.createUser("user", "user", UserType.LOCAL, false, false);
-    users.createUser("user_ldap", "user_ldap", UserType.LDAP, true, true);
-    User createdUser = users.getUser("user", UserType.LOCAL);
-    User createdUser1 = users.getAnyUser("user1");
-    User createdLdapUser = users.getUser("user_ldap", UserType.LDAP);
+    users.createUser("user1", "user1", null);
+    users.createUser("user", "user", null, false);
+
+    UserEntity userEntity = users.createUser("user_ldap", "user_ldap", null);
+    users.grantAdminPrivilege(userEntity);
+    users.addLdapAuthentication(userEntity, "some dn");
+
+    User createdUser = users.getUser("user");
+    User createdUser1 = users.getUser("user1");
+    User createdLdapUser = users.getUser("user_ldap");
 
     Assert.assertEquals("user1", createdUser1.getUserName());
     Assert.assertEquals(true, createdUser1.isActive());
@@ -200,21 +231,23 @@ public class TestUsers {
     Assert.assertEquals(true, createdLdapUser.isLdapUser());
     Assert.assertEquals(true, createdLdapUser.isAdmin());
 
-    assertEquals("user", users.getAnyUser("user").getUserName());
-    assertEquals("user_ldap", users.getAnyUser("user_ldap").getUserName());
-    Assert.assertNull(users.getAnyUser("non_existing"));
+    assertEquals("user", users.getUser("user").getUserName());
+    assertEquals("user_ldap", users.getUser("user_ldap").getUserName());
+    Assert.assertNull(users.getUser("non_existing"));
 
     // create duplicate user
     try {
-      users.createUser("user1", "user1");
+      users.createUser("user1", "user1", null);
       Assert.fail("It shouldn't be possible to create duplicate user");
     } catch (AmbariException e) {
+      // This is expected
     }
 
     try {
-      users.createUser("USER1", "user1");
+      users.createUser("USER1", "user1", null);
       Assert.fail("It shouldn't be possible to create duplicate user");
     } catch (AmbariException e) {
+      // This is expected
     }
 
     // test get all users
@@ -223,9 +256,9 @@ public class TestUsers {
     Assert.assertEquals(3, userList.size());
 
     // check get any user case insensitive
-    assertEquals("user", users.getAnyUser("USER").getUserName());
-    assertEquals("user_ldap", users.getAnyUser("USER_LDAP").getUserName());
-    Assert.assertNull(users.getAnyUser("non_existing"));
+    assertEquals("user", users.getUser("USER").getUserName());
+    assertEquals("user_ldap", users.getUser("USER_LDAP").getUserName());
+    Assert.assertNull(users.getUser("non_existing"));
 
     // get user by id
     User userById = users.getUser(createdUser.getUserId());
@@ -239,45 +272,52 @@ public class TestUsers {
     assertNull(userByInvalidId);
 
     // get user if unique
-    Assert.assertNotNull(users.getUserIfUnique("user"));
+    Assert.assertNotNull(users.getUser("user"));
 
     //remove user
     Assert.assertEquals(3, users.getAllUsers().size());
 
-    users.removeUser(users.getAnyUser("user1"));
+    users.removeUser(users.getUser("user1"));
 
-    Assert.assertNull(users.getAnyUser("user1"));
+    Assert.assertNull(users.getUser("user1"));
     Assert.assertEquals(2, users.getAllUsers().size());
   }
 
   @Test
   public void testSetUserActive() throws Exception {
-    users.createUser("user", "user");
+    users.createUser("user", "user", null);
 
     users.setUserActive("user", false);
-    Assert.assertEquals(false, users.getAnyUser("user").isActive());
+    Assert.assertEquals(false, users.getUser("user").isActive());
     users.setUserActive("user", true);
-    Assert.assertEquals(true, users.getAnyUser("user").isActive());
+    Assert.assertEquals(true, users.getUser("user").isActive());
 
     try {
       users.setUserActive("fake user", true);
       Assert.fail("It shouldn't be possible to call setUserActive() on non-existing user");
     } catch (Exception ex) {
+      // This is expected
     }
   }
 
   @Test
   public void testSetUserLdap() throws Exception {
-    users.createUser("user", "user");
-    users.createUser("user_ldap", "user_ldap", UserType.LDAP, true, false);
+    UserEntity userEntity;
+
+    users.createUser("user", "user", null);
+    users.addLdapAuthentication(users.getUserEntity("user"), "some dn");
 
-    users.setUserLdap("user");
-    Assert.assertEquals(true, users.getAnyUser("user").isLdapUser());
+    userEntity = users.createUser("user_ldap", "user_ldap", null);
+    users.addLdapAuthentication(userEntity, "some dn");
+
+    Assert.assertEquals(true, users.getUser("user").isLdapUser());
+    Assert.assertEquals(true, users.getUser("user_ldap").isLdapUser());
 
     try {
-      users.setUserLdap("fake user");
+      users.addLdapAuthentication(users.getUserEntity("fake user"), "some other dn");
       Assert.fail("It shouldn't be possible to call setUserLdap() on non-existing user");
     } catch (AmbariException ex) {
+      // This is expected
     }
   }
 
@@ -293,6 +333,7 @@ public class TestUsers {
       users.setGroupLdap("fake group");
       Assert.fail("It shouldn't be possible to call setGroupLdap() on non-existing group");
     } catch (AmbariException ex) {
+      // This is expected
     }
   }
 
@@ -328,9 +369,9 @@ public class TestUsers {
     final String groupName2 = "engineering2";
     users.createGroup(groupName, GroupType.LOCAL);
     users.createGroup(groupName2, GroupType.LOCAL);
-    users.createUser("user1", "user1");
-    users.createUser("user2", "user2");
-    users.createUser("user3", "user3");
+    users.createUser("user1", "user1", null);
+    users.createUser("user2", "user2", null);
+    users.createUser("user3", "user3", null);
     users.addMemberToGroup(groupName, "user1");
     users.addMemberToGroup(groupName, "user2");
     assertEquals(2, users.getAllMembers(groupName).size());
@@ -340,6 +381,7 @@ public class TestUsers {
       users.getAllMembers("non existing");
       Assert.fail("It shouldn't be possible to call getAllMembers() on non-existing group");
     } catch (Exception ex) {
+      // This is expected
     }
 
     // get members from not unexisting group
@@ -356,16 +398,22 @@ public class TestUsers {
     Authentication auth = new UsernamePasswordAuthenticationToken("user", null);
     SecurityContextHolder.getContext().setAuthentication(auth);
 
-    users.createUser("user", "user");
+    UserEntity userEntity = users.createUser("user", "user", null);
+    users.addLocalAuthentication(userEntity, "user");
 
-    UserEntity userEntity = userDAO.findUserByName("user");
+    userEntity = userDAO.findUserByName("user");
+    UserAuthenticationEntity localAuthenticationEntity = getLocalAuthenticationEntity(userEntity);
+    assertNotNull(localAuthenticationEntity);
 
-    assertNotSame("user", userEntity.getUserPassword());
-    assertTrue(passwordEncoder.matches("user", userEntity.getUserPassword()));
+    assertNotSame("user", localAuthenticationEntity.getAuthenticationKey());
+    assertTrue(passwordEncoder.matches("user", localAuthenticationEntity.getAuthenticationKey()));
 
     users.modifyPassword("user", "user", "user_new_password");
+    userEntity = userDAO.findUserByName("user");
+    localAuthenticationEntity = getLocalAuthenticationEntity(userEntity);
+    assertNotNull(localAuthenticationEntity);
 
-    assertTrue(passwordEncoder.matches("user_new_password", userDAO.findUserByName("user").getUserPassword()));
+    assertTrue(passwordEncoder.matches("user_new_password", localAuthenticationEntity.getAuthenticationKey()));
   }
 
   @Test
@@ -373,17 +421,21 @@ public class TestUsers {
     Authentication auth = new UsernamePasswordAuthenticationToken("user", null);
     SecurityContextHolder.getContext().setAuthentication(auth);
 
-    users.createUser("user", "user");
-
-    UserEntity userEntity = userDAO.findUserByName("user");
+    UserEntity userEntity = users.createUser("user", "user", null);
+    users.addLocalAuthentication(userEntity, "user");
 
-    assertNotSame("user", userEntity.getUserPassword());
-    assertTrue(passwordEncoder.matches("user", userEntity.getUserPassword()));
+    userEntity = userDAO.findUserByName("user");
+    UserAuthenticationEntity foundLocalAuthenticationEntity;
+    foundLocalAuthenticationEntity = getLocalAuthenticationEntity(userEntity);
+    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");
     } catch (AmbariException ex) {
+      // This is expected
     }
   }
 
@@ -392,18 +444,23 @@ public class TestUsers {
     Authentication auth = new UsernamePasswordAuthenticationToken("user2", null);
     SecurityContextHolder.getContext().setAuthentication(auth);
 
-    users.createUser("user", "user");
-    users.createUser("user2", "user2");
+    UserEntity userEntity;
+    userEntity = users.createUser("user", "user", null);
+    users.addLocalAuthentication(userEntity, "user");
 
-    UserEntity userEntity = userDAO.findUserByName("user");
+    userEntity = users.createUser("user2", "user2", null);
+    users.addLocalAuthentication(userEntity, "user2");
 
-    assertNotSame("user", userEntity.getUserPassword());
-    assertTrue(passwordEncoder.matches("user", userEntity.getUserPassword()));
+    UserAuthenticationEntity foundLocalAuthenticationEntity = getLocalAuthenticationEntity(userDAO.findUserByName("user"));
+    assertNotNull(foundLocalAuthenticationEntity);
+    assertNotSame("user", foundLocalAuthenticationEntity.getAuthenticationKey());
+    assertTrue(passwordEncoder.matches("user", foundLocalAuthenticationEntity.getAuthenticationKey()));
 
     try {
       users.modifyPassword("user", "user2", "user_new_password");
       Assert.fail("Exception should be thrown here as user2 can't change password of user");
-    } catch (AmbariException ex) {
+    } catch (AuthorizationException ex) {
+      // This is expected
     }
   }
 
@@ -411,9 +468,20 @@ public class TestUsers {
   @Ignore // TODO @Transactional annotation breaks this test
   public void testCreateUserDefaultParams() throws Exception {
     final Users spy = Mockito.spy(users);
-    spy.createUser("user", "user");
-    Mockito.verify(spy).createUser("user", "user", UserType.LOCAL, true, false);
+    spy.createUser("user", "user", null);
+    Mockito.verify(spy).createUser("user", "user", null);
   }
 
+  private UserAuthenticationEntity getLocalAuthenticationEntity(UserEntity userEntity) {
+    assertNotNull(userEntity);
+    Collection<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+    assertNotNull(authenticationEntities);
+    for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+      if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LOCAL) {
+        return authenticationEntity;
+      }
+    }
 
+    return null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java
index ac91c90..ffa68fa 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java
@@ -63,7 +63,7 @@ import junit.framework.Assert;
 
 public class UsersTest extends EasyMockSupport {
 
-  public static final String SERVICEOP_USER_NAME = "serviceopuser";
+  private static final String SERVICEOP_USER_NAME = "serviceopuser";
   private Injector injector;
 
   @Test
@@ -76,7 +76,7 @@ public class UsersTest extends EasyMockSupport {
     expect(userEntity.getPrincipal()).andReturn(userPrincipalEntity).times(1);
 
     UserDAO userDAO = injector.getInstance(UserDAO.class);
-    expect(userDAO.findUserByNameAndType("user1", UserType.LOCAL)).andReturn(userEntity).times(1);
+    expect(userDAO.findUserByName("user1")).andReturn(userEntity).times(1);
 
     PrincipalEntity groupPrincipalEntity = createMock(PrincipalEntity.class);
 
@@ -125,7 +125,7 @@ public class UsersTest extends EasyMockSupport {
     replayAll();
 
     Users user = injector.getInstance(Users.class);
-    Collection<AmbariGrantedAuthority> authorities = user.getUserAuthorities("user1", UserType.LOCAL);
+    Collection<AmbariGrantedAuthority> authorities = user.getUserAuthorities("user1");
 
     verifyAll();
 
@@ -151,7 +151,7 @@ public class UsersTest extends EasyMockSupport {
   public void testCreateUser_NoDuplicates() throws Exception {
     initForCreateUser(null);
     Users users = injector.getInstance(Users.class);
-    users.createUser(SERVICEOP_USER_NAME, "qwert");
+    users.createUser(SERVICEOP_USER_NAME, SERVICEOP_USER_NAME, SERVICEOP_USER_NAME);
   }
 
   /**
@@ -161,8 +161,7 @@ public class UsersTest extends EasyMockSupport {
   @Test(expected = AmbariException.class)
   public void testCreateUser_Duplicate() throws Exception {
     UserEntity existing = new UserEntity();
-    existing.setUserName(UserName.fromString(SERVICEOP_USER_NAME));
-    existing.setUserType(UserType.LDAP);
+    existing.setUserName(UserName.fromString(SERVICEOP_USER_NAME).toString());
     existing.setUserId(1);
     existing.setMemberEntities(Collections.<MemberEntity>emptySet());
     PrincipalEntity principal = new PrincipalEntity();
@@ -171,12 +170,12 @@ public class UsersTest extends EasyMockSupport {
     initForCreateUser(existing);
 
     Users users = injector.getInstance(Users.class);
-    users.createUser(SERVICEOP_USER_NAME, "qwert");
+    users.createUser(SERVICEOP_USER_NAME, SERVICEOP_USER_NAME, SERVICEOP_USER_NAME);
   }
 
   private void initForCreateUser(@Nullable UserEntity existingUser) {
     UserDAO userDao = createStrictMock(UserDAO.class);
-    expect(userDao.findSingleUserByName(anyString())).andReturn(existingUser);
+    expect(userDao.findUserByName(anyString())).andReturn(existingUser);
     userDao.create(anyObject(UserEntity.class));
     expectLastCall();
     EntityManager entityManager = createNiceMock(EntityManager.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java
index 24f5f88..47df030 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java
@@ -47,7 +47,6 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 import org.apache.ambari.server.security.authorization.User;
-import org.apache.ambari.server.security.authorization.UserType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
@@ -170,16 +169,15 @@ public class JwtAuthenticationFilterTest {
       withConstructor(properties, entryPoint, users).createNiceMock();
 
     expect(filter.getJWTFromCookie(anyObject(HttpServletRequest.class))).andReturn(signedJWT.serialize());
-    expect(users.getUser(eq("test-user"), eq(UserType.JWT))).andReturn(null).once();
-    expect(users.getUser(eq("test-user"), eq(UserType.JWT))).andReturn(user).anyTimes();
+    expect(users.getUser(eq("test-user"))).andReturn(null).once();
+    expect(users.getUser(eq("test-user"))).andReturn(user).anyTimes();
 
-    users.createUser(eq("test-user"), anyObject(String.class), eq(UserType.JWT), eq(true), eq(false));
+    users.createUser(eq("test-user"), eq("test-user"), eq("test-user"));
     expectLastCall();
 
-    expect(users.getUserAuthorities(eq("test-user"), eq(UserType.JWT))).andReturn(Collections.singletonList(authority));
+    expect(users.getUserAuthorities(eq("test-user"))).andReturn(Collections.singletonList(authority));
 
     expect(user.getUserName()).andReturn("test-user");
-    expect(user.getUserType()).andReturn(UserType.JWT);
 
     expect(user.getUserId()).andReturn(1);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
index 63b6927..cf05425 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulatorTest.java
@@ -53,12 +53,14 @@ import org.apache.ambari.server.orm.entities.GroupEntity;
 import org.apache.ambari.server.orm.entities.MemberEntity;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.authorization.AmbariLdapUtils;
 import org.apache.ambari.server.security.authorization.Group;
 import org.apache.ambari.server.security.authorization.GroupType;
 import org.apache.ambari.server.security.authorization.LdapServerProperties;
 import org.apache.ambari.server.security.authorization.User;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.security.authorization.UserName;
 import org.apache.ambari.server.security.authorization.Users;
 import org.easymock.Capture;
@@ -1971,14 +1973,15 @@ public class AmbariLdapDataPopulatorTest {
   private User createUser(String name, boolean ldapUser, GroupEntity group) {
     final UserEntity userEntity = new UserEntity();
     userEntity.setUserId(userIdCounter++);
-    userEntity.setUserName(UserName.fromString(name));
+    userEntity.setUserName(UserName.fromString(name).toString());
     userEntity.setCreateTime(new Date());
-    userEntity.setLdapUser(ldapUser);
     userEntity.setActive(true);
     userEntity.setMemberEntities(new HashSet<MemberEntity>());
+
     final PrincipalEntity principalEntity = new PrincipalEntity();
     principalEntity.setPrivileges(new HashSet<PrivilegeEntity>());
     userEntity.setPrincipal(principalEntity);
+
     if (group != null) {
       final MemberEntity member = new MemberEntity();
       member.setUser(userEntity);
@@ -1986,6 +1989,18 @@ public class AmbariLdapDataPopulatorTest {
       group.getMemberEntities().add(member);
       userEntity.getMemberEntities().add(member);
     }
+
+    UserAuthenticationEntity userAuthenticationEntity = new UserAuthenticationEntity();
+    if(ldapUser) {
+      userAuthenticationEntity.setAuthenticationType(UserAuthenticationType.LDAP);
+      userAuthenticationEntity.setAuthenticationKey("some dn");
+    }
+    else {
+      userAuthenticationEntity.setAuthenticationType(UserAuthenticationType.LOCAL);
+      userAuthenticationEntity.setAuthenticationKey("some password (normally encoded)");
+    }
+    userEntity.setAuthenticationEntities(Collections.singletonList(userAuthenticationEntity));
+
     return new User(userEntity);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
index f106658..55a6436 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
@@ -93,7 +93,6 @@ import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 import org.apache.ambari.server.orm.entities.WidgetEntity;
 import org.apache.ambari.server.security.authorization.ResourceType;
 import org.apache.ambari.server.security.authorization.User;
-import org.apache.ambari.server.security.authorization.UserName;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.stack.StackManagerFactory;
 import org.apache.ambari.server.state.AlertFirmness;
@@ -2614,11 +2613,11 @@ public class UpgradeCatalog240Test {
     expect(requestScheduleDAO.findAll()).andReturn(Collections.singletonList(requestScheduleEntity)).once();
 
     UserEntity userEntity = new UserEntity();
-    userEntity.setUserName(UserName.fromString("createdUser"));
+    userEntity.setUserName("createdUser");
     userEntity.setUserId(1);
     userEntity.setPrincipal(new PrincipalEntity());
     User user = new User(userEntity);
-    expect(users.getUserIfUnique("createdUser")).andReturn(user).once();
+    expect(users.getUser("createdUser")).andReturn(user).once();
 
     expect(requestScheduleDAO.merge(requestScheduleEntity)).andReturn(requestScheduleEntity).once();
 
@@ -2658,7 +2657,7 @@ public class UpgradeCatalog240Test {
 
     expect(requestScheduleDAO.findAll()).andReturn(Collections.singletonList(requestScheduleEntity)).once();
 
-    expect(users.getUserIfUnique("createdUser")).andReturn(null).once();
+    expect(users.getUser("createdUser")).andReturn(null).once();
 
     final Injector injector = Guice.createInjector(new AbstractModule() {
       @Override


[6/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 d7d54a5..6347bfa 100644
--- a/ambari-server/docs/api/generated/swagger.json
+++ b/ambari-server/docs/api/generated/swagger.json
@@ -17,23 +17,22 @@
     "name" : "Blueprints",
     "description" : "Endpoint for blueprint specific operations"
   }, {
+    "name" : "Cluster Services",
+    "description" : "Endpoint for service specific operations"
+  }, {
     "name" : "Groups",
     "description" : "Endpoint for group specific operations"
   }, {
     "name" : "Requests",
     "description" : "Endpoint for request specific operations"
   }, {
-    "name" : "Services",
-    "description" : "Endpoint for service specific operations"
-  }, {
     "name" : "Stacks",
     "description" : "Endpoint for stack specific operations"
   }, {
     "name" : "Users",
     "description" : "Endpoint for user specific operations"
   }, {
-    "name" : "Views",
-    "description" : "Endpoint for view specific operations"
+    "name" : "Views"
   }, {
     "name" : "clusters",
     "description" : "Endpoint for cluster-specific operations"
@@ -1018,27 +1017,27 @@
         }
       }
     },
-    "/groups" : {
+    "/clusters/{clusterName}/services" : {
       "get" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Get all groups",
-        "description" : "Returns details of all groups.",
-        "operationId" : "GroupService#getGroups",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Get all services",
+        "description" : "Returns all services.",
+        "operationId" : "ServiceService#getServices",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter group details",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Groups/*"
+          "default" : "ServiceInfo/service_name, ServiceInfo/cluster_name"
         }, {
           "name" : "sortBy",
           "in" : "query",
-          "description" : "Sort groups (asc | desc)",
+          "description" : "Sort resources in result by (asc | desc)",
           "required" : false,
           "type" : "string",
-          "default" : "Groups/group_name.asc"
+          "default" : "ServiceInfo/service_name.asc, ServiceInfo/cluster_name.asc"
         }, {
           "name" : "page_size",
           "in" : "query",
@@ -1049,94 +1048,194 @@
         }, {
           "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"
         }, {
           "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"
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
-            "description" : "Successful retrieval of all group entries",
+            "description" : "Successful operation",
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/GroupResponse"
+                "$ref" : "#/definitions/ServiceResponseSwagger"
+              }
+            }
+          },
+          "500" : {
+            "description" : "Internal server error"
+          }
+        }
+      }
+    },
+    "/clusters/{clusterName}/services/{serviceName}" : {
+      "get" : {
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Get the details of a service",
+        "description" : "Returns the details of a service.",
+        "operationId" : "ServiceService#getService",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "serviceName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "required" : false,
+          "type" : "string",
+          "default" : "ServiceInfo/*"
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation",
+            "schema" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/definitions/ServiceResponseSwagger"
               }
             }
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "500" : {
+            "description" : "Internal server error"
           }
         }
       },
       "post" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Create new group",
-        "description" : "Creates group resource.",
-        "operationId" : "GroupService#createGroup",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Creates a service",
+        "description" : "",
+        "operationId" : "ServiceService#createServices",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
+          "name" : "serviceName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
           "in" : "body",
           "name" : "body",
-          "description" : "input parameters in json form",
-          "required" : true,
+          "required" : false,
           "schema" : {
-            "$ref" : "#/definitions/GroupRequest"
+            "$ref" : "#/definitions/ServiceRequestSwagger"
           }
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
-          "200" : {
-            "description" : "successful operation"
+          "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"
           }
         }
-      }
-    },
-    "/groups/{groupName}" : {
-      "get" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Get group",
-        "description" : "Returns group details.",
-        "operationId" : "GroupService#getGroup",
+      },
+      "put" : {
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Updates a service",
+        "description" : "",
+        "operationId" : "ServiceService#updateService",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "groupName",
+          "name" : "serviceName",
           "in" : "path",
-          "description" : "group name",
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter group details",
+          "in" : "body",
+          "name" : "body",
           "required" : false,
-          "type" : "string",
-          "default" : "Groups"
+          "schema" : {
+            "$ref" : "#/definitions/ServiceRequestSwagger"
+          }
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
-            "description" : "Successful retrieval of group resource",
-            "schema" : {
-              "$ref" : "#/definitions/GroupResponse"
-            }
+            "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."
+          },
+          "500" : {
+            "description" : "Internal server error"
           }
         }
       },
       "delete" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Delete group",
-        "description" : "Delete group resource.",
-        "operationId" : "GroupService#deleteGroup",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Deletes a service",
+        "description" : "",
+        "operationId" : "ServiceService#deleteService",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "groupName",
+          "name" : "serviceName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "clusterName",
           "in" : "path",
-          "description" : "group name",
           "required" : true,
           "type" : "string"
         } ],
@@ -1144,39 +1243,47 @@
           "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" : "Server Error"
+            "description" : "Internal server error"
           }
         }
       }
     },
-    "/groups/{groupName}/members" : {
+    "/clusters/{clusterName}/services/{serviceName}/artifacts" : {
       "get" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Get all group members",
-        "description" : "Returns details of all members.",
-        "operationId" : "MemberService#getMembers",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Get all service artifacts",
+        "description" : "",
+        "operationId" : "ServiceService#getArtifacts",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "groupName",
+          "name" : "serviceName",
           "in" : "path",
-          "description" : "group name",
           "required" : true,
           "type" : "string"
         }, {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter member details",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "MemberInfo/*"
+          "default" : "Artifacts/artifact_name"
         }, {
           "name" : "sortBy",
           "in" : "query",
-          "description" : "Sort members (asc | desc)",
+          "description" : "Sort resources in result by (asc | desc)",
           "required" : false,
           "type" : "string",
-          "default" : "MemberInfo/user_name.asc"
+          "default" : "Artifacts/artifact_name"
         }, {
           "name" : "page_size",
           "in" : "query",
@@ -1187,16 +1294,21 @@
         }, {
           "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"
         }, {
           "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"
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
@@ -1204,95 +1316,80 @@
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/MemberResponse"
+                "$ref" : "#/definitions/ClusterServiceArtifactResponse"
               }
             }
+          },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
+          "500" : {
+            "description" : "Internal server error"
           }
         }
       },
       "put" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Update group members",
-        "description" : "Updates group member resources.",
-        "operationId" : "MemberService#updateMembers",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Updates multiple artifacts",
+        "description" : "",
+        "operationId" : "ServiceService#updateArtifacts",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "groupName",
+          "name" : "serviceName",
           "in" : "path",
-          "description" : "group name",
           "required" : true,
           "type" : "string"
         }, {
           "in" : "body",
           "name" : "body",
-          "description" : "input parameters in json form",
-          "required" : true,
+          "required" : false,
           "schema" : {
-            "$ref" : "#/definitions/MemberRequest"
+            "$ref" : "#/definitions/ClusterServiceArtifactRequest"
           }
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation"
           },
-          "500" : {
-            "description" : "Server Error"
-          }
-        }
-      }
-    },
-    "/groups/{groupName}/members/{userName}" : {
-      "get" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Get group member",
-        "description" : "Returns member details.",
-        "operationId" : "MemberService#getMember",
-        "produces" : [ "text/plain" ],
-        "parameters" : [ {
-          "name" : "groupName",
-          "in" : "path",
-          "description" : "group name",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "userName",
-          "in" : "path",
-          "description" : "user name",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter member details",
-          "required" : false,
-          "type" : "string",
-          "default" : "MemberInfo"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "Successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/MemberResponse"
-            }
+          "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."
+          },
+          "500" : {
+            "description" : "Internal server error"
           }
         }
       },
       "delete" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Delete group member",
-        "description" : "Delete member resource.",
-        "operationId" : "MemberService#deleteMember",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Deletes all artifacts of a service that match the provided predicate",
+        "description" : "",
+        "operationId" : "ServiceService#deleteArtifacts",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "groupName",
+          "name" : "serviceName",
           "in" : "path",
-          "description" : "group name",
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "userName",
+          "name" : "clusterName",
           "in" : "path",
-          "description" : "user name",
           "required" : true,
           "type" : "string"
         } ],
@@ -1300,131 +1397,52 @@
           "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" : "Server Error"
-          }
-        }
-      }
-    },
-    "/groups/{groupName}/privileges" : {
-      "get" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Get all privileges",
-        "description" : "Returns all privileges for group.",
-        "operationId" : "GroupPrivilegeService#getPrivileges",
-        "produces" : [ "text/plain" ],
-        "parameters" : [ {
-          "name" : "groupName",
-          "in" : "path",
-          "description" : "group name",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter user privileges",
-          "required" : false,
-          "type" : "string",
-          "default" : "PrivilegeInfo/*"
-        }, {
-          "name" : "sortBy",
-          "in" : "query",
-          "description" : "Sort user privileges (asc | desc)",
-          "required" : false,
-          "type" : "string",
-          "default" : "PrivilegeInfo/user_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/GroupPrivilegeResponse"
-              }
-            }
+            "description" : "Internal server error"
           }
         }
       }
     },
-    "/groups/{groupName}/privileges/{privilegeId}" : {
+    "/clusters/{clusterName}/services/{serviceName}/artifacts/{artifactName}" : {
       "get" : {
-        "tags" : [ "Groups" ],
-        "summary" : "Get group privilege",
-        "description" : "Returns group privilege details.",
-        "operationId" : "GroupPrivilegeService#getPrivilege",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Get the details of a service artifact",
+        "description" : "",
+        "operationId" : "ServiceService#getArtifact",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "groupName",
+          "name" : "serviceName",
           "in" : "path",
-          "description" : "group name",
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "privilegeId",
+          "name" : "artifactName",
           "in" : "path",
-          "description" : "privilege id",
           "required" : true,
           "type" : "string"
         }, {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter group privilege details",
-          "required" : false,
-          "type" : "string",
-          "default" : "PrivilegeInfo/*"
-        } ],
-        "responses" : {
-          "200" : {
-            "description" : "Successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/PrivilegeResponse"
-            }
-          }
-        }
-      }
-    },
-    "/hosts" : {
-      "get" : {
-        "tags" : [ "hosts" ],
-        "summary" : "Returns a collection of all hosts",
-        "description" : "",
-        "operationId" : "getHosts",
-        "produces" : [ "text/plain" ],
-        "parameters" : [ {
-          "name" : "fields",
-          "in" : "query",
           "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Hosts/*"
+          "default" : "Artifacts/artifact_name"
         }, {
           "name" : "sortBy",
           "in" : "query",
           "description" : "Sort resources in result by (asc | desc)",
           "required" : false,
           "type" : "string",
-          "default" : "Hosts/host_name.asc"
+          "default" : "Artifacts/artifact_name"
         }, {
           "name" : "page_size",
           "in" : "query",
@@ -1437,16 +1455,19 @@
           "in" : "query",
           "description" : "The starting page resource (inclusive).  \"start\" is also accepted.",
           "required" : false,
-          "type" : "integer",
-          "default" : 0,
-          "minimum" : 0.0
+          "type" : "string",
+          "default" : "0"
         }, {
           "name" : "to",
           "in" : "query",
           "description" : "The ending page resource (inclusive).  \"end\" is also accepted.",
           "required" : false,
-          "type" : "integer",
-          "minimum" : 1.0
+          "type" : "string"
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
@@ -1454,18 +1475,12 @@
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/Wrapper"
+                "$ref" : "#/definitions/ClusterServiceArtifactResponse"
               }
             }
           },
-          "401" : {
-            "description" : "Not authenticated"
-          },
-          "403" : {
-            "description" : "Not permitted to perform the operation"
-          },
           "404" : {
-            "description" : "Cluster not found"
+            "description" : "The requested resource doesn't exist."
           },
           "500" : {
             "description" : "Internal server error"
@@ -1473,18 +1488,33 @@
         }
       },
       "post" : {
-        "tags" : [ "hosts" ],
-        "summary" : "Creates multiple hosts in a single request",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Creates a service artifact",
         "description" : "",
-        "operationId" : "createHosts",
+        "operationId" : "ServiceService#createArtifact",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
+          "name" : "serviceName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "artifactName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
           "in" : "body",
           "name" : "body",
           "required" : false,
           "schema" : {
-            "$ref" : "#/definitions/HostRequest"
+            "$ref" : "#/definitions/ClusterServiceArtifactRequest"
           }
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
           "201" : {
@@ -1494,7 +1524,7 @@
             "description" : "Request is accepted, but not completely processed yet"
           },
           "400" : {
-            "description" : "Attempt to add hosts that have not been registered"
+            "description" : "Invalid arguments"
           },
           "401" : {
             "description" : "Not authenticated"
@@ -1503,10 +1533,10 @@
             "description" : "Not permitted to perform the operation"
           },
           "404" : {
-            "description" : "Cluster not found"
+            "description" : "The requested resource doesn't exist."
           },
           "409" : {
-            "description" : "Attempt to create a host which already exists"
+            "description" : "The requested resource already exists."
           },
           "500" : {
             "description" : "Internal server error"
@@ -1514,18 +1544,33 @@
         }
       },
       "put" : {
-        "tags" : [ "hosts" ],
-        "summary" : "Updates multiple hosts in a single request",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Updates a single artifact",
         "description" : "",
-        "operationId" : "updateHosts",
+        "operationId" : "ServiceService#updateArtifact",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
+          "name" : "serviceName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "artifactName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
           "in" : "body",
           "name" : "body",
           "required" : false,
           "schema" : {
-            "$ref" : "#/definitions/HostRequest"
+            "$ref" : "#/definitions/ClusterServiceArtifactRequest"
           }
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
@@ -1544,7 +1589,7 @@
             "description" : "Not permitted to perform the operation"
           },
           "404" : {
-            "description" : "Cluster or host not found"
+            "description" : "The requested resource doesn't exist."
           },
           "500" : {
             "description" : "Internal server error"
@@ -1552,18 +1597,26 @@
         }
       },
       "delete" : {
-        "tags" : [ "hosts" ],
-        "summary" : "Deletes multiple hosts in a single request",
+        "tags" : [ "Cluster Services" ],
+        "summary" : "Deletes a single service artifact",
         "description" : "",
-        "operationId" : "deleteHosts",
+        "operationId" : "ServiceService#deleteArtifact",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "in" : "body",
-          "name" : "body",
-          "required" : false,
-          "schema" : {
-            "$ref" : "#/definitions/HostRequest"
-          }
+          "name" : "serviceName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "artifactName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "clusterName",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
@@ -1576,7 +1629,7 @@
             "description" : "Not permitted to perform the operation"
           },
           "404" : {
-            "description" : "Cluster or host not found"
+            "description" : "The requested resource doesn't exist."
           },
           "500" : {
             "description" : "Internal server error"
@@ -1584,148 +1637,125 @@
         }
       }
     },
-    "/hosts/{hostName}" : {
+    "/groups" : {
       "get" : {
-        "tags" : [ "hosts" ],
-        "summary" : "Returns information about a single host",
-        "description" : "",
-        "operationId" : "getHost",
+        "tags" : [ "Groups" ],
+        "summary" : "Get all groups",
+        "description" : "Returns details of all groups.",
+        "operationId" : "GroupService#getGroups",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "hostName",
-          "in" : "path",
-          "description" : "host name",
-          "required" : true,
-          "type" : "string"
-        }, {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "description" : "Filter group details",
+          "required" : false,
+          "type" : "string",
+          "default" : "Groups/*"
+        }, {
+          "name" : "sortBy",
+          "in" : "query",
+          "description" : "Sort groups (asc | desc)",
+          "required" : false,
+          "type" : "string",
+          "default" : "Groups/group_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",
+            "description" : "Successful retrieval of all group entries",
             "schema" : {
-              "$ref" : "#/definitions/Wrapper"
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/definitions/GroupResponse"
+              }
             }
-          },
-          "401" : {
-            "description" : "Not authenticated"
-          },
-          "403" : {
-            "description" : "Not permitted to perform the operation"
-          },
-          "404" : {
-            "description" : "Cluster or host not found"
-          },
-          "500" : {
-            "description" : "Internal server error"
           }
         }
       },
       "post" : {
-        "tags" : [ "hosts" ],
-        "summary" : "Creates a host",
-        "description" : "",
-        "operationId" : "createHost",
+        "tags" : [ "Groups" ],
+        "summary" : "Create new group",
+        "description" : "Creates group resource.",
+        "operationId" : "GroupService#createGroup",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "hostName",
-          "in" : "path",
-          "description" : "host name",
-          "required" : true,
-          "type" : "string"
-        }, {
           "in" : "body",
           "name" : "body",
-          "required" : false,
+          "description" : "input parameters in json form",
+          "required" : true,
           "schema" : {
-            "$ref" : "#/definitions/HostRequest"
+            "$ref" : "#/definitions/GroupRequest"
           }
         } ],
         "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" : "Cluster not found"
-          },
-          "409" : {
-            "description" : "Attempt to create a host which already exists"
+          "200" : {
+            "description" : "successful operation"
           },
           "500" : {
-            "description" : "Internal server error"
+            "description" : "Server Error"
           }
         }
-      },
-      "put" : {
-        "tags" : [ "hosts" ],
-        "summary" : "Updates a host",
-        "description" : "",
-        "operationId" : "updateHost",
+      }
+    },
+    "/groups/{groupName}" : {
+      "get" : {
+        "tags" : [ "Groups" ],
+        "summary" : "Get group",
+        "description" : "Returns group details.",
+        "operationId" : "GroupService#getGroup",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "hostName",
+          "name" : "groupName",
           "in" : "path",
-          "description" : "host name",
+          "description" : "group name",
           "required" : true,
           "type" : "string"
         }, {
-          "in" : "body",
-          "name" : "body",
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter group details",
           "required" : false,
-          "schema" : {
-            "$ref" : "#/definitions/HostRequest"
-          }
+          "type" : "string",
+          "default" : "Groups"
         } ],
         "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" : "Cluster or host not found"
-          },
-          "500" : {
-            "description" : "Internal server error"
+            "description" : "Successful retrieval of group resource",
+            "schema" : {
+              "$ref" : "#/definitions/GroupResponse"
+            }
           }
         }
       },
       "delete" : {
-        "tags" : [ "hosts" ],
-        "summary" : "Deletes a host",
-        "description" : "",
-        "operationId" : "deleteHost",
+        "tags" : [ "Groups" ],
+        "summary" : "Delete group",
+        "description" : "Delete group resource.",
+        "operationId" : "GroupService#deleteGroup",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "hostName",
+          "name" : "groupName",
           "in" : "path",
-          "description" : "host name",
+          "description" : "group name",
           "required" : true,
           "type" : "string"
         } ],
@@ -1733,42 +1763,39 @@
           "200" : {
             "description" : "Successful operation"
           },
-          "401" : {
-            "description" : "Not authenticated"
-          },
-          "403" : {
-            "description" : "Not permitted to perform the operation"
-          },
-          "404" : {
-            "description" : "Cluster or host not found"
-          },
           "500" : {
-            "description" : "Internal server error"
+            "description" : "Server Error"
           }
         }
       }
     },
-    "/requests" : {
+    "/groups/{groupName}/members" : {
       "get" : {
-        "tags" : [ "Requests" ],
-        "summary" : "Get all requests. A predicate can be given to filter results.",
-        "description" : "",
-        "operationId" : "RequestService#getRequests",
+        "tags" : [ "Groups" ],
+        "summary" : "Get all group members",
+        "description" : "Returns details of all members.",
+        "operationId" : "MemberService#getMembers",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
+          "name" : "groupName",
+          "in" : "path",
+          "description" : "group name",
+          "required" : true,
+          "type" : "string"
+        }, {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "description" : "Filter member details",
           "required" : false,
           "type" : "string",
-          "default" : "Requests/id"
+          "default" : "MemberInfo/*"
         }, {
           "name" : "sortBy",
           "in" : "query",
-          "description" : "Sort resources in result by (asc | desc)",
+          "description" : "Sort members (asc | desc)",
           "required" : false,
           "type" : "string",
-          "default" : "Requests/id.asc"
+          "default" : "MemberInfo/user_name.asc"
         }, {
           "name" : "page_size",
           "in" : "query",
@@ -1779,14 +1806,14 @@
         }, {
           "name" : "from",
           "in" : "query",
-          "description" : "The starting page resource (inclusive).  \"start\" is also accepted.",
+          "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).  \"end\" is also accepted.",
+          "description" : "The ending page resource (inclusive). Valid values are :offset | \"end\"",
           "required" : false,
           "type" : "string"
         } ],
@@ -1796,95 +1823,309 @@
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/RequestResponse"
+                "$ref" : "#/definitions/MemberResponse"
               }
             }
-          },
-          "401" : {
-            "description" : "Not authenticated"
-          },
-          "500" : {
-            "description" : "Internal server error"
           }
         }
       },
-      "post" : {
-        "tags" : [ "Requests" ],
-        "summary" : "Creates one or more Requests",
-        "description" : "",
-        "operationId" : "RequestService#createRequests",
-        "produces" : [ "text/plain" ],
-        "parameters" : [ {
-          "in" : "body",
-          "name" : "body",
-          "required" : false,
+      "put" : {
+        "tags" : [ "Groups" ],
+        "summary" : "Update group members",
+        "description" : "Updates group member resources.",
+        "operationId" : "MemberService#updateMembers",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "groupName",
+          "in" : "path",
+          "description" : "group name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "in" : "body",
+          "name" : "body",
+          "description" : "input parameters in json form",
+          "required" : true,
           "schema" : {
-            "$ref" : "#/definitions/RequestPostRequest"
+            "$ref" : "#/definitions/MemberRequest"
           }
         } ],
         "responses" : {
-          "201" : {
+          "200" : {
             "description" : "Successful operation"
           },
-          "202" : {
-            "description" : "Request is accepted, but not completely processed yet",
+          "500" : {
+            "description" : "Server Error"
+          }
+        }
+      }
+    },
+    "/groups/{groupName}/members/{userName}" : {
+      "get" : {
+        "tags" : [ "Groups" ],
+        "summary" : "Get group member",
+        "description" : "Returns member details.",
+        "operationId" : "MemberService#getMember",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "groupName",
+          "in" : "path",
+          "description" : "group name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "userName",
+          "in" : "path",
+          "description" : "user name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter member details",
+          "required" : false,
+          "type" : "string",
+          "default" : "MemberInfo"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation",
             "schema" : {
-              "$ref" : "#/definitions/RequestPostResponse"
+              "$ref" : "#/definitions/MemberResponse"
             }
-          },
-          "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."
+          }
+        }
+      },
+      "delete" : {
+        "tags" : [ "Groups" ],
+        "summary" : "Delete group member",
+        "description" : "Delete member resource.",
+        "operationId" : "MemberService#deleteMember",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "groupName",
+          "in" : "path",
+          "description" : "group name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "userName",
+          "in" : "path",
+          "description" : "user name",
+          "required" : true,
+          "type" : "string"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation"
           },
           "500" : {
-            "description" : "Internal server error"
+            "description" : "Server Error"
           }
         }
       }
     },
-    "/requests/{requestId}" : {
+    "/groups/{groupName}/privileges" : {
       "get" : {
-        "tags" : [ "Requests" ],
-        "summary" : "Get the details of a request",
-        "description" : "",
-        "operationId" : "RequestService#getRequest",
+        "tags" : [ "Groups" ],
+        "summary" : "Get all privileges",
+        "description" : "Returns all privileges for group.",
+        "operationId" : "GroupPrivilegeService#getPrivileges",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "requestId",
+          "name" : "groupName",
           "in" : "path",
+          "description" : "group name",
           "required" : true,
           "type" : "string"
         }, {
           "name" : "fields",
           "in" : "query",
+          "description" : "Filter user privileges",
+          "required" : false,
+          "type" : "string",
+          "default" : "PrivilegeInfo/*"
+        }, {
+          "name" : "sortBy",
+          "in" : "query",
+          "description" : "Sort user privileges (asc | desc)",
+          "required" : false,
+          "type" : "string",
+          "default" : "PrivilegeInfo/user_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/GroupPrivilegeResponse"
+              }
+            }
+          }
+        }
+      }
+    },
+    "/groups/{groupName}/privileges/{privilegeId}" : {
+      "get" : {
+        "tags" : [ "Groups" ],
+        "summary" : "Get group privilege",
+        "description" : "Returns group privilege details.",
+        "operationId" : "GroupPrivilegeService#getPrivilege",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "groupName",
+          "in" : "path",
+          "description" : "group name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "privilegeId",
+          "in" : "path",
+          "description" : "privilege id",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter group privilege details",
+          "required" : false,
+          "type" : "string",
+          "default" : "PrivilegeInfo/*"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation",
+            "schema" : {
+              "$ref" : "#/definitions/PrivilegeResponse"
+            }
+          }
+        }
+      }
+    },
+    "/hosts" : {
+      "get" : {
+        "tags" : [ "hosts" ],
+        "summary" : "Returns a collection of all hosts",
+        "description" : "",
+        "operationId" : "getHosts",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "fields",
+          "in" : "query",
           "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Requests/*"
+          "default" : "Hosts/*"
+        }, {
+          "name" : "sortBy",
+          "in" : "query",
+          "description" : "Sort resources in result by (asc | desc)",
+          "required" : false,
+          "type" : "string",
+          "default" : "Hosts/host_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).  \"start\" is also accepted.",
+          "required" : false,
+          "type" : "integer",
+          "default" : 0,
+          "minimum" : 0.0
+        }, {
+          "name" : "to",
+          "in" : "query",
+          "description" : "The ending page resource (inclusive).  \"end\" is also accepted.",
+          "required" : false,
+          "type" : "integer",
+          "minimum" : 1.0
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation",
             "schema" : {
-              "$ref" : "#/definitions/RequestResponse"
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/definitions/Wrapper"
+              }
             }
           },
           "401" : {
             "description" : "Not authenticated"
           },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
           "404" : {
-            "description" : "The requested resource doesn't exist."
+            "description" : "Cluster not found"
+          },
+          "500" : {
+            "description" : "Internal server error"
+          }
+        }
+      },
+      "post" : {
+        "tags" : [ "hosts" ],
+        "summary" : "Creates multiple hosts in a single request",
+        "description" : "",
+        "operationId" : "createHosts",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "in" : "body",
+          "name" : "body",
+          "required" : false,
+          "schema" : {
+            "$ref" : "#/definitions/HostRequest"
+          }
+        } ],
+        "responses" : {
+          "201" : {
+            "description" : "Successful operation"
+          },
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet"
+          },
+          "400" : {
+            "description" : "Attempt to add hosts that have not been registered"
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "Cluster not found"
+          },
+          "409" : {
+            "description" : "Attempt to create a host which already exists"
           },
           "500" : {
             "description" : "Internal server error"
@@ -1892,22 +2133,17 @@
         }
       },
       "put" : {
-        "tags" : [ "Requests" ],
-        "summary" : "Updates a request, usually used to cancel running requests.",
-        "description" : "Changes the state of an existing request. Usually used to cancel running requests.",
-        "operationId" : "RequestService#updateRequests",
+        "tags" : [ "hosts" ],
+        "summary" : "Updates multiple hosts in a single request",
+        "description" : "",
+        "operationId" : "updateHosts",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "requestId",
-          "in" : "path",
-          "required" : true,
-          "type" : "string"
-        }, {
           "in" : "body",
           "name" : "body",
           "required" : false,
           "schema" : {
-            "$ref" : "#/definitions/RequestPutRequest"
+            "$ref" : "#/definitions/HostRequest"
           }
         } ],
         "responses" : {
@@ -1927,38 +2163,30 @@
             "description" : "Not permitted to perform the operation"
           },
           "404" : {
-            "description" : "The requested resource doesn't exist."
+            "description" : "Cluster or host not found"
           },
           "500" : {
             "description" : "Internal server error"
           }
         }
-      }
-    },
-    "/services" : {
-      "get" : {
-        "tags" : [ "services" ],
-        "summary" : "Returns the list of root-level services",
+      },
+      "delete" : {
+        "tags" : [ "hosts" ],
+        "summary" : "Deletes multiple hosts in a single request",
         "description" : "",
-        "operationId" : "getRootServices",
+        "operationId" : "deleteHosts",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "in" : "body",
+          "name" : "body",
           "required" : false,
-          "type" : "string",
-          "default" : "RootService/service_name"
+          "schema" : {
+            "$ref" : "#/definitions/HostRequest"
+          }
         } ],
         "responses" : {
           "200" : {
-            "description" : "Successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "$ref" : "#/definitions/RootServiceResponseWrapper"
-              }
-            }
+            "description" : "Successful operation"
           },
           "401" : {
             "description" : "Not authenticated"
@@ -1966,23 +2194,26 @@
           "403" : {
             "description" : "Not permitted to perform the operation"
           },
+          "404" : {
+            "description" : "Cluster or host not found"
+          },
           "500" : {
             "description" : "Internal server error"
           }
         }
       }
     },
-    "/services/{serviceName}" : {
+    "/hosts/{hostName}" : {
       "get" : {
-        "tags" : [ "services" ],
-        "summary" : "Returns information about the given root-level service, including a list of its components",
+        "tags" : [ "hosts" ],
+        "summary" : "Returns information about a single host",
         "description" : "",
-        "operationId" : "getRootService",
+        "operationId" : "getHost",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "serviceName",
+          "name" : "hostName",
           "in" : "path",
-          "description" : "service name",
+          "description" : "host name",
           "required" : true,
           "type" : "string"
         }, {
@@ -1990,14 +2221,13 @@
           "in" : "query",
           "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
-          "type" : "string",
-          "default" : "RootService/service_name, components/RootServiceComponents/component_name, components/RootServiceComponents/service_name"
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation",
             "schema" : {
-              "$ref" : "#/definitions/RootServiceResponseWithComponentList"
+              "$ref" : "#/definitions/Wrapper"
             }
           },
           "401" : {
@@ -2007,44 +2237,42 @@
             "description" : "Not permitted to perform the operation"
           },
           "404" : {
-            "description" : "The requested resource doesn't exist."
+            "description" : "Cluster or host not found"
           },
           "500" : {
             "description" : "Internal server error"
           }
         }
-      }
-    },
-    "/services/{serviceName}/components" : {
-      "get" : {
-        "tags" : [ "services" ],
-        "summary" : "Returns the list of components for the given root-level service",
+      },
+      "post" : {
+        "tags" : [ "hosts" ],
+        "summary" : "Creates a host",
         "description" : "",
-        "operationId" : "getRootServiceComponents",
+        "operationId" : "createHost",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "serviceName",
+          "name" : "hostName",
           "in" : "path",
-          "description" : "service name",
+          "description" : "host name",
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "in" : "body",
+          "name" : "body",
           "required" : false,
-          "type" : "string",
-          "default" : "RootServiceComponents/component_name, RootServiceComponents/service_name"
+          "schema" : {
+            "$ref" : "#/definitions/HostRequest"
+          }
         } ],
         "responses" : {
-          "200" : {
-            "description" : "Successful operation",
-            "schema" : {
-              "type" : "array",
-              "items" : {
-                "$ref" : "#/definitions/RootServiceComponentResponseWrapper"
-              }
-            }
+          "201" : {
+            "description" : "Successful operation"
+          },
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet"
+          },
+          "400" : {
+            "description" : "Invalid arguments"
           },
           "401" : {
             "description" : "Not authenticated"
@@ -2053,100 +2281,179 @@
             "description" : "Not permitted to perform the operation"
           },
           "404" : {
-            "description" : "The requested resource doesn't exist."
+            "description" : "Cluster not found"
+          },
+          "409" : {
+            "description" : "Attempt to create a host which already exists"
           },
           "500" : {
             "description" : "Internal server error"
           }
         }
-      }
-    },
-    "/services/{serviceName}/components/{componentName}" : {
-      "get" : {
-        "tags" : [ "services" ],
-        "summary" : "Returns information about the given component for the given root-level service",
+      },
+      "put" : {
+        "tags" : [ "hosts" ],
+        "summary" : "Updates a host",
         "description" : "",
-        "operationId" : "getRootServiceComponent",
+        "operationId" : "updateHost",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "serviceName",
+          "name" : "hostName",
           "in" : "path",
-          "description" : "service name",
+          "description" : "host name",
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "componentName",
+          "in" : "body",
+          "name" : "body",
+          "required" : false,
+          "schema" : {
+            "$ref" : "#/definitions/HostRequest"
+          }
+        } ],
+        "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" : "Cluster or host not found"
+          },
+          "500" : {
+            "description" : "Internal server error"
+          }
+        }
+      },
+      "delete" : {
+        "tags" : [ "hosts" ],
+        "summary" : "Deletes a host",
+        "description" : "",
+        "operationId" : "deleteHost",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "hostName",
           "in" : "path",
-          "description" : "component name",
+          "description" : "host name",
           "required" : true,
           "type" : "string"
+        } ],
+        "responses" : {
+          "200" : {
+            "description" : "Successful operation"
+          },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
+          "404" : {
+            "description" : "Cluster or host not found"
+          },
+          "500" : {
+            "description" : "Internal server error"
+          }
+        }
+      }
+    },
+    "/requests" : {
+      "get" : {
+        "tags" : [ "Requests" ],
+        "summary" : "Get all requests. A predicate can be given to filter results.",
+        "description" : "",
+        "operationId" : "RequestService#getRequests",
+        "produces" : [ "text/plain" ],
+        "parameters" : [ {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "required" : false,
+          "type" : "string",
+          "default" : "Requests/id"
+        }, {
+          "name" : "sortBy",
+          "in" : "query",
+          "description" : "Sort resources in result by (asc | desc)",
+          "required" : false,
+          "type" : "string",
+          "default" : "Requests/id.asc"
         }, {
-          "name" : "fields",
+          "name" : "page_size",
           "in" : "query",
-          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "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).  \"start\" is also accepted.",
           "required" : false,
           "type" : "string",
-          "default" : "RootServiceComponents/*, hostComponents/RootServiceHostComponents/component_name, hostComponents/RootServiceHostComponents/host_name, hostComponents/RootServiceHostComponents/service_name"
+          "default" : "0"
+        }, {
+          "name" : "to",
+          "in" : "query",
+          "description" : "The ending page resource (inclusive).  \"end\" is also accepted.",
+          "required" : false,
+          "type" : "string"
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation",
             "schema" : {
-              "$ref" : "#/definitions/RootServiceComponentWithHostComponentList"
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/definitions/RequestResponse"
+              }
             }
           },
           "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"
           }
         }
-      }
-    },
-    "/services/{serviceName}/components/{componentName}/hostComponents" : {
-      "get" : {
-        "tags" : [ "services" ],
-        "summary" : "Returns the list of hosts for the given root-level service component",
+      },
+      "post" : {
+        "tags" : [ "Requests" ],
+        "summary" : "Creates one or more Requests",
         "description" : "",
-        "operationId" : "getRootServiceComponentHosts",
+        "operationId" : "RequestService#createRequests",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "serviceName",
-          "in" : "path",
-          "description" : "service name",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "componentName",
-          "in" : "path",
-          "description" : "component name",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "in" : "body",
+          "name" : "body",
           "required" : false,
-          "type" : "string",
-          "default" : "RootServiceHostComponents/component_name, RootServiceHostComponents/host_name, RootServiceHostComponents/service_name"
+          "schema" : {
+            "$ref" : "#/definitions/RequestPostRequest"
+          }
         } ],
         "responses" : {
-          "200" : {
-            "description" : "Successful operation",
+          "201" : {
+            "description" : "Successful operation"
+          },
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet",
             "schema" : {
-              "type" : "array",
-              "items" : {
-                "$ref" : "#/definitions/RootServiceHostComponentResponseWrapper"
-              }
+              "$ref" : "#/definitions/RequestPostResponse"
             }
           },
+          "400" : {
+            "description" : "Invalid arguments"
+          },
           "401" : {
             "description" : "Not authenticated"
           },
@@ -2156,43 +2463,45 @@
           "404" : {
             "description" : "The requested resource doesn't exist."
           },
+          "409" : {
+            "description" : "The requested resource already exists."
+          },
           "500" : {
             "description" : "Internal server error"
           }
         }
       }
     },
-    "/services/{serviceName}/hosts" : {
+    "/requests/{requestId}" : {
       "get" : {
-        "tags" : [ "services" ],
-        "summary" : "Returns the list of hosts for the given root-level service",
+        "tags" : [ "Requests" ],
+        "summary" : "Get the details of a request",
         "description" : "",
-        "operationId" : "getRootHosts",
+        "operationId" : "RequestService#getRequest",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
+          "name" : "requestId",
+          "in" : "path",
+          "required" : true,
+          "type" : "string"
+        }, {
           "name" : "fields",
           "in" : "query",
           "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Hosts/host_name"
+          "default" : "Requests/*"
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation",
             "schema" : {
-              "type" : "array",
-              "items" : {
-                "$ref" : "#/definitions/Wrapper"
-              }
+              "$ref" : "#/definitions/RequestResponse"
             }
           },
           "401" : {
             "description" : "Not authenticated"
           },
-          "403" : {
-            "description" : "Not permitted to perform the operation"
-          },
           "404" : {
             "description" : "The requested resource doesn't exist."
           },
@@ -2200,35 +2509,35 @@
             "description" : "Internal server error"
           }
         }
-      }
-    },
-    "/services/{serviceName}/hosts/{hostName}" : {
-      "get" : {
-        "tags" : [ "services" ],
-        "summary" : "Returns information about the given host",
-        "description" : "",
-        "operationId" : "getRootHost",
+      },
+      "put" : {
+        "tags" : [ "Requests" ],
+        "summary" : "Updates a request, usually used to cancel running requests.",
+        "description" : "Changes the state of an existing request. Usually used to cancel running requests.",
+        "operationId" : "RequestService#updateRequests",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "hostName",
+          "name" : "requestId",
           "in" : "path",
-          "description" : "host name",
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "in" : "body",
+          "name" : "body",
           "required" : false,
-          "type" : "string",
-          "default" : "Hosts/*"
+          "schema" : {
+            "$ref" : "#/definitions/RequestPutRequest"
+          }
         } ],
         "responses" : {
           "200" : {
-            "description" : "Successful operation",
-            "schema" : {
-              "$ref" : "#/definitions/Wrapper"
-            }
+            "description" : "Successful operation"
+          },
+          "202" : {
+            "description" : "Request is accepted, but not completely processed yet"
+          },
+          "400" : {
+            "description" : "Invalid arguments"
           },
           "401" : {
             "description" : "Not authenticated"
@@ -2245,32 +2554,20 @@
         }
       }
     },
-    "/services/{serviceName}/hosts/{hostName}/hostComponents" : {
+    "/services" : {
       "get" : {
         "tags" : [ "services" ],
-        "summary" : "Returns the list of components for the given root-level service on the given host",
+        "summary" : "Returns the list of root-level services",
         "description" : "",
-        "operationId" : "getRootServiceHostComponents",
+        "operationId" : "getRootServices",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "serviceName",
-          "in" : "path",
-          "description" : "service name",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "hostName",
-          "in" : "path",
-          "description" : "host name",
-          "required" : true,
-          "type" : "string"
-        }, {
           "name" : "fields",
           "in" : "query",
           "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "RootServiceHostComponents/component_name, RootServiceHostComponents/host_name, RootServiceHostComponents/service_name"
+          "default" : "RootService/service_name"
         } ],
         "responses" : {
           "200" : {
@@ -2278,7 +2575,7 @@
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/RootServiceHostComponentResponseWrapper"
+                "$ref" : "#/definitions/RootServiceResponseWrapper"
               }
             }
           },
@@ -2288,21 +2585,18 @@
           "403" : {
             "description" : "Not permitted to perform the operation"
           },
-          "404" : {
-            "description" : "The requested resource doesn't exist."
-          },
           "500" : {
             "description" : "Internal server error"
           }
         }
       }
     },
-    "/services/{serviceName}/hosts/{hostName}/hostComponents/{hostComponent}" : {
+    "/services/{serviceName}" : {
       "get" : {
         "tags" : [ "services" ],
-        "summary" : "Returns information about the given component for the given root-level service on the given host",
+        "summary" : "Returns information about the given root-level service, including a list of its components",
         "description" : "",
-        "operationId" : "getRootServiceHostComponent",
+        "operationId" : "getRootService",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
           "name" : "serviceName",
@@ -2311,30 +2605,18 @@
           "required" : true,
           "type" : "string"
         }, {
-          "name" : "hostName",
-          "in" : "path",
-          "description" : "host name",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "name" : "hostComponent",
-          "in" : "path",
-          "description" : "component name",
-          "required" : true,
-          "type" : "string"
-        }, {
           "name" : "fields",
           "in" : "query",
           "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "RootServiceHostComponents/component_name, RootServiceHostComponents/host_name, RootServiceHostComponents/service_name"
+          "default" : "RootService/service_name, components/RootServiceComponents/component_name, components/RootServiceComponents/service_name"
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation",
             "schema" : {
-              "$ref" : "#/definitions/RootServiceHostComponentResponseWrapper"
+              "$ref" : "#/definitions/RootServiceResponseWithComponentList"
             }
           },
           "401" : {
@@ -2352,48 +2634,26 @@
         }
       }
     },
-    "/settings" : {
+    "/services/{serviceName}/components" : {
       "get" : {
-        "tags" : [ "settings" ],
-        "summary" : "Returns all settings",
+        "tags" : [ "services" ],
+        "summary" : "Returns the list of components for the given root-level service",
         "description" : "",
-        "operationId" : "getSettings",
+        "operationId" : "getRootServiceComponents",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
+          "name" : "serviceName",
+          "in" : "path",
+          "description" : "service name",
+          "required" : true,
+          "type" : "string"
+        }, {
           "name" : "fields",
           "in" : "query",
           "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Settings/name"
-        }, {
-          "name" : "sortBy",
-          "in" : "query",
-          "description" : "Sort resources in result by (asc | desc)",
-          "required" : false,
-          "type" : "string"
-        }, {
-          "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).  \"start\" is also accepted.",
-          "required" : false,
-          "type" : "integer",
-          "default" : 0,
-          "minimum" : 0.0
-        }, {
-          "name" : "to",
-          "in" : "query",
-          "description" : "The ending page resource (inclusive).  \"end\" is also accepted.",
-          "required" : false,
-          "type" : "integer",
-          "minimum" : 1.0
+          "default" : "RootServiceComponents/component_name, RootServiceComponents/service_name"
         } ],
         "responses" : {
           "200" : {
@@ -2401,7 +2661,7 @@
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/SettingResponseWrapper"
+                "$ref" : "#/definitions/RootServiceComponentResponseWrapper"
               }
             }
           },
@@ -2411,34 +2671,48 @@
           "403" : {
             "description" : "Not permitted to perform the operation"
           },
+          "404" : {
+            "description" : "The requested resource doesn't exist."
+          },
           "500" : {
             "description" : "Internal server error"
           }
         }
-      },
-      "post" : {
-        "tags" : [ "settings" ],
-        "summary" : "Creates a setting",
+      }
+    },
+    "/services/{serviceName}/components/{componentName}" : {
+      "get" : {
+        "tags" : [ "services" ],
+        "summary" : "Returns information about the given component for the given root-level service",
         "description" : "",
-        "operationId" : "createSetting",
+        "operationId" : "getRootServiceComponent",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "in" : "body",
-          "name" : "body",
+          "name" : "serviceName",
+          "in" : "path",
+          "description" : "service name",
           "required" : true,
-          "schema" : {
-            "$ref" : "#/definitions/SettingRequestSwagger"
-          }
+          "type" : "string"
+        }, {
+          "name" : "componentName",
+          "in" : "path",
+          "description" : "component name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "required" : false,
+          "type" : "string",
+          "default" : "RootServiceComponents/*, hostComponents/RootServiceHostComponents/component_name, hostComponents/RootServiceHostComponents/host_name, hostComponents/RootServiceHostComponents/service_name"
         } ],
         "responses" : {
-          "201" : {
-            "description" : "Successful operation"
-          },
-          "202" : {
-            "description" : "Request is accepted, but not completely processed yet"
-          },
-          "400" : {
-            "description" : "Invalid arguments"
+          "200" : {
+            "description" : "Successful operation",
+            "schema" : {
+              "$ref" : "#/definitions/RootServiceComponentWithHostComponentList"
+            }
           },
           "401" : {
             "description" : "Not authenticated"
@@ -2447,10 +2721,7 @@
             "description" : "Not permitted to perform the operation"
           },
           "404" : {
-            "description" : "Cluster not found"
-          },
-          "409" : {
-            "description" : "The requested resource already exists."
+            "description" : "The requested resource doesn't exist."
           },
           "500" : {
             "description" : "Internal server error"
@@ -2458,17 +2729,23 @@
         }
       }
     },
-    "/settings/{settingName}" : {
+    "/services/{serviceName}/components/{componentName}/hostComponents" : {
       "get" : {
-        "tags" : [ "settings" ],
-        "summary" : "Returns a specific setting",
+        "tags" : [ "services" ],
+        "summary" : "Returns the list of hosts for the given root-level service component",
         "description" : "",
-        "operationId" : "getSetting",
+        "operationId" : "getRootServiceComponentHosts",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "settingName",
+          "name" : "serviceName",
           "in" : "path",
-          "description" : "setting name",
+          "description" : "service name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "componentName",
+          "in" : "path",
+          "description" : "component name",
           "required" : true,
           "type" : "string"
         }, {
@@ -2477,41 +2754,16 @@
           "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Settings/*"
-        }, {
-          "name" : "sortBy",
-          "in" : "query",
-          "description" : "Sort resources in result by (asc | desc)",
-          "required" : false,
-          "type" : "string"
-        }, {
-          "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).  \"start\" is also accepted.",
-          "required" : false,
-          "type" : "integer",
-          "default" : 0,
-          "minimum" : 0.0
-        }, {
-          "name" : "to",
-          "in" : "query",
-          "description" : "The ending page resource (inclusive).  \"end\" is also accepted.",
-          "required" : false,
-          "type" : "integer",
-          "minimum" : 1.0
+          "default" : "RootServiceHostComponents/component_name, RootServiceHostComponents/host_name, RootServiceHostComponents/service_name"
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation",
             "schema" : {
-              "$ref" : "#/definitions/SettingResponseWrapper"
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/definitions/RootServiceHostComponentResponseWrapper"
+              }
             }
           },
           "401" : {
@@ -2527,30 +2779,32 @@
             "description" : "Internal server error"
           }
         }
-      },
-      "put" : {
-        "tags" : [ "settings" ],
-        "summary" : "Updates a setting",
+      }
+    },
+    "/services/{serviceName}/hosts" : {
+      "get" : {
+        "tags" : [ "services" ],
+        "summary" : "Returns the list of hosts for the given root-level service",
         "description" : "",
-        "operationId" : "updateSetting",
+        "operationId" : "getRootHosts",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "settingName",
-          "in" : "path",
-          "description" : "setting name",
-          "required" : true,
-          "type" : "string"
-        }, {
-          "in" : "body",
-          "name" : "body",
-          "required" : true,
-          "schema" : {
-            "$ref" : "#/definitions/SettingRequestSwagger"
-          }
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "required" : false,
+          "type" : "string",
+          "default" : "Hosts/host_name"
         } ],
         "responses" : {
           "200" : {
-            "description" : "Successful operation"
+            "description" : "Successful operation",
+            "schema" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/definitions/Wrapper"
+              }
+            }
           },
           "401" : {
             "description" : "Not authenticated"
@@ -2565,23 +2819,35 @@
             "description" : "Internal server error"
           }
         }
-      },
-      "delete" : {
-        "tags" : [ "settings" ],
-        "summary" : "Deletes a setting",
+      }
+    },
+    "/services/{serviceName}/hosts/{hostName}" : {
+      "get" : {
+        "tags" : [ "services" ],
+        "summary" : "Returns information about the given host",
         "description" : "",
-        "operationId" : "deleteSetting",
+        "operationId" : "getRootHost",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "settingName",
+          "name" : "hostName",
           "in" : "path",
-          "description" : "setting name",
+          "description" : "host name",
           "required" : true,
           "type" : "string"
+        }, {
+          "name" : "fields",
+          "in" : "query",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
+          "required" : false,
+          "type" : "string",
+          "default" : "Hosts/*"
         } ],
         "responses" : {
           "200" : {
-            "description" : "Successful operation"
+            "description" : "Successful operation",
+            "schema" : {
+              "$ref" : "#/definitions/Wrapper"
+            }
           },
           "401" : {
             "description" : "Not authenticated"
@@ -2598,47 +2864,32 @@
         }
       }
     },
-    "/stacks" : {
+    "/services/{serviceName}/hosts/{hostName}/hostComponents" : {
       "get" : {
-        "tags" : [ "Stacks" ],
-        "summary" : "Get all stacks",
-        "description" : "Returns all stacks.",
-        "operationId" : "StacksService#getStacks",
+        "tags" : [ "services" ],
+        "summary" : "Returns the list of components for the given root-level service on the given host",
+        "description" : "",
+        "operationId" : "getRootServiceHostComponents",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "fields",
-          "in" : "query",
-          "description" : "Filter stack details",
-          "required" : false,
-          "type" : "string",
-          "default" : "Stacks/stack_name"
-        }, {
-          "name" : "sortBy",
-          "in" : "query",
-          "description" : "Sort stack privileges (asc | desc)",
-          "required" : false,
-          "type" : "string",
-          "default" : "Stacks/stack_name.asc"
+          "name" : "serviceName",
+          "in" : "path",
+          "description" : "service name",
+          "required" : true,
+          "type" : "string"
         }, {
-          "name" : "page_size",
-          "in" : "query",
-          "description" : "The number of resources to be returned for the paged response.",
-          "required" : false,
-          "type" : "integer",
-          "default" : 10
+          "name" : "hostName",
+          "in" : "path",
+          "description" : "host name",
+          "required" : true,
+          "type" : "string"
         }, {
-          "name" : "from",
+          "name" : "fields",
           "in" : "query",
-          "description" : "The starting page resource (inclusive).  \"start\" is also accepted.",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "0"
-        }, {
-          "name" : "to",
-          "in" : "query",
-          "description" : "The ending page resource (inclusive).  \"end\" is also accepted.",
-          "required" : false,
-          "type" : "string"
+          "default" : "RootServiceHostComponents/component_name, RootServiceHostComponents/host_name, RootServiceHostComponents/service_name"
         } ],
         "responses" : {
           "200" : {
@@ -2646,46 +2897,71 @@
             "schema" : {
               "type" : "array",
               "items" : {
-                "$ref" : "#/definitions/StackResponseSwagger"
+                "$ref" : "#/definitions/RootServiceHostComponentResponseWrapper"
               }
             }
           },
+          "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"
           }
         }
       }
     },
-    "/stacks/{stackName}" : {
+    "/services/{serviceName}/hosts/{hostName}/hostComponents/{hostComponent}" : {
       "get" : {
-        "tags" : [ "Stacks" ],
-        "summary" : "Get a stack",
-        "description" : "Returns stack details.",
-        "operationId" : "StacksService#getStack",
+        "tags" : [ "services" ],
+        "summary" : "Returns information about the given component for the given root-level service on the given host",
+        "description" : "",
+        "operationId" : "getRootServiceHostComponent",
         "produces" : [ "text/plain" ],
         "parameters" : [ {
-          "name" : "stackName",
+          "name" : "serviceName",
+          "in" : "path",
+          "description" : "service name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "hostName",
+          "in" : "path",
+          "description" : "host name",
+          "required" : true,
+          "type" : "string"
+        }, {
+          "name" : "hostComponent",
           "in" : "path",
+          "description" : "component name",
           "required" : true,
           "type" : "string"
         }, {
           "name" : "fields",
           "in" : "query",
-          "description" : "Filter stack details",
+          "description" : "Filter fields in the response (identifier fields are mandatory)",
           "required" : false,
           "type" : "string",
-          "default" : "Stacks/*"
+          "default" : "RootServiceHostComponents/component_name, RootServiceHostComponents/host_name, RootServiceHostComponents/service_name"
         } ],
         "responses" : {
           "200" : {
             "description" : "Successful operation",
             "schema" : {
-              "type" : "array",
-              "items" : {
-                "$ref" : "#/definitions/StackResponseSwagger"
-              }
+              "$ref" : "#/definitions/RootServiceHostComponentResponseWrapper"
             }
           },
+          "401" : {
+            "description" : "Not authenticated"
+          },
+          "403" : {
+            "description" : "Not permitted to perform the operation"
+          },
           "404" : {
             

<TRUNCATED>

[8/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

Posted by rl...@apache.org.
AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: f76c87a699dad1b5a85f6fc13fd76b82818c6e58
Parents: d7bc588
Author: Robert Levas <rl...@hortonworks.com>
Authored: Thu Jun 15 11:04:49 2017 -0400
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Thu Jun 15 11:04:49 2017 -0400

----------------------------------------------------------------------
 ambari-server/docs/api/generated/index.html     | 15868 +++++++++--------
 ambari-server/docs/api/generated/swagger.json   |  4393 ++---
 .../server/configuration/Configuration.java     |     8 +-
 .../controller/AmbariManagementController.java  |    39 -
 .../AmbariManagementControllerImpl.java         |   147 -
 .../ambari/server/controller/AmbariServer.java  |    13 +-
 .../server/controller/ControllerModule.java     |     2 +
 .../controller/ResourceProviderFactory.java     |     5 +
 .../ambari/server/controller/UserRequest.java   |    29 +-
 .../ambari/server/controller/UserResponse.java  |    23 +-
 .../AbstractControllerResourceProvider.java     |     2 +-
 .../ActiveWidgetLayoutResourceProvider.java     |     2 +-
 .../internal/UserPrivilegeResourceProvider.java |    20 +-
 .../internal/UserResourceProvider.java          |   268 +-
 .../server/orm/dao/UserAuthenticationDAO.java   |    93 +
 .../apache/ambari/server/orm/dao/UserDAO.java   |    93 +-
 .../orm/entities/UserAuthenticationEntity.java  |   167 +
 .../ambari/server/orm/entities/UserEntity.java  |   221 +-
 .../AmbariJWTAuthenticationFilter.java          |     5 +-
 ...AuthenticationMethodNotAllowedException.java |    65 +
 .../authentication/UserNotFoundException.java   |    43 +
 .../AmbariAuthToLocalUserDetailsService.java    |   112 +-
 .../AmbariKerberosAuthenticationProperties.java |    18 +-
 .../AmbariAuthorizationFilter.java              |     4 +-
 .../AmbariLdapAuthenticationProvider.java       |    19 +-
 .../AmbariLdapAuthoritiesPopulator.java         |     2 +-
 .../authorization/AmbariLocalUserProvider.java  |    46 +-
 .../AmbariPamAuthenticationProvider.java        |   204 +-
 .../AmbariUserAuthorizationFilter.java          |    11 +-
 .../authorization/AuthenticationMethod.java     |    37 +
 .../authorization/AuthorizationHelper.java      |     4 +-
 .../server/security/authorization/User.java     |    61 +-
 .../authorization/UserAuthenticationType.java   |    26 +
 .../server/security/authorization/UserType.java |    25 -
 .../server/security/authorization/Users.java    |   729 +-
 .../AmbariInternalAuthenticationProvider.java   |     2 +-
 .../AuthenticationJwtUserNotFoundException.java |    43 -
 .../jwt/JwtAuthenticationFilter.java            |    69 +-
 .../server/upgrade/UpgradeCatalog240.java       |     5 +-
 .../src/main/resources/META-INF/persistence.xml |     1 +
 .../server/configuration/ConfigurationTest.java |     6 +-
 .../AmbariManagementControllerTest.java         |    73 -
 .../AbstractPrivilegeResourceProviderTest.java  |    38 -
 .../ActiveWidgetLayoutResourceProviderTest.java |     4 +-
 .../GroupPrivilegeResourceProviderTest.java     |    44 +-
 .../UserPrivilegeResourceProviderTest.java      |   107 +-
 .../internal/UserResourceProviderDBTest.java    |   426 +-
 .../internal/UserResourceProviderTest.java      |   152 +-
 .../apache/ambari/server/orm/OrmTestHelper.java |     7 +-
 .../ambari/server/orm/dao/UserDAOTest.java      |    53 +-
 .../server/security/SecurityHelperImplTest.java |     5 +-
 .../AmbariJWTAuthenticationFilterTest.java      |    12 +-
 ...AmbariAuthToLocalUserDetailsServiceTest.java |    22 +-
 ...ariKerberosAuthenticationPropertiesTest.java |    16 -
 .../AmbariAuthorizationFilterTest.java          |     5 +-
 ...ariAuthorizationProviderDisableUserTest.java |    16 +-
 ...uthenticationProviderForDNWithSpaceTest.java |     7 +-
 .../AmbariLdapAuthenticationProviderTest.java   |    18 +-
 .../AmbariLocalUserProviderTest.java            |    24 +-
 .../AmbariPamAuthenticationProviderTest.java    |    23 +-
 .../AmbariUserAuthenticationFilterTest.java     |    20 +-
 .../TestAmbariLdapAuthoritiesPopulator.java     |     4 +-
 .../security/authorization/TestUsers.java       |   196 +-
 .../security/authorization/UsersTest.java       |    15 +-
 .../jwt/JwtAuthenticationFilterTest.java        |    10 +-
 .../ldap/AmbariLdapDataPopulatorTest.java       |    19 +-
 .../server/upgrade/UpgradeCatalog240Test.java   |     7 +-
 67 files changed, 13111 insertions(+), 11142 deletions(-)
----------------------------------------------------------------------



[2/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 c4f0f34..db7548f 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
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -45,8 +46,8 @@ import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.security.TestAuthenticationFactory;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.springframework.security.core.Authentication;
@@ -63,221 +64,232 @@ import com.google.inject.persist.PersistService;
  */
 @PrepareForTest({AuthorizationHelper.class})
 public class UserResourceProviderDBTest {
-    private static Injector injector;
-    private static AmbariManagementController amc;
-    private static Resource.Type userType = Resource.Type.User;
-    private static UserResourceProvider userResourceProvider;
-    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 =
-            String.format("jdbc:derby:memory:myDB/%s;drop=true", Configuration.DEFAULT_DERBY_SCHEMA);
-
-    /**
-     * Sets up the in-memory database for the test suite.
-     */
-    @BeforeClass
-    public static void setupInMemoryDB() {
-        InMemoryDefaultTestModule testModule = new InMemoryDefaultTestModule();
-
-        Properties properties = testModule.getProperties();
-        properties.setProperty(Configuration.SERVER_JDBC_URL.getKey(), JDBC_IN_MEMORY_URL_CREATE);
-        properties.setProperty(Configuration.SERVER_JDBC_DRIVER.getKey(), Configuration.JDBC_IN_MEMORY_DRIVER);
-        injector = Guice.createInjector(testModule);
-
-        injector.getInstance(PersistService.class).start();
-
-        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);
+  private static Injector injector;
+  private static AmbariManagementController amc;
+  private static Resource.Type userType = Resource.Type.User;
+  private static UserResourceProvider userResourceProvider;
+  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 =
+      String.format("jdbc:derby:memory:myDB/%s;drop=true", Configuration.DEFAULT_DERBY_SCHEMA);
+
+  /**
+   * Sets up the in-memory database for the test suite.
+   */
+  @Before
+  public void setupInMemoryDB() {
+    InMemoryDefaultTestModule testModule = new InMemoryDefaultTestModule();
+
+    Properties properties = testModule.getProperties();
+    properties.setProperty(Configuration.SERVER_JDBC_URL.getKey(), JDBC_IN_MEMORY_URL_CREATE);
+    properties.setProperty(Configuration.SERVER_JDBC_DRIVER.getKey(), Configuration.JDBC_IN_MEMORY_DRIVER);
+    injector = Guice.createInjector(testModule);
+
+    injector.getInstance(PersistService.class).start();
+
+    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);
+    injector.injectMembers(userResourceProvider);
+  }
+
+  /**
+   * Closes the JPA connection after executing the test suite.
+   */
+  @After
+  public void teardownInMemoryDB() throws AmbariException, SQLException {
+    if (injector != null) {
+      H2DatabaseCleaner.clearDatabaseAndStopPersistenceService(injector);
     }
+  }
+
+  /**
+   * Creates a user, retrieves it and verifies that the username matches the one that was
+   * created. Deletes the created user and verifies that the username was deleted.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void createUserTest() throws Exception {
+    Authentication authentication = TestAuthenticationFactory.createAdministrator();
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    // create a new user viewUser
+    Map<String, Object> requestProperties = new HashMap<>();
+    requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "viewUser");
+    requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
+    requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
+    requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
+
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
+    RequestStatus requestStatus = userResourceProvider.createResources(request);
+    assertNotNull(requestStatus);
+
+    // verify the created username
+    Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Collections.singleton("Users")));
+    Predicate predicate = new PredicateBuilder()
+        .property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("viewUser").toPredicate();
+    Set<Resource> resources = userResourceProvider.getResources(getRequest, predicate);
+    assertEquals(resources.size(), 1);
+    Resource resource = resources.iterator().next();
+
+    String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
+    assertEquals("viewuser", userName);
+
+    // delete the created username
+    requestStatus = userResourceProvider.deleteResources(request, predicate);
+    assertNotNull(requestStatus);
+
+    // verify that the username was deleted
+    resources = userResourceProvider.getResources(getRequest, null);
+    assertEquals(resources.size(), 0);
+  }
+
+  /**
+   * Creates a username in all lowercase. Attempt to add another user whose username differs only
+   * by case to the previously added user. Verifies that the user cannot be added.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void createExistingUserTest() throws Exception {
+    Authentication authentication = TestAuthenticationFactory.createAdministrator();
+    SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    /**
-     * Closes the JPA connection after executing the test suite.
-     */
-    @AfterClass
-    public static void teardownInMemoryDB() throws AmbariException, SQLException {
-        if (injector != null) {
-            H2DatabaseCleaner.clearDatabaseAndStopPersistenceService(injector);
-        }
-    }
+        /* add a new user */
+    Map<String, Object> requestProperties = new HashMap<>();
+    requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "abcd");
+    requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
+    requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
+    requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
 
-    /**
-     * Creates a user, retrieves it and verifies that the username matches the one that was
-     * created. Deletes the created user and verifies that the username was deleted.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void createUserTest() throws Exception {
-        Authentication authentication = TestAuthenticationFactory.createAdministrator();
-        SecurityContextHolder.getContext().setAuthentication(authentication);
-
-        // create a new user viewUser
-        Map<String, Object> requestProperties = new HashMap<>();
-        requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "viewUser");
-        requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
-        requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
-        requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
-
-        Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
-        RequestStatus requestStatus = userResourceProvider.createResources(request);
-        assertNotNull(requestStatus);
-
-        // verify the created username
-        Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
-        Predicate predicate = new PredicateBuilder()
-                .property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("viewUser").toPredicate();
-        Set<Resource> resources = userResourceProvider.getResources(getRequest, predicate);
-        assertEquals(resources.size(), 1);
-        Resource resource = resources.iterator().next();
-
-        String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
-        assertEquals(userName, "viewUser");
-
-        // delete the created username
-        requestStatus = userResourceProvider.deleteResources(request, predicate);
-        assertNotNull(requestStatus);
-
-        // verify that the username was deleted
-        resources = userResourceProvider.getResources(getRequest, null);
-        assertEquals(resources.size(), 0);
-    }
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
+    RequestStatus requestStatus = userResourceProvider.createResources(request);
+    assertNotNull(requestStatus);
 
-    /**
-     * Creates a username in all lowercase. Attempt to add another user whose username differs only
-     * by case to the previously added user. Verifies that the user cannot be added.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void createExistingUserTest() throws Exception {
-        Authentication authentication = TestAuthenticationFactory.createAdministrator();
-        SecurityContextHolder.getContext().setAuthentication(authentication);
+        /* try with uppercase version of an existing user */
+    requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "ABCD");
+    request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
+    try {
+      requestStatus = userResourceProvider.createResources(request);
+      assertTrue("Should fail with user exists", false);
+    } catch (Exception ex) {
+      assertTrue(ex.getMessage().contains("User already exists"));
+    }
 
-        /* add a new user */
-        Map<String, Object> requestProperties = new HashMap<>();
-        requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "abcd");
-        requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
-        requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
-        requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
+    // delete the created username
+    Predicate predicate = new PredicateBuilder()
+        .property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("abcd").toPredicate();
+    requestStatus = userResourceProvider.deleteResources(request, predicate);
+    assertNotNull(requestStatus);
+
+    // verify that the username was deleted
+    Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
+    Set<Resource> resources = userResourceProvider.getResources(getRequest, null);
+    assertEquals(resources.size(), 0);
+  }
+
+  /**
+   * Creates a user and retrieves the user using the same username but in lowercase. Verifies
+   * that the retrieval is successful and that the retrieved username is the same as the one
+   * that was used during creation.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void getExistingUser() throws Exception {
+    Authentication authentication = TestAuthenticationFactory.createAdministrator();
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    // create a new user viewUser
+    Map<String, Object> requestProperties = new HashMap<>();
+    requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "viewUser");
+    requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
+    requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
+    requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
+
+    Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
+    RequestStatus requestStatus = userResourceProvider.createResources(request);
+    assertNotNull(requestStatus);
+
+    // verify the created username
+    Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
+    Predicate predicate = new PredicateBuilder()
+        .property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("viewuser").toPredicate();
+    Set<Resource> resources = userResourceProvider.getResources(getRequest, predicate);
+    assertEquals(resources.size(), 1);
+    Resource resource = resources.iterator().next();
+
+    String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
+    assertEquals("viewuser", userName);
+
+    // delete the created username
+    requestStatus = userResourceProvider.deleteResources(request, predicate);
+    assertNotNull(requestStatus);
+
+    // verify that the username was deleted
+    resources = userResourceProvider.getResources(getRequest, null);
+    assertEquals(resources.size(), 0);
+  }
+
+  /**
+   * Adds an array of users, retrieves the users and verifies that the usernames do not differ
+   * from the ones that were used during creation.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void getAllUserTest() throws Exception {
+    Authentication authentication = TestAuthenticationFactory.createAdministrator();
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    List<String> userNames = Arrays.asList("user1", "uSer2", "User3", "useR4");
+    List<String> lowercaseUserNames = new ArrayList<>();
+
+    for (String username : userNames) {
+      lowercaseUserNames.add(username.toLowerCase());
+    }
 
-        Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
-        RequestStatus requestStatus = userResourceProvider.createResources(request);
-        assertNotNull(requestStatus);
+    for (String userName : userNames) {
+      Map<String, Object> requestProperties = new HashMap<>();
+      requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, userName);
+      requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
+      requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
+      requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
 
-        /* try with uppercase version of an existing user */
-        requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "ABCD");
-        request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
-        try {
-            requestStatus = userResourceProvider.createResources(request);
-            assertTrue("Should fail with user exists", false);
-        }
-        catch(Exception ex) {
-            assertTrue(ex.getMessage().contains("User abcd already exists"));
-        }
-
-        // delete the created username
-        Predicate predicate = new PredicateBuilder()
-                .property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("abcd").toPredicate();
-        requestStatus = userResourceProvider.deleteResources(request, predicate);
-        assertNotNull(requestStatus);
-
-        // verify that the username was deleted
-        Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
-        Set<Resource> resources = userResourceProvider.getResources(getRequest, null);
-        assertEquals(resources.size(), 0);
+      Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
+      RequestStatus requestStatus = userResourceProvider.createResources(request);
+      assertNotNull(requestStatus);
     }
 
-    /**
-     * Creates a user and retrieves the user using the same username but in lowercase. Verifies
-     * that the retrieval is successful and that the retrieved username is the same as the one
-     * that was used during creation.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void getExistingUserCaseInsensitiveTest() throws Exception {
-        Authentication authentication = TestAuthenticationFactory.createAdministrator();
-        SecurityContextHolder.getContext().setAuthentication(authentication);
-
-        // create a new user viewUser
-        Map<String, Object> requestProperties = new HashMap<>();
-        requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "viewUser");
-        requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
-        requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
-        requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
-
-        Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
-        RequestStatus requestStatus = userResourceProvider.createResources(request);
-        assertNotNull(requestStatus);
-
-        // verify the created username
-        Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
-        Predicate predicate = new PredicateBuilder()
-                .property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals("viewuser").toPredicate();
-        Set<Resource> resources = userResourceProvider.getResources(getRequest, predicate);
-        assertEquals(resources.size(), 1);
-        Resource resource = resources.iterator().next();
-
-        String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
-        assertEquals(userName, "viewUser");
-
-        // delete the created username
-        requestStatus = userResourceProvider.deleteResources(request, predicate);
-        assertNotNull(requestStatus);
-
-        // verify that the username was deleted
-        resources = userResourceProvider.getResources(getRequest, null);
-        assertEquals(resources.size(), 0);
+    // verify the created username
+    Request getRequest = PropertyHelper.getReadRequest(Collections.singleton(("Users")));
+    Set<Resource> resources = userResourceProvider.getResources(getRequest, null);
+    for (Resource resource : resources) {
+      System.out.println("Resource: " + resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString());
+    }
+    for (String s: lowercaseUserNames) {
+      System.out.println("LC UN: " + s);
+    }
+    assertEquals(lowercaseUserNames.size(), resources.size());
+    for (Resource resource : resources) {
+      String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
+      assertTrue(lowercaseUserNames.contains(userName));
     }
 
-    /**
-     * Adds an array of users, retrieves the users and verifies that the usernames do not differ
-     * from the ones that were used during creation.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void getAllUserTest() throws Exception {
-        Authentication authentication = TestAuthenticationFactory.createAdministrator();
-        SecurityContextHolder.getContext().setAuthentication(authentication);
-
-        List<String> userNames =  Arrays.asList("user1", "uSer2", "User3", "useR4");
-
-        for (String userName : userNames) {
-            Map<String, Object> requestProperties = new HashMap<>();
-            requestProperties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, userName);
-            requestProperties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
-            requestProperties.put(UserResourceProvider.USER_ADMIN_PROPERTY_ID, false);
-            requestProperties.put(UserResourceProvider.USER_ACTIVE_PROPERTY_ID, true);
-
-            Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProperties), null);
-            RequestStatus requestStatus = userResourceProvider.createResources(request);
-            assertNotNull(requestStatus);
-        }
-
-        // verify the created username
-        Request getRequest = PropertyHelper.getReadRequest(new HashSet<>(Arrays.asList("Users")));
-        Set<Resource> resources = userResourceProvider.getResources(getRequest, null);
-        assertEquals(resources.size(), userNames.size());
-        for (Resource resource : resources) {
-            String userName = resource.getPropertyValue(UserResourceProvider.USER_USERNAME_PROPERTY_ID).toString();
-            assertTrue(userNames.contains(userName));
-        }
-
-        // delete the users
-        for (String userName : userNames) {
-            Predicate predicate = new PredicateBuilder()
-                    .property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals(userName).toPredicate();
-            RequestStatus requestStatus = userResourceProvider.deleteResources(null /* not used */, predicate);
-            assertNotNull(requestStatus);
-        }
-
-        // verify that the username was deleted
-        resources = userResourceProvider.getResources(getRequest, null);
-        assertEquals(resources.size(), 0);
+    // delete the users
+    for (String userName : userNames) {
+      Predicate predicate = new PredicateBuilder()
+          .property(UserResourceProvider.USER_USERNAME_PROPERTY_ID).equals(userName).toPredicate();
+      RequestStatus requestStatus = userResourceProvider.deleteResources(null /* not used */, predicate);
+      assertNotNull(requestStatus);
     }
+
+    // verify that the username was deleted
+    resources = userResourceProvider.getResources(getRequest, null);
+    assertEquals(resources.size(), 0);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 d298b7f..4530d40 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
@@ -6,9 +6,9 @@
  * 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
- * <p/>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p/>
+ *
+ *     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.
@@ -55,11 +55,12 @@ 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.HostRoleCommandDAO;
+import org.apache.ambari.server.orm.entities.MemberEntity;
+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.User;
-import org.apache.ambari.server.security.authorization.UserType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.security.encryption.CredentialStoreService;
 import org.apache.ambari.server.security.encryption.CredentialStoreServiceImpl;
@@ -266,9 +267,20 @@ public class UserResourceProviderTest extends EasyMockSupport {
   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);
-    users.createUser("User100", "password", UserType.LOCAL, (Boolean) null, null);
-    expectLastCall().atLeastOnce();
+    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();
 
     // replay
     replayAll();
@@ -278,19 +290,21 @@ public class UserResourceProviderTest extends EasyMockSupport {
     AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
     ambariMetaInfo.init();
 
-    AmbariManagementController managementController = injector.getInstance(AmbariManagementController.class);
-
-    ResourceProvider provider = getResourceProvider(managementController);
+    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 = new LinkedHashMap<>();
+    Map<String, Object> properties;
 
-    // add properties to the request map
+    properties = new LinkedHashMap<>();
     properties.put(UserResourceProvider.USER_USERNAME_PROPERTY_ID, "User100");
-    properties.put(UserResourceProvider.USER_PASSWORD_PROPERTY_ID, "password");
+    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
@@ -308,15 +322,23 @@ public class UserResourceProviderTest extends EasyMockSupport {
     Users users = injector.getInstance(Users.class);
 
     if ("admin".equals(authentication.getName())) {
-      List<User> allUsers = Arrays.asList(
-          createMockUser("User1"),
-          createMockUser("User10"),
-          createMockUser("User100"),
-          createMockUser("admin")
-      );
-      expect(users.getAllUsers()).andReturn(allUsers).atLeastOnce();
+      UserEntity userEntity1 = createMockUserEntity("User1");
+      UserEntity userEntity10 = createMockUserEntity("User10");
+      UserEntity userEntity100 = createMockUserEntity("User100");
+      UserEntity userEntityAdmin = createMockUserEntity("admin");
+
+      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();
     } else {
-      expect(users.getAnyUser("User1")).andReturn(createMockUser("User1")).atLeastOnce();
+
+      UserEntity userEntity = createMockUserEntity("User1");
+      expect(users.getUserEntity("User1")).andReturn(userEntity).once();
+      expect(users.hasAdminPrivilege(userEntity)).andReturn(false).once();
     }
 
     replayAll();
@@ -326,9 +348,7 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    AmbariManagementController managementController = injector.getInstance(AmbariManagementController.class);
-
-    ResourceProvider provider = getResourceProvider(managementController);
+    ResourceProvider provider = getResourceProvider(injector);
 
     Set<String> propertyIds = new HashSet<>();
     propertyIds.add(UserResourceProvider.USER_USERNAME_PROPERTY_ID);
@@ -358,8 +378,11 @@ public class UserResourceProviderTest extends EasyMockSupport {
   private void getResourceTest(Authentication authentication, String requestedUsername) throws Exception {
     Injector injector = createInjector();
 
+    UserEntity userEntity = createMockUserEntity(requestedUsername);
+
     Users users = injector.getInstance(Users.class);
-    expect(users.getAnyUser(requestedUsername)).andReturn(createMockUser(requestedUsername)).atLeastOnce();
+    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
+    expect(users.hasAdminPrivilege(userEntity)).andReturn(false).once();
 
     replayAll();
 
@@ -368,9 +391,7 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    AmbariManagementController managementController = injector.getInstance(AmbariManagementController.class);
-
-    ResourceProvider provider = getResourceProvider(managementController);
+    ResourceProvider provider = getResourceProvider(injector);
 
     Set<String> propertyIds = new HashSet<>();
     propertyIds.add(UserResourceProvider.USER_USERNAME_PROPERTY_ID);
@@ -389,14 +410,16 @@ public class UserResourceProviderTest extends EasyMockSupport {
     verifyAll();
   }
 
-  public void updateResources_SetAdmin(Authentication authentication, String requestedUsername) throws Exception {
+  private void updateResources_SetAdmin(Authentication authentication, String requestedUsername) throws Exception {
     Injector injector = createInjector();
 
+    UserEntity userEntity = createMockUserEntity(requestedUsername);
+
     Users users = injector.getInstance(Users.class);
-    expect(users.getAnyUser(requestedUsername)).andReturn(createMockUser(requestedUsername)).once();
+    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
 
     if ("admin".equals(authentication.getName())) {
-      users.grantAdminPrivilege(requestedUsername.hashCode());
+      users.grantAdminPrivilege(userEntity);
       expectLastCall().once();
     }
 
@@ -407,9 +430,7 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    AmbariManagementController managementController = injector.getInstance(AmbariManagementController.class);
-
-    ResourceProvider provider = getResourceProvider(managementController);
+    ResourceProvider provider = getResourceProvider(injector);
 
     // add the property map to a set for the request.
     Map<String, Object> properties = new LinkedHashMap<>();
@@ -423,14 +444,16 @@ public class UserResourceProviderTest extends EasyMockSupport {
     verifyAll();
   }
 
-  public void updateResources_SetActive(Authentication authentication, String requestedUsername) throws Exception {
+  private void updateResources_SetActive(Authentication authentication, String requestedUsername) throws Exception {
     Injector injector = createInjector();
 
+    UserEntity userEntity = createMockUserEntity(requestedUsername);
+
     Users users = injector.getInstance(Users.class);
-    expect(users.getAnyUser(requestedUsername)).andReturn(createMockUser(requestedUsername)).once();
+    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
 
     if ("admin".equals(authentication.getName())) {
-      users.setUserActive(requestedUsername, true);
+      users.setUserActive(userEntity, true);
       expectLastCall().once();
     }
 
@@ -441,9 +464,7 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    AmbariManagementController managementController = injector.getInstance(AmbariManagementController.class);
-
-    ResourceProvider provider = getResourceProvider(managementController);
+    ResourceProvider provider = getResourceProvider(injector);
 
     // add the property map to a set for the request.
     Map<String, Object> properties = new LinkedHashMap<>();
@@ -456,12 +477,14 @@ public class UserResourceProviderTest extends EasyMockSupport {
     verifyAll();
   }
 
-  public void updateResources_SetPassword(Authentication authentication, String requestedUsername) throws Exception {
+  private void updateResources_SetPassword(Authentication authentication, String requestedUsername) throws Exception {
     Injector injector = createInjector();
 
+    UserEntity userEntity = createMockUserEntity(requestedUsername);
+
     Users users = injector.getInstance(Users.class);
-    expect(users.getAnyUser(requestedUsername)).andReturn(createMockUser(requestedUsername)).once();
-    users.modifyPassword(requestedUsername, "old_password", "new_password");
+    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
+    users.modifyPassword(userEntity, "old_password", "new_password");
     expectLastCall().once();
 
     replayAll();
@@ -471,9 +494,7 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    AmbariManagementController managementController = injector.getInstance(AmbariManagementController.class);
-
-    ResourceProvider provider = getResourceProvider(managementController);
+    ResourceProvider provider = getResourceProvider(injector);
 
     // add the property map to a set for the request.
     Map<String, Object> properties = new LinkedHashMap<>();
@@ -491,11 +512,11 @@ public class UserResourceProviderTest extends EasyMockSupport {
   private void deleteResourcesTest(Authentication authentication, String requestedUsername) throws Exception {
     Injector injector = createInjector();
 
-    User user = createMockUser(requestedUsername);
+    UserEntity userEntity = createMockUserEntity(requestedUsername);
 
     Users users = injector.getInstance(Users.class);
-    expect(users.getAnyUser(requestedUsername)).andReturn(user).atLeastOnce();
-    users.removeUser(user);
+    expect(users.getUserEntity(requestedUsername)).andReturn(userEntity).once();
+    users.removeUser(userEntity);
     expectLastCall().atLeastOnce();
 
     // replay
@@ -506,9 +527,7 @@ public class UserResourceProviderTest extends EasyMockSupport {
 
     SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    AmbariManagementController managementController = injector.getInstance(AmbariManagementController.class);
-
-    ResourceProvider provider = getResourceProvider(managementController);
+    ResourceProvider provider = getResourceProvider(injector);
 
     provider.deleteResources(new RequestImpl(null, null, null, null), createPredicate(requestedUsername));
 
@@ -524,24 +543,23 @@ public class UserResourceProviderTest extends EasyMockSupport {
         .toPredicate();
   }
 
-  private User createMockUser(String username) {
-    User user = createMock(User.class);
-    expect(user.getUserId()).andReturn(username.hashCode()).anyTimes();
-    expect(user.getUserName()).andReturn(username).anyTimes();
-    expect(user.getUserType()).andReturn(UserType.LOCAL).anyTimes();
-    expect(user.isLdapUser()).andReturn(false).anyTimes();
-    expect(user.isActive()).andReturn(true).anyTimes();
-    expect(user.isAdmin()).andReturn(false).anyTimes();
-    expect(user.getGroups()).andReturn(Collections.<String>emptyList()).anyTimes();
-
-    return user;
+  private UserEntity createMockUserEntity(String username) {
+    UserEntity userEntity = createMock(UserEntity.class);
+    expect(userEntity.getUserId()).andReturn(username.hashCode()).anyTimes();
+    expect(userEntity.getUserName()).andReturn(username).anyTimes();
+    expect(userEntity.getActive()).andReturn(true).anyTimes();
+    expect(userEntity.getAuthenticationEntities()).andReturn(Collections.<UserAuthenticationEntity>emptyList()).anyTimes();
+    expect(userEntity.getMemberEntities()).andReturn(Collections.<MemberEntity>emptySet()).anyTimes();
+    return userEntity;
   }
 
-  private ResourceProvider getResourceProvider(AmbariManagementController managementController) {
-    return AbstractControllerResourceProvider.getResourceProvider(
-        Resource.Type.User,
+  private ResourceProvider getResourceProvider(Injector injector) {
+    UserResourceProvider resourceProvider = new UserResourceProvider(
         PropertyHelper.getPropertyIds(Resource.Type.User),
         PropertyHelper.getKeyPropertyIds(Resource.Type.User),
-        managementController);
+        injector.getInstance(AmbariManagementController.class));
+
+    injector.injectMembers(resourceProvider);
+    return resourceProvider;
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
index 271d536..99cc286 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
@@ -227,8 +227,7 @@ public class OrmTestHelper {
     PasswordEncoder encoder = injector.getInstance(PasswordEncoder.class);
 
     UserEntity admin = new UserEntity();
-    admin.setUserName(UserName.fromString("administrator"));
-    admin.setUserPassword(encoder.encode("admin"));
+    admin.setUserName(UserName.fromString("administrator").toString());
     admin.setPrincipal(principalEntity);
 
     Set<UserEntity> users = new HashSet<>();
@@ -242,11 +241,9 @@ public class OrmTestHelper {
     getEntityManager().persist(principalEntity);
 
     UserEntity userWithoutRoles = new UserEntity();
-    userWithoutRoles.setUserName(UserName.fromString("userWithoutRoles"));
-    userWithoutRoles.setUserPassword(encoder.encode("test"));
+    userWithoutRoles.setUserName(UserName.fromString("userWithoutRoles").toString());
     userWithoutRoles.setPrincipal(principalEntity);
     userDAO.create(userWithoutRoles);
-
   }
 
   @Transactional

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UserDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UserDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UserDAOTest.java
index 05733fa..e3c904d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UserDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/UserDAOTest.java
@@ -25,9 +25,6 @@ import static org.easymock.EasyMock.createStrictMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-import java.util.Arrays;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
@@ -35,7 +32,6 @@ import javax.persistence.TypedQuery;
 import org.apache.ambari.server.orm.DBAccessor;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.authorization.UserName;
-import org.apache.ambari.server.security.authorization.UserType;
 import org.junit.Test;
 
 import com.google.inject.AbstractModule;
@@ -52,7 +48,7 @@ public class UserDAOTest {
   private static String SERVICEOP_USER_NAME = "serviceopuser";
   private UserDAO userDAO;
 
-  public void init(UserEntity... usersInDB) {
+  public void init(UserEntity userInDB) {
     final EntityManager entityManager = createStrictMock(EntityManager.class);
     final DaoUtils daoUtils = createNiceMock(DaoUtils.class);
     final DBAccessor dbAccessor = createNiceMock(DBAccessor.class);
@@ -68,55 +64,24 @@ public class UserDAOTest {
     userDAO = mockInjector.getInstance(UserDAO.class);
 
     TypedQuery<UserEntity> userQuery = createNiceMock(TypedQuery.class);
-    expect(userQuery.getResultList()).andReturn(Arrays.asList(usersInDB));
+    expect(userQuery.getSingleResult()).andReturn(userInDB);
     expect(entityManager.createNamedQuery(anyString(), anyObject(Class.class))).andReturn(userQuery);
     replay(entityManager, daoUtils, dbAccessor, userQuery);
   }
 
   @Test
-  public void testFindSingleUserByName_NoUsers() {
-    init();
-    assertNull(userDAO.findSingleUserByName(SERVICEOP_USER_NAME));
-  }
-
-  @Test
-  public void testFindSingleUserByName_SingleUser() {
-    init(user(UserType.PAM));
-    assertEquals(UserType.PAM, userDAO.findSingleUserByName(SERVICEOP_USER_NAME).getUserType());
-  }
-
-  @Test
-  public void testFindSingleUserByName_LocalIsFirstPrecedence() {
-    init(user(UserType.LOCAL),
-        user(UserType.LDAP),
-        user(UserType.JWT),
-        user(UserType.PAM));
-    assertEquals(UserType.LOCAL, userDAO.findSingleUserByName(SERVICEOP_USER_NAME).getUserType());
-  }
-
-  @Test
-  public void testFindSingleUserByName_LdapIsSecondPrecedence() {
-    init(user(UserType.LDAP),
-        user(UserType.JWT),
-        user(UserType.PAM));
-    assertEquals(UserType.LDAP, userDAO.findSingleUserByName(SERVICEOP_USER_NAME).getUserType());
-  }
-
-  @Test
-  public void testFindSingleUserByName_JwtIsThirdPrecedence() {
-    init(user(UserType.JWT),
-        user(UserType.PAM));
-    assertEquals(UserType.JWT, userDAO.findSingleUserByName(SERVICEOP_USER_NAME).getUserType());
+  public void testUserByName() {
+    init(user());
+    assertEquals(SERVICEOP_USER_NAME, userDAO.findUserByName(SERVICEOP_USER_NAME).getUserName());
   }
 
-  private static final UserEntity user(UserType type) {
-    return user(SERVICEOP_USER_NAME, type);
+  private static final UserEntity user() {
+    return user(SERVICEOP_USER_NAME);
   }
 
-  private static final UserEntity user(String name, UserType type) {
+  private static final UserEntity user(String name) {
     UserEntity userEntity = new UserEntity();
-    userEntity.setUserName(UserName.fromString(name));
-    userEntity.setUserType(type);
+    userEntity.setUserName(UserName.fromString(name).toString());
     return userEntity;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHelperImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHelperImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHelperImplTest.java
index f15f2f5..4d6d5a9 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHelperImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/SecurityHelperImplTest.java
@@ -44,13 +44,14 @@ public class SecurityHelperImplTest {
     SecurityContext ctx = SecurityContextHolder.getContext();
     UserEntity userEntity = new UserEntity();
     userEntity.setPrincipal(new PrincipalEntity());
-    userEntity.setUserName(UserName.fromString("userName"));
+    userEntity.setUserName(UserName.fromString("userName").toString());
     userEntity.setUserId(1);
     User user = new User(userEntity);
     Authentication auth = new AmbariUserAuthentication(null, user, null);
     ctx.setAuthentication(auth);
 
-    Assert.assertEquals("userName", SecurityHelperImpl.getInstance().getCurrentUserName());
+    // Username is expected to be lowercase
+    Assert.assertEquals("username", SecurityHelperImpl.getInstance().getCurrentUserName());
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
index de5b768..961e65d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
@@ -37,10 +37,10 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.ambari.server.audit.AuditLogger;
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.AmbariEntryPoint;
 import org.apache.ambari.server.security.authorization.PermissionHelper;
-import org.apache.ambari.server.security.authorization.User;
-import org.apache.ambari.server.security.authorization.UserType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationProperties;
 import org.easymock.EasyMockSupport;
@@ -83,13 +83,11 @@ public class AmbariJWTAuthenticationFilterTest extends EasyMockSupport {
     Configuration configuration = createMock(Configuration.class);
     expect(configuration.getJwtProperties()).andReturn(properties).once();
 
-    User user = createMock(User.class);
-    expect(user.getUserName()).andReturn("test-user").once();
-    expect(user.getUserType()).andReturn(UserType.JWT).once();
+    UserEntity userEntity = createMock(UserEntity.class);
+    expect(userEntity.getAuthenticationEntities()).andReturn(Collections.<UserAuthenticationEntity>emptyList()).once();
 
     Users users = createMock(Users.class);
-    expect(users.getUser("test-user", UserType.JWT)).andReturn(user).once();
-    expect(users.getUserAuthorities("test-user", UserType.JWT)).andReturn(null).once();
+    expect(users.getUserEntity("test-user")).andReturn(userEntity).once();
 
     AuditLogger auditLogger = createMock(AuditLogger.class);
     expect(auditLogger.isEnabled()).andReturn(false).times(2);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java
index 530bf65..c6ee706 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java
@@ -24,9 +24,10 @@ import java.util.Collection;
 import java.util.Collections;
 
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
-import org.apache.ambari.server.security.authorization.User;
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.easymock.EasyMockSupport;
 import org.junit.Before;
@@ -53,15 +54,19 @@ public class AmbariAuthToLocalUserDetailsServiceTest extends EasyMockSupport {
     Configuration configuration = createMock(Configuration.class);
     expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
 
-    User user = createMock(User.class);
-    expect(user.getUserName()).andReturn("user1").once();
-    expect(user.getUserType()).andReturn(UserType.LDAP).once();
+    UserAuthenticationEntity kerberosAuthenticationEntity = createMock(UserAuthenticationEntity.class);
+    expect(kerberosAuthenticationEntity.getAuthenticationType()).andReturn(UserAuthenticationType.KERBEROS).anyTimes();
+    expect(kerberosAuthenticationEntity.getAuthenticationKey()).andReturn("user1@EXAMPLE.COM").anyTimes();
+
+    UserEntity userEntity = createMock(UserEntity.class);
+    expect(userEntity.getActive()).andReturn(true).once();
+    expect(userEntity.getAuthenticationEntities()).andReturn(Collections.singletonList(kerberosAuthenticationEntity)).once();
 
     Collection<AmbariGrantedAuthority> userAuthorities = Collections.singletonList(createNiceMock(AmbariGrantedAuthority.class));
 
     Users users = createMock(Users.class);
-    expect(users.getUser("user1", UserType.LDAP)).andReturn(user).once();
-    expect(users.getUserAuthorities("user1", UserType.LDAP)).andReturn(userAuthorities).once();
+    expect(users.getUserEntity("user1")).andReturn(userEntity).atLeastOnce();
+    expect(users.getUserAuthorities(userEntity)).andReturn(userAuthorities).atLeastOnce();
 
     replayAll();
 
@@ -85,8 +90,7 @@ public class AmbariAuthToLocalUserDetailsServiceTest extends EasyMockSupport {
     expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
 
     Users users = createMock(Users.class);
-    expect(users.getUser("user1", UserType.LDAP)).andReturn(null).once();
-    expect(users.getUser("user1", UserType.LOCAL)).andReturn(null).once();
+    expect(users.getUserEntity("user1")).andReturn(null).times(2);
 
     replayAll();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationPropertiesTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationPropertiesTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationPropertiesTest.java
index eb26cd8..bf170fe 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationPropertiesTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationPropertiesTest.java
@@ -18,11 +18,6 @@
 
 package org.apache.ambari.server.security.authentication.kerberos;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
-import org.apache.ambari.server.security.authorization.UserType;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -61,17 +56,6 @@ public class AmbariKerberosAuthenticationPropertiesTest {
   }
 
   @Test
-  public void testOrderedUserTypes() throws Exception {
-    AmbariKerberosAuthenticationProperties properties = new AmbariKerberosAuthenticationProperties();
-
-    properties.setOrderedUserTypes(new ArrayList<>(Arrays.asList(UserType.LDAP, UserType.LOCAL)));
-    Assert.assertEquals(new ArrayList<>(Arrays.asList(UserType.LDAP, UserType.LOCAL)), properties.getOrderedUserTypes());
-
-    properties.setOrderedUserTypes(Collections.singletonList(UserType.JWT));
-    Assert.assertEquals(new ArrayList<>(Collections.singletonList(UserType.JWT)), properties.getOrderedUserTypes());
-  }
-
-  @Test
   public void testAuthToLocalRules() throws Exception {
     AmbariKerberosAuthenticationProperties properties = new AmbariKerberosAuthenticationProperties();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
index 15e243e..1d46b89 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
@@ -317,11 +317,10 @@ public class AmbariAuthorizationFilterTest {
 
     User user = EasyMock.createMock(User.class);
     expect(user.getUserName()).andReturn("user1").anyTimes();
-    expect(user.getUserType()).andReturn(UserType.LOCAL).anyTimes();
 
     final Users users = EasyMock.createMock(Users.class);
-    expect(users.getUser("user1", UserType.LOCAL)).andReturn(user).once();
-    expect(users.getUserAuthorities("user1", UserType.LOCAL)).andReturn(Collections.<AmbariGrantedAuthority>emptyList()).once();
+    expect(users.getUser("user1")).andReturn(user).once();
+    expect(users.getUserAuthorities("user1")).andReturn(Collections.<AmbariGrantedAuthority>emptyList()).once();
 
     replay(request, response, chain, configuration, users, user);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java
index 891ab38..33100dd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java
@@ -18,10 +18,13 @@
 
 package org.apache.ambari.server.security.authorization;
 
+import java.util.Collections;
+
 import org.apache.ambari.server.orm.dao.MemberDAO;
 import org.apache.ambari.server.orm.dao.PrivilegeDAO;
 import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.junit.Assert;
 import org.junit.Before;
@@ -87,13 +90,18 @@ public class AmbariAuthorizationProviderDisableUserTest {
   
   private void createUser(String login, boolean isActive) {
     PrincipalEntity principalEntity = new PrincipalEntity();
+
+    UserAuthenticationEntity userAuthenticationEntity = new UserAuthenticationEntity();
+    userAuthenticationEntity.setAuthenticationType(UserAuthenticationType.LOCAL);
+    userAuthenticationEntity.setAuthenticationKey(encoder.encode("pwd"));
+
     UserEntity activeUser = new UserEntity();
     activeUser.setUserId(1);
     activeUser.setActive(isActive);
-    activeUser.setUserName(UserName.fromString(login));
-    activeUser.setUserPassword(encoder.encode("pwd"));
+    activeUser.setUserName(UserName.fromString(login).toString());
+    activeUser.setAuthenticationEntities(Collections.singletonList(userAuthenticationEntity));
     activeUser.setPrincipal(principalEntity);
-    Mockito.when(userDAO.findLocalUserByName(login)).thenReturn(activeUser);
-    Mockito.when(userDAO.findLdapUserByName(login)).thenReturn(activeUser);
+    Mockito.when(userDAO.findUserByName(login)).thenReturn(activeUser);
+    Mockito.when(userDAO.findUserByName(login)).thenReturn(activeUser);
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java
index 442414f..1bf122e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java
@@ -28,6 +28,7 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.ControllerModule;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.dao.UserDAO;
+import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.ClientSecurityType;
 import org.apache.directory.server.annotations.CreateLdapServer;
 import org.apache.directory.server.annotations.CreateTransport;
@@ -104,8 +105,10 @@ public class AmbariLdapAuthenticationProviderForDNWithSpaceTest extends AmbariLd
 
   @Test
   public void testAuthenticate() throws Exception {
-    assertNull("User alread exists in DB", userDAO.findLdapUserByName("the allowedUser"));
-    users.createUser("the allowedUser", "password", UserType.LDAP, true, false);
+    assertNull("User already exists in DB", userDAO.findUserByName("the allowedUser"));
+    UserEntity userEntity = users.createUser("the allowedUser", null, null);
+    users.addLdapAuthentication(userEntity, "some Dn");
+
     Authentication authentication = new UsernamePasswordAuthenticationToken("the allowedUser", "password");
     Authentication result = authenticationProvider.authenticate(authentication);
     assertTrue(result.isAuthenticated());

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java
index 4941bc7..d9eb335 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java
@@ -181,9 +181,11 @@ public class AmbariLdapAuthenticationProviderTest extends AmbariLdapAuthenticati
 
   @Test
   public void testAuthenticate() throws Exception {
-    assertNull("User alread exists in DB", userDAO.findLdapUserByName("allowedUser"));
-    users.createUser("allowedUser", "password", UserType.LDAP, true, false);
-    UserEntity ldapUser = userDAO.findLdapUserByName("allowedUser");
+    assertNull("User alread exists in DB", userDAO.findUserByName("allowedUser"));
+    UserEntity userEntity = users.createUser("allowedUser", null, null);
+    users.addLdapAuthentication(userEntity, "some dn");
+
+    UserEntity ldapUser = userDAO.findUserByName("allowedUser");
     Authentication authentication = new UsernamePasswordAuthenticationToken("allowedUser", "password");
 
     AmbariAuthentication result = (AmbariAuthentication) authenticationProvider.authenticate(authentication);
@@ -206,8 +208,10 @@ public class AmbariLdapAuthenticationProviderTest extends AmbariLdapAuthenticati
   @Test
   public void testAuthenticateLoginAlias() throws Exception {
     // Given
-    assertNull("User already exists in DB", userDAO.findLdapUserByName("allowedUser@ambari.apache.org"));
-    users.createUser("allowedUser@ambari.apache.org", "password", UserType.LDAP, true, false);
+    assertNull("User already exists in DB", userDAO.findUserByName("allowedUser@ambari.apache.org"));
+    UserEntity userEntity = users.createUser("allowedUser@ambari.apache.org", null, null);
+    users.addLdapAuthentication(userEntity, "some dn");
+
     Authentication authentication = new UsernamePasswordAuthenticationToken("allowedUser@ambari.apache.org", "password");
     configuration.setProperty(Configuration.LDAP_ALT_USER_SEARCH_ENABLED.getKey(), "true");
 
@@ -221,7 +225,7 @@ public class AmbariLdapAuthenticationProviderTest extends AmbariLdapAuthenticati
   @Test(expected = InvalidUsernamePasswordCombinationException.class)
   public void testBadCredentialsForMissingLoginAlias() throws Exception {
     // Given
-    assertNull("User already exists in DB", userDAO.findLdapUserByName("allowedUser"));
+    assertNull("User already exists in DB", userDAO.findUserByName("allowedUser"));
     Authentication authentication = new UsernamePasswordAuthenticationToken("missingloginalias@ambari.apache.org", "password");
     configuration.setProperty(Configuration.LDAP_ALT_USER_SEARCH_ENABLED.getKey(), "true");
 
@@ -237,7 +241,7 @@ public class AmbariLdapAuthenticationProviderTest extends AmbariLdapAuthenticati
   @Test(expected = InvalidUsernamePasswordCombinationException.class)
   public void testBadCredentialsBadPasswordForLoginAlias() throws Exception {
     // Given
-    assertNull("User already exists in DB", userDAO.findLdapUserByName("allowedUser"));
+    assertNull("User already exists in DB", userDAO.findUserByName("allowedUser"));
     Authentication authentication = new UsernamePasswordAuthenticationToken("allowedUser@ambari.apache.org", "bad_password");
     configuration.setProperty(Configuration.LDAP_ALT_USER_SEARCH_ENABLED.getKey(), "true");
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java
index 2362823..65a5400 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java
@@ -25,12 +25,15 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Collections;
+
 import org.apache.ambari.server.H2DatabaseCleaner;
 import org.apache.ambari.server.audit.AuditLoggerModule;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -81,9 +84,9 @@ public class AmbariLocalUserProviderTest {
     UserEntity userEntity = combineUserEntity();
 
     expect(authentication.getName()).andReturn(TEST_USER_NAME);
-    expect(userDAO.findLocalUserByName(TEST_USER_NAME)).andReturn(userEntity);
+    expect(userDAO.findUserByName(TEST_USER_NAME)).andReturn(userEntity);
     expect(authentication.getCredentials()).andReturn(TEST_USER_PASS).anyTimes();
-    expect(users.getUserAuthorities(userEntity.getUserName(), userEntity.getUserType())).andReturn(null);
+    expect(users.getUserAuthorities(userEntity)).andReturn(null);
 
     replay(users, userDAO, authentication);
 
@@ -105,7 +108,7 @@ public class AmbariLocalUserProviderTest {
     Authentication authentication = createMock(Authentication.class);
 
     expect(authentication.getName()).andReturn(TEST_USER_NAME);
-    expect(userDAO.findLocalUserByName(TEST_USER_NAME)).andReturn(null);
+    expect(userDAO.findUserByName(TEST_USER_NAME)).andReturn(null);
 
     replay(users, userDAO, authentication);
 
@@ -122,7 +125,7 @@ public class AmbariLocalUserProviderTest {
     UserEntity userEntity = combineUserEntity();
 
     expect(authentication.getName()).andReturn(TEST_USER_NAME);
-    expect(userDAO.findLocalUserByName(TEST_USER_NAME)).andReturn(userEntity);
+    expect(userDAO.findUserByName(TEST_USER_NAME)).andReturn(userEntity);
     expect(authentication.getCredentials()).andReturn(null);
 
     replay(users, userDAO, authentication);
@@ -140,7 +143,7 @@ public class AmbariLocalUserProviderTest {
     UserEntity userEntity = combineUserEntity();
 
     expect(authentication.getName()).andReturn(TEST_USER_NAME);
-    expect(userDAO.findLocalUserByName(TEST_USER_NAME)).andReturn(userEntity);
+    expect(userDAO.findUserByName(TEST_USER_NAME)).andReturn(userEntity);
     expect(authentication.getCredentials()).andReturn(TEST_USER_INCORRECT_PASS).anyTimes();
 
     replay(users, userDAO, authentication);
@@ -153,13 +156,16 @@ public class AmbariLocalUserProviderTest {
 
   private UserEntity combineUserEntity() {
     PrincipalEntity principalEntity = new PrincipalEntity();
+
+    UserAuthenticationEntity userAuthenticationEntity = new UserAuthenticationEntity();
+    userAuthenticationEntity.setAuthenticationType(UserAuthenticationType.LOCAL);
+    userAuthenticationEntity.setAuthenticationKey(passwordEncoder.encode(TEST_USER_PASS));
+
     UserEntity userEntity = new UserEntity();
     userEntity.setUserId(1);
-    userEntity.setUserName(UserName.fromString(TEST_USER_NAME));
-    userEntity.setUserPassword(passwordEncoder.encode(TEST_USER_PASS));
-    userEntity.setUserType(UserType.LOCAL);
+    userEntity.setUserName(UserName.fromString(TEST_USER_NAME).toString());
     userEntity.setPrincipal(principalEntity);
-
+    userEntity.setAuthenticationEntities(Collections.singletonList(userAuthenticationEntity));
     return userEntity;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java
index 8faa6ce..1145954 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java
@@ -20,10 +20,8 @@ package org.apache.ambari.server.security.authorization;
 import static org.easymock.EasyMock.createNiceMock;
 import static org.easymock.EasyMock.expect;
 
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 
 import org.apache.ambari.server.H2DatabaseCleaner;
 import org.apache.ambari.server.audit.AuditLoggerModule;
@@ -31,6 +29,7 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.ClientSecurityType;
 import org.easymock.EasyMock;
@@ -41,7 +40,6 @@ import org.jvnet.libpam.PAM;
 import org.jvnet.libpam.UnixUser;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.crypto.password.PasswordEncoder;
 
 import com.google.inject.Guice;
 import com.google.inject.Inject;
@@ -54,15 +52,11 @@ public class AmbariPamAuthenticationProviderTest {
   private static Injector injector;
 
   @Inject
-  PasswordEncoder passwordEncoder;
-  @Inject
   private AmbariPamAuthenticationProvider authenticationProvider;
   @Inject
-  Configuration configuration;
+  private Configuration configuration;
 
   private static final String TEST_USER_NAME = "userName";
-  private static final String TEST_USER_PASS = "userPass";
-  private static final String TEST_USER_INCORRECT_PASS = "userIncorrectPass";
 
   @Before
   public void setUp() {
@@ -91,12 +85,13 @@ public class AmbariPamAuthenticationProviderTest {
   public void testAuthenticate() throws Exception {
     PAM pam = createNiceMock(PAM.class);
     UnixUser unixUser = createNiceMock(UnixUser.class);
+    expect(unixUser.getUserName()).andReturn(TEST_USER_NAME).atLeastOnce();
     UserEntity userEntity = combineUserEntity();
     User user = new User(userEntity);
     UserDAO userDAO = createNiceMock(UserDAO.class);
     Collection<AmbariGrantedAuthority> userAuthorities = Collections.singletonList(createNiceMock(AmbariGrantedAuthority.class));
     expect(pam.authenticate(EasyMock.anyObject(String.class), EasyMock.anyObject(String.class))).andReturn(unixUser).atLeastOnce();
-    expect(unixUser.getGroups()).andReturn(new HashSet<>(Arrays.asList("group"))).atLeastOnce();
+    expect(unixUser.getGroups()).andReturn(Collections.singleton("group")).atLeastOnce();
     EasyMock.replay(unixUser);
     EasyMock.replay(pam);
     Authentication authentication = new AmbariUserAuthentication("userPass", user, userAuthorities);
@@ -120,12 +115,16 @@ public class AmbariPamAuthenticationProviderTest {
 
   private UserEntity combineUserEntity() {
     PrincipalEntity principalEntity = new PrincipalEntity();
+
+    UserAuthenticationEntity userAuthenticationEntity = new UserAuthenticationEntity();
+    userAuthenticationEntity.setAuthenticationType(UserAuthenticationType.PAM);
+    userAuthenticationEntity.setAuthenticationKey(TEST_USER_NAME);
+
     UserEntity userEntity = new UserEntity();
     userEntity.setUserId(1);
-    userEntity.setUserName(UserName.fromString(TEST_USER_NAME));
-    userEntity.setUserPassword(passwordEncoder.encode(TEST_USER_PASS));
-    userEntity.setUserType(UserType.PAM);
+    userEntity.setUserName(UserName.fromString(TEST_USER_NAME).toString());
     userEntity.setPrincipal(principalEntity);
+    userEntity.setAuthenticationEntities(Collections.singletonList(userAuthenticationEntity));
     return userEntity;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java
index 0483b04..7c3a7fd 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java
@@ -72,10 +72,11 @@ public class AmbariUserAuthenticationFilterTest {
     expect(tokenStorage.isValidInternalToken(TEST_INTERNAL_TOKEN)).andReturn(true);
     expect(request.getHeader(ExecutionScheduleManager.USER_ID_HEADER)).andReturn(TEST_USER_ID_HEADER);
 
-    User user = combineUser();
+    UserEntity userEntity = createUserEntity();
 
-    expect(users.getUser(TEST_USER_ID)).andReturn(user);
-    expect(users.getUserAuthorities(user.getUserName(), user.getUserType())).andReturn(new HashSet<AmbariGrantedAuthority>());
+    expect(users.getUserEntity(TEST_USER_ID)).andReturn(userEntity);
+    expect(users.getUserAuthorities(userEntity)).andReturn(new HashSet<AmbariGrantedAuthority>());
+    expect(users.getUser(userEntity)).andReturn(new User(userEntity));
     Capture<String> userHeaderValue = newCapture();
     response.setHeader(eq("User"), capture(userHeaderValue));
     expectLastCall();
@@ -93,7 +94,7 @@ public class AmbariUserAuthenticationFilterTest {
     Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
     assertNotNull(authentication);
     assertEquals(true, authentication.isAuthenticated());
-    assertEquals(TEST_USER_NAME, userHeaderValue.getValue());
+    assertEquals(TEST_USER_NAME.toLowerCase(), userHeaderValue.getValue());
   }
 
   @Test
@@ -158,7 +159,7 @@ public class AmbariUserAuthenticationFilterTest {
     expect(tokenStorage.isValidInternalToken(TEST_INTERNAL_TOKEN)).andReturn(true);
     expect(request.getHeader(ExecutionScheduleManager.USER_ID_HEADER)).andReturn(TEST_USER_ID_HEADER);
 
-    expect(users.getUser(TEST_USER_ID)).andReturn(null);
+    expect(users.getUserEntity(TEST_USER_ID)).andReturn(null);
 
     response.sendError(HttpServletResponse.SC_FORBIDDEN, "Authentication required");
     expectLastCall();
@@ -204,15 +205,12 @@ public class AmbariUserAuthenticationFilterTest {
     assertNull(authentication);
   }
 
-  private User combineUser() {
+  private UserEntity createUserEntity() {
     PrincipalEntity principalEntity = new PrincipalEntity();
     UserEntity userEntity = new UserEntity();
     userEntity.setUserId(TEST_USER_ID);
-    userEntity.setUserName(UserName.fromString(TEST_USER_NAME));
-    userEntity.setUserType(UserType.LOCAL);
+    userEntity.setUserName(UserName.fromString(TEST_USER_NAME).toString());
     userEntity.setPrincipal(principalEntity);
-    User user = new User(userEntity);
-
-    return user;
+    return userEntity;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestAmbariLdapAuthoritiesPopulator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestAmbariLdapAuthoritiesPopulator.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestAmbariLdapAuthoritiesPopulator.java
index fff39d8..314e8d8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestAmbariLdapAuthoritiesPopulator.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestAmbariLdapAuthoritiesPopulator.java
@@ -64,7 +64,7 @@ public class TestAmbariLdapAuthoritiesPopulator extends EasyMockSupport {
     expect(userEntity.getActive()).andReturn(true);
     expect(users.getUserPrivileges(userEntity)).andReturn(Collections.singletonList(privilegeEntity));
 
-    expect(userDAO.findLdapUserByName(username)).andReturn(userEntity);
+    expect(userDAO.findUserByName(username)).andReturn(userEntity);
     replayAll();
 
     populator.getGrantedAuthorities(userData, username);
@@ -90,7 +90,7 @@ public class TestAmbariLdapAuthoritiesPopulator extends EasyMockSupport {
     expect(userEntity.getActive()).andReturn(true);
     expect(users.getUserPrivileges(userEntity)).andReturn(Collections.singletonList(privilegeEntity));
 
-    expect(userDAO.findLdapUserByName(ambariUserName)).andReturn(userEntity); // user should be looked up by user name instead of login alias
+    expect(userDAO.findUserByName(ambariUserName)).andReturn(userEntity); // user should be looked up by user name instead of login alias
 
     replayAll();
 


[7/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 7ea4297..21e043b 100644
--- a/ambari-server/docs/api/generated/index.html
+++ b/ambari-server/docs/api/generated/index.html
@@ -901,16 +901,16 @@ margin-bottom: 20px;
     defs.Artifacts = {
   "type" : "object",
   "properties" : {
-    "stack_name" : {
+    "service_name" : {
       "type" : "string"
     },
     "stack_version" : {
       "type" : "string"
     },
-    "artifact_name" : {
+    "stack_name" : {
       "type" : "string"
     },
-    "service_name" : {
+    "artifact_name" : {
       "type" : "string"
     }
   }
@@ -921,14 +921,14 @@ margin-bottom: 20px;
     "security" : {
       "$ref" : "#/definitions/SecurityInfo"
     },
-    "stack_name" : {
-      "type" : "string"
-    },
     "stack_version" : {
       "type" : "string"
     },
     "blueprint_name" : {
       "type" : "string"
+    },
+    "stack_name" : {
+      "type" : "string"
     }
   }
 };
@@ -981,15 +981,15 @@ margin-bottom: 20px;
     defs.ClusterArtifactRequest = {
   "type" : "object",
   "properties" : {
-    "Artifacts" : {
-      "$ref" : "#/definitions/ClusterArtifactRequestInfo"
-    },
     "artifact_data" : {
       "type" : "object",
       "additionalProperties" : {
         "type" : "object",
         "properties" : { }
       }
+    },
+    "Artifacts" : {
+      "$ref" : "#/definitions/ClusterArtifactRequestInfo"
     }
   }
 };
@@ -1176,15 +1176,15 @@ margin-bottom: 20px;
     defs.ClusterServiceArtifactRequest = {
   "type" : "object",
   "properties" : {
-    "Artifacts" : {
-      "$ref" : "#/definitions/ClusterServiceArtifactRequestInfo"
-    },
     "artifact_data" : {
       "type" : "object",
       "additionalProperties" : {
         "type" : "object",
         "properties" : { }
       }
+    },
+    "Artifacts" : {
+      "$ref" : "#/definitions/ClusterServiceArtifactRequestInfo"
     }
   }
 };
@@ -1199,15 +1199,15 @@ margin-bottom: 20px;
     defs.ClusterServiceArtifactResponse = {
   "type" : "object",
   "properties" : {
-    "Artifacts" : {
-      "$ref" : "#/definitions/ClusterServiceArtifactResponseInfo"
-    },
     "artifact_data" : {
       "type" : "object",
       "additionalProperties" : {
         "type" : "object",
         "properties" : { }
       }
+    },
+    "Artifacts" : {
+      "$ref" : "#/definitions/ClusterServiceArtifactResponseInfo"
     }
   }
 };
@@ -1217,10 +1217,10 @@ margin-bottom: 20px;
     "cluster_name" : {
       "type" : "string"
     },
-    "artifact_name" : {
+    "service_name" : {
       "type" : "string"
     },
-    "service_name" : {
+    "artifact_name" : {
       "type" : "string"
     }
   }
@@ -1239,18 +1239,15 @@ margin-bottom: 20px;
     "scope" : {
       "type" : "string"
     },
-    "component_name" : {
+    "service_name" : {
       "type" : "string"
     },
-    "stack_name" : {
+    "component_name" : {
       "type" : "string"
     },
     "stack_version" : {
       "type" : "string"
     },
-    "service_name" : {
-      "type" : "string"
-    },
     "conditions" : {
       "type" : "array",
       "items" : {
@@ -1262,16 +1259,19 @@ margin-bottom: 20px;
     },
     "dependent_service_name" : {
       "type" : "string"
+    },
+    "stack_name" : {
+      "type" : "string"
     }
   }
 };
     defs.ComponentInfo = {
   "type" : "object",
   "properties" : {
-    "provision_action" : {
+    "name" : {
       "type" : "string"
     },
-    "name" : {
+    "provision_action" : {
       "type" : "string"
     }
   }
@@ -1630,12 +1630,6 @@ margin-bottom: 20px;
     defs.HostGroupInfo = {
   "type" : "object",
   "properties" : {
-    "components" : {
-      "type" : "array",
-      "items" : {
-        "$ref" : "#/definitions/ComponentInfo"
-      }
-    },
     "configurations" : {
       "type" : "array",
       "items" : {
@@ -1646,12 +1640,18 @@ margin-bottom: 20px;
         }
       }
     },
-    "cardinality" : {
-      "type" : "integer",
-      "format" : "int32"
+    "components" : {
+      "type" : "array",
+      "items" : {
+        "$ref" : "#/definitions/ComponentInfo"
+      }
     },
     "name" : {
       "type" : "string"
+    },
+    "cardinality" : {
+      "type" : "integer",
+      "format" : "int32"
     }
   }
 };
@@ -1709,13 +1709,13 @@ margin-bottom: 20px;
     "maintenance_state" : {
       "type" : "string"
     },
-    "public_host_name" : {
+    "host_group" : {
       "type" : "string"
     },
     "blueprint" : {
       "type" : "string"
     },
-    "host_group" : {
+    "public_host_name" : {
       "type" : "string"
     }
   }
@@ -1796,10 +1796,10 @@ margin-bottom: 20px;
       "type" : "string",
       "enum" : [ "OFF", "ON", "IMPLIED_FROM_SERVICE", "IMPLIED_FROM_HOST", "IMPLIED_FROM_SERVICE_AND_HOST" ]
     },
-    "host_health_report" : {
+    "public_host_name" : {
       "type" : "string"
     },
-    "public_host_name" : {
+    "host_health_report" : {
       "type" : "string"
     }
   }
@@ -2145,23 +2145,23 @@ margin-bottom: 20px;
     defs.QuickLinksResponseInfo = {
   "type" : "object",
   "properties" : {
-    "file_name" : {
-      "type" : "string"
-    },
     "default" : {
       "type" : "boolean",
       "default" : false
     },
-    "stack_name" : {
+    "file_name" : {
       "type" : "string"
     },
-    "stack_version" : {
+    "service_name" : {
       "type" : "string"
     },
     "quicklink_data" : {
       "$ref" : "#/definitions/QuickLinksConfiguration"
     },
-    "service_name" : {
+    "stack_version" : {
+      "type" : "string"
+    },
+    "stack_name" : {
       "type" : "string"
     }
   }
@@ -2235,14 +2235,14 @@ margin-bottom: 20px;
     "mirrorsList" : {
       "type" : "string"
     },
-    "repoId" : {
-      "type" : "string"
-    },
     "latestUri" : {
       "type" : "string"
     },
     "repoName" : {
       "type" : "string"
+    },
+    "repoId" : {
+      "type" : "string"
     }
   }
 };
@@ -2346,24 +2346,24 @@ margin-bottom: 20px;
         "$ref" : "#/definitions/RepositoryVersionEntity"
       }
     },
-    "stackId" : {
-      "$ref" : "#/definitions/StackId"
-    },
-    "stackName" : {
+    "operatingSystemsJson" : {
       "type" : "string"
     },
+    "parentId" : {
+      "type" : "integer",
+      "format" : "int64"
+    },
     "stackVersion" : {
       "type" : "string"
     },
-    "operatingSystemsJson" : {
+    "stackId" : {
+      "$ref" : "#/definitions/StackId"
+    },
+    "stackName" : {
       "type" : "string"
     },
     "repositoryXml" : {
       "$ref" : "#/definitions/VersionDefinitionXml"
-    },
-    "parentId" : {
-      "type" : "integer",
-      "format" : "int64"
     }
   }
 };
@@ -2389,14 +2389,14 @@ margin-bottom: 20px;
         "$ref" : "#/definitions/RepositoryInfo"
       }
     },
+    "latestURI" : {
+      "type" : "string"
+    },
     "errors" : {
       "type" : "array",
       "items" : {
         "type" : "string"
       }
-    },
-    "latestURI" : {
-      "type" : "string"
     }
   },
   "xml" : {
@@ -2406,6 +2406,9 @@ margin-bottom: 20px;
     defs.Request = {
   "type" : "object",
   "properties" : {
+    "cluster_name" : {
+      "type" : "string"
+    },
     "exclusive" : {
       "type" : "boolean",
       "default" : false
@@ -2415,9 +2418,6 @@ margin-bottom: 20px;
       "items" : {
         "$ref" : "#/definitions/RequestResourceFilter"
       }
-    },
-    "cluster_name" : {
-      "type" : "string"
     }
   }
 };
@@ -2431,14 +2431,14 @@ margin-bottom: 20px;
         "properties" : { }
       }
     },
+    "action" : {
+      "type" : "string"
+    },
     "command" : {
       "type" : "string"
     },
     "operation_level" : {
       "$ref" : "#/definitions/OperationLevel"
-    },
-    "action" : {
-      "type" : "string"
     }
   }
 };
@@ -2495,6 +2495,9 @@ margin-bottom: 20px;
     defs.RequestResourceFilter = {
   "type" : "object",
   "properties" : {
+    "service_name" : {
+      "type" : "string"
+    },
     "component_name" : {
       "type" : "string"
     },
@@ -2503,9 +2506,6 @@ margin-bottom: 20px;
     },
     "hosts" : {
       "type" : "string"
-    },
-    "service_name" : {
-      "type" : "string"
     }
   }
 };
@@ -2526,19 +2526,18 @@ margin-bottom: 20px;
     "start_time" : {
       "type" : "string"
     },
+    "request_context" : {
+      "type" : "string"
+    },
     "request_status" : {
       "type" : "string"
     },
-    "request_context" : {
+    "cluster_name" : {
       "type" : "string"
     },
     "request_schedule" : {
       "type" : "string"
     },
-    "create_time" : {
-      "type" : "integer",
-      "format" : "int64"
-    },
     "id" : {
       "type" : "string"
     },
@@ -2546,6 +2545,10 @@ margin-bottom: 20px;
       "type" : "integer",
       "format" : "int32"
     },
+    "create_time" : {
+      "type" : "integer",
+      "format" : "int64"
+    },
     "end_time" : {
       "type" : "string"
     },
@@ -2581,9 +2584,6 @@ margin-bottom: 20px;
         "$ref" : "#/definitions/RequestResourceFilter"
       }
     },
-    "cluster_name" : {
-      "type" : "string"
-    },
     "task_count" : {
       "type" : "integer",
       "format" : "int32"
@@ -2745,9 +2745,6 @@ margin-bottom: 20px;
     defs.SecurityInfo = {
   "type" : "object",
   "properties" : {
-    "kerberos_descriptor_reference" : {
-      "type" : "string"
-    },
     "kerberos_descriptor" : {
       "type" : "object",
       "additionalProperties" : {
@@ -2758,6 +2755,9 @@ margin-bottom: 20px;
     "security_type" : {
       "type" : "string",
       "enum" : [ "NONE", "KERBEROS" ]
+    },
+    "kerberos_descriptor_reference" : {
+      "type" : "string"
     }
   }
 };
@@ -2903,7 +2903,7 @@ margin-bottom: 20px;
     },
     "repositoryVersionState" : {
       "type" : "string",
-      "enum" : [ "INIT", "NOT_REQUIRED", "INSTALLING", "INSTALLED", "INSTALL_FAILED", "OUT_OF_SYNC", "CURRENT" ]
+      "enum" : [ "NOT_REQUIRED", "INSTALLING", "INSTALLED", "INSTALL_FAILED", "OUT_OF_SYNC", "CURRENT" ]
     },
     "state" : {
       "type" : "string"
@@ -3505,24 +3505,24 @@ margin-bottom: 20px;
     defs.ThemeInfoResponse = {
   "type" : "object",
   "properties" : {
-    "file_name" : {
-      "type" : "string"
-    },
     "default" : {
       "type" : "boolean",
       "default" : false
     },
-    "stack_name" : {
+    "file_name" : {
+      "type" : "string"
+    },
+    "service_name" : {
       "type" : "string"
     },
     "stack_version" : {
       "type" : "string"
     },
+    "stack_name" : {
+      "type" : "string"
+    },
     "theme_data" : {
       "$ref" : "#/definitions/Theme"
-    },
-    "service_name" : {
-      "type" : "string"
     }
   }
 };
@@ -3641,6 +3641,12 @@ margin-bottom: 20px;
     "Users/admin" : {
       "type" : "boolean",
       "default" : false
+    },
+    "Users/display_name" : {
+      "type" : "string"
+    },
+    "Users/local_user_name" : {
+      "type" : "string"
     }
   }
 };
@@ -3648,9 +3654,9 @@ margin-bottom: 20px;
   "type" : "object",
   "required" : [ "Users/user_name" ],
   "properties" : {
-    "Users/user_type" : {
+    "Users/authentication_type" : {
       "type" : "string",
-      "enum" : [ "LOCAL", "LDAP", "JWT", "PAM" ]
+      "enum" : [ "LOCAL", "LDAP", "JWT", "PAM", "KERBEROS" ]
     },
     "Users/groups" : {
       "type" : "array",
@@ -3659,18 +3665,18 @@ margin-bottom: 20px;
         "type" : "string"
       }
     },
-    "Users/user_name" : {
-      "type" : "string"
-    },
     "Users/active" : {
       "type" : "boolean",
       "default" : false
     },
-    "Users/ldap_user" : {
+    "Users/user_name" : {
+      "type" : "string"
+    },
+    "Users/admin" : {
       "type" : "boolean",
       "default" : false
     },
-    "Users/admin" : {
+    "Users/ldap_user" : {
       "type" : "boolean",
       "default" : false
     }
@@ -4271,6 +4277,43 @@ margin-bottom: 20px;
                     <li data-group="Blueprints" data-name="blueprintServiceGetBlueprints" class="">
                       <a href="#api-Blueprints-blueprintServiceGetBlueprints">blueprintServiceGetBlueprints</a>
                     </li>
+                  <li class="nav-header" data-group="ClusterServices"><a href="#api-ClusterServices">API Methods - ClusterServices</a></li>
+                    <li data-group="ClusterServices" data-name="serviceServiceCreateArtifact" class="">
+                      <a href="#api-ClusterServices-serviceServiceCreateArtifact">serviceServiceCreateArtifact</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceCreateServices" class="">
+                      <a href="#api-ClusterServices-serviceServiceCreateServices">serviceServiceCreateServices</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceDeleteArtifact" class="">
+                      <a href="#api-ClusterServices-serviceServiceDeleteArtifact">serviceServiceDeleteArtifact</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceDeleteArtifacts" class="">
+                      <a href="#api-ClusterServices-serviceServiceDeleteArtifacts">serviceServiceDeleteArtifacts</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceDeleteService" class="">
+                      <a href="#api-ClusterServices-serviceServiceDeleteService">serviceServiceDeleteService</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceGetArtifact" class="">
+                      <a href="#api-ClusterServices-serviceServiceGetArtifact">serviceServiceGetArtifact</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceGetArtifacts" class="">
+                      <a href="#api-ClusterServices-serviceServiceGetArtifacts">serviceServiceGetArtifacts</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceGetService" class="">
+                      <a href="#api-ClusterServices-serviceServiceGetService">serviceServiceGetService</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceGetServices" class="">
+                      <a href="#api-ClusterServices-serviceServiceGetServices">serviceServiceGetServices</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceUpdateArtifact" class="">
+                      <a href="#api-ClusterServices-serviceServiceUpdateArtifact">serviceServiceUpdateArtifact</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceUpdateArtifacts" class="">
+                      <a href="#api-ClusterServices-serviceServiceUpdateArtifacts">serviceServiceUpdateArtifacts</a>
+                    </li>
+                    <li data-group="ClusterServices" data-name="serviceServiceUpdateService" class="">
+                      <a href="#api-ClusterServices-serviceServiceUpdateService">serviceServiceUpdateService</a>
+                    </li>
                   <li class="nav-header" data-group="Clusters"><a href="#api-Clusters">API Methods - Clusters</a></li>
                     <li data-group="Clusters" data-name="createCluster" class="">
                       <a href="#api-Clusters-createCluster">createCluster</a>
@@ -4405,39 +4448,6 @@ margin-bottom: 20px;
                     <li data-group="Services" data-name="getRootServices" class="">
                       <a href="#api-Services-getRootServices">getRootServices</a>
                     </li>
-                    <li data-group="Services" data-name="serviceServiceCreateArtifact" class="">
-                      <a href="#api-Services-serviceServiceCreateArtifact">serviceServiceCreateArtifact</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceCreateServices" class="">
-                      <a href="#api-Services-serviceServiceCreateServices">serviceServiceCreateServices</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceDeleteArtifact" class="">
-                      <a href="#api-Services-serviceServiceDeleteArtifact">serviceServiceDeleteArtifact</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceDeleteArtifacts" class="">
-                      <a href="#api-Services-serviceServiceDeleteArtifacts">serviceServiceDeleteArtifacts</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceDeleteService" class="">
-                      <a href="#api-Services-serviceServiceDeleteService">serviceServiceDeleteService</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceGetArtifact" class="">
-                      <a href="#api-Services-serviceServiceGetArtifact">serviceServiceGetArtifact</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceGetArtifacts" class="">
-                      <a href="#api-Services-serviceServiceGetArtifacts">serviceServiceGetArtifacts</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceGetService" class="">
-                      <a href="#api-Services-serviceServiceGetService">serviceServiceGetService</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceUpdateArtifact" class="">
-                      <a href="#api-Services-serviceServiceUpdateArtifact">serviceServiceUpdateArtifact</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceUpdateArtifacts" class="">
-                      <a href="#api-Services-serviceServiceUpdateArtifacts">serviceServiceUpdateArtifacts</a>
-                    </li>
-                    <li data-group="Services" data-name="serviceServiceUpdateService" class="">
-                      <a href="#api-Services-serviceServiceUpdateService">serviceServiceUpdateService</a>
-                    </li>
                   <li class="nav-header" data-group="Settings"><a href="#api-Settings">API Methods - Settings</a></li>
                     <li data-group="Settings" data-name="createSetting" class="">
                       <a href="#api-Settings-createSetting">createSetting</a>
@@ -8234,13 +8244,13 @@ except ApiException as e:
                       </div>
                       <hr>
                   </section>
-                <section id="api-Clusters">
-                  <h1>Clusters</h1>
-                    <div id="api-Clusters-createCluster">
-                      <article id="api-Clusters-createCluster-0" data-group="User" data-name="createCluster" data-version="0">
+                <section id="api-ClusterServices">
+                  <h1>ClusterServices</h1>
+                    <div id="api-ClusterServices-serviceServiceCreateArtifact">
+                      <article id="api-ClusterServices-serviceServiceCreateArtifact-0" data-group="User" data-name="serviceServiceCreateArtifact" data-version="0">
                         <div class="pull-left">
-                          <h1>createCluster</h1>
-                          <p>Creates a cluster</p>
+                          <h1>serviceServiceCreateArtifact</h1>
+                          <p>Creates a service artifact</p>
                         </div>
                         <div class="pull-right"></div>
                         <div class="clearfix"></div>
@@ -8248,84 +8258,92 @@ except ApiException as e:
                         <p class="marked"></p>
                         <p></p>
                         <br />
-                        <pre class="prettyprint language-html prettyprinted" data-type="post"><code><span class="pln">/clusters/{clusterName}</span></code></pre>
+                        <pre class="prettyprint language-html prettyprinted" data-type="post"><code><span class="pln">/clusters/{clusterName}/services/{serviceName}/artifacts/{artifactName}</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-Clusters-createCluster-0-curl">Curl</a></li>
-                          <li class=""><a href="#examples-Clusters-createCluster-0-java">Java</a></li>
-                          <li class=""><a href="#examples-Clusters-createCluster-0-android">Android</a></li>
-                          <!--<li class=""><a href="#examples-Clusters-createCluster-0-groovy">Groovy</a></li>-->
-                          <li class=""><a href="#examples-Clusters-createCluster-0-objc">Obj-C</a></li>
-                          <li class=""><a href="#examples-Clusters-createCluster-0-javascript">JavaScript</a></li>
-                          <!--<li class=""><a href="#examples-Clusters-createCluster-0-angular">Angular</a></li>-->
-                          <li class=""><a href="#examples-Clusters-createCluster-0-csharp">C#</a></li>
-                          <li class=""><a href="#examples-Clusters-createCluster-0-php">PHP</a></li>
-                          <li class=""><a href="#examples-Clusters-createCluster-0-perl">Perl</a></li>
-                          <li class=""><a href="#examples-Clusters-createCluster-0-python">Python</a></li>
+                          <li class="active"><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-curl">Curl</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-java">Java</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-android">Android</a></li>
+                          <!--<li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-groovy">Groovy</a></li>-->
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-objc">Obj-C</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-javascript">JavaScript</a></li>
+                          <!--<li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-angular">Angular</a></li>-->
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-csharp">C#</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-php">PHP</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-perl">Perl</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateArtifact-0-python">Python</a></li>
                         </ul>
 
                         <div class="tab-content">
-                          <div class="tab-pane active" id="examples-Clusters-createCluster-0-curl">
-                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">post</span> "http://localhost/api/v1/clusters/{clusterName}"</code></pre>
+                          <div class="tab-pane active" id="examples-ClusterServices-serviceServiceCreateArtifact-0-curl">
+                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">post</span> "http://localhost/api/v1/clusters/{clusterName}/services/{serviceName}/artifacts/{artifactName}"</code></pre>
                           </div>
-                          <div class="tab-pane" id="examples-Clusters-createCluster-0-java">
+                          <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-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.ClustersApi;
+import io.swagger.client.api.ClusterServicesApi;
 
 import java.io.File;
 import java.util.*;
 
-public class ClustersApiExample {
+public class ClusterServicesApiExample {
 
     public static void main(String[] args) {
         
-        ClustersApi apiInstance = new ClustersApi();
+        ClusterServicesApi apiInstance = new ClusterServicesApi();
+        String serviceName = serviceName_example; // String | 
+        String artifactName = artifactName_example; // String | 
         String clusterName = clusterName_example; // String | 
-        ClusterRequestSwagger body = ; // ClusterRequestSwagger | 
+        ClusterServiceArtifactRequest body = ; // ClusterServiceArtifactRequest | 
         try {
-            apiInstance.createCluster(clusterName, body);
+            apiInstance.serviceServiceCreateArtifact(serviceName, artifactName, clusterName, body);
         } catch (ApiException e) {
-            System.err.println("Exception when calling ClustersApi#createCluster");
+            System.err.println("Exception when calling ClusterServicesApi#serviceServiceCreateArtifact");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
 
-                          <div class="tab-pane" id="examples-Clusters-createCluster-0-android">
-                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.ClustersApi;
+                          <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-android">
+                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.ClusterServicesApi;
 
-public class ClustersApiExample {
+public class ClusterServicesApiExample {
 
     public static void main(String[] args) {
-        ClustersApi apiInstance = new ClustersApi();
+        ClusterServicesApi apiInstance = new ClusterServicesApi();
+        String serviceName = serviceName_example; // String | 
+        String artifactName = artifactName_example; // String | 
         String clusterName = clusterName_example; // String | 
-        ClusterRequestSwagger body = ; // ClusterRequestSwagger | 
+        ClusterServiceArtifactRequest body = ; // ClusterServiceArtifactRequest | 
         try {
-            apiInstance.createCluster(clusterName, body);
+            apiInstance.serviceServiceCreateArtifact(serviceName, artifactName, clusterName, body);
         } catch (ApiException e) {
-            System.err.println("Exception when calling ClustersApi#createCluster");
+            System.err.println("Exception when calling ClusterServicesApi#serviceServiceCreateArtifact");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
   <!--
-  <div class="tab-pane" id="examples-Clusters-createCluster-0-groovy">
+  <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-groovy">
   <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
   </div> -->
-                            <div class="tab-pane" id="examples-Clusters-createCluster-0-objc">
-                              <pre class="prettyprint"><code class="language-cpp">String *clusterName = clusterName_example; // 
-ClusterRequestSwagger *body = ; //  (optional)
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-objc">
+                              <pre class="prettyprint"><code class="language-cpp">String *serviceName = serviceName_example; // 
+String *artifactName = artifactName_example; // 
+String *clusterName = clusterName_example; // 
+ClusterServiceArtifactRequest *body = ; //  (optional)
 
-ClustersApi *apiInstance = [[ClustersApi alloc] init];
+ClusterServicesApi *apiInstance = [[ClusterServicesApi alloc] init];
 
-// Creates a cluster
-[apiInstance createClusterWith:clusterName
+// Creates a service artifact
+[apiInstance serviceServiceCreateArtifactWith:serviceName
+    artifactName:artifactName
+    clusterName:clusterName
     body:body
               completionHandler: ^(NSError* error) {
                             if (error) {
@@ -8335,15 +8353,19 @@ ClustersApi *apiInstance = [[ClustersApi alloc] init];
 </code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-createCluster-0-javascript">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-javascript">
                               <pre class="prettyprint"><code class="language-js">var SwaggerSpecForAmbariRestApi = require('swagger_spec_for_ambari_rest_api');
 
-var api = new SwaggerSpecForAmbariRestApi.ClustersApi()
+var api = new SwaggerSpecForAmbariRestApi.ClusterServicesApi()
+
+var serviceName = serviceName_example; // {String} 
+
+var artifactName = artifactName_example; // {String} 
 
 var clusterName = clusterName_example; // {String} 
 
 var opts = { 
-  'body':  // {ClusterRequestSwagger} 
+  'body':  // {ClusterServiceArtifactRequest} 
 };
 
 var callback = function(error, data, response) {
@@ -8353,14 +8375,14 @@ var callback = function(error, data, response) {
     console.log('API called successfully.');
   }
 };
-api.createCluster(clusterName, opts, callback);
+api.serviceServiceCreateArtifact(serviceName, artifactName, clusterName, opts, callback);
 </code></pre>
                             </div>
 
-                            <!--<div class="tab-pane" id="examples-Clusters-createCluster-0-angular">
+                            <!--<div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-angular">
               <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
             </div>-->
-                            <div class="tab-pane" id="examples-Clusters-createCluster-0-csharp">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-csharp">
                               <pre class="prettyprint"><code class="language-cs">using System;
 using System.Diagnostics;
 using IO.Swagger.Api;
@@ -8369,63 +8391,69 @@ using IO.Swagger.Model;
 
 namespace Example
 {
-    public class createClusterExample
+    public class serviceServiceCreateArtifactExample
     {
         public void main()
         {
             
-            var apiInstance = new ClustersApi();
+            var apiInstance = new ClusterServicesApi();
+            var serviceName = serviceName_example;  // String | 
+            var artifactName = artifactName_example;  // String | 
             var clusterName = clusterName_example;  // String | 
-            var body = new ClusterRequestSwagger(); // ClusterRequestSwagger |  (optional) 
+            var body = new ClusterServiceArtifactRequest(); // ClusterServiceArtifactRequest |  (optional) 
 
             try
             {
-                // Creates a cluster
-                apiInstance.createCluster(clusterName, body);
+                // Creates a service artifact
+                apiInstance.serviceServiceCreateArtifact(serviceName, artifactName, clusterName, body);
             }
             catch (Exception e)
             {
-                Debug.Print("Exception when calling ClustersApi.createCluster: " + e.Message );
+                Debug.Print("Exception when calling ClusterServicesApi.serviceServiceCreateArtifact: " + e.Message );
             }
         }
     }
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-createCluster-0-php">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-php">
                               <pre class="prettyprint"><code class="language-php"><&#63;php
 require_once(__DIR__ . '/vendor/autoload.php');
 
-$api_instance = new Swagger\Client\Api\ClustersApi();
+$api_instance = new Swagger\Client\Api\ClusterServicesApi();
+$serviceName = serviceName_example; // String | 
+$artifactName = artifactName_example; // String | 
 $clusterName = clusterName_example; // String | 
-$body = ; // ClusterRequestSwagger | 
+$body = ; // ClusterServiceArtifactRequest | 
 
 try {
-    $api_instance->createCluster($clusterName, $body);
+    $api_instance->serviceServiceCreateArtifact($serviceName, $artifactName, $clusterName, $body);
 } catch (Exception $e) {
-    echo 'Exception when calling ClustersApi->createCluster: ', $e->getMessage(), PHP_EOL;
+    echo 'Exception when calling ClusterServicesApi->serviceServiceCreateArtifact: ', $e->getMessage(), PHP_EOL;
 }
 ?></code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-createCluster-0-perl">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-perl">
                               <pre class="prettyprint"><code class="language-perl">use Data::Dumper;
 use WWW::SwaggerClient::Configuration;
-use WWW::SwaggerClient::ClustersApi;
+use WWW::SwaggerClient::ClusterServicesApi;
 
-my $api_instance = WWW::SwaggerClient::ClustersApi->new();
+my $api_instance = WWW::SwaggerClient::ClusterServicesApi->new();
+my $serviceName = serviceName_example; # String | 
+my $artifactName = artifactName_example; # String | 
 my $clusterName = clusterName_example; # String | 
-my $body = WWW::SwaggerClient::Object::ClusterRequestSwagger->new(); # ClusterRequestSwagger | 
+my $body = WWW::SwaggerClient::Object::ClusterServiceArtifactRequest->new(); # ClusterServiceArtifactRequest | 
 
 eval { 
-    $api_instance->createCluster(clusterName => $clusterName, body => $body);
+    $api_instance->serviceServiceCreateArtifact(serviceName => $serviceName, artifactName => $artifactName, clusterName => $clusterName, body => $body);
 };
 if ($@) {
-    warn "Exception when calling ClustersApi->createCluster: $@\n";
+    warn "Exception when calling ClusterServicesApi->serviceServiceCreateArtifact: $@\n";
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-createCluster-0-python">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateArtifact-0-python">
                               <pre class="prettyprint"><code class="language-python">from __future__ import print_statement
 import time
 import swagger_client
@@ -8433,15 +8461,17 @@ from swagger_client.rest import ApiException
 from pprint import pprint
 
 # create an instance of the API class
-api_instance = swagger_client.ClustersApi()
+api_instance = swagger_client.ClusterServicesApi()
+serviceName = serviceName_example # String | 
+artifactName = artifactName_example # String | 
 clusterName = clusterName_example # String | 
-body =  # ClusterRequestSwagger |  (optional)
+body =  # ClusterServiceArtifactRequest |  (optional)
 
 try: 
-    # Creates a cluster
-    api_instance.createCluster(clusterName, body=body)
+    # Creates a service artifact
+    api_instance.serviceServiceCreateArtifact(serviceName, artifactName, clusterName, body=body)
 except ApiException as e:
-    print("Exception when calling ClustersApi->createCluster: %s\n" % e)</code></pre>
+    print("Exception when calling ClusterServicesApi->serviceServiceCreateArtifact: %s\n" % e)</code></pre>
                             </div>
                           </div>
 
@@ -8453,6 +8483,70 @@ except ApiException as e:
                                   <th width="150px">Name</th>
                                   <th>Description</th>
                                 </tr>
+                                  <tr><td style="width:150px;">serviceName*</td>
+<td>
+
+
+<script>
+												$(document).ready(function() {
+													var schemaWrapper = {
+  "name" : "serviceName",
+  "in" : "path",
+  "required" : true,
+  "type" : "string"
+};
+													var schema = schemaWrapper;
+
+
+
+
+													var view = new JSONSchemaView(schema,1);
+													var result = $('#d2e199_serviceServiceCreateArtifact_serviceName');
+													result.empty();
+													result.append(view.render());
+
+
+
+
+
+												});
+												</script>
+												<div id="d2e199_serviceServiceCreateArtifact_serviceName"></div>
+</td>
+</tr>
+
+                                  <tr><td style="width:150px;">artifactName*</td>
+<td>
+
+
+<script>
+												$(document).ready(function() {
+													var schemaWrapper = {
+  "name" : "artifactName",
+  "in" : "path",
+  "required" : true,
+  "type" : "string"
+};
+													var schema = schemaWrapper;
+
+
+
+
+													var view = new JSONSchemaView(schema,1);
+													var result = $('#d2e199_serviceServiceCreateArtifact_artifactName');
+													result.empty();
+													result.append(view.render());
+
+
+
+
+
+												});
+												</script>
+												<div id="d2e199_serviceServiceCreateArtifact_artifactName"></div>
+</td>
+</tr>
+
                                   <tr><td style="width:150px;">clusterName*</td>
 <td>
 
@@ -8471,7 +8565,7 @@ except ApiException as e:
 
 
 													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_createCluster_clusterName');
+													var result = $('#d2e199_serviceServiceCreateArtifact_clusterName');
 													result.empty();
 													result.append(view.render());
 
@@ -8481,7 +8575,7 @@ except ApiException as e:
 
 												});
 												</script>
-												<div id="d2e199_createCluster_clusterName"></div>
+												<div id="d2e199_serviceServiceCreateArtifact_clusterName"></div>
 </td>
 </tr>
 
@@ -8505,7 +8599,7 @@ except ApiException as e:
   "name" : "body",
   "required" : false,
   "schema" : {
-    "$ref" : "#/definitions/ClusterRequestSwagger"
+    "$ref" : "#/definitions/ClusterServiceArtifactRequest"
   }
 };
 													
@@ -8517,7 +8611,7 @@ except ApiException as e:
 														
 													var view = new JSONSchemaView(resolved.schema,2,{isBodyParam: true});
 													 
-													var result = $('#d2e199_createCluster_body');
+													var result = $('#d2e199_serviceServiceCreateArtifact_body');
 													result.empty();
 													result.append(view.render());
 													
@@ -8533,7 +8627,7 @@ except ApiException as e:
 
 												});
 												</script>
-												<div id="d2e199_createCluster_body"></div>
+												<div id="d2e199_serviceServiceCreateArtifact_body"></div>
 </td>
 </tr>
 
@@ -8582,6 +8676,14 @@ except ApiException as e:
                             <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>
 
                             <ul class="nav nav-tabs nav-tabs-examples" >
@@ -8601,11 +8703,11 @@ except ApiException as e:
                         </article>
                       </div>
                       <hr>
-                    <div id="api-Clusters-createClusterArtifact">
-                      <article id="api-Clusters-createClusterArtifact-0" data-group="User" data-name="createClusterArtifact" data-version="0">
+                    <div id="api-ClusterServices-serviceServiceCreateServices">
+                      <article id="api-ClusterServices-serviceServiceCreateServices-0" data-group="User" data-name="serviceServiceCreateServices" data-version="0">
                         <div class="pull-left">
-                          <h1>createClusterArtifact</h1>
-                          <p>Creates a cluster artifact</p>
+                          <h1>serviceServiceCreateServices</h1>
+                          <p>Creates a service</p>
                         </div>
                         <div class="pull-right"></div>
                         <div class="clearfix"></div>
@@ -8613,88 +8715,88 @@ except ApiException as e:
                         <p class="marked"></p>
                         <p></p>
                         <br />
-                        <pre class="prettyprint language-html prettyprinted" data-type="post"><code><span class="pln">/clusters/{clusterName}/artifacts/{artifactName}</span></code></pre>
+                        <pre class="prettyprint language-html prettyprinted" data-type="post"><code><span class="pln">/clusters/{clusterName}/services/{serviceName}</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-Clusters-createClusterArtifact-0-curl">Curl</a></li>
-                          <li class=""><a href="#examples-Clusters-createClusterArtifact-0-java">Java</a></li>
-                          <li class=""><a href="#examples-Clusters-createClusterArtifact-0-android">Android</a></li>
-                          <!--<li class=""><a href="#examples-Clusters-createClusterArtifact-0-groovy">Groovy</a></li>-->
-                          <li class=""><a href="#examples-Clusters-createClusterArtifact-0-objc">Obj-C</a></li>
-                          <li class=""><a href="#examples-Clusters-createClusterArtifact-0-javascript">JavaScript</a></li>
-                          <!--<li class=""><a href="#examples-Clusters-createClusterArtifact-0-angular">Angular</a></li>-->
-                          <li class=""><a href="#examples-Clusters-createClusterArtifact-0-csharp">C#</a></li>
-                          <li class=""><a href="#examples-Clusters-createClusterArtifact-0-php">PHP</a></li>
-                          <li class=""><a href="#examples-Clusters-createClusterArtifact-0-perl">Perl</a></li>
-                          <li class=""><a href="#examples-Clusters-createClusterArtifact-0-python">Python</a></li>
+                          <li class="active"><a href="#examples-ClusterServices-serviceServiceCreateServices-0-curl">Curl</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-java">Java</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-android">Android</a></li>
+                          <!--<li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-groovy">Groovy</a></li>-->
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-objc">Obj-C</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-javascript">JavaScript</a></li>
+                          <!--<li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-angular">Angular</a></li>-->
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-csharp">C#</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-php">PHP</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-perl">Perl</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceCreateServices-0-python">Python</a></li>
                         </ul>
 
                         <div class="tab-content">
-                          <div class="tab-pane active" id="examples-Clusters-createClusterArtifact-0-curl">
-                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">post</span> "http://localhost/api/v1/clusters/{clusterName}/artifacts/{artifactName}"</code></pre>
+                          <div class="tab-pane active" id="examples-ClusterServices-serviceServiceCreateServices-0-curl">
+                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">post</span> "http://localhost/api/v1/clusters/{clusterName}/services/{serviceName}"</code></pre>
                           </div>
-                          <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-java">
+                          <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-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.ClustersApi;
+import io.swagger.client.api.ClusterServicesApi;
 
 import java.io.File;
 import java.util.*;
 
-public class ClustersApiExample {
+public class ClusterServicesApiExample {
 
     public static void main(String[] args) {
         
-        ClustersApi apiInstance = new ClustersApi();
+        ClusterServicesApi apiInstance = new ClusterServicesApi();
+        String serviceName = serviceName_example; // String | 
         String clusterName = clusterName_example; // String | 
-        String artifactName = artifactName_example; // String | 
-        ClusterArtifactRequest body = ; // ClusterArtifactRequest | 
+        ServiceRequestSwagger body = ; // ServiceRequestSwagger | 
         try {
-            apiInstance.createClusterArtifact(clusterName, artifactName, body);
+            apiInstance.serviceServiceCreateServices(serviceName, clusterName, body);
         } catch (ApiException e) {
-            System.err.println("Exception when calling ClustersApi#createClusterArtifact");
+            System.err.println("Exception when calling ClusterServicesApi#serviceServiceCreateServices");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
 
-                          <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-android">
-                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.ClustersApi;
+                          <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-android">
+                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.ClusterServicesApi;
 
-public class ClustersApiExample {
+public class ClusterServicesApiExample {
 
     public static void main(String[] args) {
-        ClustersApi apiInstance = new ClustersApi();
+        ClusterServicesApi apiInstance = new ClusterServicesApi();
+        String serviceName = serviceName_example; // String | 
         String clusterName = clusterName_example; // String | 
-        String artifactName = artifactName_example; // String | 
-        ClusterArtifactRequest body = ; // ClusterArtifactRequest | 
+        ServiceRequestSwagger body = ; // ServiceRequestSwagger | 
         try {
-            apiInstance.createClusterArtifact(clusterName, artifactName, body);
+            apiInstance.serviceServiceCreateServices(serviceName, clusterName, body);
         } catch (ApiException e) {
-            System.err.println("Exception when calling ClustersApi#createClusterArtifact");
+            System.err.println("Exception when calling ClusterServicesApi#serviceServiceCreateServices");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
   <!--
-  <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-groovy">
+  <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-groovy">
   <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
   </div> -->
-                            <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-objc">
-                              <pre class="prettyprint"><code class="language-cpp">String *clusterName = clusterName_example; // 
-String *artifactName = artifactName_example; // 
-ClusterArtifactRequest *body = ; //  (optional)
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-objc">
+                              <pre class="prettyprint"><code class="language-cpp">String *serviceName = serviceName_example; // 
+String *clusterName = clusterName_example; // 
+ServiceRequestSwagger *body = ; //  (optional)
 
-ClustersApi *apiInstance = [[ClustersApi alloc] init];
+ClusterServicesApi *apiInstance = [[ClusterServicesApi alloc] init];
 
-// Creates a cluster artifact
-[apiInstance createClusterArtifactWith:clusterName
-    artifactName:artifactName
+// Creates a service
+[apiInstance serviceServiceCreateServicesWith:serviceName
+    clusterName:clusterName
     body:body
               completionHandler: ^(NSError* error) {
                             if (error) {
@@ -8704,17 +8806,17 @@ ClustersApi *apiInstance = [[ClustersApi alloc] init];
 </code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-javascript">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-javascript">
                               <pre class="prettyprint"><code class="language-js">var SwaggerSpecForAmbariRestApi = require('swagger_spec_for_ambari_rest_api');
 
-var api = new SwaggerSpecForAmbariRestApi.ClustersApi()
+var api = new SwaggerSpecForAmbariRestApi.ClusterServicesApi()
 
-var clusterName = clusterName_example; // {String} 
+var serviceName = serviceName_example; // {String} 
 
-var artifactName = artifactName_example; // {String} 
+var clusterName = clusterName_example; // {String} 
 
 var opts = { 
-  'body':  // {ClusterArtifactRequest} 
+  'body':  // {ServiceRequestSwagger} 
 };
 
 var callback = function(error, data, response) {
@@ -8724,14 +8826,14 @@ var callback = function(error, data, response) {
     console.log('API called successfully.');
   }
 };
-api.createClusterArtifact(clusterName, artifactName, opts, callback);
+api.serviceServiceCreateServices(serviceName, clusterName, opts, callback);
 </code></pre>
                             </div>
 
-                            <!--<div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-angular">
+                            <!--<div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-angular">
               <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
             </div>-->
-                            <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-csharp">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-csharp">
                               <pre class="prettyprint"><code class="language-cs">using System;
 using System.Diagnostics;
 using IO.Swagger.Api;
@@ -8740,66 +8842,66 @@ using IO.Swagger.Model;
 
 namespace Example
 {
-    public class createClusterArtifactExample
+    public class serviceServiceCreateServicesExample
     {
         public void main()
         {
             
-            var apiInstance = new ClustersApi();
+            var apiInstance = new ClusterServicesApi();
+            var serviceName = serviceName_example;  // String | 
             var clusterName = clusterName_example;  // String | 
-            var artifactName = artifactName_example;  // String | 
-            var body = new ClusterArtifactRequest(); // ClusterArtifactRequest |  (optional) 
+            var body = new ServiceRequestSwagger(); // ServiceRequestSwagger |  (optional) 
 
             try
             {
-                // Creates a cluster artifact
-                apiInstance.createClusterArtifact(clusterName, artifactName, body);
+                // Creates a service
+                apiInstance.serviceServiceCreateServices(serviceName, clusterName, body);
             }
             catch (Exception e)
             {
-                Debug.Print("Exception when calling ClustersApi.createClusterArtifact: " + e.Message );
+                Debug.Print("Exception when calling ClusterServicesApi.serviceServiceCreateServices: " + e.Message );
             }
         }
     }
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-php">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-php">
                               <pre class="prettyprint"><code class="language-php"><&#63;php
 require_once(__DIR__ . '/vendor/autoload.php');
 
-$api_instance = new Swagger\Client\Api\ClustersApi();
+$api_instance = new Swagger\Client\Api\ClusterServicesApi();
+$serviceName = serviceName_example; // String | 
 $clusterName = clusterName_example; // String | 
-$artifactName = artifactName_example; // String | 
-$body = ; // ClusterArtifactRequest | 
+$body = ; // ServiceRequestSwagger | 
 
 try {
-    $api_instance->createClusterArtifact($clusterName, $artifactName, $body);
+    $api_instance->serviceServiceCreateServices($serviceName, $clusterName, $body);
 } catch (Exception $e) {
-    echo 'Exception when calling ClustersApi->createClusterArtifact: ', $e->getMessage(), PHP_EOL;
+    echo 'Exception when calling ClusterServicesApi->serviceServiceCreateServices: ', $e->getMessage(), PHP_EOL;
 }
 ?></code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-perl">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-perl">
                               <pre class="prettyprint"><code class="language-perl">use Data::Dumper;
 use WWW::SwaggerClient::Configuration;
-use WWW::SwaggerClient::ClustersApi;
+use WWW::SwaggerClient::ClusterServicesApi;
 
-my $api_instance = WWW::SwaggerClient::ClustersApi->new();
+my $api_instance = WWW::SwaggerClient::ClusterServicesApi->new();
+my $serviceName = serviceName_example; # String | 
 my $clusterName = clusterName_example; # String | 
-my $artifactName = artifactName_example; # String | 
-my $body = WWW::SwaggerClient::Object::ClusterArtifactRequest->new(); # ClusterArtifactRequest | 
+my $body = WWW::SwaggerClient::Object::ServiceRequestSwagger->new(); # ServiceRequestSwagger | 
 
 eval { 
-    $api_instance->createClusterArtifact(clusterName => $clusterName, artifactName => $artifactName, body => $body);
+    $api_instance->serviceServiceCreateServices(serviceName => $serviceName, clusterName => $clusterName, body => $body);
 };
 if ($@) {
-    warn "Exception when calling ClustersApi->createClusterArtifact: $@\n";
+    warn "Exception when calling ClusterServicesApi->serviceServiceCreateServices: $@\n";
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-createClusterArtifact-0-python">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceCreateServices-0-python">
                               <pre class="prettyprint"><code class="language-python">from __future__ import print_statement
 import time
 import swagger_client
@@ -8807,16 +8909,16 @@ from swagger_client.rest import ApiException
 from pprint import pprint
 
 # create an instance of the API class
-api_instance = swagger_client.ClustersApi()
+api_instance = swagger_client.ClusterServicesApi()
+serviceName = serviceName_example # String | 
 clusterName = clusterName_example # String | 
-artifactName = artifactName_example # String | 
-body =  # ClusterArtifactRequest |  (optional)
+body =  # ServiceRequestSwagger |  (optional)
 
 try: 
-    # Creates a cluster artifact
-    api_instance.createClusterArtifact(clusterName, artifactName, body=body)
+    # Creates a service
+    api_instance.serviceServiceCreateServices(serviceName, clusterName, body=body)
 except ApiException as e:
-    print("Exception when calling ClustersApi->createClusterArtifact: %s\n" % e)</code></pre>
+    print("Exception when calling ClusterServicesApi->serviceServiceCreateServices: %s\n" % e)</code></pre>
                             </div>
                           </div>
 
@@ -8828,14 +8930,14 @@ except ApiException as e:
                                   <th width="150px">Name</th>
                                   <th>Description</th>
                                 </tr>
-                                  <tr><td style="width:150px;">clusterName*</td>
+                                  <tr><td style="width:150px;">serviceName*</td>
 <td>
 
 
 <script>
 												$(document).ready(function() {
 													var schemaWrapper = {
-  "name" : "clusterName",
+  "name" : "serviceName",
   "in" : "path",
   "required" : true,
   "type" : "string"
@@ -8846,7 +8948,7 @@ except ApiException as e:
 
 
 													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_createClusterArtifact_clusterName');
+													var result = $('#d2e199_serviceServiceCreateServices_serviceName');
 													result.empty();
 													result.append(view.render());
 
@@ -8856,18 +8958,18 @@ except ApiException as e:
 
 												});
 												</script>
-												<div id="d2e199_createClusterArtifact_clusterName"></div>
+												<div id="d2e199_serviceServiceCreateServices_serviceName"></div>
 </td>
 </tr>
 
-                                  <tr><td style="width:150px;">artifactName*</td>
+                                  <tr><td style="width:150px;">clusterName*</td>
 <td>
 
 
 <script>
 												$(document).ready(function() {
 													var schemaWrapper = {
-  "name" : "artifactName",
+  "name" : "clusterName",
   "in" : "path",
   "required" : true,
   "type" : "string"
@@ -8878,7 +8980,7 @@ except ApiException as e:
 
 
 													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_createClusterArtifact_artifactName');
+													var result = $('#d2e199_serviceServiceCreateServices_clusterName');
 													result.empty();
 													result.append(view.render());
 
@@ -8888,7 +8990,7 @@ except ApiException as e:
 
 												});
 												</script>
-												<div id="d2e199_createClusterArtifact_artifactName"></div>
+												<div id="d2e199_serviceServiceCreateServices_clusterName"></div>
 </td>
 </tr>
 
@@ -8912,7 +9014,7 @@ except ApiException as e:
   "name" : "body",
   "required" : false,
   "schema" : {
-    "$ref" : "#/definitions/ClusterArtifactRequest"
+    "$ref" : "#/definitions/ServiceRequestSwagger"
   }
 };
 													
@@ -8924,7 +9026,7 @@ except ApiException as e:
 														
 													var view = new JSONSchemaView(resolved.schema,2,{isBodyParam: true});
 													 
-													var result = $('#d2e199_createClusterArtifact_body');
+													var result = $('#d2e199_serviceServiceCreateServices_body');
 													result.empty();
 													result.append(view.render());
 													
@@ -8940,7 +9042,7 @@ except ApiException as e:
 
 												});
 												</script>
-												<div id="d2e199_createClusterArtifact_body"></div>
+												<div id="d2e199_serviceServiceCreateServices_body"></div>
 </td>
 </tr>
 
@@ -9016,11 +9118,11 @@ except ApiException as e:
                         </article>
                       </div>
                       <hr>
-                    <div id="api-Clusters-deleteCluster">
-                      <article id="api-Clusters-deleteCluster-0" data-group="User" data-name="deleteCluster" data-version="0">
+                    <div id="api-ClusterServices-serviceServiceDeleteArtifact">
+                      <article id="api-ClusterServices-serviceServiceDeleteArtifact-0" data-group="User" data-name="serviceServiceDeleteArtifact" data-version="0">
                         <div class="pull-left">
-                          <h1>deleteCluster</h1>
-                          <p>Deletes a cluster</p>
+                          <h1>serviceServiceDeleteArtifact</h1>
+                          <p>Deletes a single service artifact</p>
                         </div>
                         <div class="pull-right"></div>
                         <div class="clearfix"></div>
@@ -9028,81 +9130,89 @@ except ApiException as e:
                         <p class="marked"></p>
                         <p></p>
                         <br />
-                        <pre class="prettyprint language-html prettyprinted" data-type="delete"><code><span class="pln">/clusters/{clusterName}</span></code></pre>
+                        <pre class="prettyprint language-html prettyprinted" data-type="delete"><code><span class="pln">/clusters/{clusterName}/services/{serviceName}/artifacts/{artifactName}</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-Clusters-deleteCluster-0-curl">Curl</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteCluster-0-java">Java</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteCluster-0-android">Android</a></li>
-                          <!--<li class=""><a href="#examples-Clusters-deleteCluster-0-groovy">Groovy</a></li>-->
-                          <li class=""><a href="#examples-Clusters-deleteCluster-0-objc">Obj-C</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteCluster-0-javascript">JavaScript</a></li>
-                          <!--<li class=""><a href="#examples-Clusters-deleteCluster-0-angular">Angular</a></li>-->
-                          <li class=""><a href="#examples-Clusters-deleteCluster-0-csharp">C#</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteCluster-0-php">PHP</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteCluster-0-perl">Perl</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteCluster-0-python">Python</a></li>
+                          <li class="active"><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-curl">Curl</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-java">Java</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-android">Android</a></li>
+                          <!--<li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-groovy">Groovy</a></li>-->
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-objc">Obj-C</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-javascript">JavaScript</a></li>
+                          <!--<li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-angular">Angular</a></li>-->
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-csharp">C#</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-php">PHP</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-perl">Perl</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifact-0-python">Python</a></li>
                         </ul>
 
                         <div class="tab-content">
-                          <div class="tab-pane active" id="examples-Clusters-deleteCluster-0-curl">
-                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">delete</span> "http://localhost/api/v1/clusters/{clusterName}"</code></pre>
+                          <div class="tab-pane active" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-curl">
+                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">delete</span> "http://localhost/api/v1/clusters/{clusterName}/services/{serviceName}/artifacts/{artifactName}"</code></pre>
                           </div>
-                          <div class="tab-pane" id="examples-Clusters-deleteCluster-0-java">
+                          <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-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.ClustersApi;
+import io.swagger.client.api.ClusterServicesApi;
 
 import java.io.File;
 import java.util.*;
 
-public class ClustersApiExample {
+public class ClusterServicesApiExample {
 
     public static void main(String[] args) {
         
-        ClustersApi apiInstance = new ClustersApi();
+        ClusterServicesApi apiInstance = new ClusterServicesApi();
+        String serviceName = serviceName_example; // String | 
+        String artifactName = artifactName_example; // String | 
         String clusterName = clusterName_example; // String | 
         try {
-            apiInstance.deleteCluster(clusterName);
+            apiInstance.serviceServiceDeleteArtifact(serviceName, artifactName, clusterName);
         } catch (ApiException e) {
-            System.err.println("Exception when calling ClustersApi#deleteCluster");
+            System.err.println("Exception when calling ClusterServicesApi#serviceServiceDeleteArtifact");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
 
-                          <div class="tab-pane" id="examples-Clusters-deleteCluster-0-android">
-                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.ClustersApi;
+                          <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-android">
+                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.ClusterServicesApi;
 
-public class ClustersApiExample {
+public class ClusterServicesApiExample {
 
     public static void main(String[] args) {
-        ClustersApi apiInstance = new ClustersApi();
+        ClusterServicesApi apiInstance = new ClusterServicesApi();
+        String serviceName = serviceName_example; // String | 
+        String artifactName = artifactName_example; // String | 
         String clusterName = clusterName_example; // String | 
         try {
-            apiInstance.deleteCluster(clusterName);
+            apiInstance.serviceServiceDeleteArtifact(serviceName, artifactName, clusterName);
         } catch (ApiException e) {
-            System.err.println("Exception when calling ClustersApi#deleteCluster");
+            System.err.println("Exception when calling ClusterServicesApi#serviceServiceDeleteArtifact");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
   <!--
-  <div class="tab-pane" id="examples-Clusters-deleteCluster-0-groovy">
+  <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-groovy">
   <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
   </div> -->
-                            <div class="tab-pane" id="examples-Clusters-deleteCluster-0-objc">
-                              <pre class="prettyprint"><code class="language-cpp">String *clusterName = clusterName_example; // 
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-objc">
+                              <pre class="prettyprint"><code class="language-cpp">String *serviceName = serviceName_example; // 
+String *artifactName = artifactName_example; // 
+String *clusterName = clusterName_example; // 
 
-ClustersApi *apiInstance = [[ClustersApi alloc] init];
+ClusterServicesApi *apiInstance = [[ClusterServicesApi alloc] init];
 
-// Deletes a cluster
-[apiInstance deleteClusterWith:clusterName
+// Deletes a single service artifact
+[apiInstance serviceServiceDeleteArtifactWith:serviceName
+    artifactName:artifactName
+    clusterName:clusterName
               completionHandler: ^(NSError* error) {
                             if (error) {
                                 NSLog(@"Error: %@", error);
@@ -9111,10 +9221,14 @@ ClustersApi *apiInstance = [[ClustersApi alloc] init];
 </code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-deleteCluster-0-javascript">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-javascript">
                               <pre class="prettyprint"><code class="language-js">var SwaggerSpecForAmbariRestApi = require('swagger_spec_for_ambari_rest_api');
 
-var api = new SwaggerSpecForAmbariRestApi.ClustersApi()
+var api = new SwaggerSpecForAmbariRestApi.ClusterServicesApi()
+
+var serviceName = serviceName_example; // {String} 
+
+var artifactName = artifactName_example; // {String} 
 
 var clusterName = clusterName_example; // {String} 
 
@@ -9126,14 +9240,14 @@ var callback = function(error, data, response) {
     console.log('API called successfully.');
   }
 };
-api.deleteCluster(clusterName, callback);
+api.serviceServiceDeleteArtifact(serviceName, artifactName, clusterName, callback);
 </code></pre>
                             </div>
 
-                            <!--<div class="tab-pane" id="examples-Clusters-deleteCluster-0-angular">
+                            <!--<div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-angular">
               <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
             </div>-->
-                            <div class="tab-pane" id="examples-Clusters-deleteCluster-0-csharp">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-csharp">
                               <pre class="prettyprint"><code class="language-cs">using System;
 using System.Diagnostics;
 using IO.Swagger.Api;
@@ -9142,60 +9256,66 @@ using IO.Swagger.Model;
 
 namespace Example
 {
-    public class deleteClusterExample
+    public class serviceServiceDeleteArtifactExample
     {
         public void main()
         {
             
-            var apiInstance = new ClustersApi();
+            var apiInstance = new ClusterServicesApi();
+            var serviceName = serviceName_example;  // String | 
+            var artifactName = artifactName_example;  // String | 
             var clusterName = clusterName_example;  // String | 
 
             try
             {
-                // Deletes a cluster
-                apiInstance.deleteCluster(clusterName);
+                // Deletes a single service artifact
+                apiInstance.serviceServiceDeleteArtifact(serviceName, artifactName, clusterName);
             }
             catch (Exception e)
             {
-                Debug.Print("Exception when calling ClustersApi.deleteCluster: " + e.Message );
+                Debug.Print("Exception when calling ClusterServicesApi.serviceServiceDeleteArtifact: " + e.Message );
             }
         }
     }
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-deleteCluster-0-php">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-php">
                               <pre class="prettyprint"><code class="language-php"><&#63;php
 require_once(__DIR__ . '/vendor/autoload.php');
 
-$api_instance = new Swagger\Client\Api\ClustersApi();
+$api_instance = new Swagger\Client\Api\ClusterServicesApi();
+$serviceName = serviceName_example; // String | 
+$artifactName = artifactName_example; // String | 
 $clusterName = clusterName_example; // String | 
 
 try {
-    $api_instance->deleteCluster($clusterName);
+    $api_instance->serviceServiceDeleteArtifact($serviceName, $artifactName, $clusterName);
 } catch (Exception $e) {
-    echo 'Exception when calling ClustersApi->deleteCluster: ', $e->getMessage(), PHP_EOL;
+    echo 'Exception when calling ClusterServicesApi->serviceServiceDeleteArtifact: ', $e->getMessage(), PHP_EOL;
 }
 ?></code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-deleteCluster-0-perl">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-perl">
                               <pre class="prettyprint"><code class="language-perl">use Data::Dumper;
 use WWW::SwaggerClient::Configuration;
-use WWW::SwaggerClient::ClustersApi;
+use WWW::SwaggerClient::ClusterServicesApi;
 
-my $api_instance = WWW::SwaggerClient::ClustersApi->new();
+my $api_instance = WWW::SwaggerClient::ClusterServicesApi->new();
+my $serviceName = serviceName_example; # String | 
+my $artifactName = artifactName_example; # String | 
 my $clusterName = clusterName_example; # String | 
 
 eval { 
-    $api_instance->deleteCluster(clusterName => $clusterName);
+    $api_instance->serviceServiceDeleteArtifact(serviceName => $serviceName, artifactName => $artifactName, clusterName => $clusterName);
 };
 if ($@) {
-    warn "Exception when calling ClustersApi->deleteCluster: $@\n";
+    warn "Exception when calling ClusterServicesApi->serviceServiceDeleteArtifact: $@\n";
 }</code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-deleteCluster-0-python">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifact-0-python">
                               <pre class="prettyprint"><code class="language-python">from __future__ import print_statement
 import time
 import swagger_client
@@ -9203,14 +9323,16 @@ from swagger_client.rest import ApiException
 from pprint import pprint
 
 # create an instance of the API class
-api_instance = swagger_client.ClustersApi()
+api_instance = swagger_client.ClusterServicesApi()
+serviceName = serviceName_example # String | 
+artifactName = artifactName_example # String | 
 clusterName = clusterName_example # String | 
 
 try: 
-    # Deletes a cluster
-    api_instance.deleteCluster(clusterName)
+    # Deletes a single service artifact
+    api_instance.serviceServiceDeleteArtifact(serviceName, artifactName, clusterName)
 except ApiException as e:
-    print("Exception when calling ClustersApi->deleteCluster: %s\n" % e)</code></pre>
+    print("Exception when calling ClusterServicesApi->serviceServiceDeleteArtifact: %s\n" % e)</code></pre>
                             </div>
                           </div>
 
@@ -9222,6 +9344,70 @@ except ApiException as e:
                                   <th width="150px">Name</th>
                                   <th>Description</th>
                                 </tr>
+                                  <tr><td style="width:150px;">serviceName*</td>
+<td>
+
+
+<script>
+												$(document).ready(function() {
+													var schemaWrapper = {
+  "name" : "serviceName",
+  "in" : "path",
+  "required" : true,
+  "type" : "string"
+};
+													var schema = schemaWrapper;
+
+
+
+
+													var view = new JSONSchemaView(schema,1);
+													var result = $('#d2e199_serviceServiceDeleteArtifact_serviceName');
+													result.empty();
+													result.append(view.render());
+
+
+
+
+
+												});
+												</script>
+												<div id="d2e199_serviceServiceDeleteArtifact_serviceName"></div>
+</td>
+</tr>
+
+                                  <tr><td style="width:150px;">artifactName*</td>
+<td>
+
+
+<script>
+												$(document).ready(function() {
+													var schemaWrapper = {
+  "name" : "artifactName",
+  "in" : "path",
+  "required" : true,
+  "type" : "string"
+};
+													var schema = schemaWrapper;
+
+
+
+
+													var view = new JSONSchemaView(schema,1);
+													var result = $('#d2e199_serviceServiceDeleteArtifact_artifactName');
+													result.empty();
+													result.append(view.render());
+
+
+
+
+
+												});
+												</script>
+												<div id="d2e199_serviceServiceDeleteArtifact_artifactName"></div>
+</td>
+</tr>
+
                                   <tr><td style="width:150px;">clusterName*</td>
 <td>
 
@@ -9240,7 +9426,7 @@ except ApiException as e:
 
 
 													var view = new JSONSchemaView(schema,1);
-													var result = $('#d2e199_deleteCluster_clusterName');
+													var result = $('#d2e199_serviceServiceDeleteArtifact_clusterName');
 													result.empty();
 													result.append(view.render());
 
@@ -9250,7 +9436,7 @@ except ApiException as e:
 
 												});
 												</script>
-												<div id="d2e199_deleteCluster_clusterName"></div>
+												<div id="d2e199_serviceServiceDeleteArtifact_clusterName"></div>
 </td>
 </tr>
 
@@ -9304,11 +9490,11 @@ except ApiException as e:
                         </article>
                       </div>
                       <hr>
-                    <div id="api-Clusters-deleteClusterArtifact">
-                      <article id="api-Clusters-deleteClusterArtifact-0" data-group="User" data-name="deleteClusterArtifact" data-version="0">
+                    <div id="api-ClusterServices-serviceServiceDeleteArtifacts">
+                      <article id="api-ClusterServices-serviceServiceDeleteArtifacts-0" data-group="User" data-name="serviceServiceDeleteArtifacts" data-version="0">
                         <div class="pull-left">
-                          <h1>deleteClusterArtifact</h1>
-                          <p>Deletes a single artifact</p>
+                          <h1>serviceServiceDeleteArtifacts</h1>
+                          <p>Deletes all artifacts of a service that match the provided predicate</p>
                         </div>
                         <div class="pull-right"></div>
                         <div class="clearfix"></div>
@@ -9316,85 +9502,85 @@ except ApiException as e:
                         <p class="marked"></p>
                         <p></p>
                         <br />
-                        <pre class="prettyprint language-html prettyprinted" data-type="delete"><code><span class="pln">/clusters/{clusterName}/artifacts/{artifactName}</span></code></pre>
+                        <pre class="prettyprint language-html prettyprinted" data-type="delete"><code><span class="pln">/clusters/{clusterName}/services/{serviceName}/artifacts</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-Clusters-deleteClusterArtifact-0-curl">Curl</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-java">Java</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-android">Android</a></li>
-                          <!--<li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-groovy">Groovy</a></li>-->
-                          <li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-objc">Obj-C</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-javascript">JavaScript</a></li>
-                          <!--<li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-angular">Angular</a></li>-->
-                          <li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-csharp">C#</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-php">PHP</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-perl">Perl</a></li>
-                          <li class=""><a href="#examples-Clusters-deleteClusterArtifact-0-python">Python</a></li>
+                          <li class="active"><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-curl">Curl</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-java">Java</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-android">Android</a></li>
+                          <!--<li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-groovy">Groovy</a></li>-->
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-objc">Obj-C</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-javascript">JavaScript</a></li>
+                          <!--<li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-angular">Angular</a></li>-->
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-csharp">C#</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-php">PHP</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-perl">Perl</a></li>
+                          <li class=""><a href="#examples-ClusterServices-serviceServiceDeleteArtifacts-0-python">Python</a></li>
                         </ul>
 
                         <div class="tab-content">
-                          <div class="tab-pane active" id="examples-Clusters-deleteClusterArtifact-0-curl">
-                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">delete</span> "http://localhost/api/v1/clusters/{clusterName}/artifacts/{artifactName}"</code></pre>
+                          <div class="tab-pane active" id="examples-ClusterServices-serviceServiceDeleteArtifacts-0-curl">
+                            <pre class="prettyprint"><code class="language-bsh">curl -X <span style="text-transform: uppercase;">delete</span> "http://localhost/api/v1/clusters/{clusterName}/services/{serviceName}/artifacts"</code></pre>
                           </div>
-                          <div class="tab-pane" id="examples-Clusters-deleteClusterArtifact-0-java">
+                          <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifacts-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.ClustersApi;
+import io.swagger.client.api.ClusterServicesApi;
 
 import java.io.File;
 import java.util.*;
 
-public class ClustersApiExample {
+public class ClusterServicesApiExample {
 
     public static void main(String[] args) {
         
-        ClustersApi apiInstance = new ClustersApi();
+        ClusterServicesApi apiInstance = new ClusterServicesApi();
+        String serviceName = serviceName_example; // String | 
         String clusterName = clusterName_example; // String | 
-        String artifactName = artifactName_example; // String | 
         try {
-            apiInstance.deleteClusterArtifact(clusterName, artifactName);
+            apiInstance.serviceServiceDeleteArtifacts(serviceName, clusterName);
         } catch (ApiException e) {
-            System.err.println("Exception when calling ClustersApi#deleteClusterArtifact");
+            System.err.println("Exception when calling ClusterServicesApi#serviceServiceDeleteArtifacts");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
 
-                          <div class="tab-pane" id="examples-Clusters-deleteClusterArtifact-0-android">
-                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.ClustersApi;
+                          <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifacts-0-android">
+                            <pre class="prettyprint"><code class="language-java">import io.swagger.client.api.ClusterServicesApi;
 
-public class ClustersApiExample {
+public class ClusterServicesApiExample {
 
     public static void main(String[] args) {
-        ClustersApi apiInstance = new ClustersApi();
+        ClusterServicesApi apiInstance = new ClusterServicesApi();
+        String serviceName = serviceName_example; // String | 
         String clusterName = clusterName_example; // String | 
-        String artifactName = artifactName_example; // String | 
         try {
-            apiInstance.deleteClusterArtifact(clusterName, artifactName);
+            apiInstance.serviceServiceDeleteArtifacts(serviceName, clusterName);
         } catch (ApiException e) {
-            System.err.println("Exception when calling ClustersApi#deleteClusterArtifact");
+            System.err.println("Exception when calling ClusterServicesApi#serviceServiceDeleteArtifacts");
             e.printStackTrace();
         }
     }
 }</code></pre>
                           </div>
   <!--
-  <div class="tab-pane" id="examples-Clusters-deleteClusterArtifact-0-groovy">
+  <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifacts-0-groovy">
   <pre class="prettyprint language-json prettyprinted" data-type="json"><code>Coming Soon!</code></pre>
   </div> -->
-                            <div class="tab-pane" id="examples-Clusters-deleteClusterArtifact-0-objc">
-                              <pre class="prettyprint"><code class="language-cpp">String *clusterName = clusterName_example; // 
-String *artifactName = artifactName_example; // 
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifacts-0-objc">
+                              <pre class="prettyprint"><code class="language-cpp">String *serviceName = serviceName_example; // 
+String *clusterName = clusterName_example; // 
 
-ClustersApi *apiInstance = [[ClustersApi alloc] init];
+ClusterServicesApi *apiInstance = [[ClusterServicesApi alloc] init];
 
-// Deletes a single artifact
-[apiInstance deleteClusterArtifactWith:clusterName
-    artifactName:artifactName
+// Deletes all artifacts of a service that match the provided predicate
+[apiInstance serviceServiceDeleteArtifactsWith:serviceName
+    clusterName:clusterName
               completionHandler: ^(NSError* error) {
                             if (error) {
                                 NSLog(@"Error: %@", error);
@@ -9403,14 +9589,14 @@ ClustersApi *apiInstance = [[ClustersApi alloc] init];
 </code></pre>
                             </div>
 
-                            <div class="tab-pane" id="examples-Clusters-deleteClusterArtifact-0-javascript">
+                            <div class="tab-pane" id="examples-ClusterServices-serviceServiceDeleteArtifacts-0-javascript">
                               <pre class="prettyprint"><code class="language-js">var SwaggerSpecForAmbariRestApi = require('swagger_spec_for_ambari_rest_api');
 
-var api = new SwaggerSpecForAmbariRestApi.ClustersApi()
+var api = new SwaggerSpecForAmbariRestApi.ClusterServicesApi()
 
-var clusterName = clusterName_example; // {String} 
+var serviceName = serviceName_example; // {String} 
 
-var artifactName = artifactName_example; // {String} 
+var clusterName = clusterName_example; // {String} 
 
 
 var callback = function(error, data, response) {
@@ -9420,14 +9606,14 @@ var callback = function(error, data, response) {
     console.log('API called successfully.');
   }
 };
-api.deleteClusterArtifact(clusterName, artifactName, callback);
+api.serviceServiceDeleteArtifacts(serviceName, clusterName, callback);
 </code></pre>
                 

<TRUNCATED>

[3/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 9cdde8f..35eb255 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
@@ -22,16 +22,15 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import javax.inject.Inject;
 import javax.persistence.EntityManager;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.hooks.HookContextFactory;
 import org.apache.ambari.server.hooks.HookService;
 import org.apache.ambari.server.orm.dao.GroupDAO;
@@ -41,7 +40,7 @@ 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.ResourceTypeDAO;
+import org.apache.ambari.server.orm.dao.UserAuthenticationDAO;
 import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.entities.GroupEntity;
 import org.apache.ambari.server.orm.entities.MemberEntity;
@@ -50,17 +49,16 @@ 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.ResourceTypeEntity;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.ldap.LdapBatchDto;
 import org.apache.ambari.server.security.ldap.LdapUserGroupMemberDto;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 
+import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.persist.Transactional;
@@ -74,31 +72,37 @@ public class Users {
   private static final Logger LOG = LoggerFactory.getLogger(Users.class);
 
   @Inject
-  Provider<EntityManager> entityManagerProvider;
-  @Inject
-  protected UserDAO userDAO;
-  @Inject
-  protected GroupDAO groupDAO;
+  private Provider<EntityManager> entityManagerProvider;
+
   @Inject
-  protected MemberDAO memberDAO;
+  private UserDAO userDAO;
+
   @Inject
-  protected PrincipalDAO principalDAO;
+  private UserAuthenticationDAO userAuthenticationDAO;
+
   @Inject
-  protected PermissionDAO permissionDAO;
+  private GroupDAO groupDAO;
+
   @Inject
-  protected PrivilegeDAO privilegeDAO;
+  private MemberDAO memberDAO;
+
   @Inject
-  protected ResourceDAO resourceDAO;
+  private PrincipalDAO principalDAO;
+
   @Inject
-  protected ResourceTypeDAO resourceTypeDAO;
+  private PermissionDAO permissionDAO;
+
   @Inject
-  protected PrincipalTypeDAO principalTypeDAO;
+  private PrivilegeDAO privilegeDAO;
+
   @Inject
-  protected PasswordEncoder passwordEncoder;
+  private ResourceDAO resourceDAO;
+
   @Inject
-  protected Configuration configuration;
+  private PrincipalTypeDAO principalTypeDAO;
+
   @Inject
-  private AmbariLdapAuthenticationProvider ldapAuthenticationProvider;
+  private PasswordEncoder passwordEncoder;
 
   @Inject
   private Provider<HookService> hookServiceProvider;
@@ -117,52 +121,38 @@ public class Users {
     return users;
   }
 
-  /**
-   * This method works incorrectly, userName is not unique if users have different types
-   *
-   * @return One user. Priority is LOCAL -> LDAP -> JWT -> PAM
-   */
-  @Deprecated
-  public User getAnyUser(String userName) {
-    UserEntity userEntity = userDAO.findSingleUserByName(userName);
-    return (null == userEntity) ? null : new User(userEntity);
+  public List<UserEntity> getAllUserEntities() {
+    return userDAO.findAll();
+  }
+
+  public UserEntity getUserEntity(String userName) {
+    return (userName == null) ? null : userDAO.findUserByName(userName);
+  }
+
+  public UserEntity getUserEntity(Integer userId) {
+    return (userId == null) ? null : userDAO.findByPK(userId);
   }
 
-  public User getUser(String userName, UserType userType) {
-    UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
+  public User getUser(UserEntity userEntity) {
     return (null == userEntity) ? null : new User(userEntity);
   }
 
   public User getUser(Integer userId) {
-    UserEntity userEntity = userDAO.findByPK(userId);
-    return (null == userEntity) ? null : new User(userEntity);
+    return getUser(getUserEntity(userId));
+  }
+
+  public User getUser(String userName) {
+    return getUser(getUserEntity(userName));
   }
 
   /**
-   * Retrieves User then userName is unique in users DB. Will return null if there no user with provided userName or
-   * there are some users with provided userName but with different types.
-   *
-   * <p>User names in the future will likely be unique hence the deprecation.</p>
+   * Modifies password of local user
    *
-   * @param userName
-   * @return User if userName is unique in DB, null otherwise
+   * @throws AmbariException
    */
-  @Deprecated
-  public User getUserIfUnique(String userName) {
-    List<UserEntity> userEntities = new ArrayList<>();
-    UserEntity userEntity = userDAO.findUserByNameAndType(userName, UserType.LOCAL);
-    if (userEntity != null) {
-      userEntities.add(userEntity);
-    }
-    userEntity = userDAO.findUserByNameAndType(userName, UserType.LDAP);
-    if (userEntity != null) {
-      userEntities.add(userEntity);
-    }
-    userEntity = userDAO.findUserByNameAndType(userName, UserType.JWT);
-    if (userEntity != null) {
-      userEntities.add(userEntity);
-    }
-    return (userEntities.isEmpty() || userEntities.size() > 1) ? null : new User(userEntities.get(0));
+  public synchronized void modifyPassword(String userName, String currentUserPassword, String newPassword) throws AmbariException, AuthorizationException {
+    UserEntity userEntity = userDAO.findUserByName(userName);
+    modifyPassword(userEntity, currentUserPassword, newPassword);
   }
 
   /**
@@ -170,59 +160,58 @@ public class Users {
    *
    * @throws AmbariException
    */
-  public synchronized void modifyPassword(String userName, String currentUserPassword, String newPassword) throws AmbariException {
+  public synchronized void modifyPassword(UserEntity userEntity, String currentUserPassword, String newPassword) throws AmbariException, AuthorizationException {
 
-    SecurityContext securityContext = SecurityContextHolder.getContext();
-    String currentUserName = securityContext.getAuthentication().getName();
-    if (currentUserName == null) {
+    String authenticatedUserName = AuthorizationHelper.getAuthenticatedName();
+    if (authenticatedUserName == null) {
       throw new AmbariException("Authentication required. Please sign in.");
     }
 
-    UserEntity currentUserEntity = userDAO.findLocalUserByName(currentUserName);
-
-    //Authenticate LDAP user
-    boolean isLdapUser = false;
-    if (currentUserEntity == null) {
-      currentUserEntity = userDAO.findLdapUserByName(currentUserName);
-      try {
-        ldapAuthenticationProvider.authenticate(
-            new UsernamePasswordAuthenticationToken(currentUserName, currentUserPassword));
-        isLdapUser = true;
-      } catch (InvalidUsernamePasswordCombinationException ex) {
-        throw new AmbariException(ex.getMessage());
-      }
-    }
-
-    boolean isCurrentUserAdmin = false;
-    for (PrivilegeEntity privilegeEntity : currentUserEntity.getPrincipal().getPrivileges()) {
-      if (privilegeEntity.getPermission().getPermissionName().equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION_NAME)) {
-        isCurrentUserAdmin = true;
-        break;
+    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");
       }
-    }
 
-    UserEntity userEntity = userDAO.findLocalUserByName(userName);
+      List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+      UserAuthenticationEntity localAuthenticationEntity = null;
 
-    if ((userEntity != null) && (currentUserEntity != null)) {
-      if (!isCurrentUserAdmin && !userName.equals(currentUserName)) {
-        throw new AmbariException("You can't change password of another user");
+      // 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 ((isLdapUser && isCurrentUserAdmin) || (StringUtils.isNotEmpty(currentUserPassword) &&
-          passwordEncoder.matches(currentUserPassword, currentUserEntity.getUserPassword()))) {
-        userEntity.setUserPassword(passwordEncoder.encode(newPassword));
-        userDAO.merge(userEntity);
-      } else {
+      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");
       }
 
-    } else {
-      userEntity = userDAO.findLdapUserByName(userName);
-      if (userEntity != null) {
-        throw new AmbariException("Password of LDAP user cannot be modified");
-      } else {
-        throw new AmbariException("User " + userName + " not found");
+      // 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");
     }
   }
 
@@ -230,32 +219,28 @@ public class Users {
    * Enables/disables user.
    *
    * @param userName user name
+   * @param active   true if active; false if not active
    * @throws AmbariException if user does not exist
    */
   public synchronized void setUserActive(String userName, boolean active) throws AmbariException {
     UserEntity userEntity = userDAO.findUserByName(userName);
     if (userEntity != null) {
-      userEntity.setActive(active);
-      userDAO.merge(userEntity);
+      setUserActive(userEntity, active);
     } else {
       throw new AmbariException("User " + userName + " doesn't exist");
     }
   }
 
   /**
-   * Converts user to LDAP user.
+   * Enables/disables user.
    *
-   * @param userName user name
+   * @param userEntity the user
+   * @param active     true if active; false if not active
    * @throws AmbariException if user does not exist
    */
-  public synchronized void setUserLdap(String userName) throws AmbariException {
-    UserEntity userEntity = userDAO.findUserByName(userName);
-    if (userEntity != null) {
-      userEntity.setLdapUser(true);
-      userDAO.merge(userEntity);
-    } else {
-      throw new AmbariException("User " + userName + " doesn't exist");
-    }
+  public synchronized void setUserActive(UserEntity userEntity, boolean active) throws AmbariException {
+    userEntity.setActive(active);
+    userDAO.merge(userEntity);
   }
 
   /**
@@ -275,40 +260,45 @@ public class Users {
   }
 
   /**
-   * Creates new local user with provided userName and password.
+   * Creates new, active, user with provided userName, local username, and display name.
    *
-   * @param userName user name
-   * @param password password
+   * @param userName      user name
+   * @param localUserName the local username to use; if <code>null</code> or empty, userName will be used
+   * @param displayName   the name to display for presentation; if <code>null</code> or empty, userName will be used
+   * @return the new UserEntity
    * @throws AmbariException if user already exists
    */
-  public void createUser(String userName, String password) throws AmbariException {
-    createUser(userName, password, UserType.LOCAL, true, false);
+  public UserEntity createUser(String userName, String localUserName, String displayName) throws AmbariException {
+    return createUser(userName, localUserName, displayName, true);
   }
 
   /**
-   * Creates new user with provided userName and password.
+   * Creates new, user with provided userName, local username, and display name.
    *
-   * @param userName user name
-   * @param password password
-   * @param userType user type
-   * @param active   is user active
-   * @param admin    is user admin
+   * @param userName      user name
+   * @param localUserName the local username to use; if <code>null</code> or empty, userName will be used
+   * @param displayName   the name to display for presentation; if <code>null</code> or empty, userName will be used
+   * @param active        is user active
+   * @return the new UserEntity
    * @throws AmbariException if user already exists
    */
-  public synchronized void createUser(String userName, String password, UserType userType, Boolean active, Boolean
-      admin) throws AmbariException {
-    // if user type is not provided, assume LOCAL since the default
-    // value of user_type in the users table is LOCAL
-    if (userType == null) {
-      throw new AmbariException("UserType not specified.");
-    }
-
-    User existingUser = getAnyUser(userName);
-    if (existingUser != null) {
-      throw new AmbariException("User " + existingUser.getUserName() + " already exists with type "
-          + existingUser.getUserType());
+  @Transactional
+  public synchronized UserEntity createUser(String userName, String localUserName, String displayName, Boolean active) throws AmbariException {
+
+    String validatedUserName = UserName.fromString(userName).toString();
+    String validatedDisplayName = (StringUtils.isEmpty(displayName))
+        ? validatedUserName
+        : UserName.fromString(displayName).toString();
+    String validatedLocalUserName = (StringUtils.isEmpty(localUserName))
+        ? validatedUserName
+        : UserName.fromString(localUserName).toString();
+
+    // Ensure that the user does not already exist
+    if (userDAO.findUserByName(validatedUserName) != null) {
+      throw new AmbariException("User already exists");
     }
 
+    // Create the PrincipalEntity - needed for assigning privileges/roles
     PrincipalTypeEntity principalTypeEntity = principalTypeDAO.findById(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
     if (principalTypeEntity == null) {
       principalTypeEntity = new PrincipalTypeEntity();
@@ -320,42 +310,62 @@ public class Users {
     principalEntity.setPrincipalType(principalTypeEntity);
     principalDAO.create(principalEntity);
 
+    // Create the new UserEntity Record
     UserEntity userEntity = new UserEntity();
-    userEntity.setUserName(UserName.fromString(userName));
-    if (userType == UserType.LOCAL) {
-      //passwords should be stored for local users only
-      userEntity.setUserPassword(passwordEncoder.encode(password));
-    }
+    userEntity.setUserName(validatedUserName);
+    userEntity.setDisplayName(validatedDisplayName);
+    userEntity.setLocalUsername(validatedLocalUserName);
+
     userEntity.setPrincipal(principalEntity);
     if (active != null) {
       userEntity.setActive(active);
     }
 
-    userEntity.setUserType(userType);
-    if (userType == UserType.LDAP) {
-      userEntity.setLdapUser(true);
-    }
-
     userDAO.create(userEntity);
 
-    if (admin != null && admin) {
-      grantAdminPrivilege(userEntity.getUserId());
-    }
-
     // execute user initialization hook if required ()
-    hookServiceProvider.get().execute(hookContextFactory.createUserHookContext(userName));
+    hookServiceProvider.get().execute(hookContextFactory.createUserHookContext(validatedUserName));
+
+    return userEntity;
   }
 
+
+  /**
+   * Removes a user from the Ambari database.
+   * <p>
+   * It is expected that the assoicated user authencation records are removed by this operation
+   * as well.
+   *
+   * @param user the user to remove
+   * @throws AmbariException
+   */
+  @Transactional
   public synchronized void removeUser(User user) throws AmbariException {
     UserEntity userEntity = userDAO.findByPK(user.getUserId());
     if (userEntity != null) {
+      removeUser(userEntity);
+    } else {
+      throw new AmbariException("User " + user + " doesn't exist");
+    }
+  }
+
+  /**
+   * Removes a user from the Ambari database.
+   * <p>
+   * It is expected that the assoicated user authencation records are removed by this operation
+   * as well.
+   *
+   * @param userEntity the user to remove
+   * @throws AmbariException
+   */
+  @Transactional
+  public synchronized void removeUser(UserEntity userEntity) throws AmbariException {
+    if (userEntity != null) {
       if (!isUserCanBeRemoved(userEntity)) {
         throw new AmbariException("Could not remove user " + userEntity.getUserName() +
             ". System should have at least one administrator.");
       }
       userDAO.remove(userEntity);
-    } else {
-      throw new AmbariException("User " + user + " doesn't exist");
     }
   }
 
@@ -410,7 +420,7 @@ public class Users {
    * Creates new group with provided name & type
    */
   @Transactional
-  public synchronized void createGroup(String groupName, GroupType groupType) {
+  public synchronized GroupEntity createGroup(String groupName, GroupType groupType) {
     // create an admin principal to represent this group
     PrincipalTypeEntity principalTypeEntity = principalTypeDAO.findById(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE);
     if (principalTypeEntity == null) {
@@ -429,6 +439,7 @@ public class Users {
     groupEntity.setGroupType(groupType);
 
     groupDAO.create(groupEntity);
+    return groupEntity;
   }
 
   /**
@@ -476,30 +487,66 @@ public class Users {
   }
 
   /**
-   * Grants AMBARI.ADMINISTRATOR privilege to provided user.
+   * Test the user for Ambari Admistrator privileges.
+   *
+   * @param userEntity the user to test
+   * @return true if the user has Ambari Administrator privileges; otherwise false
+   */
+  public synchronized boolean hasAdminPrivilege(UserEntity userEntity) {
+    PrincipalEntity principalEntity = userEntity.getPrincipal();
+    if (principalEntity != null) {
+      Set<PrivilegeEntity> roles = principalEntity.getPrivileges();
+      if (roles != null) {
+        PermissionEntity adminPermission = permissionDAO.findAmbariAdminPermission();
+        Integer adminPermissionId = (adminPermission == null) ? null : adminPermission.getId();
+
+        if (adminPermissionId != null) {
+          for (PrivilegeEntity privilegeEntity : roles) {
+            PermissionEntity rolePermission = privilegeEntity.getPermission();
+            if ((rolePermission != null) && (adminPermissionId.equals(rolePermission.getId()))) {
+              return true;
+            }
+          }
+        }
+      }
+    }
+
+    return false;
+  }
+
+  /**
+   * Grants Ambari Administrator privilege to provided user.
    *
    * @param userId user id
    */
   public synchronized void grantAdminPrivilege(Integer userId) {
-    final UserEntity user = userDAO.findByPK(userId);
+    grantAdminPrivilege(userDAO.findByPK(userId));
+  }
+
+  /**
+   * Grants Ambari Administrator privilege to provided user.
+   *
+   * @param userEntity the user
+   */
+  public synchronized void grantAdminPrivilege(UserEntity userEntity) {
     final PrivilegeEntity adminPrivilege = new PrivilegeEntity();
     adminPrivilege.setPermission(permissionDAO.findAmbariAdminPermission());
-    adminPrivilege.setPrincipal(user.getPrincipal());
+    adminPrivilege.setPrincipal(userEntity.getPrincipal());
     adminPrivilege.setResource(resourceDAO.findAmbariResource());
-    if (!user.getPrincipal().getPrivileges().contains(adminPrivilege)) {
+    if (!userEntity.getPrincipal().getPrivileges().contains(adminPrivilege)) {
       privilegeDAO.create(adminPrivilege);
-      user.getPrincipal().getPrivileges().add(adminPrivilege);
-      principalDAO.merge(user.getPrincipal()); //explicit merge for Derby support
-      userDAO.merge(user);
+      userEntity.getPrincipal().getPrivileges().add(adminPrivilege);
+      principalDAO.merge(userEntity.getPrincipal()); //explicit merge for Derby support
+      userDAO.merge(userEntity);
     }
   }
 
   /**
    * Grants privilege to provided group.
    *
-   * @param groupId group id
-   * @param resourceId resource id
-   * @param resourceType resource type
+   * @param groupId        group id
+   * @param resourceId     resource id
+   * @param resourceType   resource type
    * @param permissionName permission name
    */
   public synchronized void grantPrivilegeToGroup(Integer groupId, Long resourceId, ResourceType resourceType, String permissionName) {
@@ -508,7 +555,7 @@ public class Users {
     ResourceTypeEntity resourceTypeEntity = new ResourceTypeEntity();
     resourceTypeEntity.setId(resourceType.getId());
     resourceTypeEntity.setName(resourceType.name());
-    privilege.setPermission(permissionDAO.findPermissionByNameAndType(permissionName,resourceTypeEntity));
+    privilege.setPermission(permissionDAO.findPermissionByNameAndType(permissionName, resourceTypeEntity));
     privilege.setPrincipal(group.getPrincipal());
     privilege.setResource(resourceDAO.findById(resourceId));
     if (!group.getPrincipal().getPrivileges().contains(privilege)) {
@@ -521,17 +568,25 @@ public class Users {
   }
 
   /**
-   * Revokes AMBARI.ADMINISTRATOR privilege from provided user.
+   * Revokes Ambari Administrator privileges from provided user.
    *
    * @param userId user id
    */
   public synchronized void revokeAdminPrivilege(Integer userId) {
-    final UserEntity user = userDAO.findByPK(userId);
-    for (PrivilegeEntity privilege : user.getPrincipal().getPrivileges()) {
+    revokeAdminPrivilege(userDAO.findByPK(userId));
+  }
+
+  /**
+   * Revokes Ambari Administrator privileges from provided user.
+   *
+   * @param userEntity the user
+   */
+  public synchronized void revokeAdminPrivilege(UserEntity userEntity) {
+    for (PrivilegeEntity privilege : userEntity.getPrincipal().getPrivileges()) {
       if (privilege.getPermission().getPermissionName().equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION_NAME)) {
-        user.getPrincipal().getPrivileges().remove(privilege);
-        principalDAO.merge(user.getPrincipal()); //explicit merge for Derby support
-        userDAO.merge(user);
+        userEntity.getPrincipal().getPrivileges().remove(privilege);
+        principalDAO.merge(userEntity.getPrincipal()); //explicit merge for Derby support
+        userDAO.merge(userEntity);
         privilegeDAO.remove(privilege);
         break;
       }
@@ -552,9 +607,22 @@ public class Users {
       throw new AmbariException("User " + userName + " doesn't exist");
     }
 
-    if (isUserInGroup(userEntity, groupEntity)) {
-      throw new AmbariException("User " + userName + " is already present in group " + groupName);
-    } else {
+    addMemberToGroup(groupEntity, userEntity);
+  }
+
+  @Transactional
+  public synchronized void addMemberToGroup(GroupEntity groupEntity, UserEntity userEntity)
+      throws AmbariException {
+
+    if (groupEntity == null) {
+      throw new NullPointerException();
+    }
+
+    if (userEntity == null) {
+      throw new NullPointerException();
+    }
+
+    if (!isUserInGroup(userEntity, groupEntity)) {
       final MemberEntity memberEntity = new MemberEntity();
       memberEntity.setGroup(groupEntity);
       memberEntity.setUser(userEntity);
@@ -580,6 +648,13 @@ public class Users {
       throw new AmbariException("User " + userName + " doesn't exist");
     }
 
+    removeMemberFromGroup(groupEntity, userEntity);
+  }
+
+  @Transactional
+  public synchronized void removeMemberFromGroup(GroupEntity groupEntity, UserEntity userEntity)
+      throws AmbariException {
+
     if (isUserInGroup(userEntity, groupEntity)) {
       MemberEntity memberEntity = null;
       for (MemberEntity entity : userEntity.getMemberEntities()) {
@@ -593,10 +668,7 @@ public class Users {
       userDAO.merge(userEntity);
       groupDAO.merge(groupEntity);
       memberDAO.remove(memberEntity);
-    } else {
-      throw new AmbariException("User " + userName + " is not present in group " + groupName);
     }
-
   }
 
   /**
@@ -632,6 +704,9 @@ public class Users {
    *
    * @param batchInfo DTO with batch information
    */
+  // TODO: ************
+  // TODO: This is to be revisited for AMBARI-21222 (Update LDAP sync process to work with improved user management facility)
+  // TODO: ************
   public void processLdapSync(LdapBatchDto batchInfo) {
     final Map<String, UserEntity> allUsers = new HashMap<>();
     final Map<String, GroupEntity> allGroups = new HashMap<>();
@@ -646,21 +721,38 @@ public class Users {
       allGroups.put(groupEntity.getGroupName(), groupEntity);
     }
 
-    final PrincipalTypeEntity userPrincipalType = principalTypeDAO
-        .ensurePrincipalTypeCreated(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
     final PrincipalTypeEntity groupPrincipalType = principalTypeDAO
         .ensurePrincipalTypeCreated(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE);
 
-    // remove users
+    /* *****
+     * Remove users
+     *   First remove the relevant LDAP entries for this user.
+     *   If no more user authentication items exists for the user, then remove the user.
+     * ***** */
     final Set<UserEntity> usersToRemove = new HashSet<>();
+    final Set<UserAuthenticationEntity> authenticationEntitiesToRemove = new HashSet<>();
     for (String userName : batchInfo.getUsersToBeRemoved()) {
       UserEntity userEntity = userDAO.findUserByName(userName);
-      if (userEntity == null) {
-        continue;
+      if (userEntity != null) {
+        List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+        Iterator<UserAuthenticationEntity> iterator = authenticationEntities.iterator();
+        while (iterator.hasNext()) {
+          UserAuthenticationEntity authenticationEntity = iterator.next();
+
+          if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LDAP) {
+            // TODO: Determine if this is the _relevant_ LDAP authentication entry - for now there will only be one..
+            authenticationEntitiesToRemove.add(authenticationEntity);
+            iterator.remove();
+          }
+        }
+
+        if (authenticationEntities.isEmpty()) {
+          allUsers.remove(userEntity.getUserName());
+          usersToRemove.add(userEntity);
+        }
       }
-      allUsers.remove(userEntity.getUserName());
-      usersToRemove.add(userEntity);
     }
+    userAuthenticationDAO.remove(authenticationEntitiesToRemove);
     userDAO.remove(usersToRemove);
 
     // remove groups
@@ -672,21 +764,46 @@ public class Users {
     }
     groupDAO.remove(groupsToRemove);
 
-    // update users
-    final Set<UserEntity> usersToBecomeLdap = new HashSet<>();
+    /* *****
+     * Update users
+     * ***** */
+    final Set<UserEntity> userEntitiesToUpdate = new HashSet<>();
     for (String userName : batchInfo.getUsersToBecomeLdap()) {
-      UserEntity userEntity = userDAO.findLocalUserByName(userName);
-      if (userEntity == null) {
-        userEntity = userDAO.findLdapUserByName(userName);
-        if (userEntity == null) {
-          continue;
+      // Ensure the username is all lowercase
+      userName = userName.toLowerCase();
+
+      UserEntity userEntity = userDAO.findUserByName(userName);
+      if (userEntity != null) {
+        LOG.trace("Enabling LDAP authentication for the user account with the username {}.", userName);
+        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;
+            }
+          }
+
+        if (createNew) {
+          LOG.debug("Creating new LDAP authentication record for the user account with the username {}.", userName);
+
+          UserAuthenticationEntity authenticationEntity = new UserAuthenticationEntity();
+          authenticationEntity.setUser(userEntity);
+          authenticationEntity.setAuthenticationType(UserAuthenticationType.LDAP);
+          authenticationEntity.setAuthenticationKey("DN to be set");
+          authenticationEntities.add(authenticationEntity);
+
+          userEntity.setAuthenticationEntities(authenticationEntities);
+          userEntitiesToUpdate.add(userEntity);
         }
+      } else {
+        LOG.warn("Failed to find user account for {} while enabling LDAP authentication for the user.", userName);
       }
-      userEntity.setLdapUser(true);
-      allUsers.put(userEntity.getUserName(), userEntity);
-      usersToBecomeLdap.add(userEntity);
     }
-    userDAO.merge(usersToBecomeLdap);
+    userDAO.merge(userEntitiesToUpdate);
 
     // update groups
     final Set<GroupEntity> groupsToBecomeLdap = new HashSet<>();
@@ -701,21 +818,25 @@ public class Users {
     // prepare create principals
     final List<PrincipalEntity> principalsToCreate = new ArrayList<>();
 
-    // prepare create users
-    final Set<UserEntity> usersToCreate = new HashSet<>();
+    // Create users
     for (String userName : batchInfo.getUsersToBeCreated()) {
-      final PrincipalEntity principalEntity = new PrincipalEntity();
-      principalEntity.setPrincipalType(userPrincipalType);
-      principalsToCreate.add(principalEntity);
+      UserEntity userEntity;
 
-      final UserEntity userEntity = new UserEntity();
-      userEntity.setUserName(UserName.fromString(userName));
-      userEntity.setUserPassword("");
-      userEntity.setPrincipal(principalEntity);
-      userEntity.setLdapUser(true);
+      try {
+        userEntity = createUser(userName, userName, userName, true);
+      } catch (AmbariException e) {
+        LOG.error(String.format("Failed to create new user: %s", userName), e);
+        userEntity = null;
+      }
 
-      allUsers.put(userEntity.getUserName(), userEntity);
-      usersToCreate.add(userEntity);
+      if (userEntity != null) {
+        UserAuthenticationEntity authenticationEntity = new UserAuthenticationEntity();
+        authenticationEntity.setUser(userEntity);
+        authenticationEntity.setAuthenticationType(UserAuthenticationType.LDAP);
+        authenticationEntity.setAuthenticationKey("DN to be set");
+        userEntity.setAuthenticationEntities(Collections.singletonList(authenticationEntity));
+        userDAO.merge(userEntity);
+      }
     }
 
     // prepare create groups
@@ -734,9 +855,8 @@ public class Users {
       groupsToCreate.add(groupEntity);
     }
 
-    // create users and groups
+    // create groups
     principalDAO.create(principalsToCreate);
-    userDAO.create(usersToCreate);
     groupDAO.create(groupsToCreate);
 
     // create membership
@@ -766,12 +886,6 @@ public class Users {
 
     // clear cached entities
     entityManagerProvider.get().getEntityManagerFactory().getCache().evictAll();
-
-    if (!usersToCreate.isEmpty()) {
-      // entry point in the hook logic
-      hookServiceProvider.get().execute(hookContextFactory.createBatchUserHookContext(getUsersToGroupMap(usersToCreate)));
-    }
-
   }
 
   /**
@@ -900,11 +1014,29 @@ public class Users {
    * granted View User access on that File View instance.
    *
    * @param userName the username for the relevant user
-   * @param userType the user type for the relevant user
    * @return the users collection of implicit and explicit granted authorities
    */
-  public Collection<AmbariGrantedAuthority> getUserAuthorities(String userName, UserType userType) {
-    UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
+  public Collection<AmbariGrantedAuthority> getUserAuthorities(String userName) {
+    return getUserAuthorities(getUserEntity(userName));
+  }
+
+  /**
+   * Gets the explicit and implicit authorities for the given user.
+   * <p>
+   * The explicit authorities are the authorities that have be explicitly set by assigning roles to
+   * a user.  For example the Cluster Operator role on a given cluster gives that the ability to
+   * start and stop services in that cluster, among other privileges for that particular cluster.
+   * <p>
+   * The implicit authorities are the authorities that have been given to the roles themselves which
+   * in turn are granted to the users that have been assigned those roles. For example if the
+   * Cluster User role for a given cluster has been given View User access on a specified File View
+   * instance, then all users who have the Cluster User role for that cluster will implicitly be
+   * granted View User access on that File View instance.
+   *
+   * @param userEntity the relevant user
+   * @return the users collection of implicit and explicit granted authorities
+   */
+  public Collection<AmbariGrantedAuthority> getUserAuthorities(UserEntity userEntity) {
     if (userEntity == null) {
       return Collections.emptyList();
     }
@@ -964,4 +1096,175 @@ public class Users {
     return implicitPrivileges;
   }
 
+  /**
+   * 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.
+   * <p>
+   * The key for this authentication mechanism is the username expected to be in the JWT token.
+   *
+   * @param userEntity the user
+   * @param key        the relevant key
+   * @throws AmbariException
+   */
+  public void addJWTAuthentication(UserEntity userEntity, String key) throws AmbariException {
+    addAuthentication(userEntity, UserAuthenticationType.JWT, key, new Validator() {
+      public void validate(UserEntity userEntity, String key) throws AmbariException {
+        List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+
+        // Ensure only one UserAuthenticationEntity exists for JWT for the user...
+        for (UserAuthenticationEntity entity : authenticationEntities) {
+          if ((entity.getAuthenticationType() == UserAuthenticationType.JWT) &&
+              ((key == null) ? (entity.getAuthenticationKey() == null) : key.equals(entity.getAuthenticationKey()))) {
+            throw new AmbariException("The authentication type already exists for this user");
+          }
+        }
+      }
+    });
+  }
+
+  /**
+   * TODO: This is to be revisited for AMBARI-21223 (Update Kerberos Authentication process to work with improved user management facility)
+   * Adds the ability for a user to authenticate using a Kerberos token.
+   *
+   * @param userEntity    the user
+   * @param principalName the user's principal name
+   * @throws AmbariException
+   */
+  public void addKerberosAuthentication(UserEntity userEntity, String principalName) throws AmbariException {
+    addAuthentication(userEntity, UserAuthenticationType.KERBEROS, principalName, new Validator() {
+      public void validate(UserEntity userEntity, String key) throws AmbariException {
+        List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+
+        // Ensure only one UserAuthenticationEntity exists for LOCAL for the user...
+        for (UserAuthenticationEntity entity : authenticationEntities) {
+          if ((entity.getAuthenticationType() == UserAuthenticationType.KERBEROS) &&
+              ((key == null) ? (entity.getAuthenticationKey() == null) : key.equals(entity.getAuthenticationKey()))) {
+            throw new AmbariException("The authentication type already exists for this user");
+          }
+        }
+      }
+    });
+  }
+
+  /**
+   * TODO: This is to be revisited for AMBARI-21220 (Update Local Authentication process to work with improved user management facility)
+   * Adds the ability for a user to authenticate using a password stored in Ambari's database
+   * <p>
+   * The supplied plaintext password will be encoded before storing.
+   *
+   * @param userEntity the user
+   * @param password   the user's plaintext password
+   * @throws AmbariException
+   */
+  public void addLocalAuthentication(UserEntity userEntity, String password) throws AmbariException {
+
+    // Encode the password..
+    String encodedPassword = passwordEncoder.encode(password);
+
+    addAuthentication(userEntity, UserAuthenticationType.LOCAL, encodedPassword, new Validator() {
+      public void validate(UserEntity userEntity, String key) throws AmbariException {
+        List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+
+        // Ensure only one UserAuthenticationEntity exists for LOCAL for the user...
+        for (UserAuthenticationEntity entity : authenticationEntities) {
+          if (entity.getAuthenticationType() == UserAuthenticationType.LOCAL) {
+            throw new AmbariException("The authentication type already exists for this user");
+          }
+        }
+      }
+    });
+  }
+
+  /**
+   * TODO: This is to be revisited for AMBARI-21221 (Update Pam Authentication process to work with improved user management facility)
+   * Adds the ability for a user to authenticate using Pam
+   *
+   * @param userEntity the user
+   * @param userName   the user's os-level username
+   * @throws AmbariException
+   */
+  public void addPamAuthentication(UserEntity userEntity, String userName) throws AmbariException {
+    addAuthentication(userEntity, UserAuthenticationType.PAM, userName, new Validator() {
+      public void validate(UserEntity userEntity, String key) throws AmbariException {
+        List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+
+        // Ensure only one UserAuthenticationEntity exists for PAM for the user...
+        for (UserAuthenticationEntity entity : authenticationEntities) {
+          if (entity.getAuthenticationType() == UserAuthenticationType.PAM) {
+            throw new AmbariException("The authentication type already exists for this user");
+          }
+        }
+      }
+    });
+  }
+
+  /**
+   * TODO: This is to be revisited for AMBARI-21219 (Update LDAP Authentication process to work with improved user management facility)
+   * Adds the ability for a user to authenticate using a remote LDAP server
+   *
+   * @param userEntity the user
+   * @param dn         the user's distinguished name
+   * @throws AmbariException
+   */
+  public void addLdapAuthentication(UserEntity userEntity, String dn) throws AmbariException {
+    addAuthentication(userEntity, UserAuthenticationType.LDAP, dn, new Validator() {
+      public void validate(UserEntity userEntity, String key) throws AmbariException {
+        List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+
+        // Ensure only one UserAuthenticationEntity exists for PAM for the user...
+        for (UserAuthenticationEntity entity : authenticationEntities) {
+          if ((entity.getAuthenticationType() == UserAuthenticationType.LDAP) &&
+              ((key == null) ? (entity.getAuthenticationKey() == null) : key.equalsIgnoreCase(entity.getAuthenticationKey()))) {
+            throw new AmbariException("The authentication type already exists for this user");
+          }
+        }
+      }
+    });
+  }
+
+  /**
+   * Worker to add a user authentication methods for a user.
+   *
+   * @param userEntity the user
+   * @param type       the authentication type
+   * @param key        the authentication type specific metadata
+   * @param validator  the authentication type specific validator
+   * @throws AmbariException
+   */
+  private void addAuthentication(UserEntity userEntity, UserAuthenticationType type, String key, Validator validator) throws AmbariException {
+
+    if (userEntity == null) {
+      throw new AmbariException("Missing user");
+    }
+
+    validator.validate(userEntity, key);
+
+    List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+
+    UserAuthenticationEntity authenticationEntity = new UserAuthenticationEntity();
+    authenticationEntity.setUser(userEntity);
+    authenticationEntity.setAuthenticationType(type);
+    authenticationEntity.setAuthenticationKey(key);
+    authenticationEntities.add(authenticationEntity);
+
+    userEntity.setAuthenticationEntities(authenticationEntities);
+    userDAO.merge(userEntity);
+  }
+
+  /**
+   * 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.
+   */
+  private interface Validator {
+    /**
+     * Valudate the authentication type specific key meets the requirments for the relative user
+     * authentication type.
+     *
+     * @param userEntity the user
+     * @param key        the key (or metadata)
+     * @throws AmbariException
+     */
+    void validate(UserEntity userEntity, String key) throws AmbariException;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java
index 383e8fa..c57bdf1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java
@@ -40,7 +40,7 @@ public class AmbariInternalAuthenticationProvider implements AuthenticationProvi
     if (internalTokenStorage.isValidInternalToken(token.getCredentials())) {
       token.setAuthenticated(true);
     } else {
-      throw new InvalidUsernamePasswordCombinationException();
+      throw new InvalidUsernamePasswordCombinationException(null);
     }
     return token;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/AuthenticationJwtUserNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/AuthenticationJwtUserNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/AuthenticationJwtUserNotFoundException.java
deleted file mode 100644
index f18af10..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/AuthenticationJwtUserNotFoundException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.server.security.authorization.jwt;
-
-import org.springframework.security.core.AuthenticationException;
-
-/**
- * AuthenticationJwtUserNotFoundException is an AuthenticationException implementation to be thrown
- * when the user specified in a JTW token is not found in the Ambari user database.
- */
-public class AuthenticationJwtUserNotFoundException extends AuthenticationException {
-  private final String username;
-
-  public AuthenticationJwtUserNotFoundException(String username, String message) {
-    super(message);
-    this.username = username;
-  }
-
-  public AuthenticationJwtUserNotFoundException(String username, String message, Throwable throwable) {
-    super(message, throwable);
-    this.username = username;
-  }
-
-  public String getUsername() {
-    return username;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
index e27afdb..3c3a446 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
@@ -33,11 +33,14 @@ import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter;
+import org.apache.ambari.server.security.authentication.UserNotFoundException;
 import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
-import org.apache.ambari.server.security.authorization.User;
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -116,6 +119,9 @@ public class JwtAuthenticationFilter implements AmbariAuthenticationFilter {
 
   }
 
+  // TODO: ************
+  // TODO: This is to be revisited for AMBARI-21217 (Update JWT Authentication process to work with improved user management facility)
+  // TODO: ************
   @Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 
@@ -138,27 +144,50 @@ public class JwtAuthenticationFilter implements AmbariAuthenticationFilter {
 
           if (valid) {
             String userName = jwtToken.getJWTClaimsSet().getSubject();
-            User user = users.getUser(userName, UserType.JWT);
-            //fixme temporary solution for LDAP username conflicts, auth ldap users via JWT
-            if (user == null) {
-              user = users.getUser(userName, UserType.LDAP);
-            }
+            UserEntity userEntity = users.getUserEntity(userName);
 
-            if (user == null) {
-              //TODO this is temporary check for conflicts, until /users API will change to use user_id instead of name as PK
-              User existingUser = users.getUser(userName, UserType.LOCAL);
-              if (existingUser != null) {
-                LOG.error("Access for JWT user [{}] restricted. Detected conflict with local user ", userName);
+            if (userEntity == null) {
+              //TODO we temporary expect that LDAP is configured to same server as JWT source
+              throw new UserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.");
+            } else {
+              // Check to see if the user is allowed to authenticate using JWT or LDAP
+              Collection<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+              boolean hasJWT = false;
+              boolean hasLDAP = false;
+
+              if (authenticationEntities != null) {
+                for (UserAuthenticationEntity entity : authenticationEntities) {
+                  if (entity.getAuthenticationType() == UserAuthenticationType.JWT) {
+                    // TODO: possibly check the authentication key to see if it is relevant
+                    hasJWT = true;
+                    break;
+                  } else if (entity.getAuthenticationType() == UserAuthenticationType.LDAP) {
+                    hasLDAP = true;
+                  }
+                }
               }
 
-              //TODO we temporary expect that LDAP is configured to same server as JWT source
-              throw new AuthenticationJwtUserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.");
+              if(!hasJWT) {
+                if (hasLDAP) {
+                  // TODO: Determine if LDAP users can authenticate using JWT
+                  try {
+                    users.addJWTAuthentication(userEntity, userName);
+                  } catch (AmbariException e) {
+                    LOG.error(String.format("Failed to add the JWT authentication method for %s: %s", userName, e.getLocalizedMessage()), e);
+                  }
+                  hasJWT = true;
+                }
+              }
+
+              if (!hasJWT) {
+                throw new UserNotFoundException(userName, "User is not authorized to authenticate from JWT. Please, ensure LDAP is configured and users are synced.");
+              }
             }
 
-            Collection<AmbariGrantedAuthority> userAuthorities =
-                users.getUserAuthorities(user.getUserName(), user.getUserType());
+            // If we made it this far, the user was found and is authorized to authenticate via JWT
+            Collection<AmbariGrantedAuthority> userAuthorities = users.getUserAuthorities(userEntity);
 
-            JwtAuthentication authentication = new JwtAuthentication(serializedJWT, user, userAuthorities);
+            JwtAuthentication authentication = new JwtAuthentication(serializedJWT, users.getUser(userEntity), userAuthorities);
             authentication.setAuthenticated(true);
 
             SecurityContextHolder.getContext().setAuthentication(authentication);
@@ -221,11 +250,7 @@ public class JwtAuthenticationFilter implements AmbariAuthenticationFilter {
     }
 
     //always try to authenticate in case of anonymous user
-    if (existingAuth instanceof AnonymousAuthenticationToken) {
-      return true;
-    }
-
-    return false;
+    return (existingAuth instanceof AnonymousAuthenticationToken);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
index f413c69..4e4b1b6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
@@ -429,9 +429,10 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
       String createdUserName = requestScheduleEntity.getCreateUser();
 
       if (createdUserName != null) {
-        User user = users.getUserIfUnique(createdUserName);
+        // NOTE: This class is expected to go away in Ambari 3.0.0. Apache JIRA not available.
+        User user = users.getUser(createdUserName);
 
-        if (user != null && StringUtils.equals(user.getUserName(), createdUserName)) {
+        if (user != null && StringUtils.equalsIgnoreCase(user.getUserName(), createdUserName)) {
           requestScheduleEntity.setAuthenticatedUserId(user.getUserId());
           requestScheduleDAO.merge(requestScheduleEntity);
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index e4045ef..fa8e8ab 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -74,6 +74,7 @@
     <class>org.apache.ambari.server.orm.entities.UpgradeItemEntity</class>
     <class>org.apache.ambari.server.orm.entities.UpgradeHistoryEntity</class>
     <class>org.apache.ambari.server.orm.entities.UserEntity</class>
+    <class>org.apache.ambari.server.orm.entities.UserAuthenticationEntity</class>
     <class>org.apache.ambari.server.orm.entities.WidgetEntity</class>
     <class>org.apache.ambari.server.orm.entities.ViewEntity</class>
     <class>org.apache.ambari.server.orm.entities.ViewEntityEntity</class>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java b/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
index 1b8de79..2b78f79 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
@@ -44,7 +44,7 @@ import org.apache.ambari.server.configuration.Configuration.DatabaseType;
 import org.apache.ambari.server.controller.metrics.ThreadPoolEnabledPropertyProvider;
 import org.apache.ambari.server.security.authentication.kerberos.AmbariKerberosAuthenticationProperties;
 import org.apache.ambari.server.security.authorization.LdapServerProperties;
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.state.services.MetricsRetrievalService;
 import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.io.FileUtils;
@@ -905,7 +905,7 @@ public class ConfigurationTest {
     Assert.assertEquals(keytabFile.getAbsolutePath(), kerberosAuthenticationProperties.getSpnegoKeytabFilePath());
     Assert.assertEquals("spnego/principal@REALM", kerberosAuthenticationProperties.getSpnegoPrincipalName());
     Assert.assertEquals("DEFAULT", kerberosAuthenticationProperties.getAuthToLocalRules());
-    Assert.assertEquals(Arrays.asList(UserType.LDAP, UserType.LOCAL), kerberosAuthenticationProperties.getOrderedUserTypes());
+    Assert.assertEquals(Arrays.asList(UserAuthenticationType.LDAP, UserAuthenticationType.LOCAL), kerberosAuthenticationProperties.getOrderedUserTypes());
   }
 
   /**
@@ -930,7 +930,7 @@ public class ConfigurationTest {
     Assert.assertEquals(keytabFile.getAbsolutePath(), kerberosAuthenticationProperties.getSpnegoKeytabFilePath());
     Assert.assertEquals("HTTP/" + StageUtils.getHostName(), kerberosAuthenticationProperties.getSpnegoPrincipalName());
     Assert.assertEquals("DEFAULT", kerberosAuthenticationProperties.getAuthToLocalRules());
-    Assert.assertEquals(Collections.singletonList(UserType.LDAP), kerberosAuthenticationProperties.getOrderedUserTypes());
+    Assert.assertEquals(Collections.singletonList(UserAuthenticationType.LDAP), kerberosAuthenticationProperties.getOrderedUserTypes());
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index 3215e72..c8eb6d6 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -4547,80 +4547,7 @@ public class AmbariManagementControllerTest {
     assertEquals("", response.getRequestContext());
   }
 
-  private void createUser(String userName) throws Exception {
-    UserRequest request = new UserRequest(userName);
-    request.setPassword("password");
 
-    controller.createUsers(new HashSet<>(Collections.singleton(request)));
-  }
-
-  @Test
-  public void testCreateAndGetUsers() throws Exception {
-    createUser("user1");
-
-    Set<UserResponse> r =
-        controller.getUsers(Collections.singleton(new UserRequest("user1")));
-
-    Assert.assertEquals(1, r.size());
-    UserResponse resp = r.iterator().next();
-    Assert.assertEquals("user1", resp.getUsername());
-  }
-
-  @Test
-  public void testGetUsers() throws Exception {
-    String user1 = getUniqueName();
-    String user2 = getUniqueName();
-    String user3 = getUniqueName();
-    List<String> users = Arrays.asList(user1, user2, user3);
-
-    for (String user : users) {
-      createUser(user);
-    }
-
-    UserRequest request = new UserRequest(null);
-
-    Set<UserResponse> responses = controller.getUsers(Collections.singleton(request));
-
-    // other tests are making user requests, so let's make sure we have the 3 just made
-    List<String> contained = new ArrayList<>();
-    for (UserResponse ur : responses) {
-      if (users.contains(ur.getUsername())) {
-        contained.add(ur.getUsername());
-      }
-    }
-
-    Assert.assertEquals(3, contained.size());
-  }
-
-  @SuppressWarnings("serial")
-  @Test
-  public void testUpdateUsers() throws Exception {
-    String user1 = getUniqueName();
-    createUser(user1);
-
-    UserRequest request = new UserRequest(user1);
-
-    controller.updateUsers(Collections.singleton(request));
-  }
-
-  @SuppressWarnings("serial")
-  @Ignore
-  @Test
-  public void testDeleteUsers() throws Exception {
-    String user1 = getUniqueName();
-    createUser(user1);
-
-    UserRequest request = new UserRequest(user1);
-    controller.updateUsers(Collections.singleton(request));
-
-    request = new UserRequest(user1);
-    controller.deleteUsers(Collections.singleton(request));
-
-    Set<UserResponse> responses = controller.getUsers(
-        Collections.singleton(new UserRequest(null)));
-
-    Assert.assertEquals(0, responses.size());
-  }
 
   @Test
   public void testUpdateConfigForRunningService() throws Exception {

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractPrivilegeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractPrivilegeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractPrivilegeResourceProviderTest.java
deleted file mode 100644
index 547bba5..0000000
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AbstractPrivilegeResourceProviderTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.server.controller.internal;
-
-import org.apache.ambari.server.orm.dao.MemberDAO;
-import org.apache.ambari.server.orm.dao.PrivilegeDAO;
-import org.apache.ambari.server.security.authorization.Users;
-import org.easymock.EasyMockSupport;
-
-class AbstractPrivilegeResourceProviderTest extends EasyMockSupport {
-
-  static class TestUsers extends Users {
-
-    void setPrivilegeDAO(PrivilegeDAO privilegeDAO) {
-      this.privilegeDAO = privilegeDAO;
-    }
-
-    public void setMemberDAO(MemberDAO memberDAO) {
-      this.memberDAO = memberDAO;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProviderTest.java
index 4dc06b9..487c02a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProviderTest.java
@@ -64,7 +64,6 @@ import org.apache.ambari.server.orm.entities.WidgetLayoutUserWidgetEntity;
 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.UserType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.security.encryption.CredentialStoreService;
 import org.apache.ambari.server.security.encryption.CredentialStoreServiceImpl;
@@ -172,7 +171,7 @@ public class ActiveWidgetLayoutResourceProviderTest extends EasyMockSupport {
     UserEntity userEntity = createMockUserEntity(requestedUsername);
 
     UserDAO userDAO = injector.getInstance(UserDAO.class);
-    expect(userDAO.findSingleUserByName(requestedUsername)).andReturn(userEntity).atLeastOnce();
+    expect(userDAO.findUserByName(requestedUsername)).andReturn(userEntity).atLeastOnce();
 
     WidgetLayoutDAO widgetLayoutDAO = injector.getInstance(WidgetLayoutDAO.class);
     expect(widgetLayoutDAO.findById(1L)).andReturn(createMockWidgetLayout(1L, requestedUsername)).atLeastOnce();
@@ -368,7 +367,6 @@ public class ActiveWidgetLayoutResourceProviderTest extends EasyMockSupport {
     UserEntity userEntity = createMock(UserEntity.class);
     expect(userEntity.getUserId()).andReturn(username.hashCode()).anyTimes();
     expect(userEntity.getUserName()).andReturn(username).anyTimes();
-    expect(userEntity.getUserType()).andReturn(UserType.LOCAL).anyTimes();
     expect(userEntity.getActiveWidgetLayouts()).andReturn("[{\"id\":\"1\"},{\"id\":\"2\"}]").anyTimes();
 
     return userEntity;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProviderTest.java
index 36f6a1e..ea981e2 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProviderTest.java
@@ -27,6 +27,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
+import javax.persistence.EntityManager;
+
 import org.apache.ambari.server.controller.GroupPrivilegeResponse;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
@@ -34,6 +36,9 @@ import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.SystemException;
 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.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.GroupDAO;
 import org.apache.ambari.server.orm.dao.PrivilegeDAO;
@@ -52,16 +57,22 @@ import org.apache.ambari.server.security.TestAuthenticationFactory;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
 import org.apache.ambari.server.security.authorization.ResourceType;
 import org.apache.ambari.server.security.authorization.Users;
+import org.easymock.EasyMockSupport;
 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;
 
 import junit.framework.Assert;
 
 /**
  * GroupPrivilegeResourceProvider tests.
  */
-public class GroupPrivilegeResourceProviderTest extends AbstractPrivilegeResourceProviderTest {
+public class GroupPrivilegeResourceProviderTest extends EasyMockSupport{
 
   @Test(expected = SystemException.class)
   public void testCreateResources() throws Exception {
@@ -79,7 +90,7 @@ public class GroupPrivilegeResourceProviderTest extends AbstractPrivilegeResourc
   public void testGetResources_NonAdministrator() throws Exception {
     getResourcesTest(TestAuthenticationFactory.createClusterAdministrator("user1", 2L), "Group1");
   }
-  
+
   @Test(expected = SystemException.class)
   public void testUpdateResources() throws Exception {
     SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createClusterAdministrator("user1", 2L));
@@ -230,7 +241,7 @@ public class GroupPrivilegeResourceProviderTest extends AbstractPrivilegeResourc
     expect(groupEntity.getGroupName()).andReturn("group1").atLeastOnce();
 
     ClusterDAO clusterDAO = createMock(ClusterDAO.class);
-    
+
     ViewInstanceDAO viewInstanceDAO = createMock(ViewInstanceDAO.class);
     expect(viewInstanceDAO.findByResourceId(1L)).andReturn(viewInstanceEntity).atLeastOnce();
 
@@ -328,8 +339,31 @@ public class GroupPrivilegeResourceProviderTest extends AbstractPrivilegeResourc
     final ResourceTypeEntity resourceTypeEntity = createNiceMock(ResourceTypeEntity.class);
     final PrivilegeDAO privilegeDAO = createMock(PrivilegeDAO.class);
 
-    final TestUsers users = new TestUsers();
-    users.setPrivilegeDAO(privilegeDAO);
+    final Injector injector = Guice.createInjector(new AbstractModule() {
+                                                     @Override
+                                                     protected void configure() {
+                                                       bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
+                                                       bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class));
+                                                       bind(PasswordEncoder.class).toInstance(createNiceMock(PasswordEncoder.class));
+                                                       bind(HookService.class).toInstance(createMock(HookService.class));
+                                                       bind(HookContextFactory.class).toInstance(createMock(HookContextFactory.class));
+
+                                                       bind(GroupDAO.class).toInstance(groupDAO);
+                                                       bind(ClusterDAO.class).toInstance(clusterDAO);
+                                                       bind(ViewInstanceDAO.class).toInstance(viewInstanceDAO);
+                                                       bind(GroupEntity.class).toInstance(groupEntity);
+                                                       bind(PrincipalEntity.class).toInstance(principalEntity);
+                                                       bind(PrivilegeEntity.class).toInstance(privilegeEntity);
+                                                       bind(PermissionEntity.class).toInstance(permissionEntity);
+                                                       bind(PrincipalTypeEntity.class).toInstance(principalTypeEntity);
+                                                       bind(ResourceEntity.class).toInstance(resourceEntity);
+                                                       bind(ResourceTypeEntity.class).toInstance(resourceTypeEntity);
+                                                       bind(PrivilegeDAO.class).toInstance(privilegeDAO);
+                                                     }
+                                                   }
+    );
+
+    final Users users = injector.getInstance(Users.class);
 
     List<PrincipalEntity> groupPrincipals = new LinkedList<>();
     groupPrincipals.add(principalEntity);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java
index 9ccbc11..499354f 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProviderTest.java
@@ -28,6 +28,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
+import javax.persistence.EntityManager;
+
 import org.apache.ambari.server.controller.UserPrivilegeResponse;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
@@ -35,6 +37,9 @@ import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.SystemException;
 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.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.GroupDAO;
 import org.apache.ambari.server.orm.dao.MemberDAO;
@@ -56,16 +61,22 @@ import org.apache.ambari.server.security.TestAuthenticationFactory;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
 import org.apache.ambari.server.security.authorization.ResourceType;
 import org.apache.ambari.server.security.authorization.Users;
+import org.easymock.EasyMockSupport;
 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;
 
 import junit.framework.Assert;
 
 /**
  * UserPrivilegeResourceProvider tests.
  */
-public class UserPrivilegeResourceProviderTest extends AbstractPrivilegeResourceProviderTest {
+public class UserPrivilegeResourceProviderTest extends EasyMockSupport {
 
   @Test(expected = SystemException.class)
   public void testCreateResources() throws Exception {
@@ -334,45 +345,56 @@ public class UserPrivilegeResourceProviderTest extends AbstractPrivilegeResource
   public void testToResource_SpecificVIEW_WithClusterInheritedPermission() throws Exception {
     SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createClusterAdministrator("jdoe", 2L));
 
-    PrincipalTypeEntity rolePrincipalTypeEntity = createMock(PrincipalTypeEntity.class);
+    Injector injector = createInjector();
+
+    final UserPrivilegeResourceProvider resourceProvider = new UserPrivilegeResourceProvider();
+    final UserDAO userDAO = injector.getInstance(UserDAO.class);
+    final GroupDAO groupDAO = injector.getInstance(GroupDAO.class);
+    final ClusterDAO clusterDAO = injector.getInstance(ClusterDAO.class);
+    final ViewInstanceDAO viewInstanceDAO = injector.getInstance(ViewInstanceDAO.class);
+    final PrivilegeDAO privilegeDAO = injector.getInstance(PrivilegeDAO.class);
+    final MemberDAO memberDAO = injector.getInstance(MemberDAO.class);
+
+
+    final PrincipalTypeEntity rolePrincipalTypeEntity = createMock(PrincipalTypeEntity.class);
     expect(rolePrincipalTypeEntity.getName()).andReturn("ROLE").atLeastOnce();
 
-    PrincipalEntity rolePrincipalEntity = createMock(PrincipalEntity.class);
+    final PrincipalEntity rolePrincipalEntity = createMock(PrincipalEntity.class);
     expect(rolePrincipalEntity.getPrincipalType()).andReturn(rolePrincipalTypeEntity).atLeastOnce();
 
-    PermissionEntity permissionEntity = createMock(PermissionEntity.class);
+    final PermissionEntity permissionEntity = createMock(PermissionEntity.class);
     expect(permissionEntity.getPrincipal()).andReturn(rolePrincipalEntity).atLeastOnce();
     expect(permissionEntity.getPermissionName()).andReturn("CLUSTER.ADMINISTRATOR").atLeastOnce();
     expect(permissionEntity.getPermissionLabel()).andReturn("Cluster Administrator").atLeastOnce();
 
-    PrincipalTypeEntity principalTypeEntity = createMock(PrincipalTypeEntity.class);
+    final PrincipalTypeEntity principalTypeEntity = createMock(PrincipalTypeEntity.class);
     expect(principalTypeEntity.getName()).andReturn("USER").atLeastOnce();
 
-    PrincipalEntity principalEntity = createMock(PrincipalEntity.class);
+    final PrincipalEntity principalEntity = createMock(PrincipalEntity.class);
     expect(principalEntity.getPrincipalType()).andReturn(principalTypeEntity).atLeastOnce();
 
-    ViewEntity viewEntity = createMock(ViewEntity.class);
+    final ViewEntity viewEntity = createMock(ViewEntity.class);
     expect(viewEntity.getCommonName()).andReturn("TestView").atLeastOnce();
     expect(viewEntity.getVersion()).andReturn("1.2.3.4").atLeastOnce();
 
-    ResourceTypeEntity resourceTypeEntity = createMock(ResourceTypeEntity.class);
+    final ResourceTypeEntity resourceTypeEntity = createMock(ResourceTypeEntity.class);
     expect(resourceTypeEntity.getName()).andReturn("TestView{1.2.3.4}").atLeastOnce();
 
-    ResourceEntity resourceEntity = createMock(ResourceEntity.class);
+    final ResourceEntity resourceEntity = createMock(ResourceEntity.class);
     expect(resourceEntity.getId()).andReturn(1L).anyTimes();
     expect(resourceEntity.getResourceType()).andReturn(resourceTypeEntity).anyTimes();
 
-    ViewInstanceEntity viewInstanceEntity = createMock(ViewInstanceEntity.class);
+    final ViewInstanceEntity viewInstanceEntity = createMock(ViewInstanceEntity.class);
     expect(viewInstanceEntity.getViewEntity()).andReturn(viewEntity).atLeastOnce();
     expect(viewInstanceEntity.getName()).andReturn("Test View").atLeastOnce();
 
-    PrivilegeEntity explicitPrivilegeEntity = createMock(PrivilegeEntity.class);
+    final PrivilegeEntity explicitPrivilegeEntity = createMock(PrivilegeEntity.class);
     expect(explicitPrivilegeEntity.getId()).andReturn(1).atLeastOnce();
     expect(explicitPrivilegeEntity.getPermission()).andReturn(permissionEntity).atLeastOnce();
     expect(explicitPrivilegeEntity.getPrincipal()).andReturn(principalEntity).atLeastOnce();
     expect(explicitPrivilegeEntity.getResource()).andReturn(resourceEntity).atLeastOnce();
 
-    PrivilegeEntity implicitPrivilegeEntity = createMock(PrivilegeEntity.class);
+    final PrivilegeEntity implicitPrivilegeEntity = createMock(PrivilegeEntity.class);
     expect(implicitPrivilegeEntity.getId()).andReturn(2).atLeastOnce();
     expect(implicitPrivilegeEntity.getPermission()).andReturn(permissionEntity).atLeastOnce();
     expect(implicitPrivilegeEntity.getPrincipal()).andReturn(rolePrincipalEntity).atLeastOnce();
@@ -382,23 +404,13 @@ public class UserPrivilegeResourceProviderTest extends AbstractPrivilegeResource
     expect(userEntity.getUserName()).andReturn("jdoe").atLeastOnce();
     expect(userEntity.getPrincipal()).andReturn(principalEntity).atLeastOnce();
 
-    ClusterDAO clusterDAO = createMock(ClusterDAO.class);
-    GroupDAO groupDAO = createMock(GroupDAO.class);
-
-    ViewInstanceDAO viewInstanceDAO = createMock(ViewInstanceDAO.class);
     expect(viewInstanceDAO.findByResourceId(1L)).andReturn(viewInstanceEntity).atLeastOnce();
 
-    final UserDAO userDAO = createNiceMock(UserDAO.class);
-    expect(userDAO.findLocalUserByName("jdoe")).andReturn(userEntity).anyTimes();
+    expect(userDAO.findUserByName("jdoe")).andReturn(userEntity).anyTimes();
     expect(userDAO.findUserByPrincipal(anyObject(PrincipalEntity.class))).andReturn(userEntity).anyTimes();
     expect(userDAO.findAll()).andReturn(Collections.<UserEntity>emptyList()).anyTimes();
 
-    final PrivilegeDAO privilegeDAO = createMock(PrivilegeDAO.class);
-    final MemberDAO memberDAO = createMock(MemberDAO.class);
-
-    final TestUsers users = new TestUsers();
-    users.setPrivilegeDAO(privilegeDAO);
-    users.setMemberDAO(memberDAO);
+    final Users users = injector.getInstance(Users.class);
 
     List<PrincipalEntity> rolePrincipals = new LinkedList<>();
     rolePrincipals.add(rolePrincipalEntity);
@@ -422,9 +434,9 @@ public class UserPrivilegeResourceProviderTest extends AbstractPrivilegeResource
     final Set<String> propertyIds = new HashSet<>();
     propertyIds.add(UserPrivilegeResourceProvider.PRIVILEGE_USER_NAME_PROPERTY_ID);
     final Predicate predicate = new PredicateBuilder()
-      .property(UserPrivilegeResourceProvider.PRIVILEGE_USER_NAME_PROPERTY_ID)
-      .equals("jdoe")
-      .toPredicate();
+        .property(UserPrivilegeResourceProvider.PRIVILEGE_USER_NAME_PROPERTY_ID)
+        .equals("jdoe")
+        .toPredicate();
     TestAuthenticationFactory.createClusterAdministrator("jdoe", 2L);
     Request request = PropertyHelper.getReadRequest(propertyIds);
 
@@ -443,11 +455,16 @@ public class UserPrivilegeResourceProviderTest extends AbstractPrivilegeResource
 
   //  @SuppressWarnings("serial")
   private void getResourcesTest(Authentication authentication, String requestedUsername) throws Exception {
+    Injector injector = createInjector();
+
     final UserPrivilegeResourceProvider resourceProvider = new UserPrivilegeResourceProvider();
-    final UserDAO userDAO = createNiceMock(UserDAO.class);
-    final GroupDAO groupDAO = createNiceMock(GroupDAO.class);
-    final ClusterDAO clusterDAO = createNiceMock(ClusterDAO.class);
-    final ViewInstanceDAO viewInstanceDAO = createNiceMock(ViewInstanceDAO.class);
+    final UserDAO userDAO = injector.getInstance(UserDAO.class);
+    final GroupDAO groupDAO = injector.getInstance(GroupDAO.class);
+    final ClusterDAO clusterDAO = injector.getInstance(ClusterDAO.class);
+    final ViewInstanceDAO viewInstanceDAO = injector.getInstance(ViewInstanceDAO.class);
+    final PrivilegeDAO privilegeDAO = injector.getInstance(PrivilegeDAO.class);
+    final MemberDAO memberDAO = injector.getInstance(MemberDAO.class);
+
     final UserEntity userEntity = createNiceMock(UserEntity.class);
     final PrincipalEntity principalEntity = createNiceMock(PrincipalEntity.class);
     final PrivilegeEntity privilegeEntity = createNiceMock(PrivilegeEntity.class);
@@ -455,12 +472,8 @@ public class UserPrivilegeResourceProviderTest extends AbstractPrivilegeResource
     final PrincipalTypeEntity principalTypeEntity = createNiceMock(PrincipalTypeEntity.class);
     final ResourceEntity resourceEntity = createNiceMock(ResourceEntity.class);
     final ResourceTypeEntity resourceTypeEntity = createNiceMock(ResourceTypeEntity.class);
-    final PrivilegeDAO privilegeDAO = createMock(PrivilegeDAO.class);
-    final MemberDAO memberDAO = createMock(MemberDAO.class);
 
-    final TestUsers users = new TestUsers();
-    users.setPrivilegeDAO(privilegeDAO);
-    users.setMemberDAO(memberDAO);
+    final Users users = injector.getInstance(Users.class);
 
     List<PrincipalEntity> userPrincipals = new LinkedList<>();
     userPrincipals.add(principalEntity);
@@ -471,7 +484,7 @@ public class UserPrivilegeResourceProviderTest extends AbstractPrivilegeResource
     expect(memberDAO.findAllMembersByUser(userEntity)).
         andReturn(Collections.<MemberEntity>emptyList())
         .atLeastOnce();
-    expect(userDAO.findLocalUserByName(requestedUsername)).andReturn(userEntity).anyTimes();
+    expect(userDAO.findUserByName(requestedUsername)).andReturn(userEntity).anyTimes();
     expect(userDAO.findAll()).andReturn(Collections.<UserEntity>emptyList()).anyTimes();
     expect(userEntity.getPrincipal()).andReturn(principalEntity).anyTimes();
     expect(userEntity.getMemberEntities()).andReturn(Collections.<MemberEntity>emptySet()).anyTimes();
@@ -518,4 +531,24 @@ public class UserPrivilegeResourceProviderTest extends AbstractPrivilegeResource
     verifyAll();
   }
 
+  private Injector createInjector() {
+    return Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
+        bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class));
+        bind(PasswordEncoder.class).toInstance(createNiceMock(PasswordEncoder.class));
+        bind(HookService.class).toInstance(createMock(HookService.class));
+        bind(HookContextFactory.class).toInstance(createMock(HookContextFactory.class));
+
+        bind(UserDAO.class).toInstance(createNiceMock(UserDAO.class));
+        bind(GroupDAO.class).toInstance(createNiceMock(GroupDAO.class));
+        bind(ClusterDAO.class).toInstance(createNiceMock(ClusterDAO.class));
+        bind(ViewInstanceDAO.class).toInstance(createNiceMock(ViewInstanceDAO.class));
+        bind(PrivilegeDAO.class).toInstance(createMock(PrivilegeDAO.class));
+        bind(MemberDAO.class).toInstance(createMock(MemberDAO.class));
+      }
+    });
+  }
+
 }


[4/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
index 1e4f6ea..261b94e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
@@ -19,19 +19,21 @@
 package org.apache.ambari.server.security.authentication.kerberos;
 
 import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authentication.AuthenticationMethodNotAllowedException;
+import org.apache.ambari.server.security.authentication.UserNotFoundException;
+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.hadoop.security.authentication.util.KerberosName;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.userdetails.User;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
@@ -47,8 +49,6 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
 
   private final Users users;
 
-  private final List<UserType> userTypeOrder;
-
   private final String authToLocalRules;
 
   /**
@@ -63,14 +63,12 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
    */
   public AmbariAuthToLocalUserDetailsService(Configuration configuration, Users users) throws AmbariException {
     String authToLocalRules = null;
-    List<UserType> orderedUserTypes = null;
 
     if (configuration != null) {
       AmbariKerberosAuthenticationProperties properties = configuration.getKerberosAuthenticationProperties();
 
       if (properties != null) {
         authToLocalRules = properties.getAuthToLocalRules();
-        orderedUserTypes = properties.getOrderedUserTypes();
       }
     }
 
@@ -78,12 +76,7 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
       authToLocalRules = "DEFAULT";
     }
 
-    if ((orderedUserTypes == null) || orderedUserTypes.isEmpty()) {
-      orderedUserTypes = Collections.singletonList(UserType.LDAP);
-    }
-
     this.users = users;
-    this.userTypeOrder = orderedUserTypes;
     this.authToLocalRules = authToLocalRules;
   }
 
@@ -107,7 +100,9 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
       }
 
       LOG.info("Translated {} to {} using auth-to-local rules during Kerberos authentication.", principal, username);
-      return createUser(username);
+      return createUser(username, principal);
+    } catch (UserNotFoundException e) {
+      throw new UsernameNotFoundException(e.getMessage(), e);
     } catch (IOException e) {
       String message = String.format("Failed to translate %s to a local username during Kerberos authentication: %s", principal, e.getLocalizedMessage());
       LOG.warn(message);
@@ -121,26 +116,83 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
    * User accounts are searched in order of preferred user type as specified in the Ambari configuration
    * ({@link Configuration#KERBEROS_AUTH_USER_TYPES}).
    *
-   * @param username a username
+   * @param username  a username
+   * @param principal the user's principal
    * @return the user details of the found user, or <code>null</code> if an appropriate user was not found
    */
-  private UserDetails createUser(String username) {
-    // Iterate over the ordered user types... when an account for the username/type combination is
-    // found, build the related AmbariUserAuthentication instance and return it.  Only the first
-    // match matters... this may be an issue and cause some ambiguity in the event multiple user
-    // types are specified in the configuration and multiple accounts for the same username, but
-    // different types (LOCAL vs LDAP, etc...).
-    for (UserType userType : userTypeOrder) {
-      org.apache.ambari.server.security.authorization.User user = users.getUser(username, userType);
-
-      if (user != null) {
-        Collection<AmbariGrantedAuthority> userAuthorities = users.getUserAuthorities(user.getUserName(), user.getUserType());
-        return new User(username, "", userAuthorities);
+  private UserDetails createUser(String username, String principal) throws AuthenticationException {
+    UserEntity userEntity = users.getUserEntity(username);
+
+    if (userEntity == null) {
+      throw new UserNotFoundException(username, String.format("Cannot find user using Kerberos ticket (%s).", principal));
+    } else if (!userEntity.getActive()) {
+      LOG.debug("User account is disabled");
+      throw new UserNotFoundException(username, "User account is disabled");
+    } else {
+
+      // Check to see if the user is allowed to authenticate using KERBEROS or LDAP
+      List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+      boolean hasKerberos = false;
+      boolean hasLDAP = false;
+      boolean hasLocal = false;
+
+      for (UserAuthenticationEntity entity : authenticationEntities) {
+        UserAuthenticationType authenticationType = entity.getAuthenticationType();
+
+        switch (authenticationType) {
+          case KERBEROS:
+            if (principal.equalsIgnoreCase(entity.getAuthenticationKey())) {
+              LOG.trace("Found KERBEROS authentication method for {} using principal {}", username, principal);
+              hasKerberos = true;
+            }
+            break;
+
+          case LDAP:
+            hasLDAP = true;
+            break;
+
+          case LOCAL:
+            hasLocal = true;
+            break;
+
+          default:
+            break;
+        }
+
+        if (hasKerberos) {
+          break;
+        }
+      }
+
+      if (!hasKerberos) {
+        if (hasLDAP) {
+          // TODO: Determine if LDAP users can authenticate using Kerberos
+          try {
+            users.addKerberosAuthentication(userEntity, principal);
+            LOG.trace("Added KERBEROS authentication method for {} using principal {}", username, principal);
+          } catch (AmbariException e) {
+            LOG.error(String.format("Failed to add the KERBEROS authentication method for %s: %s", principal, e.getLocalizedMessage()), e);
+          }
+          hasKerberos = true;
+        }
+
+        if (!hasKerberos && hasLocal) {
+          // TODO: Determine if LOCAL users can authenticate using Kerberos
+          try {
+            users.addKerberosAuthentication(userEntity, username);
+            LOG.trace("Added KERBEROS authentication method for {} using principal {}", username, principal);
+          } catch (AmbariException e) {
+            LOG.error(String.format("Failed to add the KERBEROS authentication method for %s: %s", username, e.getLocalizedMessage()), e);
+          }
+          hasKerberos = true;
+        }
+      }
+
+      if (!hasKerberos) {
+        throw new AuthenticationMethodNotAllowedException(username, UserAuthenticationType.KERBEROS);
       }
     }
 
-    String message = String.format("Failed find user account for user with username of %s during Kerberos authentication.", username);
-    LOG.warn(message);
-    throw new UsernameNotFoundException(message);
+    return new User(username, "", users.getUserAuthorities(userEntity));
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java
index 09422e5..3e31e0d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 
 /**
  * AmbariKerberosAuthenticationProperties is a container for Kerberos authentication-related
@@ -51,10 +51,10 @@ public class AmbariKerberosAuthenticationProperties {
   private String spnegoKeytabFilePath = null;
 
   /**
-   * A list of {@link UserType}s in order of preference for use when looking up user accounts in the
+   * A list of {@link UserAuthenticationType}s in order of preference for use when looking up user accounts in the
    * Ambari database
    */
-  private List<UserType> orderedUserTypes = Collections.emptyList();
+  private List<UserAuthenticationType> orderedUserTypes = Collections.emptyList();
 
   /**
    * Auth-to-local rules to use to feed to an auth-to-local rules processor used to translate
@@ -119,11 +119,11 @@ public class AmbariKerberosAuthenticationProperties {
   }
 
   /**
-   * Sets the list of {@link UserType}s (in preference order) to use to look up uer accounts in the Ambari database.
+   * Sets the list of {@link UserAuthenticationType}s (in preference order) to use to look up uer accounts in the Ambari database.
    *
-   * @param orderedUserTypes a list of {@link UserType}s
+   * @param orderedUserTypes a list of {@link UserAuthenticationType}s
    */
-  public void setOrderedUserTypes(List<UserType> orderedUserTypes) {
+  public void setOrderedUserTypes(List<UserAuthenticationType> orderedUserTypes) {
     if (orderedUserTypes == null) {
       this.orderedUserTypes = Collections.emptyList();
     } else {
@@ -132,11 +132,11 @@ public class AmbariKerberosAuthenticationProperties {
   }
 
   /**
-   * Gets the list of {@link UserType}s (in preference order) to use to look up uer accounts in the Ambari database.
+   * Gets the list of {@link UserAuthenticationType}s (in preference order) to use to look up uer accounts in the Ambari database.
    *
-   * @return a list of {@link UserType}s
+   * @return a list of {@link UserAuthenticationType}s
    */
-  public List<UserType> getOrderedUserTypes() {
+  public List<UserAuthenticationType> getOrderedUserTypes() {
     return orderedUserTypes;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
index ce9a790..a31e951 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
@@ -300,7 +300,7 @@ public class AmbariAuthorizationFilter implements Filter {
       String username = configuration.getDefaultApiAuthenticatedUser();
 
       if (!StringUtils.isEmpty(username)) {
-        final User user = users.getUser(username, UserType.LOCAL);
+        final User user = users.getUser(username);
 
         if (user != null) {
           Principal principal = new Principal() {
@@ -311,7 +311,7 @@ public class AmbariAuthorizationFilter implements Filter {
           };
 
           defaultUser = new UsernamePasswordAuthenticationToken(principal, null,
-              users.getUserAuthorities(user.getUserName(), user.getUserType()));
+              users.getUserAuthorities(user.getUserName()));
         }
       }
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
index b7ff297..6137b68 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.dao.UserDAO;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.ClientSecurityType;
 import org.slf4j.Logger;
@@ -61,6 +62,9 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
     this.userDAO = userDAO;
   }
 
+  // TODO: ************
+  // TODO: This is to be revisited for AMBARI-21219 (Update LDAP Authentication process to work with improved user management facility)
+  // TODO: ************
   @Override
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
     if (isLdapEnabled()) {
@@ -100,7 +104,6 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
     } else {
       return null;
     }
-
   }
 
   @Override
@@ -196,7 +199,7 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
   private Integer getUserId(Authentication authentication) {
     String userName = AuthorizationHelper.resolveLoginAliasToUserName(authentication.getName());
 
-    UserEntity userEntity = userDAO.findLdapUserByName(userName);
+    UserEntity userEntity = userDAO.findUserByName(userName);
 
     // lookup is case insensitive, so no need for string comparison
     if (userEntity == null) {
@@ -206,11 +209,19 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
 
     if (!userEntity.getActive()) {
       LOG.debug("User account is disabled ('{}')", userName);
+    } else {
+      List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+      for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+        if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LDAP) {
+          // TODO: Ensure this is the "correct" LDAP entry..
+          return userEntity.getUserId();
+        }
+      }
 
-      throw new InvalidUsernamePasswordCombinationException();
+      LOG.debug("Failed to find LDAP authentication entry for {})", userName);
     }
 
-    return userEntity.getUserId();
+    throw new InvalidUsernamePasswordCombinationException();
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
index d38d44c..5c482a1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
@@ -64,7 +64,7 @@ public class AmbariLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
 
     UserEntity user;
 
-    user = userDAO.findLdapUserByName(username);
+    user = userDAO.findUserByName(username);
     
     if (user == null) {
       log.error("Can't get authorities for user " + username + ", he is not present in local DB");

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
index 37d5d49..517efe4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
@@ -17,9 +17,10 @@
  */
 package org.apache.ambari.server.security.authorization;
 
-import java.util.Collection;
+import java.util.List;
 
 import org.apache.ambari.server.orm.dao.UserDAO;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,47 +53,52 @@ public class AmbariLocalUserProvider extends AbstractUserDetailsAuthenticationPr
     // do nothing
   }
 
+  // TODO: ************
+  // TODO: This is to be revisited for AMBARI-21220 (Update Local Authentication process to work with improved user management facility)
+  // TODO: ************
   @Override
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
     String userName = authentication.getName().trim();
 
     LOG.info("Loading user by name: " + userName);
 
-    UserEntity userEntity = userDAO.findLocalUserByName(userName);
+    UserEntity userEntity = userDAO.findUserByName(userName);
 
     if (userEntity == null) {
-      //TODO case insensitive name comparison is a temporary solution, until users API will change to use id as PK
       LOG.info("user not found");
       throw new InvalidUsernamePasswordCombinationException();
     }
 
     if (!userEntity.getActive()) {
-      logger.debug("User account is disabled");
-
+      LOG.debug("User account is disabled");
       throw new InvalidUsernamePasswordCombinationException();
     }
 
     if (authentication.getCredentials() == null) {
-      logger.debug("Authentication failed: no credentials provided");
-
+      LOG.debug("Authentication failed: no credentials provided");
       throw new InvalidUsernamePasswordCombinationException();
     }
 
-    String password = userEntity.getUserPassword();
-    String presentedPassword = authentication.getCredentials().toString();
-
-    if (!passwordEncoder.matches(presentedPassword, password)) {
-      logger.debug("Authentication failed: password does not match stored value");
-
-      throw new InvalidUsernamePasswordCombinationException();
+    List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+    for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+      if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LOCAL) {
+        // This should only get invoked once...
+        String password = authenticationEntity.getAuthenticationKey();
+        String presentedPassword = authentication.getCredentials().toString();
+
+        if (passwordEncoder.matches(presentedPassword, password)) {
+          // The user was  authenticated, return the authenticated user object
+          User user = new User(userEntity);
+          Authentication auth = new AmbariUserAuthentication(password, user, users.getUserAuthorities(userEntity));
+          auth.setAuthenticated(true);
+          return auth;
+        }
+      }
     }
-    Collection<AmbariGrantedAuthority> userAuthorities =
-      users.getUserAuthorities(userEntity.getUserName(), userEntity.getUserType());
 
-    User user = new User(userEntity);
-    Authentication auth = new AmbariUserAuthentication(userEntity.getUserPassword(), user, userAuthorities);
-    auth.setAuthenticated(true);
-    return auth;
+    // The user was not authenticated, fail
+    LOG.debug("Authentication failed: password does not match stored value");
+    throw new InvalidUsernamePasswordCombinationException();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java
index 373552e..b9bcff6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java
@@ -17,7 +17,6 @@
  */
 package org.apache.ambari.server.security.authorization;
 
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -51,9 +50,9 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
   @Inject
   private Users users;
   @Inject
-  protected UserDAO userDAO;
+  private UserDAO userDAO;
   @Inject
-  protected GroupDAO groupDAO;
+  private GroupDAO groupDAO;
 
   private static final Logger LOG = LoggerFactory.getLogger(AmbariPamAuthenticationProvider.class);
 
@@ -64,97 +63,70 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
     this.configuration = configuration;
   }
 
-  /**
-   * Performs PAM Initialization
-   *
-   * @param authentication
-   * @return authentication
-   */
-
+  // TODO: ************
+  // TODO: This is to be revisited for AMBARI-21221 (Update Pam Authentication process to work with improved user management facility)
+  // TODO: ************
   @Override
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
-      if(isPamEnabled()){
-        PAM pam;
-        String userName = String.valueOf(authentication.getPrincipal());
-        UserEntity existingUser = userDAO.findUserByName(userName);
-        if ((existingUser != null) && (existingUser.getUserType() != UserType.PAM)) {
-          String errorMsg = String.format("%s user exists with the username %s. Cannot authenticate via PAM", existingUser.getUserType(), userName);
-          LOG.error(errorMsg);
-          return null;
-        }
-        try{
-          //Set PAM configuration file (found under /etc/pam.d)
-          String pamConfig = configuration.getPamConfigurationFile();
-          pam = new PAM(pamConfig);
-
-        } catch(PAMException ex) {
-          LOG.error("Unable to Initialize PAM." + ex.getMessage());
-          throw new AuthenticationServiceException("Unable to Initialize PAM - ", ex);
-        }
+    if (isPamEnabled()) {
+      //Set PAM configuration file (found under /etc/pam.d)
+      String pamConfig = configuration.getPamConfigurationFile();
+      PAM pam;
 
+      try {
+        //Set PAM configuration file (found under /etc/pam.d)
+        pam = new PAM(pamConfig);
+
+      } catch (PAMException ex) {
+        LOG.error("Unable to Initialize PAM: " + ex.getMessage(), ex);
+        throw new AuthenticationServiceException("Unable to Initialize PAM - ", ex);
+      }
+
+      try {
         return authenticateViaPam(pam, authentication);
+      } finally {
+        pam.dispose();
+      }
     } else {
-       return null;
+      return null;
     }
   }
 
-  /**
-   * Performs PAM Authentication
-   *
-   * @param pam
-   * @param authentication
-   * @return authentication
-   */
-
-  protected Authentication authenticateViaPam(PAM pam, Authentication authentication) throws AuthenticationException{
-    if(isPamEnabled()){
-      try {
-          String userName = String.valueOf(authentication.getPrincipal());
-          String passwd = String.valueOf(authentication.getCredentials());
-
-          // authenticate using PAM
-          UnixUser unixUser = pam.authenticate(userName,passwd);
-
-          //Get all the groups that user belongs to
-          //Change all group names to lower case.
-          Set<String> groups = new HashSet<>();
-
-          for(String group: unixUser.getGroups()){
-            groups.add(group.toLowerCase());
-          }
-
-          ambariPamAuthorization(userName,groups);
+  @Override
+  public boolean supports(Class<?> authentication) {
+    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
+  }
 
-          Collection<AmbariGrantedAuthority> userAuthorities =
-              users.getUserAuthorities(userName, UserType.PAM);
+  Authentication authenticateViaPam(PAM pam, Authentication authentication) {
+    String userName = String.valueOf(authentication.getPrincipal());
+    String password = String.valueOf(authentication.getCredentials());
 
-          final User user = users.getUser(userName, UserType.PAM);
- 
-          Authentication authToken = new AmbariUserAuthentication(passwd, user, userAuthorities);
-          authToken.setAuthenticated(true);
-          return authToken;   
-        } catch (PAMException ex) {
-          LOG.error("Unable to sign in. Invalid username/password combination - " + ex.getMessage());
-          Throwable t = ex.getCause();
-          throw new PamAuthenticationException("Unable to sign in. Invalid username/password combination.",t);
+    UnixUser unixUser;
+    try {
+      // authenticate using PAM
+      unixUser = pam.authenticate(userName, password);
+    } catch (PAMException ex) {
+      LOG.error("Unable to sign in. Invalid username/password combination - " + ex.getMessage());
+      Throwable t = ex.getCause();
+      throw new PamAuthenticationException("Unable to sign in. Invalid username/password combination.", t);
+    }
 
-        } finally {
-          pam.dispose();
-        }
+    if (unixUser != null) {
+      UserEntity userEntity = ambariPamAuthorization(unixUser);
 
+      if (userEntity != null) {
+        Authentication authToken = new AmbariUserAuthentication(password, users.getUser(userEntity), users.getUserAuthorities(userEntity));
+        authToken.setAuthenticated(true);
+        return authToken;
       }
-      else {
-        return null;
-      }
-  }
+    }
 
-  @Override
-  public boolean supports(Class<?> authentication) {
-    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
+    return null;
   }
 
   /**
    * Check if PAM authentication is enabled in server properties
+   *
    * @return true if enabled
    */
   private boolean isPamEnabled() {
@@ -163,6 +135,7 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
 
   /**
    * Check if PAM authentication is enabled in server properties
+   *
    * @return true if enabled
    */
   private boolean isAutoGroupCreationAllowed() {
@@ -173,56 +146,64 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
   /**
    * Performs PAM authorization by creating user & group(s)
    *
-   * @param userName user name
-   * @param userGroups Collection of groups
-   * @return
+   * @param unixUser the user
    */
-  private void ambariPamAuthorization(String userName,Set<String> userGroups){
+  private UserEntity ambariPamAuthorization(UnixUser unixUser) {
+    String userName = unixUser.getUserName();
+    UserEntity userEntity = null;
+
     try {
-      User existingUser = users.getUser(userName,UserType.PAM);
+      userEntity = userDAO.findUserByName(userName);
 
-      if (existingUser == null ) {
-        users.createUser(userName, null, UserType.PAM, true, false);
+      // TODO: Ensure automatically creating users when authenticating with PAM is allowed.
+      if (userEntity == null) {
+        userEntity = users.createUser(userName, userName, userName);
+        users.addPamAuthentication(userEntity, userName);
       }
 
-      UserEntity userEntity = userDAO.findUserByNameAndType(userName, UserType.PAM);
-
-      if(isAutoGroupCreationAllowed()){
-        for(String userGroup: userGroups){
-          if(users.getGroupByNameAndType(userGroup, GroupType.PAM) == null){
-            users.createGroup(userGroup, GroupType.PAM);
-          }
-
-          final GroupEntity groupEntity = groupDAO.findGroupByNameAndType(userGroup, GroupType.PAM);
-
-          if (!isUserInGroup(userEntity, groupEntity)){
-            users.addMemberToGroup(userGroup,userName);
+      if (isAutoGroupCreationAllowed()) {
+        //Get all the groups that user belongs to
+        //Change all group names to lower case.
+        Set<String> unixUserGroups = unixUser.getGroups();
+        if (unixUserGroups != null) {
+          for (String group : unixUserGroups) {
+            // Ensure group name is lowercase
+            group = group.toLowerCase();
+
+            GroupEntity groupEntity = groupDAO.findGroupByNameAndType(group, GroupType.PAM);
+            if (groupEntity == null) {
+              groupEntity = users.createGroup(group, GroupType.PAM);
+            }
+
+            if (!isUserInGroup(userEntity, groupEntity)) {
+              users.addMemberToGroup(groupEntity, userEntity);
+            }
           }
         }
 
-        Set<String> ambariUserGroups = getUserGroups(userName, UserType.PAM);
-
-        for(String group: ambariUserGroups){
-          if(userGroups == null || !userGroups.contains(group)){
-            users.removeMemberFromGroup(group, userName);
+        Set<GroupEntity> ambariUserGroups = getUserGroups(userEntity);
+        for (GroupEntity groupEntity : ambariUserGroups) {
+          if (unixUserGroups == null || !unixUserGroups.contains(groupEntity.getGroupName())) {
+            users.removeMemberFromGroup(groupEntity, userEntity);
           }
         }
       }
-
     } catch (AmbariException e) {
       e.printStackTrace();
     }
+
+    return userEntity;
   }
 
   /**
    * Performs a check if given user belongs to given group.
    *
-   * @param userEntity user entity
+   * @param userEntity  user entity
    * @param groupEntity group entity
    * @return true if user presents in group
    */
   private boolean isUserInGroup(UserEntity userEntity, GroupEntity groupEntity) {
-    for (MemberEntity memberEntity: userEntity.getMemberEntities()) {
+    for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
       if (memberEntity.getGroup().equals(groupEntity)) {
         return true;
       }
@@ -233,17 +214,20 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
   /**
    * Extracts all groups a user belongs to
    *
-   * @param userName user name
+   * @param userEntity the user
    * @return Collection of group names
    */
-  private Set<String> getUserGroups(String userName, UserType userType) {
-    UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
-    Set<String> groups = new HashSet<>();
-    for (MemberEntity memberEntity: userEntity.getMemberEntities()) {
-      groups.add(memberEntity.getGroup().getGroupName());
+  private Set<GroupEntity> getUserGroups(UserEntity userEntity) {
+    Set<GroupEntity> groups = new HashSet<>();
+    if (userEntity != null) {
+      for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
+        GroupEntity groupEntity = memberEntity.getGroup();
+        if (groupEntity.getGroupType() == GroupType.PAM) {
+          groups.add(memberEntity.getGroup());
+        }
+      }
     }
 
     return groups;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
index 95e90b3..8fbd816 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
@@ -30,6 +30,7 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
 import org.apache.ambari.server.security.authorization.internal.InternalTokenClientFilter;
 import org.apache.ambari.server.security.authorization.internal.InternalTokenStorage;
@@ -70,18 +71,18 @@ public class AmbariUserAuthorizationFilter implements Filter {
             return;
           }
           Integer userId = Integer.parseInt(userToken);
-          User user = users.getUser(userId);
-          if (user == null) {
+          UserEntity userEntity = users.getUserEntity(userId);
+          if (userEntity == null) {
             httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Authentication required");
             httpResponse.flushBuffer();
             return;
-          } if (!user.isActive()) {
+          } if (!userEntity.getActive()) {
             httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not active");
             httpResponse.flushBuffer();
             return;
           } else {
-            Collection<AmbariGrantedAuthority> userAuthorities =
-              users.getUserAuthorities(user.getUserName(), user.getUserType());
+            Collection<AmbariGrantedAuthority> userAuthorities = users.getUserAuthorities(userEntity);
+            User user = users.getUser(userEntity);
             AmbariUserAuthentication authentication = new AmbariUserAuthentication(token, user, userAuthorities);
             authentication.setAuthenticated(true);
             SecurityContextHolder.getContext().setAuthentication(authentication);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthenticationMethod.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthenticationMethod.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthenticationMethod.java
new file mode 100644
index 0000000..5670c38
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthenticationMethod.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.security.authorization;
+
+public class AuthenticationMethod {
+  private final UserAuthenticationType authenticationType;
+  private final String authenticationKey;
+
+  public AuthenticationMethod(UserAuthenticationType authenticationType, String authenticationKey) {
+    this.authenticationType = authenticationType;
+    this.authenticationKey = authenticationKey;
+  }
+
+  public UserAuthenticationType getAuthenticationType() {
+    return authenticationType;
+  }
+
+  public String getAuthenticationKey() {
+    return authenticationKey;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
index 64d5e61..a0b6029 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
@@ -125,7 +125,7 @@ public class AuthorizationHelper {
    * @return true if authorized; otherwise false
    * @see #isAuthorized(Authentication, ResourceType, Long, Set)
    */
-  public static boolean isAuthorized(ResourceType resourceType, Long resourceId, 
+  public static boolean isAuthorized(ResourceType resourceType, Long resourceId,
                                      RoleAuthorization requiredAuthorization) {
     return isAuthorized(getAuthentication(), resourceType, resourceId, EnumSet.of(requiredAuthorization));
   }
@@ -141,7 +141,7 @@ public class AuthorizationHelper {
    * @return true if authorized; otherwise false
    * @see #isAuthorized(Authentication, ResourceType, Long, Set)
    */
-  public static boolean isAuthorized(ResourceType resourceType, Long resourceId, 
+  public static boolean isAuthorized(ResourceType resourceType, Long resourceId,
                                      Set<RoleAuthorization> requiredAuthorizations) {
     return isAuthorized(getAuthentication(), resourceType, resourceId, requiredAuthorizations);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
index bff1fd2..a418451 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
@@ -25,8 +25,8 @@ import java.util.List;
 import org.apache.ambari.server.orm.entities.MemberEntity;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
-import org.springframework.security.core.GrantedAuthority;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -37,32 +37,39 @@ import io.swagger.annotations.ApiModelProperty;
  */
 @ApiModel
 public class User {
-  final int userId;
-  final String userName;
-  final boolean ldapUser;
-  final UserType userType;
-  final Date createTime;
-  final boolean active;
-  final Collection<String> groups = new ArrayList<>();
-  boolean admin = false;
-  final List<GrantedAuthority> authorities = new ArrayList<>();
+  final private int userId;
+  final private String userName;
+  final private Date createTime;
+  final private boolean active;
+  final private Collection<String> groups;
+  final private Collection<AuthenticationMethod> authenticationMethods;
+  final private boolean admin;
 
   public User(UserEntity userEntity) {
     userId = userEntity.getUserId();
     userName = userEntity.getUserName();
     createTime = userEntity.getCreateTime();
-    userType = userEntity.getUserType();
-    ldapUser = userEntity.getLdapUser();
     active = userEntity.getActive();
+
+    groups = new ArrayList<>();
     for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
       groups.add(memberEntity.getGroup().getGroupName());
     }
-    for (PrivilegeEntity privilegeEntity: userEntity.getPrincipal().getPrivileges()) {
+
+    authenticationMethods = new ArrayList<>();
+    List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+    for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+      authenticationMethods.add(new AuthenticationMethod(authenticationEntity.getAuthenticationType(), authenticationEntity.getAuthenticationKey()));
+    }
+
+    boolean admin = false;
+    for (PrivilegeEntity privilegeEntity : userEntity.getPrincipal().getPrivileges()) {
       if (privilegeEntity.getPermission().getPermissionName().equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION_NAME)) {
         admin = true;
         break;
       }
     }
+    this.admin = admin;
   }
 
   @ApiModelProperty(hidden = true)
@@ -75,16 +82,6 @@ public class User {
     return userName;
   }
 
-  @ApiModelProperty(name = "Users/ldap_user")
-  public boolean isLdapUser() {
-    return ldapUser;
-  }
-
-  @ApiModelProperty(name = "Users/user_type")
-  public UserType getUserType() {
-    return userType;
-  }
-
   @ApiModelProperty(hidden = true)
   public Date getCreateTime() {
     return createTime;
@@ -105,8 +102,24 @@ public class User {
     return groups;
   }
 
+  @ApiModelProperty(name = "Users/authentication_methods")
+  public Collection<AuthenticationMethod> getAuthenticationMethods() {
+    return authenticationMethods;
+  }
+
+  @ApiModelProperty(name = "Users/ldap_user")
+  public boolean isLdapUser() {
+    for (AuthenticationMethod authenticationMethod : authenticationMethods) {
+      if (authenticationMethod.getAuthenticationType() == UserAuthenticationType.LDAP) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   @Override
   public String toString() {
-    return "[" + getUserType() + "]" + userName;
+    return userName;
   }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserAuthenticationType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserAuthenticationType.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserAuthenticationType.java
new file mode 100644
index 0000000..ceeb7f9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserAuthenticationType.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.security.authorization;
+
+public enum UserAuthenticationType {
+  LOCAL,
+  LDAP,
+  JWT,
+  PAM,
+  KERBEROS
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
deleted file mode 100644
index aabd368..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.security.authorization;
-
-public enum UserType {
-  LOCAL,
-  LDAP,
-  JWT,
-  PAM
-}


[5/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index fb06e6d..9227366 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -65,7 +65,7 @@ import org.apache.ambari.server.orm.entities.StageEntity;
 import org.apache.ambari.server.security.ClientSecurityType;
 import org.apache.ambari.server.security.authentication.kerberos.AmbariKerberosAuthenticationProperties;
 import org.apache.ambari.server.security.authorization.LdapServerProperties;
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationProperties;
 import org.apache.ambari.server.security.encryption.CertificateUtils;
 import org.apache.ambari.server.security.encryption.CredentialProvider;
@@ -5997,7 +5997,7 @@ public class Configuration {
     // Get and process the configured user type values to convert the comma-delimited string of
     // user types into a ordered (as found in the comma-delimited value) list of UserType values.
     String userTypes = getProperty(KERBEROS_AUTH_USER_TYPES);
-    List<UserType> orderedUserTypes = new ArrayList<>();
+    List<UserAuthenticationType> orderedUserTypes = new ArrayList<>();
 
     String[] types = userTypes.split(",");
     for (String type : types) {
@@ -6005,7 +6005,7 @@ public class Configuration {
 
       if (!type.isEmpty()) {
         try {
-          orderedUserTypes.add(UserType.valueOf(type.toUpperCase()));
+          orderedUserTypes.add(UserAuthenticationType.valueOf(type.toUpperCase()));
         } catch (IllegalArgumentException e) {
           String message = String.format("While processing ordered user types from %s, " +
                   "%s was found to be an invalid user type.",
@@ -6020,7 +6020,7 @@ public class Configuration {
     if (orderedUserTypes.isEmpty()) {
       LOG.info("No (valid) user types were specified in {}. Using the default value of LOCAL.",
           KERBEROS_AUTH_USER_TYPES.getKey());
-      orderedUserTypes.add(UserType.LDAP);
+      orderedUserTypes.add(UserAuthenticationType.LDAP);
     }
 
     kerberosAuthProperties.setOrderedUserTypes(orderedUserTypes);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
index 807bded..f4220bd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
@@ -119,15 +119,6 @@ public interface AmbariManagementController {
                       String versionTag, Map<String, Map<String, String>> propertiesAttributes);
 
   /**
-   * Creates users.
-   *
-   * @param requests the request objects which define the user.
-   *
-   * @throws AmbariException when the user cannot be created.
-   */
-  void createUsers(Set<UserRequest> requests) throws AmbariException;
-
-  /**
    * Creates groups.
    *
    * @param requests the request objects which define the groups.
@@ -196,18 +187,6 @@ public interface AmbariManagementController {
       throws AmbariException;
 
   /**
-   * Gets the users identified by the given request objects.
-   *
-   * @param requests the request objects
-   *
-   * @return a set of user responses
-   *
-   * @throws AmbariException if the users could not be read
-   */
-  Set<UserResponse> getUsers(Set<UserRequest> requests)
-      throws AmbariException, AuthorizationException;
-
-  /**
    * Gets the user groups identified by the given request objects.
    *
    * @param requests the request objects
@@ -253,15 +232,6 @@ public interface AmbariManagementController {
       throws AmbariException, AuthorizationException;
 
   /**
-   * Updates the users specified.
-   *
-   * @param requests the users to modify
-   *
-   * @throws AmbariException if the resources cannot be updated
-   */
-  void updateUsers(Set<UserRequest> requests) throws AmbariException, AuthorizationException;
-
-  /**
    * Updates the groups specified.
    *
    * @param requests the groups to modify
@@ -304,15 +274,6 @@ public interface AmbariManagementController {
       Set<ServiceComponentHostRequest> requests) throws AmbariException, AuthorizationException;
 
   /**
-   * Deletes the users specified.
-   *
-   * @param requests the users to delete
-   *
-   * @throws AmbariException if the resources cannot be deleted
-   */
-  void deleteUsers(Set<UserRequest> requests) throws AmbariException;
-
-  /**
    * Deletes the user groups specified.
    *
    * @param requests the groups to delete

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 8d262e2..a979845 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -136,7 +136,6 @@ import org.apache.ambari.server.security.authorization.GroupType;
 import org.apache.ambari.server.security.authorization.ResourceType;
 import org.apache.ambari.server.security.authorization.RoleAuthorization;
 import org.apache.ambari.server.security.authorization.User;
-import org.apache.ambari.server.security.authorization.UserType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
 import org.apache.ambari.server.security.encryption.CredentialStoreService;
@@ -947,20 +946,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   @Override
-  public void createUsers(Set<UserRequest> requests) throws AmbariException {
-
-    for (UserRequest request : requests) {
-
-      if (null == request.getUsername() || request.getUsername().isEmpty() ||
-          null == request.getPassword() || request.getPassword().isEmpty()) {
-        throw new AmbariException("Username and password must be supplied.");
-      }
-
-      users.createUser(request.getUsername(), request.getPassword(), UserType.LOCAL, request.isActive(), request.isAdmin());
-    }
-  }
-
-  @Override
   public void createGroups(Set<GroupRequest> requests) throws AmbariException {
     for (GroupRequest request : requests) {
       if (StringUtils.isBlank(request.getGroupName())) {
@@ -3405,65 +3390,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     return cluster.getServiceByComponentName(componentName).getName();
   }
 
-  /**
-   * Updates the users specified.
-   *
-   * @param requests the users to modify
-   *
-   * @throws AmbariException if the resources cannot be updated
-   * @throws IllegalArgumentException if the authenticated user is not authorized to update all of
-   * the requested properties
-   */
-  @Override
-  public synchronized void updateUsers(Set<UserRequest> requests) throws AmbariException, AuthorizationException {
-    boolean isUserAdministrator = AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null,
-        RoleAuthorization.AMBARI_MANAGE_USERS);
-    String authenticatedUsername = AuthorizationHelper.getAuthenticatedName();
-
-    for (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))) {
-        throw new AuthorizationException();
-      }
-
-      User u = users.getAnyUser(requestedUsername);
-      if (null == u) {
-        continue;
-      }
-
-      if (null != request.isActive()) {
-        // 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");
-        }
-        users.setUserActive(u.getUserName(), request.isActive());
-      }
-
-      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) {
-          throw new AuthorizationException("The authenticated user is not authorized to update the requested resource property");
-        }
-
-        if (request.isAdmin()) {
-          users.grantAdminPrivilege(u.getUserId());
-        } else {
-          users.revokeAdminPrivilege(u.getUserId());
-        }
-      }
-
-      if (null != request.getOldPassword() && null != request.getPassword()) {
-        users.modifyPassword(u.getUserName(), request.getOldPassword(),
-            request.getPassword());
-      }
-    }
-  }
-
   @Override
   public synchronized void deleteCluster(ClusterRequest request)
       throws AmbariException {
@@ -3637,21 +3563,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   @Override
-  public void deleteUsers(Set<UserRequest> requests)
-    throws AmbariException {
-
-    for (UserRequest r : requests) {
-      if (LOG.isDebugEnabled()) {
-        LOG.debug("Received a delete user request, username={}", r.getUsername());
-      }
-      User u = users.getAnyUser(r.getUsername());
-      if (null != u) {
-        users.removeUser(u);
-      }
-    }
-  }
-
-  @Override
   public void deleteGroups(Set<GroupRequest> requests) throws AmbariException {
     for (GroupRequest request: requests) {
       LOG.debug("Received a delete group request, groupname={}", request.getGroupName());
@@ -3809,64 +3720,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   @Override
-  public Set<UserResponse> getUsers(Set<UserRequest> requests)
-      throws AmbariException, AuthorizationException {
-
-    Set<UserResponse> responses = new HashSet<>();
-
-    for (UserRequest r : requests) {
-
-      if (LOG.isDebugEnabled()) {
-        LOG.debug("Received a getUsers request, userRequest={}", r);
-      }
-
-      String requestedUsername = r.getUsername();
-      String authenticatedUsername = AuthorizationHelper.getAuthenticatedName();
-
-      // A user 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();
-        }
-      }
-
-      // get them all
-      if (null == requestedUsername) {
-        for (User u : users.getAllUsers()) {
-          UserResponse resp = new UserResponse(u.getUserName(), u.getUserType(), u.isLdapUser(), u.isActive(), u
-              .isAdmin());
-          resp.setGroups(new HashSet<>(u.getGroups()));
-          responses.add(resp);
-        }
-      } else {
-
-        User u = users.getAnyUser(requestedUsername);
-        if (null == u) {
-          if (requests.size() == 1) {
-            // only throw exceptin if there is a single request
-            // if there are multiple requests, this indicates an OR predicate
-            throw new ObjectNotFoundException("Cannot find user '"
-                + requestedUsername + "'");
-          }
-        } else {
-          UserResponse resp = new UserResponse(u.getUserName(), u.getUserType(), u.isLdapUser(), u.isActive(), u
-              .isAdmin());
-          resp.setGroups(new HashSet<>(u.getGroups()));
-          responses.add(resp);
-        }
-      }
-    }
-
-    return responses;
-  }
-
-  @Override
   public Set<GroupResponse> getGroups(Set<GroupRequest> requests)
       throws AmbariException {
     final Set<GroupResponse> responses = new HashSet<>();

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index aeba739..01920f8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -90,6 +90,7 @@ import org.apache.ambari.server.orm.dao.ResourceDAO;
 import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
 import org.apache.ambari.server.orm.entities.MetainfoEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.resources.ResourceManager;
 import org.apache.ambari.server.resources.api.rest.GetResource;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
@@ -866,8 +867,16 @@ public class AmbariServer {
       LOG.info("Database init needed - creating default data");
       Users users = injector.getInstance(Users.class);
 
-      users.createUser("admin", "admin");
-      users.createUser("user", "user");
+      UserEntity userEntity;
+
+      // Create the admin user
+      userEntity = users.createUser("admin", "admin", "admin");
+      users.addLocalAuthentication(userEntity, "admin");
+      users.grantAdminPrivilege(userEntity);
+
+      // Create a normal user
+      userEntity = users.createUser("user", "user", "user");
+      users.addLocalAuthentication(userEntity, "user");
 
       MetainfoEntity schemaVersion = new MetainfoEntity();
       schemaVersion.setMetainfoName(Configuration.SERVER_VERSION_KEY);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 f3c2ec8..25d12c7 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.UserResourceProvider;
 import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactory;
 import org.apache.ambari.server.controller.logging.LoggingRequestHelperFactoryImpl;
 import org.apache.ambari.server.controller.metrics.MetricPropertyProviderFactory;
@@ -464,6 +465,7 @@ public class ControllerModule extends AbstractModule {
         .implement(ResourceProvider.class, Names.named("member"), MemberResourceProvider.class)
         .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("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/f76c87a6/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 3912138..2454bf7 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
@@ -51,6 +51,11 @@ public interface ResourceProviderFactory {
       Map<Type, String> keyPropertyIds,
       AmbariManagementController managementController);
 
+  @Named("user")
+  ResourceProvider getUserResourceProvider(Set<String> propertyIds,
+                                           Map<Type, String> keyPropertyIds,
+                                           AmbariManagementController managementController);
+
   @Named("hostKerberosIdentity")
   ResourceProvider getHostKerberosIdentityResourceProvider(AmbariManagementController managementController);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 40818c8..3011d01 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
@@ -31,15 +31,18 @@ public class UserRequest {
   private Boolean active;
   private Boolean admin;
 
-  @ApiModelProperty(name = "Users/user_name",hidden = true)
-  public String getUsername() {
-    return userName;
-  }
+  private String displayName;
+  private String localUserName;
 
   public UserRequest(String name) {
     this.userName = name;
   }
 
+  @ApiModelProperty(name = "Users/user_name",hidden = true)
+  public String getUsername() {
+    return userName;
+  }
+
   @ApiModelProperty(name = "Users/password")
   public String getPassword() {
     return password;
@@ -76,6 +79,24 @@ public class UserRequest {
     this.admin = admin;
   }
 
+  @ApiModelProperty(name = "Users/display_name")
+  public String getDisplayName() {
+    return displayName;
+  }
+
+  public void setDisplayName(String displayName) {
+    this.displayName = displayName;
+  }
+
+  @ApiModelProperty(name = "Users/local_user_name")
+  public String getLocalUserName() {
+    return localUserName;
+  }
+
+  public void setLocalUserName(String localUserName) {
+    this.localUserName = localUserName;
+  }
+
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 5afacb7..bcb3aaf 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
@@ -20,25 +20,26 @@ package org.apache.ambari.server.controller;
 import java.util.Collections;
 import java.util.Set;
 
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 
 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 UserType userType;
+  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, UserType userType, boolean isLdapUser, boolean isActive, boolean isAdmin) {
+  public UserResponse(String userName, UserAuthenticationType userType, boolean isLdapUser, boolean isActive, boolean isAdmin) {
     this.userName = userName;
-    this.userType = userType;
+    this.authenticationType = userType;
     this.isLdapUser = isLdapUser;
     this.isActive = isActive;
     this.isAdmin = isAdmin;
@@ -49,7 +50,7 @@ public class UserResponse implements ApiModel {
     this.isLdapUser = isLdapUser;
     this.isActive = isActive;
     this.isAdmin = isAdmin;
-    this.userType = UserType.LOCAL;
+    this.authenticationType = UserAuthenticationType.LOCAL;
   }
 
   @ApiModelProperty(name = "Users/user_name",required = true)
@@ -84,9 +85,9 @@ public class UserResponse implements ApiModel {
     return isAdmin;
   }
 
-  @ApiModelProperty(name = "Users/user_type")
-  public UserType getUserType() {
-    return userType;
+  @ApiModelProperty(name = "Users/authentication_type")
+  public UserAuthenticationType getAuthenticationType() {
+    return authenticationType;
   }
 
   @Override
@@ -97,14 +98,14 @@ public class UserResponse implements ApiModel {
     UserResponse that = (UserResponse) o;
 
     if (userName != null ? !userName.equals(that.userName) : that.userName != null) return false;
-    return userType == that.userType;
+    return authenticationType == that.authenticationType;
 
   }
 
   @Override
   public int hashCode() {
     int result = userName != null ? userName.hashCode() : 0;
-    result = 31 * result + (userType != null ? userType.hashCode() : 0);
+    result = 31 * result + (authenticationType != null ? authenticationType.hashCode() : 0);
     return result;
   }
 }

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

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProvider.java
index 389f0b2..a0a5e38 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProvider.java
@@ -160,7 +160,7 @@ public class ActiveWidgetLayoutResourceProvider extends AbstractControllerResour
       }
 
       java.lang.reflect.Type type = new TypeToken<Set<Map<String, String>>>(){}.getType();
-        Set<Map<String, String>> activeWidgetLayouts = gson.fromJson(userDAO.findSingleUserByName(userName).getActiveWidgetLayouts(), type);
+        Set<Map<String, String>> activeWidgetLayouts = gson.fromJson(userDAO.findUserByName(userName).getActiveWidgetLayouts(), type);
         if (activeWidgetLayouts != null) {
           for (Map<String, String> widgetLayoutId : activeWidgetLayouts) {
             layoutEntities.add(widgetLayoutDAO.findById(Long.parseLong(widgetLayoutId.get(ID))));

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java
index 614f7ab..816767e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java
@@ -51,7 +51,6 @@ 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.UserType;
 import org.apache.ambari.server.security.authorization.Users;
 
 import com.google.common.cache.CacheBuilder;
@@ -187,14 +186,7 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider {
             @Override
             public UserEntity load(String key) throws Exception {
               //fallback mechanism, mostly for unit tests
-              UserEntity userEntity = userDAO.findLocalUserByName(key);
-              if (userEntity == null) {
-                userEntity = userDAO.findLdapUserByName(key);
-              }
-              if (userEntity == null) {
-                userEntity = userDAO.findUserByNameAndType(key, UserType.JWT);
-              }
-              return userEntity;
+              return userDAO.findUserByName(key);
             }
           };
 
@@ -281,9 +273,7 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider {
           Map<String, UserEntity> userNames = new TreeMap<>();
           for (UserEntity entity : userDAO.findAll()) {
             UserEntity existing = userNames.get(entity.getUserName());
-            if (existing == null ||
-                entity.getUserType() == UserType.LOCAL ||
-                existing.getUserType() == UserType.JWT) {
+            if (existing == null) {
               userNames.put(entity.getUserName(), entity);
             }
           }
@@ -292,10 +282,12 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider {
         }
 
         if (userEntity == null) {
-            userEntity = userDAO.findUserByNameAndType(userName, UserType.PAM);
+            userEntity = userDAO.findUserByName(userName);
         }
+
         if (userEntity == null) {
-          throw new SystemException("User " + userName + " was not found");
+          LOG.debug("User {} was not found", userName);
+          throw new SystemException("User was not found");
         }
 
         final Collection<PrivilegeEntity> privileges = users.getUserPrivileges(userEntity);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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 c5c36e9..45b733b 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
@@ -20,10 +20,12 @@ package org.apache.ambari.server.controller.internal;
 import java.util.Arrays;
 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.ObjectNotFoundException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.UserRequest;
 import org.apache.ambari.server.controller.UserResponse;
@@ -39,8 +41,20 @@ import org.apache.ambari.server.controller.spi.ResourcePredicateEvaluator;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.orm.entities.MemberEntity;
+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 com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
 
 /**
  * Resource provider for user resources.
@@ -50,25 +64,31 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
   // ----- Property ID constants ---------------------------------------------
 
   // 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_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 USER_LDAP_USER_PROPERTY_ID    = PropertyHelper.getPropertyId("Users", "ldap_user");
-  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");
+  @Deprecated
+  public static final String USER_LDAP_USER_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "ldap_user");
+  @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");
 
   private static Set<String> pkPropertyIds =
-    new HashSet<>(Arrays.asList(new String[]{
-      USER_USERNAME_PROPERTY_ID}));
+      new HashSet<>(Arrays.asList(new String[]{
+          USER_USERNAME_PROPERTY_ID}));
+
+  @Inject
+  private Users users;
 
   /**
    * Create a new resource provider for the given management controller.
    */
-  UserResourceProvider(Set<String> propertyIds,
-                       Map<Resource.Type, String> keyPropertyIds,
-                       AmbariManagementController managementController) {
+  @AssistedInject
+  UserResourceProvider(@Assisted Set<String> propertyIds,
+                       @Assisted Map<Resource.Type, String> keyPropertyIds,
+                       @Assisted AmbariManagementController managementController) {
     super(propertyIds, keyPropertyIds, managementController);
 
     setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_USERS));
@@ -89,7 +109,7 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
     createResources(new Command<Void>() {
       @Override
       public Void invoke() throws AmbariException {
-        getManagementController().createUsers(requests);
+        createUsers(requests);
         return null;
       }
     });
@@ -114,7 +134,7 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
     Set<UserResponse> responses = getResources(new Command<Set<UserResponse>>() {
       @Override
       public Set<UserResponse> invoke() throws AmbariException, AuthorizationException {
-        return getManagementController().getUsers(requests);
+        return getUsers(requests);
       }
     });
 
@@ -122,8 +142,8 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
       LOG.debug("Found user responses matching get user request, userRequestSize={}, userResponseSize={}", requests.size(), responses.size());
     }
 
-    Set<String>   requestedIds = getRequestPropertyIds(request, predicate);
-    Set<Resource> resources    = new HashSet<>();
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+    Set<Resource> resources = new HashSet<>();
 
     for (UserResponse userResponse : responses) {
       ResourceImpl resource = new ResourceImpl(Resource.Type.User);
@@ -131,11 +151,13 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
       setResourceProperty(resource, USER_USERNAME_PROPERTY_ID,
           userResponse.getUsername(), 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,
-          userResponse.getUserType(), requestedIds);
+          userResponse.getAuthenticationType(), requestedIds);
 
       setResourceProperty(resource, USER_ACTIVE_PROPERTY_ID,
           userResponse.isActive(), requestedIds);
@@ -154,7 +176,7 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
 
   @Override
   public RequestStatus updateResources(Request request, Predicate predicate)
-    throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
     final Set<UserRequest> requests = new HashSet<>();
 
     for (Map<String, Object> propertyMap : getPropertyMaps(request.getProperties().iterator().next(), predicate)) {
@@ -166,7 +188,7 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
     modifyResources(new Command<Void>() {
       @Override
       public Void invoke() throws AmbariException, AuthorizationException {
-        getManagementController().updateUsers(requests);
+        updateUsers(requests);
         return null;
       }
     });
@@ -188,7 +210,7 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
     modifyResources(new Command<Void>() {
       @Override
       public Void invoke() throws AmbariException {
-        getManagementController().deleteUsers(requests);
+        deleteUsers(requests);
         return null;
       }
     });
@@ -201,15 +223,14 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
    * we do a case insensitive comparison so that we can return the retrieved
    * username when it differs only in case with respect to the requested username.
    *
-   * @param predicate  the predicate
-   * @param resource   the resource
-   *
-     * @return
-     */
+   * @param predicate the predicate
+   * @param resource  the resource
+   * @return
+   */
   @Override
   public boolean evaluate(Predicate predicate, Resource resource) {
     if (predicate instanceof EqualsPredicate) {
-      EqualsPredicate equalsPredicate = (EqualsPredicate)predicate;
+      EqualsPredicate equalsPredicate = (EqualsPredicate) predicate;
       String propertyId = equalsPredicate.getPropertyId();
       if (propertyId.equals(USER_USERNAME_PROPERTY_ID)) {
         return equalsPredicate.evaluateIgnoreCase(resource);
@@ -228,7 +249,7 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
       return new UserRequest(null);
     }
 
-    UserRequest request = new UserRequest ((String) properties.get(USER_USERNAME_PROPERTY_ID));
+    UserRequest request = new UserRequest((String) properties.get(USER_USERNAME_PROPERTY_ID));
 
     request.setPassword((String) properties.get(USER_PASSWORD_PROPERTY_ID));
     request.setOldPassword((String) properties.get(USER_OLD_PASSWORD_PROPERTY_ID));
@@ -243,4 +264,197 @@ public class UserResourceProvider extends AbstractControllerResourceProvider imp
 
     return request;
   }
+
+
+  /**
+   * Creates users.
+   *
+   * @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 {
+    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.");
+      }
+
+      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);
+        }
+      }
+    }
+  }
+
+  /**
+   * Updates the users specified.
+   *
+   * @param requests the users to modify
+   * @throws AmbariException          if the resources cannot be updated
+   * @throws IllegalArgumentException if the authenticated user is not authorized to update all of
+   *                                  the requested properties
+   */
+  private void updateUsers(Set<UserRequest> requests) throws AmbariException, AuthorizationException {
+    boolean isUserAdministrator = AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null,
+        RoleAuthorization.AMBARI_MANAGE_USERS);
+    String authenticatedUsername = AuthorizationHelper.getAuthenticatedName();
+
+    for (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))) {
+        throw new AuthorizationException();
+      }
+
+      UserEntity userEntity = users.getUserEntity(requestedUsername);
+      if (null == userEntity) {
+        continue;
+      }
+
+      if (null != request.isActive()) {
+        // 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");
+        }
+        users.setUserActive(userEntity, request.isActive());
+      }
+
+      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) {
+          throw new AuthorizationException("The authenticated user is not authorized to update the requested resource property");
+        }
+
+        if (request.isAdmin()) {
+          users.grantAdminPrivilege(userEntity);
+        } else {
+          users.revokeAdminPrivilege(userEntity);
+        }
+      }
+
+      if (null != request.getOldPassword() && null != request.getPassword()) {
+        users.modifyPassword(userEntity, request.getOldPassword(), request.getPassword());
+      }
+    }
+  }
+
+  /**
+   * Deletes the users specified.
+   *
+   * @param requests the users to delete
+   * @throws AmbariException if the resources cannot be deleted
+   */
+  private void deleteUsers(Set<UserRequest> requests)
+      throws AmbariException {
+
+    for (UserRequest r : requests) {
+      String username = r.getUsername();
+      if (!StringUtils.isEmpty(username)) {
+
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Received a delete user request, username= {}", username);
+        }
+
+        users.removeUser(users.getUserEntity(username));
+      }
+    }
+  }
+
+  /**
+   * Gets the users identified by the given request objects.
+   *
+   * @param requests the request objects
+   * @return a set of user responses
+   * @throws AmbariException if the users could not be read
+   */
+  private Set<UserResponse> getUsers(Set<UserRequest> requests)
+      throws AmbariException, AuthorizationException {
+
+    Set<UserResponse> responses = new HashSet<>();
+
+    for (UserRequest r : requests) {
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Received a getUsers request, userRequest={}", r.toString());
+      }
+
+      String requestedUsername = r.getUsername();
+      String authenticatedUsername = AuthorizationHelper.getAuthenticatedName();
+
+      // A user 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();
+        }
+      }
+
+      // get them all
+      if (null == requestedUsername) {
+        for (UserEntity u : users.getAllUserEntities()) {
+          responses.add(createUserResponse(u));
+        }
+      } else {
+
+        UserEntity u = users.getUserEntity(requestedUsername);
+        if (null == u) {
+          if (requests.size() == 1) {
+            // only throw exceptin if there is a single request
+            // if there are multiple requests, this indicates an OR predicate
+            throw new ObjectNotFoundException("Cannot find user '"
+                + requestedUsername + "'");
+          }
+        } else {
+          responses.add(createUserResponse(u));
+        }
+      }
+    }
+
+    return responses;
+  }
+
+  private UserResponse createUserResponse(UserEntity userEntity) {
+    List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+    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;
+        }
+    }
+
+    Set<String> groups = new HashSet<>();
+    for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
+      groups.add(memberEntity.getGroup().getGroupName());
+    }
+
+    boolean isAdmin = users.hasAdminPrivilege(userEntity);
+
+    UserResponse userResponse = new UserResponse(userEntity.getUserName(), userType, isLdapUser, userEntity.getActive(), isAdmin);
+    userResponse.setGroups(groups);
+    return userResponse;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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
new file mode 100644
index 0000000..5ecff52
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserAuthenticationDAO.java
@@ -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.
+ */
+package org.apache.ambari.server.orm.dao;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+
+import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+
+@Singleton
+public class UserAuthenticationDAO {
+
+  @Inject
+  Provider<EntityManager> entityManagerProvider;
+  @Inject
+  DaoUtils daoUtils;
+
+  @RequiresSession
+  public UserAuthenticationEntity findByPK(Long pk) {
+    return entityManagerProvider.get().find(UserAuthenticationEntity.class, pk);
+  }
+
+  @RequiresSession
+  public List<UserAuthenticationEntity> findAll() {
+    TypedQuery<UserAuthenticationEntity> query = entityManagerProvider.get().createNamedQuery("UserAuthenticationEntity.findAll", UserAuthenticationEntity.class);
+    return daoUtils.selectList(query);
+  }
+
+  @Transactional
+  public void create(UserAuthenticationEntity entity) {
+    entityManagerProvider.get().persist(entity);
+  }
+
+  @Transactional
+  public void create(Set<UserAuthenticationEntity> entities) {
+    for (UserAuthenticationEntity entity : entities) {
+      entityManagerProvider.get().persist(entity);
+    }
+  }
+
+  @Transactional
+  public UserAuthenticationEntity merge(UserAuthenticationEntity entity) {
+    return entityManagerProvider.get().merge(entity);
+  }
+
+  @Transactional
+  public void merge(Set<UserAuthenticationEntity> entities) {
+    for (UserAuthenticationEntity entity : entities) {
+      entityManagerProvider.get().merge(entity);
+    }
+  }
+
+  @Transactional
+  public void remove(UserAuthenticationEntity entity) {
+    entityManagerProvider.get().remove(entity);
+  }
+
+  @Transactional
+  public void remove(Set<UserAuthenticationEntity> entities) {
+    for (UserAuthenticationEntity entity : entities) {
+      entityManagerProvider.get().remove(entity);
+    }
+  }
+
+  @Transactional
+  public void removeByPK(Long pk) {
+    remove(findByPK(pk));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
index ce47c4c..0e28e50 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java
@@ -17,13 +17,11 @@
  */
 package org.apache.ambari.server.orm.dao;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import javax.annotation.Nullable;
 import javax.persistence.EntityManager;
 import javax.persistence.NoResultException;
 import javax.persistence.TypedQuery;
@@ -31,9 +29,7 @@ import javax.persistence.TypedQuery;
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
-import org.apache.ambari.server.security.authorization.UserType;
 
-import com.google.common.collect.ImmutableMap;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -58,12 +54,7 @@ public class UserDAO {
     return daoUtils.selectList(query);
   }
 
-  /**
-   * Results in Exception if two users with same name but different types present in DB
-   * As such situation is valid, use {@link #findUserByNameAndType(String, UserType)} instead
-   */
   @RequiresSession
-  @Deprecated
   public UserEntity findUserByName(String userName) {
     TypedQuery<UserEntity> query = entityManagerProvider.get().createNamedQuery("userByName", UserEntity.class);
     query.setParameter("username", userName.toLowerCase());
@@ -75,81 +66,9 @@ public class UserDAO {
   }
 
   /**
-   * <p>Finds user by name. If duplicate users exists (with different type), the returned one will be chosen by this user
-   * type precedence: LOCAL -> LDAP -> JWT -> PAM</p>
-   * <p>In Ambari 3.0, user management will be rethought hence the deprecation</p>
-   * @param userName the user name
-   * @return The corresponding user or {@code null} if none is found. If multiple users exist with different types, user
-   *   type precedence (see above) will decide.
-   */
-   @RequiresSession
-   @Deprecated
-   @Nullable
-   public UserEntity findSingleUserByName(String userName) {
-     TypedQuery<UserEntity> query = entityManagerProvider.get().createNamedQuery("userByName", UserEntity.class);
-     query.setParameter("username", userName.toLowerCase());
-     List<UserEntity> resultList = query.getResultList();
-     switch (resultList.size()) {
-       case 0:
-         return null;
-       case 1:
-         return resultList.get(0);
-       default:
-         ImmutableMap.Builder<UserType, UserEntity> mapBuilder = ImmutableMap.builder();
-         for (UserEntity user: resultList) {
-           mapBuilder.put(user.getUserType(), user);
-         }
-         ImmutableMap<UserType, UserEntity> usersByType = mapBuilder.build();
-         UserEntity user =
-             usersByType.containsKey(UserType.LOCAL) ? usersByType.get(UserType.LOCAL) :
-                 usersByType.containsKey(UserType.LOCAL.LDAP) ? usersByType.get(UserType.LDAP) :
-                     usersByType.containsKey(UserType.JWT) ? usersByType.get(UserType.JWT) :
-                         usersByType.get(UserType.PAM);
-         return user;
-     }
-   }
-
-
-  @RequiresSession
-  public UserEntity findUserByNameAndType(String userName, UserType userType) {
-    TypedQuery<UserEntity> query = entityManagerProvider.get().createQuery("SELECT user FROM UserEntity user WHERE " +
-        "user.userType=:type AND lower(user.userName)=lower(:name)", UserEntity.class); // do case insensitive compare
-    query.setParameter("type", userType);
-    query.setParameter("name", userName);
-    try {
-      return query.getSingleResult();
-    } catch (NoResultException e) {
-      return null;
-    }
-  }
-
-  @RequiresSession
-  public UserEntity findLocalUserByName(String userName) {
-    TypedQuery<UserEntity> query = entityManagerProvider.get().createNamedQuery("localUserByName", UserEntity.class);
-    query.setParameter("username", userName.toLowerCase());
-    try {
-      return query.getSingleResult();
-    } catch (NoResultException e) {
-      return null;
-    }
-  }
-
-  @RequiresSession
-  public UserEntity findLdapUserByName(String userName) {
-    TypedQuery<UserEntity> query = entityManagerProvider.get().createNamedQuery("ldapUserByName", UserEntity.class);
-    query.setParameter("username", userName.toLowerCase());
-    try {
-      return query.getSingleResult();
-    } catch (NoResultException e) {
-      return null;
-    }
-  }
-
-  /**
    * Find the user entities for the given list of admin principal entities.
    *
-   * @param principalList  the list of principal entities
-   *
+   * @param principalList the list of principal entities
    * @return the matching list of user entities
    */
   @RequiresSession
@@ -166,7 +85,6 @@ public class UserDAO {
    * Find the user entity for the given admin principal entity.
    *
    * @param principal the principal entity
-   *
    * @return the matching user entity
    */
   @RequiresSession
@@ -182,27 +100,24 @@ public class UserDAO {
 
   @Transactional
   public void create(UserEntity user) {
-    create(new HashSet<>(Arrays.asList(user)));
+    create(new HashSet<>(Collections.singleton(user)));
   }
 
   @Transactional
   public void create(Set<UserEntity> users) {
     for (UserEntity user: users) {
-//      user.setUserName(user.getUserName().toLowerCase());
       entityManagerProvider.get().persist(user);
     }
   }
 
   @Transactional
   public UserEntity merge(UserEntity user) {
-//    user.setUserName(user.getUserName().toLowerCase());
     return entityManagerProvider.get().merge(user);
   }
 
   @Transactional
   public void merge(Set<UserEntity> users) {
-    for (UserEntity user: users) {
-//      user.setUserName(user.getUserName().toLowerCase());
+    for (UserEntity user : users) {
       entityManagerProvider.get().merge(user);
     }
   }
@@ -215,7 +130,7 @@ public class UserDAO {
 
   @Transactional
   public void remove(Set<UserEntity> users) {
-    for (UserEntity userEntity: users) {
+    for (UserEntity userEntity : users) {
       entityManagerProvider.get().remove(entityManagerProvider.get().merge(userEntity));
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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
new file mode 100644
index 0000000..ffb8e6d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserAuthenticationEntity.java
@@ -0,0 +1,167 @@
+/*
+ * 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.orm.entities;
+
+import java.util.Date;
+
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+@Table(name = "user_authentication")
+@Entity
+@NamedQueries({
+    @NamedQuery(name = "UserAuthenticationEntity.findAll", query = "SELECT entity FROM UserAuthenticationEntity entity")
+})
+@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 {
+
+  @Id
+  @Column(name = "user_authentication_id")
+  @GeneratedValue(strategy = GenerationType.TABLE, generator = "user_authentication_id_generator")
+  private Long userAuthenticationId;
+
+  @Column(name = "authentication_type", nullable = false)
+  @Enumerated(EnumType.STRING)
+  @Basic
+  private UserAuthenticationType authenticationType = UserAuthenticationType.LOCAL;
+
+  @Column(name = "authentication_key")
+  @Lob
+  @Basic
+  private byte[] authenticationKey;
+
+  @Column(name = "create_time", nullable = false)
+  @Basic
+  @Temporal(value = TemporalType.TIMESTAMP)
+  private Date createTime = new Date();
+
+  @Column(name = "update_time", nullable = false)
+  @Basic
+  @Temporal(value = TemporalType.TIMESTAMP)
+  private Date updateTime = new Date();
+
+  @ManyToOne(fetch = FetchType.LAZY)
+  @JoinColumn(name = "user_id", referencedColumnName = "user_id", nullable = false)
+  private UserEntity user;
+
+  public Long getUserAuthenticationId() {
+    return userAuthenticationId;
+  }
+
+  public void setUserAuthenticationId(Long userAuthenticationId) {
+    this.userAuthenticationId = userAuthenticationId;
+  }
+
+  public UserAuthenticationType getAuthenticationType() {
+    return authenticationType;
+  }
+
+  public void setAuthenticationType(UserAuthenticationType authenticationType) {
+    this.authenticationType = authenticationType;
+  }
+
+  public String getAuthenticationKey() {
+    return authenticationKey == null ? "" : new String(authenticationKey);
+  }
+
+  public void setAuthenticationKey(String authenticationKey) {
+    this.authenticationKey = (authenticationKey == null) ? null : authenticationKey.getBytes();
+  }
+
+  public Date getCreateTime() {
+    return createTime;
+  }
+
+  public Date getUpdateTime() {
+    return updateTime;
+  }
+
+  /**
+   * Get the relevant {@link UserEntity} associated with this {@link UserAuthenticationEntity}.
+   *
+   * @return a {@link UserEntity}
+   */
+  public UserEntity getUser() {
+    return user;
+  }
+
+  /**
+   * Set the relevant {@link UserEntity} associated with this {@link UserAuthenticationEntity}.
+   *
+   * @param user a {@link UserEntity}
+   */
+  public void setUser(UserEntity user) {
+    this.user = user;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    } else if (o == null || getClass() != o.getClass()) {
+      return false;
+    } else {
+      UserAuthenticationEntity that = (UserAuthenticationEntity) o;
+
+      EqualsBuilder equalsBuilder = new EqualsBuilder();
+      equalsBuilder.append(userAuthenticationId, that.userAuthenticationId);
+      equalsBuilder.append(authenticationType, that.authenticationType);
+      equalsBuilder.append(authenticationKey, that.authenticationKey);
+      equalsBuilder.append(createTime, that.createTime);
+      equalsBuilder.append(updateTime, that.updateTime);
+      return equalsBuilder.isEquals();
+    }
+  }
+
+  @Override
+  public int hashCode() {
+    HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
+    hashCodeBuilder.append(userAuthenticationId);
+    hashCodeBuilder.append(authenticationType);
+    hashCodeBuilder.append(authenticationKey);
+    hashCodeBuilder.append(createTime);
+    hashCodeBuilder.append(updateTime);
+    return hashCodeBuilder.toHashCode();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
index 9011eae..66e9003 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
@@ -17,16 +17,17 @@
  */
 package org.apache.ambari.server.orm.entities;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import javax.persistence.Basic;
 import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
@@ -42,27 +43,21 @@ import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
 import javax.persistence.UniqueConstraint;
 
-import org.apache.ambari.server.security.authorization.UserName;
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
 
-@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_name", "user_type"})})
+@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_name"})})
 @Entity
 @NamedQueries({
     @NamedQuery(name = "userByName", query = "SELECT user_entity from UserEntity user_entity " +
-        "where lower(user_entity.userName)=:username"),
-    @NamedQuery(name = "localUserByName", query = "SELECT user_entity FROM UserEntity user_entity " +
-        "where lower(user_entity.userName)=:username AND " +
-        "user_entity.userType=org.apache.ambari.server.security.authorization.UserType.LOCAL"),
-    @NamedQuery(name = "ldapUserByName", query = "SELECT user_entity FROM UserEntity user_entity " +
-        "where lower(user_entity.userName)=:username AND " +
-        "user_entity.userType=org.apache.ambari.server.security.authorization.UserType.LDAP")
+        "where lower(user_entity.userName)=lower(:username)")
 })
 @TableGenerator(name = "user_id_generator",
     table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value"
     , pkColumnValue = "user_id_seq"
     , initialValue = 2
     , allocationSize = 500
-    )
+)
 public class UserEntity {
 
   @Id
@@ -70,40 +65,41 @@ public class UserEntity {
   @GeneratedValue(strategy = GenerationType.TABLE, generator = "user_id_generator")
   private Integer userId;
 
-  @Column(name = "user_name")
+  @Column(name = "user_name", nullable = false)
   private String userName;
 
-  @Column(name = "ldap_user")
-  private Integer ldapUser = 0;
-
-  @Column(name = "user_type")
-  @Enumerated(EnumType.STRING)
-  @Basic
-  private UserType userType = UserType.LOCAL;
-
-  @Column(name = "user_password")
-  @Basic
-  private String userPassword;
-
-  @Column(name = "create_time")
+  @Column(name = "create_time", nullable = false)
   @Basic
   @Temporal(value = TemporalType.TIMESTAMP)
   private Date createTime = new Date();
 
-  @Column(name = "active")
+  @Column(name = "active", nullable = false)
   private Integer active = 1;
 
+  @Column(name = "consecutive_failures", nullable = false)
+  private Integer consecutiveFailures = 0;
+
+  @Column(name = "display_name")
+  private String displayName;
+
+  @Column(name = "local_username")
+  private String localUsername;
+
   @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
   private Set<MemberEntity> memberEntities = new HashSet<>();
 
   @OneToOne
   @JoinColumns({
-      @JoinColumn(name = "principal_id", referencedColumnName = "principal_id", nullable = false),
+      @JoinColumn(name = "principal_id", referencedColumnName = "principal_id", nullable = false)
   })
   private PrincipalEntity principal;
 
   @Column(name = "active_widget_layouts")
   private String activeWidgetLayouts;
+
+  @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
+  private List<UserAuthenticationEntity> authenticationEntities = new ArrayList<>();
+
   // ----- UserEntity --------------------------------------------------------
 
   public Integer getUserId() {
@@ -118,37 +114,96 @@ public class UserEntity {
     return userName;
   }
 
-  public void setUserName(UserName userName) {
-    this.userName = userName.toString();
+  public void setUserName(String userName) {
+    // Force the username to be lowercase
+    this.userName = (userName == null) ? null : userName.toLowerCase();
+  }
+
+  /**
+   * Returns the number of consecutive authentication failures since the last successful login.
+   * <p>
+   * This value may be used to throttle authentication attempts or lock out users. It is expected that
+   * this value is reset to <code>0</code> when a successful authentication attempt was made.
+   *
+   * @return the number of consecutive authentication failures since the last successful login
+   */
+  public Integer getConsecutiveFailures() {
+    return consecutiveFailures;
   }
 
-  public Boolean getLdapUser() {
-    return ldapUser == 0 ? Boolean.FALSE : Boolean.TRUE;
+  /**
+   * Sets the number of consecutive authentication failures since the last successful login.
+   * <p>
+   * This value may be used to throttle authentication attempts or lock out users. It is expected that
+   * this value is reset to <code>0</code> when a successful authentication attempt was made.
+   * <p>
+   * For each failed authentication attempt, {@link #incrementConsecutiveFailures()} should be called
+   * rather than explicitly setting an incremented value.
+   *
+   * @param consecutiveFailures a number of consecutive authentication failures since the last successful login
+   */
+  public void setConsecutiveFailures(Integer consecutiveFailures) {
+    this.consecutiveFailures = consecutiveFailures;
   }
 
-  public void setLdapUser(Boolean ldapUser) {
-    if (ldapUser == null) {
-      this.ldapUser = null;
-    } else {
-      this.ldapUser = ldapUser ? 1 : 0;
-      this.userType = ldapUser ? UserType.LDAP : UserType.LOCAL;
-    }
+  /**
+   * Increments the number of consecutive authentication failures since the last successful login.
+   * <p>
+   * This value may be used to throttle authentication attempts or lock out users. It is expected that
+   * this value is reset to <code>0</code> when a successful authentication attempt was made.
+   * <p>
+   * TODO: Ensure that this value is consistent when updating concurrently
+   */
+  public void incrementConsecutiveFailures() {
+    this.consecutiveFailures++;
   }
 
-  public UserType getUserType() {
-    return userType;
+  /**
+   * Returns the display name for this user.
+   * <p>
+   * This value may be used in user interfaces rather than the username to show who it logged in. If
+   * empty, it is expected that the user's {@link #userName} value would be used instead.
+   *
+   * @return the user's display name
+   */
+  public String getDisplayName() {
+    return displayName;
   }
 
-  public void setUserType(UserType userType) {
-    this.userType = userType;
+  /**
+   * Sets the display name for this user.
+   * <p>
+   * This value may be used in user interfaces rather than the username to show who it logged in. If
+   * empty, it is expected that the user's {@link #userName} value would be used instead.
+   *
+   * @param displayName the user's display name
+   */
+  public void setDisplayName(String displayName) {
+    this.displayName = displayName;
   }
 
-  public String getUserPassword() {
-    return userPassword;
+  /**
+   * Gets the local username for this user.
+   * <p>
+   * This value is intended to be used when accessing services via Ambari Views. If
+   * empty, it is expected that the user's {@link #userName} value would be used instead.
+   *
+   * @return the user's local username
+   */
+  public String getLocalUsername() {
+    return localUsername;
   }
 
-  public void setUserPassword(String userPassword) {
-    this.userPassword = userPassword;
+  /**
+   * Sets the local username for this user.
+   * <p>
+   * This value is intended to be used when accessing services via Ambari Views. If
+   * empty, it is expected that the user's {@link #userName} value would be used instead.
+   *
+   * @param localUsername the user's local username
+   */
+  public void setLocalUsername(String localUsername) {
+    this.localUsername = localUsername;
   }
 
   public Date getCreateTime() {
@@ -191,7 +246,7 @@ public class UserEntity {
   /**
    * Set the admin principal entity.
    *
-   * @param principal  the principal entity
+   * @param principal the principal entity
    */
   public void setPrincipal(PrincipalEntity principal) {
     this.principal = principal;
@@ -205,35 +260,57 @@ public class UserEntity {
     this.activeWidgetLayouts = activeWidgetLayouts;
   }
 
-// ----- Object overrides --------------------------------------------------
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
+  public List<UserAuthenticationEntity> getAuthenticationEntities() {
+    return authenticationEntities;
+  }
 
-    UserEntity that = (UserEntity) o;
+  public void setAuthenticationEntities(List<UserAuthenticationEntity> authenticationEntities) {
+    // If the passed in value is not the same list that is stored internally, clear it and set the
+    // entries to the same set that the user passed in.
+    // If the passed in value is the same list, then do nothing since the internal value is already
+    // set.
+    if (this.authenticationEntities != authenticationEntities) {  // Tests to see if the Lists are the same object, not if they have the same content.
+      this.authenticationEntities.clear();
+
+      if (authenticationEntities != null) {
+        this.authenticationEntities.addAll(authenticationEntities);
+      }
+    }
+  }
 
-    if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
-    if (createTime != null ? !createTime.equals(that.createTime) : that.createTime != null) return false;
-    if (ldapUser != null ? !ldapUser.equals(that.ldapUser) : that.ldapUser != null) return false;
-    if (userType != null ? !userType.equals(that.userType) : that.userType != null) return false;
-    if (userName != null ? !userName.equals(that.userName) : that.userName != null) return false;
-    if (userPassword != null ? !userPassword.equals(that.userPassword) : that.userPassword != null) return false;
-    if (active != null ? !active.equals(that.active) : that.active != null) return false;
+  // ----- Object overrides --------------------------------------------------
 
-    return true;
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    } else if (o == null || getClass() != o.getClass()) {
+      return false;
+    } else {
+      UserEntity that = (UserEntity) o;
+
+      EqualsBuilder equalsBuilder = new EqualsBuilder();
+      equalsBuilder.append(userId, that.userId);
+      equalsBuilder.append(userName, that.userName);
+      equalsBuilder.append(displayName, that.displayName);
+      equalsBuilder.append(localUsername, that.localUsername);
+      equalsBuilder.append(consecutiveFailures, that.consecutiveFailures);
+      equalsBuilder.append(active, that.active);
+      equalsBuilder.append(createTime, that.createTime);
+      return equalsBuilder.isEquals();
+    }
   }
 
   @Override
   public int hashCode() {
-    int result = userId != null ? userId.hashCode() : 0;
-    result = 31 * result + (userName != null ? userName.hashCode() : 0);
-    result = 31 * result + (userPassword != null ? userPassword.hashCode() : 0);
-    result = 31 * result + (ldapUser != null ? ldapUser.hashCode() : 0);
-    result = 31 * result + (userType != null ? userType.hashCode() : 0);
-    result = 31 * result + (createTime != null ? createTime.hashCode() : 0);
-    result = 31 * result + (active != null ? active.hashCode() : 0);
-    return result;
+    HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
+    hashCodeBuilder.append(userId);
+    hashCodeBuilder.append(userName);
+    hashCodeBuilder.append(displayName);
+    hashCodeBuilder.append(localUsername);
+    hashCodeBuilder.append(consecutiveFailures);
+    hashCodeBuilder.append(active);
+    hashCodeBuilder.append(createTime);
+    return hashCodeBuilder.toHashCode();
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
index 195c55a..fca8b29 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
@@ -34,7 +34,6 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 import org.apache.ambari.server.security.authorization.PermissionHelper;
 import org.apache.ambari.server.security.authorization.Users;
-import org.apache.ambari.server.security.authorization.jwt.AuthenticationJwtUserNotFoundException;
 import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationFilter;
 import org.apache.ambari.server.utils.RequestUtils;
 import org.springframework.security.core.Authentication;
@@ -124,8 +123,8 @@ public class AmbariJWTAuthenticationFilter extends JwtAuthenticationFilter imple
   protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
     if (auditLogger.isEnabled()) {
       String username = null;
-      if (authException instanceof AuthenticationJwtUserNotFoundException) {
-        username = ((AuthenticationJwtUserNotFoundException) authException).getUsername();
+      if (authException instanceof UserNotFoundException) {
+        username = ((UserNotFoundException) authException).getUsername();
       }
 
       AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AuthenticationMethodNotAllowedException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AuthenticationMethodNotAllowedException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AuthenticationMethodNotAllowedException.java
new file mode 100644
index 0000000..4c48dd7
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AuthenticationMethodNotAllowedException.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.security.authentication;
+
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * AuthenticationMethodNotAllowedException is an AuthenticationException implementation to be thrown
+ * when the specified authentication method is not allowed for the relevant user.
+ */
+public class AuthenticationMethodNotAllowedException extends AuthenticationException {
+  private final String username;
+  private final UserAuthenticationType userAuthenticationType;
+
+  public AuthenticationMethodNotAllowedException(String username, UserAuthenticationType authenticationType) {
+    this(username, authenticationType, createDefaultMessage(username, authenticationType));
+  }
+
+  public AuthenticationMethodNotAllowedException(String username, UserAuthenticationType authenticationType, Throwable cause) {
+    this(username, authenticationType, createDefaultMessage(username, authenticationType), cause);
+  }
+
+  public AuthenticationMethodNotAllowedException(String username, UserAuthenticationType authenticationType, String message) {
+    super(message);
+    this.username = username;
+    this.userAuthenticationType = authenticationType;
+  }
+
+  public AuthenticationMethodNotAllowedException(String username, UserAuthenticationType authenticationType, String message, Throwable cause) {
+    super(message, cause);
+    this.username = username;
+    this.userAuthenticationType = authenticationType;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public UserAuthenticationType getUserAuthenticationType() {
+    return userAuthenticationType;
+  }
+
+  private static String createDefaultMessage(String username, UserAuthenticationType authenticationType) {
+    return String.format("%s is not authorized to authenticate using %s",
+        username,
+        (authenticationType == null) ? "null" : authenticationType.name());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
new file mode 100644
index 0000000..f6c4bcf
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.security.authentication;
+
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * AuthenticationUserNotFoundException is an AuthenticationException implementation to be thrown
+ * when the user specified in an authentication attempt is not found in the Ambari user database.
+ */
+public class UserNotFoundException extends AuthenticationException {
+  private final String username;
+
+  public UserNotFoundException(String username, String message) {
+    super(message);
+    this.username = username;
+  }
+
+  public UserNotFoundException(String username, String message, Throwable throwable) {
+    super(message, throwable);
+    this.username = username;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+}