/* * Copyright (C) 2007-2014 Crafter Software Corporation. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.craftercms.profile.management.web.controllers; import java.util.Collections; import java.util.List; import java.util.Map; import org.craftercms.commons.security.exception.ActionDeniedException; import org.craftercms.commons.security.permissions.PermissionEvaluator; import org.craftercms.profile.api.Profile; import org.craftercms.profile.api.Tenant; import org.craftercms.profile.api.exceptions.ProfileException; import org.craftercms.profile.api.services.TenantService; import org.craftercms.profile.management.exceptions.ResourceNotFoundException; import org.craftercms.profile.management.security.AuthorizationUtils; import org.craftercms.profile.management.security.permissions.Action; import org.craftercms.security.utils.SecurityUtils; import org.craftercms.security.utils.tenant.TenantUtils; import org.springframework.beans.factory.annotation.Required; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; /** * MVC Controller for displaying and modifying tenants. * * @author avasquez */ @Controller @RequestMapping(TenantController.BASE_URL_TENANT) public class TenantController { public static final String BASE_URL_TENANT = "/tenant"; public static final String PATH_VAR_NAME = "name"; public static final String URL_VIEW_TENANT_LIST = "/list/view"; public static final String URL_VIEW_NEW_TENANT = "/new/view"; public static final String URL_VIEW_TENANT = "/view"; public static final String URL_GET_TENANT_NAMES = "/names"; public static final String URL_GET_TENANT = "/{" + PATH_VAR_NAME + "}"; public static final String URL_CREATE_TENANT = "/create"; public static final String URL_UPDATE_TENANT = "/update"; public static final String URL_DELETE_TENANT = "/{" + PATH_VAR_NAME + "}/delete"; public static final String VIEW_TENANT_LIST = "tenant-list"; public static final String VIEW_TENANT = "tenant"; public static final String MODEL_PAGE_HEADER = "pageHeader"; public static final String MODEL_MESSAGE = "message"; public static final String PAGE_HEADER_NEW = "New Tenant"; public static final String PAGE_HEADER_UPDATE = "Update Tenant"; public static final String MSG_TENANT_CREATED_FORMAT = "Tenant '%s' created"; public static final String MSG_TENANT_UPDATED_FORMAT = "Tenant '%s' updated"; public static final String MSG_TENANT_DELETED_FORMAT = "Tenant '%s' deleted"; private TenantService tenantService; private PermissionEvaluator<Profile, String> tenantPermissionEvaluator; @Required public void setTenantService(TenantService tenantService) { this.tenantService = tenantService; } @Required public void setTenantPermissionEvaluator(PermissionEvaluator<Profile, String> tenantPermissionEvaluator) { this.tenantPermissionEvaluator = tenantPermissionEvaluator; } @RequestMapping(value = URL_VIEW_TENANT_LIST, method = RequestMethod.GET) public String viewTenantList() throws ProfileException { return VIEW_TENANT_LIST; } @RequestMapping(value = URL_VIEW_NEW_TENANT, method = RequestMethod.GET) public ModelAndView viewNewTenant() throws ProfileException { return new ModelAndView(VIEW_TENANT, MODEL_PAGE_HEADER, PAGE_HEADER_NEW); } @RequestMapping(value = URL_VIEW_TENANT, method = RequestMethod.GET) public ModelAndView viewTenant() throws ProfileException { return new ModelAndView(VIEW_TENANT, MODEL_PAGE_HEADER, PAGE_HEADER_UPDATE); } @RequestMapping(value = URL_GET_TENANT_NAMES, method = RequestMethod.GET) @ResponseBody public List<String> getTenantNames() throws ProfileException { if (AuthorizationUtils.isSuperadmin(SecurityUtils.getCurrentProfile())) { return TenantUtils.getTenantNames(tenantService); } else { return Collections.singletonList(SecurityUtils.getCurrentProfile().getTenant()); } } @RequestMapping(value = URL_GET_TENANT, method = RequestMethod.GET) @ResponseBody public Tenant getTenant(@PathVariable(PATH_VAR_NAME) String name) throws ProfileException { checkIfAllowed(name, Action.GET_TENANT); Tenant tenant = tenantService.getTenant(name); if (tenant != null) { return tenant; } else { throw new ResourceNotFoundException("No tenant found with name '" + name + "'"); } } @RequestMapping(value = URL_CREATE_TENANT, method = RequestMethod.POST) @ResponseBody public Map<String, String> createTenant(@RequestBody Tenant tenant) throws ProfileException { checkIfAllowed(null, Action.CREATE_TENANT); if (tenant.getAvailableRoles().contains(AuthorizationUtils.SUPERADMIN_ROLE)) { throw new ActionDeniedException(Action.CREATE_TENANT.toString(), tenant.getName()); } tenant = tenantService.createTenant(tenant); return Collections.singletonMap(MODEL_MESSAGE, String.format(MSG_TENANT_CREATED_FORMAT, tenant.getName())); } @RequestMapping(value = URL_UPDATE_TENANT, method = RequestMethod.POST) @ResponseBody public Map<String, String> updateTenant(@RequestBody Tenant tenant) throws ProfileException { String name = tenant.getName(); checkIfAllowed(name, Action.UPDATE_TENANT); Tenant currentTenant = tenantService.getTenant(name); if (currentTenant != null) { if (!currentTenant.getAvailableRoles().contains(AuthorizationUtils.SUPERADMIN_ROLE) && tenant.getAvailableRoles().contains(AuthorizationUtils.SUPERADMIN_ROLE)) { throw new ActionDeniedException(Action.UPDATE_TENANT.toString(), name); } if (currentTenant.getAvailableRoles().contains(AuthorizationUtils.SUPERADMIN_ROLE) && !tenant.getAvailableRoles().contains(AuthorizationUtils.SUPERADMIN_ROLE)) { throw new ActionDeniedException(Action.UPDATE_TENANT.toString(), name); } tenantService.updateTenant(tenant); return Collections.singletonMap(MODEL_MESSAGE, String.format(MSG_TENANT_UPDATED_FORMAT, name)); } else { throw new ResourceNotFoundException("No tenant found with name '" + name + "'"); } } @RequestMapping(value = URL_DELETE_TENANT, method = RequestMethod.POST) @ResponseBody public Map<String, String> deleteTenant(@PathVariable(PATH_VAR_NAME) String name) throws ProfileException { checkIfAllowed(name, Action.DELETE_TENANT); Tenant tenant = tenantService.getTenant(name); if (tenant != null) { tenantService.deleteTenant(name); return Collections.singletonMap(MODEL_MESSAGE, String.format(MSG_TENANT_DELETED_FORMAT, name)); } else { throw new ResourceNotFoundException("No tenant found with name '" + name + "'"); } } private void checkIfAllowed(String tenant, Action action) throws ActionDeniedException { if (!tenantPermissionEvaluator.isAllowed(tenant, action.toString())) { if (tenant != null) { throw new ActionDeniedException(action.toString(), tenant); } else { throw new ActionDeniedException(action.toString()); } } } }