diff --git a/wrappercommon/src/main/java/com/genexus/cors/CORSHelper.java b/wrappercommon/src/main/java/com/genexus/cors/CORSHelper.java index f1c700d75..a6dc74921 100644 --- a/wrappercommon/src/main/java/com/genexus/cors/CORSHelper.java +++ b/wrappercommon/src/main/java/com/genexus/cors/CORSHelper.java @@ -1,34 +1,71 @@ package com.genexus.cors; +import com.genexus.common.interfaces.SpecificImplementation; + import java.util.HashMap; +import java.util.List; +import java.util.Map; public class CORSHelper { - private static String CORS_ALLOWED_ORIGINS_ENV_VAR_NAME = "GX_CORS_ALLOW_ORIGIN"; + public static String REQUEST_METHOD_HEADER_NAME = "Access-Control-Request-Method"; + public static String REQUEST_HEADERS_HEADER_NAME = "Access-Control-Request-Headers"; + + private static String CORS_ALLOWED_ORIGIN = "CORS_ALLOW_ORIGIN"; private static String CORS_MAX_AGE_SECONDS = "86400"; - private static String CORS_ALLOWED_METHODS = "GET, POST, PUT, DELETE, HEAD"; - private static String CORS_ALLOWED_HEADERS = "*"; - public static HashMap getCORSHeaders(String requestRequiredHeaders) { - String corsAllowedOrigin = System.getenv(CORS_ALLOWED_ORIGINS_ENV_VAR_NAME); + + public static boolean corsSupportEnabled() { + return getAllowedOrigin() != null; + } + + public static HashMap getCORSHeaders(Map> headers) { + String corsAllowedOrigin = getAllowedOrigin(); + if (corsAllowedOrigin == null) return null; + + String requestedMethod = getHeaderValue(REQUEST_METHOD_HEADER_NAME, headers); + String requestedHeaders = getHeaderValue(REQUEST_HEADERS_HEADER_NAME, headers); + if (requestedMethod == null) { + return null; + } + + return corsHeaders(corsAllowedOrigin, requestedMethod, requestedHeaders); + } + + public static HashMap getCORSHeaders(String requestedMethod, String requestedHeaders) { + String corsAllowedOrigin = getAllowedOrigin(); + + if (corsAllowedOrigin == null || requestedMethod == null) { + return null; + } + + return corsHeaders(corsAllowedOrigin, requestedMethod, requestedHeaders); + } + + private static String getAllowedOrigin() { + String corsAllowedOrigin = SpecificImplementation.Application.getClientPreferences().getProperty(CORS_ALLOWED_ORIGIN, ""); if (corsAllowedOrigin == null || corsAllowedOrigin.isEmpty()) { return null; } + return corsAllowedOrigin; + } + + private static HashMap corsHeaders(String corsAllowedOrigin, String requestedMethod, String requestedHeaders) { HashMap corsHeaders = new HashMap<>(); - corsHeaders.put( - "Access-Control-Allow-Origin", corsAllowedOrigin); - corsHeaders.put( - "Access-Control-Allow-Credentials", "true"); - - corsHeaders.put( - "Access-Control-Allow-Headers", - requestRequiredHeaders == null || requestRequiredHeaders.isEmpty() ? CORS_ALLOWED_HEADERS : requestRequiredHeaders); - - corsHeaders.put( - "Access-Control-Allow-Methods", - CORS_ALLOWED_METHODS); - corsHeaders.put( - "Access-Control-Max-Age", - CORS_MAX_AGE_SECONDS); + corsHeaders.put("Access-Control-Allow-Origin", corsAllowedOrigin); + corsHeaders.put("Access-Control-Allow-Credentials", "true"); + if (requestedHeaders != null && !requestedHeaders.isEmpty()) { + corsHeaders.put("Access-Control-Allow-Headers", requestedHeaders); + } + corsHeaders.put("Access-Control-Allow-Methods", requestedMethod); + corsHeaders.put("Access-Control-Max-Age", CORS_MAX_AGE_SECONDS); return corsHeaders; } + + private static String getHeaderValue(String headerName, Map> headers) { + List value = headers.get(headerName); + if (value != null && value.size() > 0) { + return value.get(0); + } + return null; + } } diff --git a/wrapperjakarta/src/main/java/com/genexus/servlet/CorsFilter.java b/wrapperjakarta/src/main/java/com/genexus/servlet/CorsFilter.java index 7efb59baa..ab1f4537e 100644 --- a/wrapperjakarta/src/main/java/com/genexus/servlet/CorsFilter.java +++ b/wrapperjakarta/src/main/java/com/genexus/servlet/CorsFilter.java @@ -1,9 +1,7 @@ package com.genexus.servlet; - import com.genexus.cors.CORSHelper; import jakarta.servlet.*; -import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; @@ -25,7 +23,7 @@ public void init(FilterConfig filterConfig) throws ServletException { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; - HashMap corsHeaders = CORSHelper.getCORSHeaders(request.getHeader("Access-Control-Request-Headers")); + HashMap corsHeaders = CORSHelper.getCORSHeaders(request.getHeader(CORSHelper.REQUEST_METHOD_HEADER_NAME), request.getHeader(CORSHelper.REQUEST_HEADERS_HEADER_NAME)); if (corsHeaders != null) { HttpServletResponse response = (HttpServletResponse) servletResponse; for (String headerName : corsHeaders.keySet()) { @@ -34,9 +32,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo } } } - if (!request.getMethod().equalsIgnoreCase("OPTIONS")) { - filterChain.doFilter(servletRequest, servletResponse); - } + filterChain.doFilter(servletRequest, servletResponse); } @Override diff --git a/wrapperjakarta/src/main/java/com/genexus/ws/JAXRSCorsFilter.java b/wrapperjakarta/src/main/java/com/genexus/ws/JAXRSCorsFilter.java index bad0e4f0c..4d4bd7adb 100644 --- a/wrapperjakarta/src/main/java/com/genexus/ws/JAXRSCorsFilter.java +++ b/wrapperjakarta/src/main/java/com/genexus/ws/JAXRSCorsFilter.java @@ -14,7 +14,7 @@ public class JAXRSCorsFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { - HashMap corsHeaders = CORSHelper.getCORSHeaders(requestContext.getHeaderString("Access-Control-Request-Headers")); + HashMap corsHeaders = CORSHelper.getCORSHeaders(requestContext.getHeaders()); if (corsHeaders == null) { return; } diff --git a/wrapperjakarta/src/main/java/com/genexus/ws/rs/core/Response.java b/wrapperjakarta/src/main/java/com/genexus/ws/rs/core/Response.java index aa8d92511..8435d7ff5 100644 --- a/wrapperjakarta/src/main/java/com/genexus/ws/rs/core/Response.java +++ b/wrapperjakarta/src/main/java/com/genexus/ws/rs/core/Response.java @@ -1,6 +1,6 @@ package com.genexus.ws.rs.core; -public abstract class Response extends jakarta.ws.rs.core.Response{ +public abstract class Response extends jakarta.ws.rs.core.Response { public static Response.ResponseBuilder notModifiedWrapped() { return new Response.ResponseBuilder(jakarta.ws.rs.core.Response.notModified()); @@ -14,6 +14,12 @@ public static Response.ResponseBuilder okWrapped() { return new Response.ResponseBuilder(jakarta.ws.rs.core.Response.ok()); } + public static Response.ResponseBuilder options(String allowedMethods) { + Response.ResponseBuilder builder = okWrapped(); + builder.header("Allow", allowedMethods); + return builder; + } + public static Response.ResponseBuilder notFound() { return new Response.ResponseBuilder(jakarta.ws.rs.core.Response.status(Status.NOT_FOUND)); } @@ -41,7 +47,8 @@ public static Response.ResponseBuilder createdWrapped(java.net.URI uri) { public static Response.ResponseBuilder statusWrapped(int status) { return new Response.ResponseBuilder(jakarta.ws.rs.core.Response.status(status)); } - public static class ResponseBuilder implements IResponseBuilder{ + + public static class ResponseBuilder implements IResponseBuilder { jakarta.ws.rs.core.Response.ResponseBuilder rb; ResponseBuilder(jakarta.ws.rs.core.Response.ResponseBuilder rb) { @@ -51,13 +58,22 @@ public static class ResponseBuilder implements IResponseBuilder{ public jakarta.ws.rs.core.Response build() { return rb.build(); } + public void type(String type) { rb.type(type); } - public void entity(Object entity) { rb.entity(entity); } - public IResponseBuilder status(short i) { return new ResponseBuilder(rb.status(i)); } - public IResponseBuilder entityWrapped(Object entity) { return new ResponseBuilder(rb.entity(entity)); } + public void entity(Object entity) { + rb.entity(entity); + } + + public IResponseBuilder status(short i) { + return new ResponseBuilder(rb.status(i)); + } + + public IResponseBuilder entityWrapped(Object entity) { + return new ResponseBuilder(rb.entity(entity)); + } public void header(String header, Object object) { rb.header(header, object); diff --git a/wrapperjavax/src/main/java/com/genexus/servlet/CorsFilter.java b/wrapperjavax/src/main/java/com/genexus/servlet/CorsFilter.java index 043194ae7..7f5b9a85a 100644 --- a/wrapperjavax/src/main/java/com/genexus/servlet/CorsFilter.java +++ b/wrapperjavax/src/main/java/com/genexus/servlet/CorsFilter.java @@ -11,7 +11,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.HashMap; +import java.util.*; public class CorsFilter implements Filter { @Override @@ -22,7 +22,7 @@ public void init(FilterConfig filterConfig) throws ServletException { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; - HashMap corsHeaders = CORSHelper.getCORSHeaders(request.getHeader("Access-Control-Request-Headers")); + HashMap corsHeaders = CORSHelper.getCORSHeaders(request.getHeader(CORSHelper.REQUEST_METHOD_HEADER_NAME), request.getHeader(CORSHelper.REQUEST_HEADERS_HEADER_NAME)); if (corsHeaders != null) { HttpServletResponse response = (HttpServletResponse) servletResponse; for (String headerName : corsHeaders.keySet()) { @@ -31,9 +31,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo } } } - if (!request.getMethod().equalsIgnoreCase("OPTIONS")) { - filterChain.doFilter(servletRequest, servletResponse); - } + filterChain.doFilter(servletRequest, servletResponse); } @Override diff --git a/wrapperjavax/src/main/java/com/genexus/ws/JAXRSCorsFilter.java b/wrapperjavax/src/main/java/com/genexus/ws/JAXRSCorsFilter.java index 765d8724d..992e00670 100644 --- a/wrapperjavax/src/main/java/com/genexus/ws/JAXRSCorsFilter.java +++ b/wrapperjavax/src/main/java/com/genexus/ws/JAXRSCorsFilter.java @@ -6,7 +6,6 @@ import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.ext.Provider; -import java.util.Collections; import java.util.HashMap; @Provider @@ -15,7 +14,7 @@ public class JAXRSCorsFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { - HashMap corsHeaders = CORSHelper.getCORSHeaders(requestContext.getHeaderString("Access-Control-Request-Headers")); + HashMap corsHeaders = CORSHelper.getCORSHeaders(requestContext.getHeaders()); if (corsHeaders == null) { return; } diff --git a/wrapperjavax/src/main/java/com/genexus/ws/rs/core/Response.java b/wrapperjavax/src/main/java/com/genexus/ws/rs/core/Response.java index 7379cadf8..db58b7385 100644 --- a/wrapperjavax/src/main/java/com/genexus/ws/rs/core/Response.java +++ b/wrapperjavax/src/main/java/com/genexus/ws/rs/core/Response.java @@ -1,6 +1,6 @@ package com.genexus.ws.rs.core; -public abstract class Response extends javax.ws.rs.core.Response{ +public abstract class Response extends javax.ws.rs.core.Response { public static Response.ResponseBuilder notModifiedWrapped() { return new Response.ResponseBuilder(javax.ws.rs.core.Response.notModified()); @@ -13,6 +13,13 @@ public static Response.ResponseBuilder okWrapped(Object entity) { public static Response.ResponseBuilder okWrapped() { return new Response.ResponseBuilder(javax.ws.rs.core.Response.ok()); } + + public static Response.ResponseBuilder options(String allowedMethods) { + Response.ResponseBuilder builder = okWrapped(); + builder.header("Allow", allowedMethods); + return builder; + } + public static Response.ResponseBuilder notFound() { return new Response.ResponseBuilder(javax.ws.rs.core.Response.status(Status.NOT_FOUND)); } @@ -20,12 +27,15 @@ public static Response.ResponseBuilder notFound() { public static Response.ResponseBuilder conflict() { return new Response.ResponseBuilder(javax.ws.rs.core.Response.status(Status.CONFLICT)); } + public static Response.ResponseBuilder forbidden() { return new Response.ResponseBuilder(javax.ws.rs.core.Response.status(Status.FORBIDDEN)); } + public static Response.ResponseBuilder unauthorized() { return new Response.ResponseBuilder(javax.ws.rs.core.Response.status(Status.UNAUTHORIZED)); } + public static Response.ResponseBuilder noContentWrapped() { return new Response.ResponseBuilder(javax.ws.rs.core.Response.noContent()); } @@ -38,7 +48,7 @@ public static Response.ResponseBuilder statusWrapped(int status) { return new Response.ResponseBuilder(javax.ws.rs.core.Response.status(status)); } - public static class ResponseBuilder implements IResponseBuilder{ + public static class ResponseBuilder implements IResponseBuilder { javax.ws.rs.core.Response.ResponseBuilder rb; ResponseBuilder(javax.ws.rs.core.Response.ResponseBuilder rb) { @@ -53,11 +63,17 @@ public void type(String type) { rb.type(type); } - public void entity(Object entity) { rb.entity(entity); } + public void entity(Object entity) { + rb.entity(entity); + } - public IResponseBuilder status(short i) { return new ResponseBuilder(rb.status(i)); } + public IResponseBuilder status(short i) { + return new ResponseBuilder(rb.status(i)); + } - public IResponseBuilder entityWrapped(Object entity) { return new ResponseBuilder(rb.entity(entity)); } + public IResponseBuilder entityWrapped(Object entity) { + return new ResponseBuilder(rb.entity(entity)); + } public void header(String header, Object object) { rb.header(header, object);