package io.fathom.cloud.identity.api.os.resources; import io.fathom.cloud.CloudException; import io.fathom.cloud.PATCH; import io.fathom.cloud.WellKnownRoles; import io.fathom.cloud.identity.Users; import io.fathom.cloud.identity.api.os.model.Project; import io.fathom.cloud.identity.api.os.model.Projects; import io.fathom.cloud.identity.api.os.model.Roles; import io.fathom.cloud.identity.api.os.model.WrappedProject; import io.fathom.cloud.identity.api.os.model.v2.Role; import io.fathom.cloud.identity.model.AuthenticatedProject; import io.fathom.cloud.identity.model.AuthenticatedUser; import io.fathom.cloud.identity.state.AuthRepository; import io.fathom.cloud.protobuf.IdentityModel.ProjectData; import io.fathom.cloud.protobuf.IdentityModel.ProjectRoles; import io.fathom.cloud.protobuf.IdentityModel.RoleData; import io.fathom.cloud.protobuf.IdentityModel.UserData; import io.fathom.cloud.server.auth.Auth; import javax.inject.Inject; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.inject.persist.Transactional; @Path("/openstack/identity/v3/projects") @Produces({ "application/json" }) public class ProjectsResource extends IdentityResourceBase { private static final Logger log = LoggerFactory.getLogger(ProjectsResource.class); // Should use identity service instead @Deprecated @Inject AuthRepository authRepository; @GET @Transactional public Projects listProjects() throws CloudException { Auth.Domain domain = findDomainWithAdminRole(); if (domain == null) { // TODO: Should we allow a non-admin to list their own projects?? throw new WebApplicationException(Status.FORBIDDEN); } Projects response = new Projects(); response.projects = Lists.newArrayList(); for (ProjectData data : authRepository.getProjects().list()) { if (data.getDomainId() != domain.getId()) { continue; } Project user = toModel(data); response.projects.add(user); } return response; } @DELETE @Path("{id}") @Transactional public Response deleteProject(@PathParam("id") long userId) throws CloudException { UserData user = getUser(userId); if (user.getId() == getAuth().getUser().getId()) { // Don't let people delete themselves // TODO: Only protect admin account?? throw new IllegalArgumentException(); } // TODO: Mark as deleted? // TODO: Deleted related things e.g. credentials? // TODO: Block delete if "in use" authRepository.getProjects().delete(user.getId()); ResponseBuilder response = Response.noContent(); return response.build(); } @PATCH @Path("{id}") @Produces({ JSON }) @Transactional public WrappedProject patchProject(@PathParam("id") long projectId, WrappedProject wrappedProject) throws CloudException { ProjectData project = getProject(projectId); ProjectData.Builder b = ProjectData.newBuilder(project); Project req = wrappedProject.project; if (!Strings.isNullOrEmpty(req.description)) { b.setDescription(req.description); } if (req.enabled != null) { b.setEnabled(req.enabled); } ProjectData created = authRepository.getProjects().update(b); WrappedProject response = new WrappedProject(); response.project = toModel(created); return response; } @PUT @Path("{project_id}/users/{user_id}/roles/{role_id}") public Response grantRoleToUserOnProject(@PathParam("project_id") long projectId, @PathParam("user_id") long userId, @PathParam("role_id") long roleId) throws CloudException { AuthenticatedUser currentUser = getAuthenticatedUser(); UserData grantee = getUser(userId); AuthenticatedProject authenticatedProject = identityService.authenticateToProject(currentUser, projectId); if (authenticatedProject == null) { // Forbidden? log.info("Cannot authenticate to project: {} as user: {}", projectId, currentUser); throw new WebApplicationException(Status.NOT_FOUND); } identityService.grantRoleToUserOnProject(authenticatedProject, grantee.getId(), roleId); return Response.noContent().build(); } @POST public WrappedProject createProject(WrappedProject wrappedProject) throws CloudException { AuthenticatedUser owner = getAuthenticatedUser(); Project req = wrappedProject.project; ProjectData.Builder b = ProjectData.newBuilder(); if (!Strings.isNullOrEmpty(req.description)) { b.setDescription(req.description); } b.setName(req.name); if (!Strings.isNullOrEmpty(req.domainId)) { // Not sure what good can come of this... throw new UnsupportedOperationException(); } b.setDomainId(owner.getDomainId()); if (req.enabled != null) { b.setEnabled(req.enabled); } else { b.setEnabled(true); } ProjectData created = identityService.createProject(b, owner, WellKnownRoles.ROLE_ID_ADMIN); WrappedProject response = new WrappedProject(); response.project = toModel(created); return response; } @GET @Path("{projectId}") public WrappedProject getProjectDetails(@PathParam("projectId") long projectId) throws CloudException { ProjectData project = getProject(projectId); WrappedProject response = new WrappedProject(); response.project = toModel(project); return response; } @GET @Path("{projectId}/users/{userId}/roles") public Roles getProjectDetails(@PathParam("projectId") long projectId, @PathParam("userId") long userId) throws CloudException { UserData user = getUser(userId); ProjectData project = getProject(projectId); Roles response = new Roles(); response.roles = Lists.newArrayList(); ProjectRoles projectRoles = Users.findProjectRoles(user, project.getId()); if (projectRoles != null) { for (long roleId : projectRoles.getRoleList()) { RoleData role = identityService.findRole(roleId); if (role == null) { log.warn("Role not found: {}", roleId); } else { response.roles.add(toModel(role)); } } } return response; } private Role toModel(RoleData data) { Role role = new Role(); role.id = "" + data.getId(); role.name = data.getName(); return role; } }