package fi.otavanopisto.muikku.rest; import java.io.IOException; import java.lang.reflect.Method; import java.util.logging.Level; import java.util.logging.Logger; import javax.enterprise.inject.Default; import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.ext.Provider; import org.jboss.resteasy.core.ResourceMethodInvoker; import fi.otavanopisto.muikku.session.RestSessionController; import fi.otavanopisto.muikku.session.RestSesssion; import fi.otavanopisto.muikku.session.SessionControllerDelegate; import fi.otavanopisto.muikku.session.local.LocalSession; import fi.otavanopisto.muikku.session.local.LocalSessionAuthentication; import fi.otavanopisto.muikku.session.local.LocalSessionController; import fi.otavanopisto.muikku.session.local.LocalSessionRestAuthentication; import fi.otavanopisto.security.ContextReference; import fi.otavanopisto.security.Identity; import fi.otavanopisto.security.Permit.Style; import fi.otavanopisto.security.PermitUtils; import fi.otavanopisto.security.rest.RESTPermit; import fi.otavanopisto.security.rest.RESTPermit.Handling; @Provider public class RestSessionFilter implements javax.ws.rs.container.ContainerRequestFilter { @Inject private Logger logger; @Context private HttpServletRequest request; @Context private HttpServletResponse response; @Inject private Instance<Identity> identityInstance; @Inject @RestSesssion private RestSessionController restSessionController; @Inject @LocalSession private LocalSessionController localSessionController; @Inject @Default private SessionControllerDelegate sessionControllerDelegate; @Inject @LocalSessionAuthentication private LocalSessionRestAuthentication localSessionRestAuthentication; @Override public void filter(ContainerRequestContext requestContext) throws IOException { localSessionRestAuthentication.setActiveUser(localSessionController.getLoggedUserSchoolDataSource(), localSessionController.getLoggedUserIdentifier()); restSessionController.setAuthentication(localSessionRestAuthentication); restSessionController.setLocale(request.getLocale()); sessionControllerDelegate.setImplementation(restSessionController); ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) requestContext.getProperty("org.jboss.resteasy.core.ResourceMethodInvoker"); Method method = methodInvoker.getMethod(); if (method == null){ requestContext.abortWith(Response.status(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR).build()); } else { if (!checkPermission(method)) { requestContext.abortWith(Response.status(javax.ws.rs.core.Response.Status.FORBIDDEN).build()); } } } private boolean checkPermission(Method method) { RESTPermit permit = method.getAnnotation(RESTPermit.class); if (permit != null) { /** * Identity bean must be satisfied and unambiguous. */ if (identityInstance.isUnsatisfied()) throw new RuntimeException("PermitInterceptor - Identity bean unavailable"); if (identityInstance.isAmbiguous()) throw new RuntimeException("PermitInterceptor - Identity bean is ambiguous"); Identity identity = identityInstance.get(); // If login is required, check that first as it's unrelated to the permission check if (permit.requireLoggedIn()) { if (!identity.isLoggedIn()) return false; } // Inline checks are handled in the rest endpoint code so they are skipped here. if ((permit.handling() == Handling.INLINE) || (permit.handling() == Handling.UNSECURED)) return true; String[] permissions = permit.value(); Style style = permit.style(); ContextReference permitContext = null; return PermitUtils.hasPermission(identity, permissions, permitContext, style); } else { /** Temporary workaround until all rest permissions are fully implemented **/ RESTPermitUnimplemented unimplemented = method.getAnnotation(RESTPermitUnimplemented.class); if (unimplemented != null) return true; // Return true for unimplemented rest endpoints /** Temporary workaround until all rest permissions are fully implemented **/ // Return false in a normal situation where RESTPermit is not defined String methodName = method != null ? method.getName() : "unknown"; logger.log(Level.WARNING, String.format("Execution of REST endpoint which doesn't have RESTPermit annotation (%s) was blocked.", methodName)); return false; } } }