001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.coop; 018 019import org.apache.wicket.coep.CrossOriginEmbedderPolicyRequestCycleListener; 020import org.apache.wicket.request.IRequestHandler; 021import org.apache.wicket.request.cycle.IRequestCycleListener; 022import org.apache.wicket.request.cycle.RequestCycle; 023import org.apache.wicket.request.http.WebResponse; 024import org.apache.wicket.util.lang.Args; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028import javax.servlet.http.HttpServletRequest; 029 030/** 031 * Sets <a href="https://github.com/whatwg/html/pull/5334/files">Cross-Origin Opener Policy</a> 032 * headers on the responses based on the policy specified by {@link CrossOriginOpenerPolicyConfiguration}. The header 033 * is not set for the paths that are exempted from COOP. 034 * <p> 035 * COOP is a mitigation against cross-origin information leaks and is used to make websites 036 * cross-origin isolated. Setting the COOP header allows you to ensure that a top-level window is 037 * isolated from other documents by putting them in a different browsing context group, so they 038 * cannot directly interact with the top-level window. Using COEP and COOP together allows 039 * developers to safely use * powerful features such as <code>SharedArrayBuffer</code>, 040 * <code>performance.measureMemory()</code>, * and the JS Self-Profiling API.See 041 * {@link CrossOriginEmbedderPolicyRequestCycleListener} for instructions * on how to enable COOP. 042 * Read more about cross-origin isolation on 043 * <a href="https://web.dev/why-coop-coep/">https://web.dev/why-coop-coep/</a> 044 * <p> 045 * 046 * @author Santiago Diaz - saldiaz@google.com 047 * @author Ecenaz Jen Ozmen - ecenazo@google.com 048 * 049 * @see CrossOriginOpenerPolicyConfiguration 050 * @see org.apache.wicket.settings.SecuritySettings 051 */ 052public class CrossOriginOpenerPolicyRequestCycleListener implements IRequestCycleListener 053{ 054 private static final Logger log = LoggerFactory.getLogger(CrossOriginOpenerPolicyRequestCycleListener.class); 055 056 static final String COOP_HEADER = "Cross-Origin-Opener-Policy"; 057 058 private final CrossOriginOpenerPolicyConfiguration coopConfig; 059 060 public CrossOriginOpenerPolicyRequestCycleListener(CrossOriginOpenerPolicyConfiguration coopConfig) 061 { 062 this.coopConfig = Args.notNull(coopConfig, "coopConfig"); 063 } 064 065 @Override 066 public void onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler) 067 { 068 // WICKET-7028- this is needed for redirect to buffer use case. 069 protect(cycle, handler); 070 } 071 072 @Override 073 public void onRequestHandlerExecuted(RequestCycle cycle, IRequestHandler handler) 074 { 075 protect(cycle, handler); 076 } 077 078 079 protected void protect(RequestCycle cycle, IRequestHandler handler) 080 { 081 final Object containerRequest = cycle.getRequest().getContainerRequest(); 082 if (containerRequest instanceof HttpServletRequest) 083 { 084 HttpServletRequest request = (HttpServletRequest) containerRequest; 085 String path = request.getContextPath(); 086 087 if (coopConfig.getExemptions().contains(path)) 088 { 089 log.debug("Request path {} is exempted from COOP, no {} header added", path, COOP_HEADER); 090 return; 091 } 092 093 if (cycle.getResponse() instanceof WebResponse) 094 { 095 WebResponse webResponse = (WebResponse) cycle.getResponse(); 096 if (webResponse.isHeaderSupported()) 097 { 098 webResponse.setHeader(COOP_HEADER, coopConfig.getHeaderValue()); 099 } 100 } 101 } 102 } 103}