You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by GitBox <gi...@apache.org> on 2020/07/14 08:43:05 UTC

[GitHub] [struts] salcho opened a new pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

salcho opened a new pull request #426:
URL: https://github.com/apache/struts/pull/426


   Hello Struts devs,
   
   This PR builds Fetch Metadata support on for Struts2, namely:
   
   - If a request has `Sec-Fetch-*` headers (i.e. comes from a modern browser), the Fetch Metadata Interceptor will reject the request if it is requested cross-site (a potential CSRF attack).
   - One default Resource Isolation Policy is provided based on https://web.dev/fetch-metadata/, which prevents all major cross-site request forgery attacks.
   - This Interceptor gives the ability to add exemptions to this security mitigation, that is: URLs that are meant to be accessed cross-site.
   - The Fetch Metadata Interceptor has been added to the default interceptor stack.
   - The `Vary` header has been added to responses to ensure that any cached responses include Fetch Metadata headers in their key. This is an added layer of security against cache poisoning.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


[GitHub] [struts] yasserzamani commented on a change in pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
yasserzamani commented on a change in pull request #426:
URL: https://github.com/apache/struts/pull/426#discussion_r455719812



##########
File path: core/src/main/java/org/apache/struts2/interceptor/FetchMetadataInterceptor.java
##########
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.interceptor;
+
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_DEST_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_MODE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_SITE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.VARY_HEADER;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.util.TextParseUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Interceptor that implements Fetch Metadata policy on incoming requests used to protect against
+ * CSRF, XSSI, and cross-origin information leaks. Uses {@link StrutsResourceIsolationPolicy} to
+ * filter the requests allowed to be processed.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ **/
+
+public class FetchMetadataInterceptor extends AbstractInterceptor implements PreResultListener {
+
+    private final Set<String> exemptedPaths = new HashSet<String>();
+    private final ResourceIsolationPolicy resourceIsolationPolicy = new StrutsResourceIsolationPolicy();
+    private static final String VARY_HEADER_VALUE = String.format("%s,%s,%s", SEC_FETCH_DEST_HEADER, SEC_FETCH_SITE_HEADER, SEC_FETCH_MODE_HEADER);
+    private static final String SC_FORBIDDEN = String.valueOf(HttpServletResponse.SC_FORBIDDEN);
+
+    public void setExemptedPaths(String paths){
+        this.exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
+    }
+
+    @Override
+    public void beforeResult(ActionInvocation invocation, String resultCode) {
+        // Add Vary headers
+        HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
+        response.setHeader(VARY_HEADER, VARY_HEADER_VALUE);
+    }
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+        ActionContext context = invocation.getInvocationContext();
+        HttpServletRequest request = context.getServletRequest();
+
+        // Adds listener that operates between interceptor and result rendering to set Vary headers
+        invocation.addPreResultListener(this);
+
+        // Apply exemptions: paths/endpoints meant to be served cross-origin
+        if (exemptedPaths.contains(request.getContextPath())) {
+            return invocation.invoke();
+        }
+
+        // Check if request is allowed
+        if (resourceIsolationPolicy.isRequestAllowed(request)) {
+            return invocation.invoke();
+        }
+
+        beforeResult(invocation, SC_FORBIDDEN);

Review comment:
       Yes likely. I'll take a look if it can be fixed. thanks!




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] coveralls edited a comment on pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
coveralls edited a comment on pull request #426:
URL: https://github.com/apache/struts/pull/426#issuecomment-658126974


   
   [![Coverage Status](https://coveralls.io/builds/32139500/badge)](https://coveralls.io/builds/32139500)
   
   Coverage increased (+0.03%) to 49.344% when pulling **8902a9a6b5564f5b9d121a1f6ff3e100f3fbb7cf on salcho:post-ww-5083** into **c2b09d76be804b3c406b0e26409388b115a49115 on apache:master**.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] salcho commented on pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
salcho commented on pull request #426:
URL: https://github.com/apache/struts/pull/426#issuecomment-659935747


   Hi @lukaszlenart , sorry, I couldn't reply to your comment so here's my reply:
   
   I think this case is slightly different than usual in that there are two outcomes for Fetch Metadata: we **always** register ourselves as a `PreResultListener` (line 69) and then we have two possible outcomes: either the request is accepted as legitimate (in which case we let the interceptor chain continue and eventually our `beforeResult` method called) or we reject the request and by doing so interrupt the chain of interceptors. In the latter, the `beforeResult` callback is never called, but because we still want to add the `Vary` headers, we call it manually to reuse that logic.
   
   If this code is somewhat harder to read, we could extract the logic for adding the `Vary` headers into a separate method and call that method explicitly in the rejection branch, so that it doesn't look like we're trying to do something related to the responsibilities of `PreResultListener`.
   
   What do you think?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] salcho commented on a change in pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
salcho commented on a change in pull request #426:
URL: https://github.com/apache/struts/pull/426#discussion_r455683472



##########
File path: core/src/main/java/org/apache/struts2/interceptor/FetchMetadataInterceptor.java
##########
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.interceptor;
+
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_DEST_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_MODE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_SITE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.VARY_HEADER;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.util.TextParseUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Interceptor that implements Fetch Metadata policy on incoming requests used to protect against
+ * CSRF, XSSI, and cross-origin information leaks. Uses {@link StrutsResourceIsolationPolicy} to
+ * filter the requests allowed to be processed.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ **/
+
+public class FetchMetadataInterceptor extends AbstractInterceptor implements PreResultListener {
+
+    private final Set<String> exemptedPaths = new HashSet<String>();
+    private final ResourceIsolationPolicy resourceIsolationPolicy = new StrutsResourceIsolationPolicy();
+    private static final String VARY_HEADER_VALUE = String.format("%s,%s,%s", SEC_FETCH_DEST_HEADER, SEC_FETCH_SITE_HEADER, SEC_FETCH_MODE_HEADER);
+    private static final String SC_FORBIDDEN = String.valueOf(HttpServletResponse.SC_FORBIDDEN);
+
+    public void setExemptedPaths(String paths){
+        this.exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
+    }
+
+    @Override
+    public void beforeResult(ActionInvocation invocation, String resultCode) {
+        // Add Vary headers
+        HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
+        response.setHeader(VARY_HEADER, VARY_HEADER_VALUE);
+    }
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+        ActionContext context = invocation.getInvocationContext();
+        HttpServletRequest request = context.getServletRequest();
+
+        // Adds listener that operates between interceptor and result rendering to set Vary headers
+        invocation.addPreResultListener(this);
+
+        // Apply exemptions: paths/endpoints meant to be served cross-origin
+        if (exemptedPaths.contains(request.getContextPath())) {
+            return invocation.invoke();
+        }
+
+        // Check if request is allowed
+        if (resourceIsolationPolicy.isRequestAllowed(request)) {
+            return invocation.invoke();
+        }
+
+        beforeResult(invocation, SC_FORBIDDEN);

Review comment:
       Unfortunately it doesn't, I was surprised too! I believe this is because the interceptor chain isn't propagated due to returning early?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] salcho commented on a change in pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
salcho commented on a change in pull request #426:
URL: https://github.com/apache/struts/pull/426#discussion_r454251354



##########
File path: core/src/main/java/org/apache/struts2/interceptor/DefaultResourceIsolationPolicy.java
##########
@@ -0,0 +1,49 @@
+package org.apache.struts2.interceptor;

Review comment:
       just pushed another commit adding the missing licenses




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] yasserzamani commented on a change in pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
yasserzamani commented on a change in pull request #426:
URL: https://github.com/apache/struts/pull/426#discussion_r455179316



##########
File path: core/src/main/java/org/apache/struts2/interceptor/FetchMetadataInterceptor.java
##########
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.interceptor;
+
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_DEST_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_MODE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_SITE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.VARY_HEADER;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.util.TextParseUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Interceptor that implements Fetch Metadata policy on incoming requests used to protect against
+ * CSRF, XSSI, and cross-origin information leaks. Uses {@link StrutsResourceIsolationPolicy} to
+ * filter the requests allowed to be processed.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ **/
+
+public class FetchMetadataInterceptor extends AbstractInterceptor implements PreResultListener {
+
+    private final Set<String> exemptedPaths = new HashSet<String>();
+    private final ResourceIsolationPolicy resourceIsolationPolicy = new StrutsResourceIsolationPolicy();
+    private static final String VARY_HEADER_VALUE = String.format("%s,%s,%s", SEC_FETCH_DEST_HEADER, SEC_FETCH_SITE_HEADER, SEC_FETCH_MODE_HEADER);
+    private static final String SC_FORBIDDEN = String.valueOf(HttpServletResponse.SC_FORBIDDEN);
+
+    public void setExemptedPaths(String paths){
+        this.exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
+    }
+
+    @Override
+    public void beforeResult(ActionInvocation invocation, String resultCode) {
+        // Add Vary headers
+        HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
+        response.setHeader(VARY_HEADER, VARY_HEADER_VALUE);
+    }
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+        ActionContext context = invocation.getInvocationContext();
+        HttpServletRequest request = context.getServletRequest();
+
+        // Adds listener that operates between interceptor and result rendering to set Vary headers
+        invocation.addPreResultListener(this);
+
+        // Apply exemptions: paths/endpoints meant to be served cross-origin
+        if (exemptedPaths.contains(request.getContextPath())) {
+            return invocation.invoke();
+        }
+
+        // Check if request is allowed
+        if (resourceIsolationPolicy.isRequestAllowed(request)) {
+            return invocation.invoke();
+        }
+
+        beforeResult(invocation, SC_FORBIDDEN);
+        return SC_FORBIDDEN;

Review comment:
       Maybe an info level log before this line will help why request is forbidden.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] aaronshim commented on pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
aaronshim commented on pull request #426:
URL: https://github.com/apache/struts/pull/426#issuecomment-658182958


   Great job, @salcho !


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] lukaszlenart commented on pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
lukaszlenart commented on pull request #426:
URL: https://github.com/apache/struts/pull/426#issuecomment-659975016


   Yeah... I think it would be better to stop using `PreResultListener` and just add the header on the beginning of the `intercept()` method.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] salcho commented on pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
salcho commented on pull request #426:
URL: https://github.com/apache/struts/pull/426#issuecomment-659320781


   Thanks for your review Yasser! The log statement will be useful for debugging endpoints that should have been added to exempted paths.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] lukaszlenart merged pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
lukaszlenart merged pull request #426:
URL: https://github.com/apache/struts/pull/426


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


[GitHub] [struts] salcho commented on a change in pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
salcho commented on a change in pull request #426:
URL: https://github.com/apache/struts/pull/426#discussion_r454252239



##########
File path: core/src/main/java/org/apache/struts2/interceptor/DefaultResourceIsolationPolicy.java
##########
@@ -0,0 +1,49 @@
+package org.apache.struts2.interceptor;
+
+import org.apache.logging.log4j.util.Strings;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * Default resource isolation policy used in {@link FetchMetadataInterceptor} that
+ * implements the {@link ResourceIsolationPolicy} interface. This default policy is based on
+ * <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ *
+ * @author Santiago Diaz - saldiaz@google.com
+ * @author Giannis Chatziveroglou - giannic@google.com

Review comment:
       haha that's fair! :)




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] lukaszlenart commented on a change in pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
lukaszlenart commented on a change in pull request #426:
URL: https://github.com/apache/struts/pull/426#discussion_r454244077



##########
File path: core/src/main/java/org/apache/struts2/interceptor/DefaultResourceIsolationPolicy.java
##########
@@ -0,0 +1,49 @@
+package org.apache.struts2.interceptor;

Review comment:
       You are missing a header with license, see other files for an example

##########
File path: core/src/main/java/org/apache/struts2/interceptor/DefaultResourceIsolationPolicy.java
##########
@@ -0,0 +1,49 @@
+package org.apache.struts2.interceptor;
+
+import org.apache.logging.log4j.util.Strings;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * Default resource isolation policy used in {@link FetchMetadataInterceptor} that
+ * implements the {@link ResourceIsolationPolicy} interface. This default policy is based on
+ * <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ *
+ * @author Santiago Diaz - saldiaz@google.com
+ * @author Giannis Chatziveroglou - giannic@google.com

Review comment:
       Please remove these tags and emails, after merging this code it will be owned by ASF and you want to be bothered by users to help them resolve their problems, it's community duty :)
   
   http://tinyurl.com/mw7t6

##########
File path: core/src/main/java/org/apache/struts2/interceptor/ResourceIsolationPolicy.java
##########
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.interceptor;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Interface for the resource isolation policies to be used for fetch metadata checks.
+ *
+ * Resource isolation policies are designed to protect against cross origin attacks and use the
+ * {@code sec-fetch-*} request headers to decide whether to accept or reject a request. Read more
+ * about <a href="https://web.dev/fetch-metadata/">Fetch Metadata.</a>
+ *
+ * See {@link DefaultResourceIsolationPolicy} for the default implementation used.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ *
+ * @author Santiago Diaz - saldiaz@google.com
+ * @author Giannis Chatziveroglou - giannic@google.com

Review comment:
       Please remove these tags as explained earlier

##########
File path: core/src/main/java/org/apache/struts2/interceptor/DefaultResourceIsolationPolicy.java
##########
@@ -0,0 +1,49 @@
+package org.apache.struts2.interceptor;
+
+import org.apache.logging.log4j.util.Strings;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * Default resource isolation policy used in {@link FetchMetadataInterceptor} that
+ * implements the {@link ResourceIsolationPolicy} interface. This default policy is based on
+ * <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ *
+ * @author Santiago Diaz - saldiaz@google.com
+ * @author Giannis Chatziveroglou - giannic@google.com
+ **/
+
+public final class DefaultResourceIsolationPolicy implements ResourceIsolationPolicy {

Review comment:
       ```suggestion
   public final class StrutsResourceIsolationPolicy implements ResourceIsolationPolicy {
   ```

##########
File path: core/src/main/java/org/apache/struts2/interceptor/FetchMetadataInterceptor.java
##########
@@ -0,0 +1,96 @@
+package org.apache.struts2.interceptor;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.util.TextParseUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * <!-- START SNIPPET: description -->

Review comment:
       It's  not needed anymore, we don't use Confluence any longer, instead you can create a PR with description about the new interceptor [here](https://github.com/apache/struts-site/blob/master/source/core-developers/interceptors.md)

##########
File path: core/src/main/java/org/apache/struts2/interceptor/FetchMetadataInterceptor.java
##########
@@ -0,0 +1,96 @@
+package org.apache.struts2.interceptor;

Review comment:
       Header with a license is missing

##########
File path: core/src/main/java/org/apache/struts2/interceptor/DefaultResourceIsolationPolicy.java
##########
@@ -0,0 +1,49 @@
+package org.apache.struts2.interceptor;
+
+import org.apache.logging.log4j.util.Strings;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * Default resource isolation policy used in {@link FetchMetadataInterceptor} that
+ * implements the {@link ResourceIsolationPolicy} interface. This default policy is based on
+ * <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ *
+ * @author Santiago Diaz - saldiaz@google.com
+ * @author Giannis Chatziveroglou - giannic@google.com
+ **/
+
+public final class DefaultResourceIsolationPolicy implements ResourceIsolationPolicy {
+
+    @Override
+    public boolean isRequestAllowed(HttpServletRequest request) {
+        String site = request.getHeader(SEC_FETCH_SITE_HEADER);
+
+        // Allow requests from browsers which don't send Fetch Metadata
+        if (Strings.isEmpty((site))){
+            return true;
+        }
+
+        // Allow same-site and browser-initiated requests
+        if (SAME_ORIGIN.equals(site) || SAME_SITE.equals(site) || NONE.equals(site)) {
+            return true;
+        }
+
+        // Allow simple top-level navigations except <object> and <embed>
+        return isAllowedTopLevelNavigation(request);
+    }
+
+    private boolean isAllowedTopLevelNavigation(HttpServletRequest request)
+    {

Review comment:
       Inconsistent formatting, please move this bracket to the end of the previous line, thanks!

##########
File path: core/src/main/java/org/apache/struts2/interceptor/DefaultResourceIsolationPolicy.java
##########
@@ -0,0 +1,49 @@
+package org.apache.struts2.interceptor;
+
+import org.apache.logging.log4j.util.Strings;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * Default resource isolation policy used in {@link FetchMetadataInterceptor} that
+ * implements the {@link ResourceIsolationPolicy} interface. This default policy is based on
+ * <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ *
+ * @author Santiago Diaz - saldiaz@google.com
+ * @author Giannis Chatziveroglou - giannic@google.com
+ **/
+
+public final class DefaultResourceIsolationPolicy implements ResourceIsolationPolicy {

Review comment:
       I prefer to use `Struts` prefix to indicate that this a default `Struts` implementation :)




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] coveralls commented on pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
coveralls commented on pull request #426:
URL: https://github.com/apache/struts/pull/426#issuecomment-658126974


   
   [![Coverage Status](https://coveralls.io/builds/32056263/badge)](https://coveralls.io/builds/32056263)
   
   Coverage increased (+0.03%) to 49.342% when pulling **5b27fc25d1abf2200cdad6a02b61a585e57c0c92 on salcho:post-ww-5083** into **c2b09d76be804b3c406b0e26409388b115a49115 on apache:master**.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] lukaszlenart commented on pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
lukaszlenart commented on pull request #426:
URL: https://github.com/apache/struts/pull/426#issuecomment-660007438


   🎉  great 🎉 
   
   LGTM 👍 


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] coveralls edited a comment on pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
coveralls edited a comment on pull request #426:
URL: https://github.com/apache/struts/pull/426#issuecomment-658126974


   
   [![Coverage Status](https://coveralls.io/builds/32109926/badge)](https://coveralls.io/builds/32109926)
   
   Coverage increased (+0.03%) to 49.345% when pulling **193856c6c28be3265e8412b4758676ea540c76aa on salcho:post-ww-5083** into **c2b09d76be804b3c406b0e26409388b115a49115 on apache:master**.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] lukaszlenart commented on a change in pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
lukaszlenart commented on a change in pull request #426:
URL: https://github.com/apache/struts/pull/426#discussion_r456250213



##########
File path: core/src/main/java/org/apache/struts2/interceptor/FetchMetadataInterceptor.java
##########
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.interceptor;
+
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_DEST_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_MODE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_SITE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.VARY_HEADER;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.util.TextParseUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Interceptor that implements Fetch Metadata policy on incoming requests used to protect against
+ * CSRF, XSSI, and cross-origin information leaks. Uses {@link StrutsResourceIsolationPolicy} to
+ * filter the requests allowed to be processed.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ **/
+
+public class FetchMetadataInterceptor extends AbstractInterceptor implements PreResultListener {
+
+    private final Set<String> exemptedPaths = new HashSet<String>();
+    private final ResourceIsolationPolicy resourceIsolationPolicy = new StrutsResourceIsolationPolicy();
+    private static final String VARY_HEADER_VALUE = String.format("%s,%s,%s", SEC_FETCH_DEST_HEADER, SEC_FETCH_SITE_HEADER, SEC_FETCH_MODE_HEADER);
+    private static final String SC_FORBIDDEN = String.valueOf(HttpServletResponse.SC_FORBIDDEN);
+
+    public void setExemptedPaths(String paths){
+        this.exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
+    }
+
+    @Override
+    public void beforeResult(ActionInvocation invocation, String resultCode) {
+        // Add Vary headers
+        HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
+        response.setHeader(VARY_HEADER, VARY_HEADER_VALUE);
+    }
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+        ActionContext context = invocation.getInvocationContext();
+        HttpServletRequest request = context.getServletRequest();
+
+        // Adds listener that operates between interceptor and result rendering to set Vary headers
+        invocation.addPreResultListener(this);
+
+        // Apply exemptions: paths/endpoints meant to be served cross-origin
+        if (exemptedPaths.contains(request.getContextPath())) {
+            return invocation.invoke();
+        }
+
+        // Check if request is allowed
+        if (resourceIsolationPolicy.isRequestAllowed(request)) {
+            return invocation.invoke();
+        }
+
+        beforeResult(invocation, SC_FORBIDDEN);

Review comment:
       Oh, good point. You must register your `PreResultListener` first instead of calling it by a hand. In such case you will execute your logic related to result as there are still some other interceptors in the execution stack.
   
   Just do `invocation.addPreResultListener(this)`, see example in [DebuggingInterceptor](https://github.com/apache/struts/blob/master/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java#L156-L161)




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [struts] yasserzamani commented on a change in pull request #426: WW-5083: Adds support for Fetch Metadata in Struts2.

Posted by GitBox <gi...@apache.org>.
yasserzamani commented on a change in pull request #426:
URL: https://github.com/apache/struts/pull/426#discussion_r455177518



##########
File path: core/src/main/java/org/apache/struts2/interceptor/FetchMetadataInterceptor.java
##########
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.interceptor;
+
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_DEST_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_MODE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_SITE_HEADER;
+import static org.apache.struts2.interceptor.ResourceIsolationPolicy.VARY_HEADER;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.util.TextParseUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Interceptor that implements Fetch Metadata policy on incoming requests used to protect against
+ * CSRF, XSSI, and cross-origin information leaks. Uses {@link StrutsResourceIsolationPolicy} to
+ * filter the requests allowed to be processed.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ **/
+
+public class FetchMetadataInterceptor extends AbstractInterceptor implements PreResultListener {
+
+    private final Set<String> exemptedPaths = new HashSet<String>();
+    private final ResourceIsolationPolicy resourceIsolationPolicy = new StrutsResourceIsolationPolicy();
+    private static final String VARY_HEADER_VALUE = String.format("%s,%s,%s", SEC_FETCH_DEST_HEADER, SEC_FETCH_SITE_HEADER, SEC_FETCH_MODE_HEADER);
+    private static final String SC_FORBIDDEN = String.valueOf(HttpServletResponse.SC_FORBIDDEN);
+
+    public void setExemptedPaths(String paths){
+        this.exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
+    }
+
+    @Override
+    public void beforeResult(ActionInvocation invocation, String resultCode) {
+        // Add Vary headers
+        HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
+        response.setHeader(VARY_HEADER, VARY_HEADER_VALUE);
+    }
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+        ActionContext context = invocation.getInvocationContext();
+        HttpServletRequest request = context.getServletRequest();
+
+        // Adds listener that operates between interceptor and result rendering to set Vary headers
+        invocation.addPreResultListener(this);
+
+        // Apply exemptions: paths/endpoints meant to be served cross-origin
+        if (exemptedPaths.contains(request.getContextPath())) {
+            return invocation.invoke();
+        }
+
+        // Check if request is allowed
+        if (resourceIsolationPolicy.isRequestAllowed(request)) {
+            return invocation.invoke();
+        }
+
+        beforeResult(invocation, SC_FORBIDDEN);

Review comment:
       Doesn't work without this line? -- it's already registered as a pre-result.

##########
File path: core/src/main/java/org/apache/struts2/interceptor/StrutsResourceIsolationPolicy.java
##########
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.interceptor;
+
+import org.apache.logging.log4j.util.Strings;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * Default resource isolation policy used in {@link FetchMetadataInterceptor} that
+ * implements the {@link ResourceIsolationPolicy} interface. This default policy is based on
+ * <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>.
+ *
+ * @see <a href="https://web.dev/fetch-metadata/">https://web.dev/fetch-metadata/</a>
+ **/
+
+public final class StrutsResourceIsolationPolicy implements ResourceIsolationPolicy {
+
+    @Override
+    public boolean isRequestAllowed(HttpServletRequest request) {
+        String site = request.getHeader(SEC_FETCH_SITE_HEADER);
+
+        // Allow requests from browsers which don't send Fetch Metadata
+        if (Strings.isEmpty((site))){

Review comment:
       nitpick: waste parenteses. Additionally you might use `org.apache.commons.lang3.StringUtils.isEmpty/isBlank` instead.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org