package alien4cloud.rest.application; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Resource; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import alien4cloud.application.ApplicationEnvironmentService; import alien4cloud.application.ApplicationService; import alien4cloud.audit.annotation.Audit; import alien4cloud.model.application.Application; import alien4cloud.model.application.ApplicationEnvironment; import alien4cloud.rest.model.RestResponse; import alien4cloud.rest.model.RestResponseBuilder; import alien4cloud.security.ResourceRoleService; import alien4cloud.security.model.ApplicationEnvironmentRole; import alien4cloud.security.model.ApplicationRole; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @RestController @RequestMapping({ "/rest/applications/{applicationId:.+}/environments/{applicationEnvironmentId:.+}/roles", "/rest/v1/applications/{applicationId:.+}/environments/{applicationEnvironmentId:.+}/roles", "/rest/latest/applications/{applicationId:.+}/environments/{applicationEnvironmentId:.+}/roles" }) @Api(value = "", description = "Manages application's environments") public class ApplicationEnvironmentRolesController { @Resource private ResourceRoleService resourceRoleService; @Resource private ApplicationEnvironmentService applicationEnvironmentService; @Resource private ApplicationService applicationService; /** * Add a role to a user on a specific application environment * * @param applicationEnvironmentId application environment id * @param username user for who to add role * @param role the application role to add to this user * @return A {@link Void} {@link RestResponse}. */ @ApiOperation(value = "Add a role to a user on a specific application environment", notes = "Any user with application role APPLICATION_MANAGER can assign any role to another user. Application role required [ APPLICATION_MANAGER ]") @RequestMapping(value = "/users/{username}/{role}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("isAuthenticated()") @Audit public RestResponse<Void> addUserRole(@PathVariable String applicationEnvironmentId, @PathVariable String username, @PathVariable String role) { ApplicationEnvironment applicationEnvironment = applicationEnvironmentService.checkAndGetApplicationEnvironment(applicationEnvironmentId, ApplicationRole.APPLICATION_MANAGER); resourceRoleService.addUserRole(applicationEnvironment, username, role); handleAddUserRoleOnApplication(applicationEnvironment.getApplicationId(), username); return RestResponseBuilder.<Void> builder().build(); } /** * Add a role to a group on a specific application environment * * @param applicationEnvironmentId application environment id * @param groupId The id of the group to update roles * @param role The role to add to the group on the application environment from {@link ApplicationEnvironmentRole} * @return A {@link Void} {@link RestResponse}. */ @ApiOperation(value = "Add a role to a group on a specific application environment", notes = "Any user with application role APPLICATION_MANAGER can assign any role to a group of users. Application role required [ APPLICATION_MANAGER ]") @RequestMapping(value = "/groups/{groupId}/{role}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("isAuthenticated()") @Audit public RestResponse<Void> addGroupRole(@PathVariable String applicationEnvironmentId, @PathVariable String groupId, @PathVariable String role) { ApplicationEnvironment applicationEnvironment = applicationEnvironmentService.checkAndGetApplicationEnvironment(applicationEnvironmentId, ApplicationRole.APPLICATION_MANAGER); resourceRoleService.addGroupRole(applicationEnvironment, groupId, role); handleAddGrpRoleOnApplication(applicationEnvironment.getApplicationId(), groupId); return RestResponseBuilder.<Void> builder().build(); } /** * Remove a role from a user on a specific application environment * * @param applicationEnvironmentId application environment id * @param username The username of the user to update roles * @param role The role to add to the user on the application environment * @return A {@link Void} {@link RestResponse} */ @ApiOperation(value = "Remove a role to a user on a specific application environment", notes = "Any user with application role APPLICATION_MANAGER can unassign any role to another user. Application role required [ APPLICATION_MANAGER ]") @RequestMapping(value = "/users/{username}/{role}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("isAuthenticated()") @Audit public RestResponse<Void> removeUserRole(@PathVariable String applicationEnvironmentId, @PathVariable String username, @PathVariable String role) { ApplicationEnvironment applicationEnvironment = applicationEnvironmentService.checkAndGetApplicationEnvironment(applicationEnvironmentId, ApplicationRole.APPLICATION_MANAGER); resourceRoleService.removeUserRole(applicationEnvironment, username, role); handleRemoveUserRoleOnApplication(applicationEnvironment.getApplicationId(), username); return RestResponseBuilder.<Void> builder().build(); } /** * Remove a role from a group on a specific application environment * * @param applicationEnvironmentId application environment id * @param groupId The id of the group to update roles * @param role The role to add to the user on the application environment * @return A {@link Void} {@link RestResponse}. */ @ApiOperation(value = "Remove a role of a group on a specific application environment", notes = "Any user with application role APPLICATION_MANAGER can un-assign any role to a group. Application role required [ APPLICATION_MANAGER ]") @RequestMapping(value = "/groups/{groupId}/{role}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("isAuthenticated()") @Audit public RestResponse<Void> removeGroupRole(@PathVariable String applicationEnvironmentId, @PathVariable String groupId, @PathVariable String role) { ApplicationEnvironment applicationEnvironment = applicationEnvironmentService.checkAndGetApplicationEnvironment(applicationEnvironmentId, ApplicationRole.APPLICATION_MANAGER); resourceRoleService.removeGroupRole(applicationEnvironment, groupId, role); handleRemoveGrpRoleOnApplication(applicationEnvironment.getApplicationId(), groupId); return RestResponseBuilder.<Void> builder().build(); } /** * Handle user roles on the targeted application * Any role on an environment implies APPLICATION_USER role on the linked application * * @param applicationId * @param username */ private void handleAddUserRoleOnApplication(String applicationId, String username) { Application application = applicationService.getOrFail(applicationId); resourceRoleService.addUserRole(application, username, ApplicationRole.APPLICATION_USER.toString()); } /** * Handle remove roles on the targeted application * * @param applicationId * @param username */ private void handleRemoveUserRoleOnApplication(String applicationId, String username) { Application application = applicationService.getOrFail(applicationId); // Check if user has at least one role on the application or the environments Set<String> applicationRoles = application.getUserRoles() != null ? application.getUserRoles().get(username) : new HashSet<>(); List<Set<String>> environmentRoles = Arrays.stream(applicationEnvironmentService.getByApplicationId(applicationId)) .map(applicationEnvironment -> (applicationEnvironment.getUserRoles() != null ? applicationEnvironment.getUserRoles().get(username) : null)) .filter(roles -> roles != null).collect(Collectors.toList()); if (mustRemoveApplicationUserRole(applicationRoles, environmentRoles)) { // If we are here, it means that we must take out the APPLICATION_USER role for application as user does not have any other role than that resourceRoleService.removeUserRole(application, username, ApplicationRole.APPLICATION_USER.toString()); } } private boolean mustRemoveApplicationUserRole(Set<String> applicationRoles, List<Set<String>> allEnvironmentRoles) { if (applicationRoles == null || applicationRoles.isEmpty()) { // User has no role on the application, nothing to do return false; } // Not take into account application user role it-self int appUserCount = applicationRoles.contains(ApplicationRole.APPLICATION_USER.toString()) ? 1 : 0; if (applicationRoles.size() > appUserCount) { // Has other role than APPLICATION_USER, then APPLICATION_USER role is necessary return false; } for (Set<String> environmentRoles : allEnvironmentRoles) { if (environmentRoles != null && !environmentRoles.isEmpty()) { // An environment role imply an application user role return false; } } return true; } /** * Handle group roles on the targeted application * Any role on an environment implies APPLICATION_USER role on the linked application * * @param applicationId * @param groupId */ private void handleAddGrpRoleOnApplication(String applicationId, String groupId) { Application application = applicationService.getOrFail(applicationId); resourceRoleService.addGroupRole(application, groupId, ApplicationRole.APPLICATION_USER.toString()); } /** * Handle group roles on the targeted application * * @param applicationId * @param groupId */ private void handleRemoveGrpRoleOnApplication(String applicationId, String groupId) { Application application = applicationService.getOrFail(applicationId); // Check if group has at least one role on the application or the environments Set<String> applicationRoles = application.getGroupRoles() != null ? application.getGroupRoles().get(groupId) : new HashSet<>(); List<Set<String>> environmentRoles = Arrays.stream(applicationEnvironmentService.getByApplicationId(applicationId)) .map(applicationEnvironment -> (applicationEnvironment.getGroupRoles() != null ? applicationEnvironment.getGroupRoles().get(groupId) : null)) .filter(roles -> roles != null).collect(Collectors.toList()); if (mustRemoveApplicationUserRole(applicationRoles, environmentRoles)) { // If we are here, it means that we must take out the APPLICATION_USER role for application as group does not have any other role than that resourceRoleService.removeGroupRole(application, groupId, ApplicationRole.APPLICATION_USER.toString()); } } }