/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ambari.server.security.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.sql.SQLException;
import java.util.List;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.H2DatabaseCleaner;
import org.apache.ambari.server.orm.GuiceJpaInitializer;
import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
import org.apache.ambari.server.orm.dao.GroupDAO;
import org.apache.ambari.server.orm.dao.PermissionDAO;
import org.apache.ambari.server.orm.dao.PrincipalDAO;
import org.apache.ambari.server.orm.dao.PrincipalTypeDAO;
import org.apache.ambari.server.orm.dao.ResourceDAO;
import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.entities.PermissionEntity;
import org.apache.ambari.server.orm.entities.PrincipalEntity;
import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
import org.apache.ambari.server.orm.entities.ResourceEntity;
import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import junit.framework.Assert;
public class TestUsers {
private Injector injector;
@Inject
protected Users users;
@Inject
protected UserDAO userDAO;
@Inject
protected GroupDAO groupDAO;
@Inject
protected PermissionDAO permissionDAO;
@Inject
protected ResourceDAO resourceDAO;
@Inject
protected ResourceTypeDAO resourceTypeDAO;
@Inject
protected PrincipalTypeDAO principalTypeDAO;
@Inject
protected PrincipalDAO principalDAO;
@Inject
protected PasswordEncoder passwordEncoder;
@Before
public void setup() throws AmbariException {
InMemoryDefaultTestModule module = new InMemoryDefaultTestModule();
injector = Guice.createInjector(module);
injector.getInstance(GuiceJpaInitializer.class);
injector.injectMembers(this);
Authentication auth = new UsernamePasswordAuthenticationToken("admin", null);
SecurityContextHolder.getContext().setAuthentication(auth);
// create admin permission
ResourceTypeEntity resourceTypeEntity = new ResourceTypeEntity();
resourceTypeEntity.setId(ResourceType.AMBARI.getId());
resourceTypeEntity.setName(ResourceType.AMBARI.name());
resourceTypeDAO.create(resourceTypeEntity);
ResourceEntity resourceEntity = new ResourceEntity();
resourceEntity.setId(ResourceEntity.AMBARI_RESOURCE_ID);
resourceEntity.setResourceType(resourceTypeEntity);
resourceDAO.create(resourceEntity);
PrincipalTypeEntity principalTypeEntity = new PrincipalTypeEntity();
principalTypeEntity.setName("ROLE");
principalTypeEntity = principalTypeDAO.merge(principalTypeEntity);
PrincipalEntity principalEntity = new PrincipalEntity();
principalEntity.setPrincipalType(principalTypeEntity);
principalEntity = principalDAO.merge(principalEntity);
PermissionEntity adminPermissionEntity = new PermissionEntity();
adminPermissionEntity.setId(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION);
adminPermissionEntity.setPermissionName(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION_NAME);
adminPermissionEntity.setPrincipal(principalEntity);
adminPermissionEntity.setResourceType(resourceTypeEntity);
permissionDAO.create(adminPermissionEntity);
}
@After
public void tearDown() throws AmbariException, SQLException {
H2DatabaseCleaner.clearDatabaseAndStopPersistenceService(injector);
}
@Test
public void testIsUserCanBeRemoved() throws Exception {
users.createUser("admin", "admin", UserType.LOCAL, true, true);
users.createUser("admin222", "admin222", UserType.LOCAL, true, true);
Assert.assertTrue(users.isUserCanBeRemoved(userDAO.findUserByName("admin")));
Assert.assertTrue(users.isUserCanBeRemoved(userDAO.findUserByName("admin222")));
users.removeUser(users.getAnyUser("admin222"));
Assert.assertFalse(users.isUserCanBeRemoved(userDAO.findUserByName("admin")));
users.createUser("user", "user");
Assert.assertFalse(users.isUserCanBeRemoved(userDAO.findUserByName("admin")));
users.createUser("admin333", "admin333", UserType.LOCAL, true, true);
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 = userDAO.findUserByName("user");
assertNotSame("user", userEntity.getUserPassword());
assertTrue(passwordEncoder.matches("user", userEntity.getUserPassword()));
users.modifyPassword("user", "admin", "user_new_password");
assertTrue(passwordEncoder.matches("user_new_password", userDAO.findUserByName("user").getUserPassword()));
}
@Test
public void testRevokeAdminPrivilege() throws Exception {
users.createUser("old_admin", "old_admin", UserType.LOCAL, true, true);
final User admin = users.getAnyUser("old_admin");
users.revokeAdminPrivilege(admin.getUserId());
Assert.assertFalse(users.getAnyUser("old_admin").isAdmin());
}
@Test
public void testGrantAdminPrivilege() throws Exception {
users.createUser("user", "user");
final User user = users.getAnyUser("user");
users.grantAdminPrivilege(user.getUserId());
Assert.assertTrue(users.getAnyUser("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);
Assert.assertEquals("user1", createdUser1.getUserName());
Assert.assertEquals(true, createdUser1.isActive());
Assert.assertEquals(false, createdUser1.isLdapUser());
Assert.assertEquals(false, createdUser1.isAdmin());
Assert.assertEquals("user", createdUser.getUserName());
Assert.assertEquals(false, createdUser.isActive());
Assert.assertEquals(false, createdUser.isLdapUser());
Assert.assertEquals(false, createdUser.isAdmin());
Assert.assertEquals("user_ldap", createdLdapUser.getUserName());
Assert.assertEquals(true, createdLdapUser.isActive());
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"));
// create duplicate user
try {
users.createUser("user1", "user1");
Assert.fail("It shouldn't be possible to create duplicate user");
} catch (AmbariException e) {
}
try {
users.createUser("USER1", "user1");
Assert.fail("It shouldn't be possible to create duplicate user");
} catch (AmbariException e) {
}
// test get all users
List<User> userList = users.getAllUsers();
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"));
// get user by id
User userById = users.getUser(createdUser.getUserId());
assertNotNull(userById);
assertEquals(createdUser.getUserId(), userById.getUserId());
// get user by invalid id
User userByInvalidId = users.getUser(-1);
assertNull(userByInvalidId);
// get user if unique
Assert.assertNotNull(users.getUserIfUnique("user"));
//remove user
Assert.assertEquals(3, users.getAllUsers().size());
users.removeUser(users.getAnyUser("user1"));
Assert.assertNull(users.getAnyUser("user1"));
Assert.assertEquals(2, users.getAllUsers().size());
}
@Test
public void testSetUserActive() throws Exception {
users.createUser("user", "user");
users.setUserActive("user", false);
Assert.assertEquals(false, users.getAnyUser("user").isActive());
users.setUserActive("user", true);
Assert.assertEquals(true, users.getAnyUser("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) {
}
}
@Test
public void testSetUserLdap() throws Exception {
users.createUser("user", "user");
users.createUser("user_ldap", "user_ldap", UserType.LDAP, true, false);
users.setUserLdap("user");
Assert.assertEquals(true, users.getAnyUser("user").isLdapUser());
try {
users.setUserLdap("fake user");
Assert.fail("It shouldn't be possible to call setUserLdap() on non-existing user");
} catch (AmbariException ex) {
}
}
@Test
public void testSetGroupLdap() throws Exception {
users.createGroup("group", GroupType.LOCAL);
users.setGroupLdap("group");
Assert.assertNotNull(users.getGroup("group"));
Assert.assertTrue(users.getGroup("group").isLdapGroup());
try {
users.setGroupLdap("fake group");
Assert.fail("It shouldn't be possible to call setGroupLdap() on non-existing group");
} catch (AmbariException ex) {
}
}
@Test
public void testCreateGetRemoveGroup() throws Exception {
final String groupName = "engineering1";
final String groupName2 = "engineering2";
users.createGroup(groupName, GroupType.LOCAL);
users.createGroup(groupName2, GroupType.LOCAL);
final Group group = users.getGroup(groupName);
assertNotNull(group);
assertEquals(false, group.isLdapGroup());
assertEquals(groupName, group.getGroupName());
assertNotNull(groupDAO.findGroupByName(groupName));
// get all groups
final List<Group> groupList = users.getAllGroups();
assertEquals(2, groupList.size());
assertEquals(2, groupDAO.findAll().size());
// remove group
users.removeGroup(group);
assertNull(users.getGroup(group.getGroupName()));
assertEquals(1, users.getAllGroups().size());
}
@Test
public void testMembers() throws Exception {
final String groupName = "engineering";
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.addMemberToGroup(groupName, "user1");
users.addMemberToGroup(groupName, "user2");
assertEquals(2, users.getAllMembers(groupName).size());
assertEquals(0, users.getAllMembers(groupName2).size());
try {
users.getAllMembers("non existing");
Assert.fail("It shouldn't be possible to call getAllMembers() on non-existing group");
} catch (Exception ex) {
}
// get members from not unexisting group
assertEquals(users.getGroupMembers("unexisting"), null);
// remove member from group
users.removeMemberFromGroup(groupName, "user1");
assertEquals(1, groupDAO.findGroupByName(groupName).getMemberEntities().size());
assertEquals("user2", groupDAO.findGroupByName(groupName).getMemberEntities().iterator().next().getUser().getUserName());
}
@Test
public void testModifyPassword_UserByHimselfPasswordOk() throws Exception {
Authentication auth = new UsernamePasswordAuthenticationToken("user", null);
SecurityContextHolder.getContext().setAuthentication(auth);
users.createUser("user", "user");
UserEntity userEntity = userDAO.findUserByName("user");
assertNotSame("user", userEntity.getUserPassword());
assertTrue(passwordEncoder.matches("user", userEntity.getUserPassword()));
users.modifyPassword("user", "user", "user_new_password");
assertTrue(passwordEncoder.matches("user_new_password", userDAO.findUserByName("user").getUserPassword()));
}
@Test
public void testModifyPassword_UserByHimselfPasswordNotOk() throws Exception {
Authentication auth = new UsernamePasswordAuthenticationToken("user", null);
SecurityContextHolder.getContext().setAuthentication(auth);
users.createUser("user", "user");
UserEntity userEntity = userDAO.findUserByName("user");
assertNotSame("user", userEntity.getUserPassword());
assertTrue(passwordEncoder.matches("user", userEntity.getUserPassword()));
try {
users.modifyPassword("user", "admin", "user_new_password");
Assert.fail("Exception should be thrown here as password is incorrect");
} catch (AmbariException ex) {
}
}
@Test
public void testModifyPassword_UserByNonAdmin() throws Exception {
Authentication auth = new UsernamePasswordAuthenticationToken("user2", null);
SecurityContextHolder.getContext().setAuthentication(auth);
users.createUser("user", "user");
users.createUser("user2", "user2");
UserEntity userEntity = userDAO.findUserByName("user");
assertNotSame("user", userEntity.getUserPassword());
assertTrue(passwordEncoder.matches("user", userEntity.getUserPassword()));
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) {
}
}
@Test
@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);
}
}