diff --git a/src/main/java/edu/umd/dawn/common/annotations/AspectBase.java b/src/main/java/edu/umd/dawn/common/annotations/AspectBase.java index fe80d974a16d6b2ed82c8cc1a10a8a66d666af48..362abda5139ffb79f1ff2dea8b6bc2b675d265af 100644 --- a/src/main/java/edu/umd/dawn/common/annotations/AspectBase.java +++ b/src/main/java/edu/umd/dawn/common/annotations/AspectBase.java @@ -1,10 +1,13 @@ package edu.umd.dawn.common.annotations; +import jakarta.servlet.http.HttpServletRequest; import java.lang.annotation.Annotation; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; /** * base class for custom aspects for annotations. includes some helper functions @@ -29,4 +32,7 @@ public class AspectBase<T extends Annotation> { ((MethodSignature) jointPoint.getSignature()).getDeclaringType().getAnnotation(clazz); } + protected HttpServletRequest grabRequest() { + return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + } } diff --git a/src/main/java/edu/umd/dawn/common/annotations/RoleRestrictionAspect.java b/src/main/java/edu/umd/dawn/common/annotations/RoleRestrictionAspect.java index e9d5f2f4335bd6ab8167b7da15928d351f315b28..278361837ca3678fdaa5fbbdaeff639a6a541d1a 100644 --- a/src/main/java/edu/umd/dawn/common/annotations/RoleRestrictionAspect.java +++ b/src/main/java/edu/umd/dawn/common/annotations/RoleRestrictionAspect.java @@ -1,8 +1,10 @@ package edu.umd.dawn.common.annotations; +import edu.umd.dawn.common.enums.Role; import edu.umd.dawn.common.exceptions.BaseExceptions; import edu.umd.dawn.common.exceptions.DawnException; import edu.umd.dawn.common.jwt.Claims; +import edu.umd.dawn.common.services.UserAuthService; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @@ -16,10 +18,10 @@ import org.springframework.stereotype.Component; @Aspect @Component @Log4j2 -@RequiredArgsConstructor(onConstructor = @__(@Autowired)) // Autowired annotated lombok generated constructor public class RoleRestrictionAspect extends AspectBase<RoleRestriction> { - private final HttpServletRequest request; + @Autowired + private UserAuthService service; @Value("${config.local}") private boolean local = false; @@ -27,12 +29,16 @@ public class RoleRestrictionAspect extends AspectBase<RoleRestriction> { @Around("@annotation(RoleRestriction) && within(edu.umd.dawn..**)") public Object run(ProceedingJoinPoint jointPoint) throws Exception, Throwable { RoleRestriction annotation = grabAnnotation(jointPoint, RoleRestriction.class); + HttpServletRequest request = grabRequest(); if (!local) { Claims claims = (Claims) request.getAttribute("claims"); if (claims == null) { throw new DawnException(BaseExceptions.FORBIDDEN); } - // call db to check + Role role = service.getUserRole(claims.getUserId()); + if (!role.isAccessAllowed(annotation.value())) { + throw new DawnException(BaseExceptions.FORBIDDEN); + } } else if (!annotation.disableWarning()) { log.warn("RoleRestriction annotation has been disabled - if this is a production environment, consider this" + " a critical security error. Request with unknown role accessed endpoint with restriction " diff --git a/src/main/java/edu/umd/dawn/common/filters/CaseInsensitiveFilter.java b/src/main/java/edu/umd/dawn/common/filters/CaseInsensitiveFilter.java index e95df9d9c00241d3f6cfdd63acbaa37aaf69a3b5..061ef6284954eb6e6b145dda7947769b77635592 100644 --- a/src/main/java/edu/umd/dawn/common/filters/CaseInsensitiveFilter.java +++ b/src/main/java/edu/umd/dawn/common/filters/CaseInsensitiveFilter.java @@ -4,12 +4,9 @@ import com.google.common.base.CaseFormat; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -42,9 +39,7 @@ public class CaseInsensitiveFilter extends OncePerRequestFilter { formattedParams.put(formattedParam, request.getParameterValues(param)); } - filterChain.doFilter( - new CaseInsensitiveFilterWrapper(request, formattedParams), - response); + filterChain.doFilter(new CaseInsensitiveFilterWrapper(request, formattedParams), response); if (invalidParameterCase.size() > 0) { log.warn(String.format( diff --git a/src/main/java/edu/umd/dawn/common/filters/CaseInsensitiveFilterWrapper.java b/src/main/java/edu/umd/dawn/common/filters/CaseInsensitiveFilterWrapper.java index 9722cc061daf7c38c58b1d703d9d76533e749864..0d7438101070be52bc42b03f43ac6b4c7e120c26 100644 --- a/src/main/java/edu/umd/dawn/common/filters/CaseInsensitiveFilterWrapper.java +++ b/src/main/java/edu/umd/dawn/common/filters/CaseInsensitiveFilterWrapper.java @@ -1,12 +1,11 @@ package edu.umd.dawn.common.filters; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; import java.util.Collections; import java.util.Enumeration; import java.util.Map; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletRequestWrapper; - public class CaseInsensitiveFilterWrapper extends HttpServletRequestWrapper { Map<String, String[]> formattedParams; @@ -18,9 +17,7 @@ public class CaseInsensitiveFilterWrapper extends HttpServletRequestWrapper { @Override public String getParameter(String name) { - return formattedParams.containsKey(name) - ? formattedParams.get(name)[0] - : null; + return formattedParams.containsKey(name) ? formattedParams.get(name)[0] : null; } @Override @@ -37,5 +34,4 @@ public class CaseInsensitiveFilterWrapper extends HttpServletRequestWrapper { public Map<String, String[]> getParameterMap() { return formattedParams; } - } diff --git a/src/main/java/edu/umd/dawn/common/interceptor/JWTInterceptor.java b/src/main/java/edu/umd/dawn/common/interceptor/JWTInterceptor.java index 828d814e808a22fb87eef2f671e9acd2036596c9..a2fff2263423defcee06e85ea04138e10d76c89a 100644 --- a/src/main/java/edu/umd/dawn/common/interceptor/JWTInterceptor.java +++ b/src/main/java/edu/umd/dawn/common/interceptor/JWTInterceptor.java @@ -1,56 +1,55 @@ -package edu.umd.dawn.common.interceptor; - -import edu.umd.dawn.common.jwt.Claims; -import edu.umd.dawn.common.jwt.JWTUtil; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.extern.log4j.Log4j2; - -import org.springframework.web.servlet.HandlerInterceptor; - -/** - * interceptor to pull the claims and token for a jwt - * @implNote This does NOT throw any error if a jwt is not provided - */ -@Log4j2 -public class JWTInterceptor implements HandlerInterceptor { - - private boolean local; - private boolean warn; - private String accessSecret; - - /** - * - * @param accessSecret JWT Access Secret from configuration - * @param local is the environment a local env or not - * @param warn should a warning be thrown if no jwt is provided - */ - public JWTInterceptor(String accessSecret, boolean local, boolean warn) { - this.local = local; - this.accessSecret = accessSecret; - this.warn = warn; - } - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) - throws Exception { - if (!local) { - String token = request.getHeader("Authorization"); - if (token != null && !token.equals("")) { - if (token.startsWith("Bearer ")) { - token = token.replace("Bearer ", ""); - } - - Claims claims = JWTUtil.parse(accessSecret, token).getClaims(); - request.setAttribute("claims", claims); - request.setAttribute("token", token); - } else if (warn) { - log.warn("No jwt provided"); - } - } else { - log.warn("JWT interceptor has been disabled - if this is a production environment, consider this a" - + " critical security error"); - } - return true; - } -} +package edu.umd.dawn.common.interceptor; + +import edu.umd.dawn.common.jwt.Claims; +import edu.umd.dawn.common.jwt.JWTUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.log4j.Log4j2; +import org.springframework.web.servlet.HandlerInterceptor; + +/** + * interceptor to pull the claims and token for a jwt + * @implNote This does NOT throw any error if a jwt is not provided + */ +@Log4j2 +public class JWTInterceptor implements HandlerInterceptor { + + private boolean local; + private boolean warn; + private String accessSecret; + + /** + * + * @param accessSecret JWT Access Secret from configuration + * @param local is the environment a local env or not + * @param warn should a warning be thrown if no jwt is provided + */ + public JWTInterceptor(String accessSecret, boolean local, boolean warn) { + this.local = local; + this.accessSecret = accessSecret; + this.warn = warn; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + if (!local) { + String token = request.getHeader("Authorization"); + if (token != null && !token.equals("")) { + if (token.startsWith("Bearer ")) { + token = token.replace("Bearer ", ""); + } + + Claims claims = JWTUtil.parse(accessSecret, token).getClaims(); + request.setAttribute("claims", claims); + request.setAttribute("token", token); + } else if (warn) { + log.warn("No jwt provided"); + } + } else { + log.warn("JWT interceptor has been disabled - if this is a production environment, consider this a" + + " critical security error"); + } + return true; + } +}