package org.craftercms.profile.management.web.controllers;
import java.util.Arrays;
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.Tenant;
import org.craftercms.profile.api.services.TenantService;
import org.craftercms.profile.management.security.permissions.CurrentUserSubjectResolver;
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.TenantController.MODEL_MESSAGE;
import static org.craftercms.profile.management.web.controllers.TenantController.MSG_TENANT_CREATED_FORMAT;
import static org.craftercms.profile.management.web.controllers.TenantController.MSG_TENANT_DELETED_FORMAT;
import static org.craftercms.profile.management.web.controllers.TenantController.MSG_TENANT_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.TenantController}.
*
* @author avasquez
*/
public class TenantControllerTest {
private static final String TENANT_NAME1 = "tenant1";
private static final String TENANT_NAME2 = "tenant2";
private static final String TENANT_NAME3 = "tenant3";
private static final ObjectId TENANT_ID1 = ObjectId.get();
private static final ObjectId TENANT_ID2 = ObjectId.get();
private static final ObjectId TENANT_ID3 = ObjectId.get();
private TenantController controller;
@Mock
private TenantService tenantService;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Tenant tenant1 = getTenant(TENANT_ID1, TENANT_NAME1, SUPERADMIN_ROLE, TENANT_ADMIN_ROLE, PROFILE_ADMIN_ROLE);
Tenant tenant2 = getTenant(TENANT_ID2, TENANT_NAME2, TENANT_ADMIN_ROLE, PROFILE_ADMIN_ROLE);
Tenant tenant3 = getTenant(TENANT_ID3, TENANT_NAME3, PROFILE_ADMIN_ROLE);
when(tenantService.getAllTenants()).thenReturn(Arrays.asList(tenant1, tenant2));
when(tenantService.getTenant(TENANT_NAME1)).thenReturn(tenant1);
when(tenantService.getTenant(TENANT_NAME2)).thenReturn(tenant2);
when(tenantService.createTenant(tenant3)).thenReturn(tenant3);
SubjectResolver<Profile> subjectResolver = new CurrentUserSubjectResolver();
TenantPermissionResolver permissionResolver = new TenantPermissionResolver();
PermissionEvaluatorImpl<Profile, String> permissionEvaluator = new PermissionEvaluatorImpl<>();
permissionEvaluator.setSubjectResolver(subjectResolver);
permissionEvaluator.setPermissionResolver(permissionResolver);
controller = new TenantController();
controller.setTenantService(tenantService);
controller.setTenantPermissionEvaluator(permissionEvaluator);
setCurrentRequestContext();
}
@After
public void tearDown() throws Exception {
clearCurrentRequestContext();
}
@Test
public void testGetTenantNamesBySuperadmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, SUPERADMIN_ROLE));
List<String> tenantNames = controller.getTenantNames();
assertNotNull(tenantNames);
assertEquals(2, tenantNames.size());
assertEquals(TENANT_NAME1, tenantNames.get(0));
assertEquals(TENANT_NAME2, tenantNames.get(1));
}
@Test
public void testGetTenantNamesByTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, TENANT_ADMIN_ROLE));
List<String> tenantNames = controller.getTenantNames();
assertNotNull(tenantNames);
assertEquals(1, tenantNames.size());
assertEquals(TENANT_NAME1, tenantNames.get(0));
}
@Test
public void testGetTenantNamesByProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ADMIN_ROLE));
List<String> tenantNames = controller.getTenantNames();
assertNotNull(tenantNames);
assertEquals(1, tenantNames.size());
assertEquals(TENANT_NAME1, tenantNames.get(0));
}
@Test
public void testGetTenant() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ADMIN_ROLE));
Tenant tenant = controller.getTenant(TENANT_NAME1);
assertNotNull(tenant);
assertEquals(TENANT_NAME1, tenant.getName());
}
@Test(expected = ActionDeniedException.class)
public void testGetTenantByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, TENANT_ADMIN_ROLE));
controller.getTenant(TENANT_NAME1);
}
@Test(expected = ActionDeniedException.class)
public void testGetTenantByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ADMIN_ROLE));
controller.getTenant(TENANT_NAME1);
}
@Test
public void testCreateTenant() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, SUPERADMIN_ROLE));
Tenant tenant = getTenant(TENANT_ID3, TENANT_NAME3, PROFILE_ADMIN_ROLE);
Map<String, String> model = controller.createTenant(tenant);
assertNotNull(model);
assertEquals(1, model.size());
assertEquals(String.format(MSG_TENANT_CREATED_FORMAT, TENANT_NAME3), model.get(MODEL_MESSAGE));
verify(tenantService).createTenant(tenant);
}
@Test(expected = ActionDeniedException.class)
public void testCreateTenantByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, TENANT_ADMIN_ROLE));
controller.createTenant(getTenant(TENANT_ID3, TENANT_NAME3, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testCreateTenantByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ADMIN_ROLE));
controller.createTenant(getTenant(TENANT_ID3, TENANT_NAME3, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testCreateTenantWithReservedSuperadminRole() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, SUPERADMIN_ROLE));
controller.createTenant(getTenant(TENANT_ID3, TENANT_NAME3, SUPERADMIN_ROLE));
}
@Test
public void testUpdateTenant() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, TENANT_ADMIN_ROLE));
Tenant tenant = getTenant(TENANT_ID2, TENANT_NAME2, TENANT_ADMIN_ROLE, PROFILE_ADMIN_ROLE);
Map<String, String> model = controller.updateTenant(tenant);
assertNotNull(model);
assertEquals(1, model.size());
assertEquals(String.format(MSG_TENANT_UPDATED_FORMAT, TENANT_NAME2), model.get(MODEL_MESSAGE));
verify(tenantService).updateTenant(tenant);
}
@Test(expected = ActionDeniedException.class)
public void testUpdateTenantByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, TENANT_ADMIN_ROLE));
controller.updateTenant(getTenant(TENANT_ID2, TENANT_NAME2, TENANT_ADMIN_ROLE, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testUpdateTenantByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, PROFILE_ADMIN_ROLE));
controller.createTenant(getTenant(TENANT_ID2, TENANT_NAME2, TENANT_ADMIN_ROLE, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testUpdateTenantWithReservedSuperadminRoleRemoved() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, TENANT_ADMIN_ROLE));
controller.updateTenant(getTenant(TENANT_ID1, TENANT_NAME1, TENANT_ADMIN_ROLE, PROFILE_ADMIN_ROLE));
}
@Test(expected = ActionDeniedException.class)
public void testUpdateTenantWithReservedSuperadminRoleAdded() throws Exception {
setCurrentUser(getProfile(TENANT_NAME2, TENANT_ADMIN_ROLE));
controller.updateTenant(getTenant(TENANT_ID2, TENANT_NAME2, SUPERADMIN_ROLE, TENANT_ADMIN_ROLE,
PROFILE_ADMIN_ROLE));
}
@Test
public void testDeleteTenant() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, SUPERADMIN_ROLE));
Map<String, String> model = controller.deleteTenant(TENANT_NAME2);
assertNotNull(model);
assertEquals(1, model.size());
assertEquals(String.format(MSG_TENANT_DELETED_FORMAT, TENANT_NAME2), model.get(MODEL_MESSAGE));
verify(tenantService).deleteTenant(TENANT_NAME2);
}
@Test(expected = ActionDeniedException.class)
public void testDeleteTenantByInvalidTenantAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, TENANT_ADMIN_ROLE));
controller.deleteTenant(TENANT_NAME2);
}
@Test(expected = ActionDeniedException.class)
public void testDeleteTenantByInvalidProfileAdmin() throws Exception {
setCurrentUser(getProfile(TENANT_NAME1, PROFILE_ADMIN_ROLE));
controller.deleteTenant(TENANT_NAME2);
}
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 Tenant getTenant(ObjectId id, String name, String... availableRoles) {
Tenant tenant = new Tenant();
tenant.setId(id);
tenant.setName(name);
tenant.setAvailableRoles(SetUtils.asSet(availableRoles));
return tenant;
}
private Profile getProfile(String tenantName, String role) {
Profile profile = new Profile();
profile.setTenant(tenantName);
profile.getRoles().add(role);
return profile;
}
}