package org.gcube.common.authorizationservice; import java.util.ArrayList; import java.util.List; import java.util.UUID; import javax.annotation.ManagedBean; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.gcube.common.authorization.library.AuthorizationEntry; import org.gcube.common.authorization.library.ExternalServiceList; import org.gcube.common.authorization.library.provider.CalledMethodProvider; import org.gcube.common.authorization.library.provider.ContainerInfo; import org.gcube.common.authorization.library.provider.ExternalServiceInfo; import org.gcube.common.authorization.library.provider.ServiceInfo; import org.gcube.common.authorization.library.provider.UserInfo; import org.gcube.common.authorization.library.utils.AuthorizationEntryList; import org.gcube.common.authorization.library.utils.ListMapper; import org.gcube.common.authorization.library.utils.MultiServiceTokenRequest; import org.gcube.common.authorizationservice.filters.AuthorizedCallFilter; import org.gcube.common.authorizationservice.util.Constants; import org.gcube.common.authorizationservice.util.TokenPersistence; import lombok.extern.slf4j.Slf4j; @Path("token") @Slf4j @ManagedBean public class TokenManager { @Inject TokenPersistence persistence; /** * * retrieves the AuthorzationEntry connected to the specified token * * @param token * @return the authorization entry */ @GET @Path("{token}") @Produces(MediaType.APPLICATION_XML) public AuthorizationEntry retrieveToken(@NotNull @PathParam("token") String token ) { CalledMethodProvider.instance.set("retrieve"); log.info("token retreiver called with token {}",token); AuthorizationEntry info = null; try { info = persistence.getAuthorizationEntry(token); } catch ( Throwable t) { log.error("erorr on authorization", t); throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("error on authorization").type(MediaType.TEXT_PLAIN).build()); } log.info("info retrieved {}",info); if (info == null){ log.error("token {} not found ", token); throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) .entity("token "+token+" not found").type(MediaType.TEXT_PLAIN).build()); } /* try{ ScopeProvider.instance.set(info.getContext()); ServiceMap map = ((ScopedServiceMap)ServiceMap.instance).currentMap(); ScopeProvider.instance.reset(); info.setMap(map); }catch(Throwable e){ log.error("error retrieving map for {}", info.getContext(), e); }*/ log.debug("returning info {}", info); return info; } /** * * retrieves the AuthorzationEntry connected to the specified token * * @param token * @return the authorization entry */ @GET @Path("bunch") @Produces(MediaType.APPLICATION_XML) public AuthorizationEntryList retrieveTokenBunch(@NotNull @QueryParam("token") List tokens ) { CalledMethodProvider.instance.set("retrieve"); log.info("token retreiver in bunch called with tokens {}",tokens); List toReturn = new ArrayList(); for (String token : tokens ) { try { AuthorizationEntry info = persistence.getAuthorizationEntry(token); /* try{ ScopeProvider.instance.set(info.getContext()); DefaultServiceMap map = (DefaultServiceMap)((ScopedServiceMap)ServiceMap.instance).currentMap(); ScopeProvider.instance.reset(); info.setMap(map); }catch(Throwable e){ log.error("error retrieving map for {}", info.getContext(), e); } */ toReturn.add(info); }catch(Exception t) { log.error("erorr on authorization", t); } } log.info("info retrieved {}",toReturn); if (toReturn.isEmpty()){ log.error("no tokens poassed have been found "); throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) .entity("no tokens poassed have been found ").type(MediaType.TEXT_PLAIN).build()); } return new AuthorizationEntryList(toReturn); } /** * * retrieves the AuthorzationEntry connected to the specified token * * @param token * @return the authorization entry */ @GET @Path("resolve/{user}") public String getTokenByUserAndContext(@NotNull @PathParam("user") String user, @QueryParam("context") String context ) { CalledMethodProvider.instance.set("retrieve"); log.info("resolving token for user {} in context {}",user, context); if (context==null){ log.error("null context found"); throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) .entity("null context found").type(MediaType.TEXT_PLAIN).build()); } String token = persistence.getExistingToken(user, context, Constants.DEFAULT_TOKEN_QUALIFIER); if (token == null){ log.error("token {} not found ", token); throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) .entity("token for user "+user+" in context "+context+" not found").type(MediaType.TEXT_PLAIN).build()); } //TODO: re-add it with common-scope 2.0 /* try{ ServiceMap map = .instance.getMap(info.getContext()); info.setMap(map); }catch(Exception e){ log.error("error retrieving map for {}", info.getContext(), e); throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Error retrieving map").type(MediaType.TEXT_PLAIN).build()); }*/ return token; } /** * * Generates a token for a user (saving the passed roles) if it doesn't exist yet. * * @param userName * @param roles * @return the generated token or the token related to the user (if it was already created) */ @Path("user") @PUT @Consumes(MediaType.APPLICATION_XML) public String generateUserToken(UserInfo clientId, @NotNull @QueryParam("context") String context) { CalledMethodProvider.instance.set("generate"); try{ log.info("generator called with user {} in context {} ",clientId, context); if (clientId.getId().split(":").length>1) throw new Exception("invalid user id: "+clientId.getId()); String token = persistence.getExistingToken(clientId.getId(), context, Constants.DEFAULT_TOKEN_QUALIFIER); if (token==null){ token = UUID.randomUUID().toString(); persistence.saveAuthorizationEntry(token, context, clientId , Constants.DEFAULT_TOKEN_QUALIFIER, null); } return token; }catch(Exception e){ log.error("error generating token ",e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Error Generating Token: "+e.getMessage()).type(MediaType.TEXT_PLAIN).build()); } } /** * * Generates a token for a user (saving the passed roles) if it doesn't exist yet. * * @param userName * @param roles * @return the generated token or the token related to the user (if it was already created) */ @Path("user/{token}/roles") @PUT @Consumes(MediaType.APPLICATION_XML) public String setRoles(ListMapper roles, @NotNull @PathParam("token") String token) { CalledMethodProvider.instance.set("setRoles"); try{ log.info("update roles called"); persistence.updateAuthorizationEntry(token, roles.getList()) ; return token; }catch(Exception e){ log.error("error setting roles to token ",e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Error setting roles to token: "+e.getMessage()).type(MediaType.TEXT_PLAIN).build()); } } /** * * REmoves a token for a user. * * @param userName * @param roles * @return the generated token or the token related to the user (if it was already created) */ @Path("user") @DELETE @Consumes(MediaType.APPLICATION_XML) public void removeUserToken(@NotNull @QueryParam("client_id") String clientId, @NotNull @QueryParam("context") String context) { CalledMethodProvider.instance.set("delete"); try{ log.info("generator called with user {} in context {} ",clientId, context); if (clientId.split(":").length>1) throw new Exception("invalid user id: "+clientId); persistence.removeAllAuthorizationsEntryForClientId(context, clientId); }catch(Exception e){ log.error("error generating token ",e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Error removing Token: "+e.getMessage()).type(MediaType.TEXT_PLAIN).build()); } } /** * * Generates a token for a service if it doesn't exist yet. * * @param userName * @param roles * @return the generated token or the token related to the user (if it was already created) */ @Path("service") @PUT @Consumes(MediaType.APPLICATION_XML) public String generateServiceToken(ServiceInfo serviceInfo, @Context HttpServletRequest req) { CalledMethodProvider.instance.set("generate"); try{ AuthorizationEntry authInfo = (AuthorizationEntry)req.getAttribute(AuthorizedCallFilter.AUTH_ATTRIBUTE); log.info("generator called with service {} in context {} ",serviceInfo.getId(), authInfo.getContext()); return generateTokenForServiceInfo(serviceInfo, authInfo); }catch(Exception e){ log.error("error generating token ",e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Error Generating Token: "+e.getMessage()).type(MediaType.TEXT_PLAIN).build()); } } /** * * Generates a list of tokens for a service if it doesn't exist yet. * * @param userName * @param MultiServiceTokenRequest entity * @return a list generated token or the token related to the user (if it was already created) */ @Path("service/bunch") @PUT @Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) public ListMapper generateServiceTokenBunch(MultiServiceTokenRequest entity, @Context HttpServletRequest req) { CalledMethodProvider.instance.set("generate"); log.info("calling generate service token bunch"); try{ AuthorizationEntry callerInfo = (AuthorizationEntry)req.getAttribute(AuthorizedCallFilter.AUTH_ATTRIBUTE); List tokensToReturn = new ArrayList(); for (String token: entity.getContainerTokens()) { AuthorizationEntry authInfo = this.retrieveToken(token); if (authInfo==null) continue; if (!authInfo.getClientInfo().getId().equals(callerInfo.getClientInfo().getId())) log.warn("a token with a different ContainerInfo of the caller used, skipping it"); else { String genToken = generateTokenForServiceInfo(entity.getInfo(), authInfo); tokensToReturn.add(genToken); } } return new ListMapper(tokensToReturn); }catch(Exception e){ log.error("error generating tokens ",e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Error Generating Token: "+e.getMessage()).type(MediaType.TEXT_PLAIN).build()); } } /** * * Generates a token for an external service if it doesn't exist yet. * * @param externalServiceInfo * @return the generated token or the token related to the external service (if it was already created) */ @Path("external/{serviceId}") @PUT @Consumes(MediaType.APPLICATION_XML) public String generateExternalServiceToken(@PathParam("serviceId") String serviceId, @Context HttpServletRequest req) { try{ CalledMethodProvider.instance.set("generate"); AuthorizationEntry info = (AuthorizationEntry)req.getAttribute(AuthorizedCallFilter.AUTH_ATTRIBUTE); log.info("generator called for external service {} in context {} ",serviceId, info.getContext()); if (serviceId.split(":").length>1) throw new Exception("invalid external service id: "+serviceId); String token = persistence.getExistingToken(serviceId, info.getContext(), Constants.DEFAULT_TOKEN_QUALIFIER); if (token==null){ token= UUID.randomUUID().toString(); persistence.saveAuthorizationEntry(token, info.getContext(), new ExternalServiceInfo(serviceId, info.getClientInfo().getId()), Constants.DEFAULT_TOKEN_QUALIFIER, info.getClientInfo().getId()); } return token; }catch(Exception e){ log.error("error generating token ",e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Error Generating Token: "+e.getMessage()).type(MediaType.TEXT_PLAIN).build()); } } /** * * Generates a token for an external service if it doesn't exist yet. * * @param externalServiceInfo * @return the generated token or the token related to the external service (if it was already created) */ @Path("external") @GET @Consumes(MediaType.APPLICATION_XML) public ExternalServiceList getExternalServiceCreated(@Context HttpServletRequest req) { CalledMethodProvider.instance.set("retrieve"); try{ AuthorizationEntry info = (AuthorizationEntry)req.getAttribute(AuthorizedCallFilter.AUTH_ATTRIBUTE); log.info("get External Service called in context {} by {} ",info.getContext(), info.getClientInfo().getId()); ExternalServiceList toReturn = new ExternalServiceList(persistence.getExistingExternalServices(info.getClientInfo().getId(), info.getContext())); return toReturn; }catch(Exception e){ log.error("error generating token ",e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Error Generating Token: "+e.getMessage()).type(MediaType.TEXT_PLAIN).build()); } } @Path("node") @PUT @Consumes(MediaType.APPLICATION_XML) public String generateContainerToken(@NotNull ContainerInfo containerInfo, @QueryParam("context") String context, @Context HttpServletRequest req) { CalledMethodProvider.instance.set("generate"); try{ AuthorizationEntry info = (AuthorizationEntry)req.getAttribute(AuthorizedCallFilter.AUTH_ATTRIBUTE); if (context!=null) return generateTokenForContainerInfo(containerInfo, context); else if (info!=null){ log.info("generator called for node {} in context {} ",containerInfo.getId(), info.getContext()); return generateTokenForContainerInfo(containerInfo, info); } throw new Exception("error trying to activate node (token and context are empty)"); }catch(Exception e){ log.error("error generating token ",e); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("Error Generating Token: "+e.getMessage()).type(MediaType.TEXT_PLAIN).build()); } } private String generateTokenForContainerInfo(ContainerInfo containerInfo,String context) throws Exception{ if (containerInfo.getId().split(":").length!=2) throw new Exception("invalid container id: "+containerInfo.getId()); String token = persistence.getExistingToken(containerInfo.getId(), context, Constants.DEFAULT_TOKEN_QUALIFIER); if( token ==null){ token = UUID.randomUUID().toString();; persistence.saveAuthorizationEntry(token, context, containerInfo, Constants.DEFAULT_TOKEN_QUALIFIER, null); } return token; } private String generateTokenForContainerInfo(ContainerInfo containerInfo, AuthorizationEntry authInfo) throws Exception{ if (containerInfo.getId().split(":").length!=2) throw new Exception("invalid container id: "+containerInfo.getId()); String token = persistence.getExistingToken(containerInfo.getId(),authInfo.getContext(), Constants.DEFAULT_TOKEN_QUALIFIER); if( token ==null){ token = UUID.randomUUID().toString();; persistence.saveAuthorizationEntry(token, authInfo.getContext(), containerInfo, Constants.DEFAULT_TOKEN_QUALIFIER, authInfo.getClientInfo().getId() ); } return token; } private String generateTokenForServiceInfo(ServiceInfo serviceInfo, AuthorizationEntry authInfo) throws Exception{ if (serviceInfo.getId().split(":").length!=3) throw new Exception("invalid service id: "+serviceInfo.getId()); String token = persistence.getExistingToken(serviceInfo.getId(), authInfo.getContext(), Constants.DEFAULT_TOKEN_QUALIFIER); if( token ==null){ token = UUID.randomUUID().toString();; persistence.saveAuthorizationEntry(token, authInfo.getContext(), serviceInfo, Constants.DEFAULT_TOKEN_QUALIFIER, authInfo.getClientInfo().getId() ); } return token; } }