package org.craftercms.profile.management.web.controllers;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bson.types.ObjectId;
import org.craftercms.commons.collections.SetUtils;
import org.craftercms.commons.http.RequestContext;
import org.craftercms.commons.security.exception.ActionDeniedException;
import org.craftercms.commons.security.permissions.SubjectResolver;
import org.craftercms.commons.security.permissions.impl.PermissionEvaluatorImpl;
import org.craftercms.profile.api.Profile;
import org.craftercms.profile.api.ProfileConstants;
import org.craftercms.profile.api.services.ProfileService;
import org.craftercms.profile.management.security.permissions.CurrentUserSubjectResolver;
import org.craftercms.profile.management.security.permissions.ProfilePermissionResolver;
import org.craftercms.profile.management.security.permissions.TenantPermissionResolver;
import org.craftercms.security.authentication.impl.DefaultAuthentication;
import org.craftercms.security.utils.SecurityUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import static org.craftercms.profile.management.security.AuthorizationUtils.PROFILE_ADMIN_ROLE;
import static org.craftercms.profile.management.security.AuthorizationUtils.SUPERADMIN_ROLE;
import static org.craftercms.profile.management.security.AuthorizationUtils.TENANT_ADMIN_ROLE;
import static org.craftercms.profile.management.web.controllers.ProfileController.FINAL_QUERY_FORMAT;
import static org.craftercms.profile.management.web.controllers.ProfileController.MODEL_MESSAGE;
import static org.craftercms.profile.management.web.controllers.ProfileController.MSG_PROFILE_CREATED_FORMAT;
import static org.craftercms.profile.management.web.controllers.ProfileController.MSG_PROFILE_DELETED_FORMAT;
import static org.craftercms.profile.management.web.controllers.ProfileController.MSG_PROFILE_UPDATED_FORMAT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Unit tests for {@link org.craftercms.profile.management.web.controllers.ProfileController}.
*
* @author avasquez
*/
public class ProfileControllerTest {
private static final String TENANT_NAME1 = "tenant1";
private static final String TENANT_NAME2 = "tenant2";
private static final ObjectId PROFILE_ID1 = ObjectId.get();
private static final ObjectId PROFILE_ID2 = ObjectId.get();
private static final ObjectId PROFILE_ID3 = ObjectId.get();
private static final ObjectId PROFILE_ID4 = ObjectId.get();
private static final String USERNAME1 = "user1";
private static final String USERNAME2 = "user2";
private static final String USERNAME3 = "user3";
private static final String USERNAME4 = "user4";
private ProfileController controller;
@Mock
private ProfileService profileService;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
String query = String.format(FINAL_QUERY_FORMAT, USERNAME1);
Profile profile1 = getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE);
Profile profile2 = getProfile(TENANT_NAME1, PROFILE_ID2, USERNAME2, PROFILE_ADMIN_ROLE);
Profile profile3 = getProfile(TENANT_NAME1, PROFILE_ID3, USERNAME3, SUPERADMIN_ROLE);
Profile profile4 = getProfile(TENANT_NAME1, PROFILE_ID4, USERNAME4, TENANT_ADMIN_ROLE);
when(profileService.getProfileCountByQuery(TENANT_NAME1, query)).thenReturn(1L);
when(profileService.getProfilesByQuery(TENANT_NAME1, query, null, null, null, null, new String[0]))
.thenReturn(Arrays.asList(profile1));
when(profileService.getProfile(PROFILE_ID1.toString(), new String[0])).thenReturn(profile1);
when(profileService.getProfile(PROFILE_ID3.toString(), new String[0])).thenReturn(profile3);
when(profileService.getProfile(PROFILE_ID4.toString(), new String[0])).thenReturn(profile4);
when(profileService.createProfile(TENANT_NAME1, USERNAME2, null, null, false, SetUtils.asSet(
PROFILE_ADMIN_ROLE), new HashMap<String, Object>(), null)).thenReturn(profile2);
SubjectResolver<Profile> subjectResolver = new CurrentUserSubjectResolver();
TenantPermissionResolver tenantPermissionResolver = new TenantPermissionResolver();
ProfilePermissionResolver profilePermissionResolver = new ProfilePermissionResolver();
PermissionEvaluatorImpl<Profile, String> tenantPermissionEvaluator = new PermissionEvaluatorImpl<>();
tenantPermissionEvaluator.setSubjectResolver(subjectResolver);
tenantPermissionEvaluator.setPermissionResolver(tenantPermissionResolver);
PermissionEvaluatorImpl<Profile, Profile> profilePermissionEvaluator = new PermissionEvaluatorImpl<>();
profilePermissionEvaluator.setSubjectResolver(subjectResolver);
profilePermissionEvaluator.setPermissionResolver(profilePermissionResolver);
controller = new ProfileController();
controller.setProfileService(profileService);
controller.setTenantPermissionEvaluator(tenantPermissionEvaluator);
controller.setProfilePermissionEvaluator(profilePermissionEvaluator);
setCurrentRequestContext();
}
@After
public void tearDown() throws Exception {
clearCurrentRequestContext();
}
@Test
public void testGetProfileCount() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
long count = controller.getProfileCount(TENANT_NAME1, USERNAME1);
assertEquals(1L, count);
}
@Test(expected = ActionDeniedException.class)
public void testGetProfileCountByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.getProfileCount(TENANT_NAME1, USERNAME1);
}
@Test(expected = ActionDeniedException.class)
public void testGetProfileCountByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.getProfileCount(TENANT_NAME1, USERNAME1);
}
@Test
public void testGetProfileList() throws Exception {
Profile currentUser = getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE);
setCurrentUser(currentUser);
List<Profile> profiles = controller.getProfileList(TENANT_NAME1, USERNAME1, null, null, null, null);
assertNotNull(profiles);
assertEquals(1, profiles.size());
assertProfiles(currentUser, profiles.get(0));
}
@Test(expected = ActionDeniedException.class)
public void testGetProfileListByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.getProfileList(TENANT_NAME1, USERNAME1, null, null, null, null);
}
@Test(expected = ActionDeniedException.class)
public void testGetProfileListByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.getProfileList(TENANT_NAME1, USERNAME1, null, null, null, null);
}
@Test
public void testGetProfile() throws Exception {
Profile currentUser = getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE);
setCurrentUser(currentUser);
Profile profile = controller.getProfile(PROFILE_ID1.toString());
assertNotNull(profile);
assertProfiles(currentUser, profile);
}
@Test(expected = ActionDeniedException.class)
public void testGetProfileByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.getProfile(PROFILE_ID1.toString());
}
@Test(expected = ActionDeniedException.class)
public void testGetProfileByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.getProfile(PROFILE_ID1.toString());
}
@Test
public void testCreateProfile() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
Map<String, String> model = controller.createProfile(getProfile(TENANT_NAME1, null, USERNAME2,
PROFILE_ADMIN_ROLE));
assertNotNull(model);
assertEquals(1, model.size());
assertEquals(String.format(MSG_PROFILE_CREATED_FORMAT, PROFILE_ID2.toString()), model.get(MODEL_MESSAGE));
verify(profileService).createProfile(TENANT_NAME1, USERNAME2, null, null, false,
SetUtils.asSet(PROFILE_ADMIN_ROLE), new HashMap<String, Object>(), null);
}
@Test(expected = ActionDeniedException.class)
public void testCreateProfileByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.createProfile(getProfile(TENANT_NAME1, null, USERNAME2, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testCreateProfileByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.createProfile(getProfile(TENANT_NAME1, null, USERNAME2, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testCreateSuperAdminByTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.createProfile(getProfile(TENANT_NAME1, null, USERNAME2, SUPERADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testCreateSuperAdminByProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.createProfile(getProfile(TENANT_NAME1, null, USERNAME2, SUPERADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testCreateTenantAdminByProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.createProfile(getProfile(TENANT_NAME1, null, USERNAME2, TENANT_ADMIN_ROLE));
}
@Test
public void testUpdateProfile() throws Exception {
Profile currentUser = getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE);
setCurrentUser(currentUser);
Map<String, String> model = controller.updateProfile(currentUser);
assertNotNull(model);
assertEquals(1, model.size());
assertEquals(String.format(MSG_PROFILE_UPDATED_FORMAT, PROFILE_ID1.toString()), model.get(MODEL_MESSAGE));
verify(profileService).updateProfile(PROFILE_ID1.toString(), USERNAME1, null, null, false,
SetUtils.asSet(PROFILE_ADMIN_ROLE), new HashMap<String, Object>(),
ProfileConstants.NO_ATTRIBUTE);
}
@Test(expected = ActionDeniedException.class)
public void testUpdateProfileByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.updateProfile(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testUpdateProfileByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.updateProfile(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testUpdateSuperadminByTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.updateProfile(getProfile(TENANT_NAME1, PROFILE_ID3, USERNAME3, SUPERADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testUpdateSuperadminByProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.updateProfile(getProfile(TENANT_NAME1, PROFILE_ID3, USERNAME3, SUPERADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testUpdateTenantAdminByProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.updateProfile(getProfile(TENANT_NAME1, PROFILE_ID4, USERNAME4, TENANT_ADMIN_ROLE));
}
@Test
public void testDeleteProfile() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
Map<String, String> model = controller.deleteProfile(PROFILE_ID1.toString());
assertNotNull(model);
assertEquals(1, model.size());
assertEquals(String.format(MSG_PROFILE_DELETED_FORMAT, PROFILE_ID1.toString()), model.get(MODEL_MESSAGE));
verify(profileService).deleteProfile(PROFILE_ID1.toString());
}
@Test(expected = ActionDeniedException.class)
public void testDeleteProfileByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.deleteProfile(PROFILE_ID1.toString());
}
@Test(expected = ActionDeniedException.class)
public void testDeleteProfileByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.deleteProfile(PROFILE_ID1.toString());
}
@Test(expected = ActionDeniedException.class)
public void testDeleteSuperadminByTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, TENANT_ADMIN_ROLE));
controller.deleteProfile(PROFILE_ID3.toString());
}
@Test(expected = ActionDeniedException.class)
public void testDeleteSuperadminByProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.deleteProfile(PROFILE_ID3.toString());
}
@Test(expected = ActionDeniedException.class)
public void testDeleteTenantAdminByProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ID1, USERNAME1, PROFILE_ADMIN_ROLE));
controller.deleteProfile(PROFILE_ID4.toString());
}
private void setCurrentRequestContext() {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
RequestContext context = new RequestContext(request, response, null);
RequestContext.setCurrent(context);
}
private void clearCurrentRequestContext() {
RequestContext.clear();
}
private void setCurrentUser(Profile profile) {
DefaultAuthentication auth = new DefaultAuthentication(null, profile);
SecurityUtils.setCurrentAuthentication(auth);
}
private Profile getProfile(String tenantName, ObjectId id, String username, String role) {
Profile profile = new Profile();
profile.setId(id);
profile.setTenant(tenantName);
profile.setUsername(username);
profile.getRoles().add(role);
return profile;
}
private void assertProfiles(Profile expected, Profile actual) {
assertEquals(expected.getId(), actual.getId());
assertEquals(expected.getTenant(), actual.getTenant());
assertEquals(expected.getUsername(), actual.getUsername());
assertEquals(expected.getRoles(), actual.getRoles());
}
}