package net.curisit.securis.security; import java.io.IOException; import java.lang.reflect.Method; import java.util.List; import java.util.Set; import javax.annotation.Priority; import javax.inject.Inject; import javax.persistence.EntityManager; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Priorities; import javax.ws.rs.WebApplicationException; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.ext.Provider; import net.curisit.securis.db.User; import net.curisit.securis.utils.CacheTTL; import net.curisit.securis.utils.TokenHelper; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.core.ResourceMethodInvoker; import org.jboss.resteasy.core.ServerResponse; import org.jboss.resteasy.spi.Failure; import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; @Provider // @PreMatching @Priority(Priorities.AUTHENTICATION) public class SecurityInterceptor implements javax.ws.rs.container.ContainerRequestFilter { private static final Logger LOG = LogManager.getLogger(SecurityInterceptor.class); @Inject private TokenHelper tokenHelper; @Context private HttpServletRequest servletRequest; @Inject CacheTTL cache; @Context Dispatcher dispatcher; @Inject com.google.inject.Provider emProvider; public void filter(ContainerRequestContext containerRequestContext) throws IOException { ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) containerRequestContext.getProperty("org.jboss.resteasy.core.ResourceMethodInvoker"); Method method = methodInvoker.getMethod(); if (!method.isAnnotationPresent(Securable.class)) return; String token = servletRequest.getHeader(TokenHelper.TOKEN_HEADER_PĂ€RAM); if (token == null || !tokenHelper.isTokenValid(token)) { LOG.info("Access denied to '{}', Token not valid.", servletRequest.getPathInfo()); containerRequestContext.abortWith(Response.status(Status.UNAUTHORIZED).build()); } else { Securable sec = method.getAnnotation(Securable.class); // If roles == 0 we only need to validate the token String username = tokenHelper.extractUserFromToken(token); int userRoles = getUserRoles(username); // if (sec.roles() != 0) { // if ((sec.roles() & userRoles) == 0) { // LOG.info("User {} has no necessary role to access url: {}", username, servletRequest.getPathInfo()); // containerRequestContext.abortWith(Response.status(Status.UNAUTHORIZED).build()); // } // } Set orgs = getUserOrganizations(username); BasicSecurityContext scw = new BasicSecurityContext(username, userRoles, servletRequest.isSecure()); scw.setOrganizationsIds(orgs); containerRequestContext.setSecurityContext(scw); // Next line provide injection in resource methods ResteasyProviderFactory.pushContext(BasicSecurityContext.class, scw); LOG.debug("Added custom SecurityContext for user {}, orgs: {}", username, orgs); } } private Set getUserOrganizations(String username) { @SuppressWarnings("unchecked") Set userOrgs = cache.get("orgs_" + username, Set.class); if (userOrgs == null) { // Theorically this shouldn't be never null, but just in case... EntityManager em = emProvider.get(); User user = em.find(User.class, username); if (user != null) { userOrgs = user.getAllOrgsIds(); // We store user orgs in cache only for one hour cache.set("orgs_" + username, userOrgs, 3600); } } return userOrgs; } private int getUserRoles(String username) { if (username == null) return 0; Integer userRoles = cache.get("roles_" + username, Integer.class); if (userRoles == null) { EntityManager em = emProvider.get(); User user = em.find(User.class, username); if (user != null) { userRoles = 0; List roles = user.getRoles(); for (Integer rol : roles) { userRoles += rol; } // We store user roles in cache only for one hour cache.set("roles_" + username, userRoles, 3600); cache.set("orgs_" + username, user.getOrgsIds(), 3600); } } return userRoles == null ? 0 : userRoles.intValue(); } // @Override public ServerResponse preProcess(HttpRequest request, ResourceMethodInvoker method) throws Failure, WebApplicationException { // TODO Auto-generated method stub return null; } }