Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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.wicket.coep;

import org.apache.wicket.Application;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.util.lang.Args;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
* Specifies the configuration for Cross-Origin Embedder Policy to be used for
* {@link CrossOriginEmbedderPolicyRequestCycleListener}. Users can specify the paths that should be exempt from COEP and
* one of 3 modes (<code>REPORTING, ENFORCING, DISABLED</code>) for the policy. The config object
* lives in {@link org.apache.wicket.settings.SecuritySettings}, users can specify their COOP
* preferences with the following lines in their application's {@link WebApplication#init()} method:
*
* <pre>
* &#064;Override
* protected void init()
* {
* // ...
* getSecuritySettings().setCrossOriginEmbedderPolicyConfiguration(CoepMode.REPORTING,
* "EXEMPTED PATHS");
* // ...
* }
* </pre>
*
* The config value will be read once at startup in {@link Application#initApplication()}, changing
* the configuration at runtime will have no effect of the COOP headers set.
*
* @author Santiago Diaz - saldiaz@google.com
* @author Ecenaz Jen Ozmen - ecenazo@google.com
*
* @see CrossOriginEmbedderPolicyRequestCycleListener
* @see org.apache.wicket.settings.SecuritySettings
*/
public class CrossOriginEmbedderPolicyConfiguration
{
public enum CoepMode
{
ENFORCING("Cross-Origin-Embedder-Policy"),
REPORTING("Cross-Origin-Embedder-Policy-Report-Only"),
DISABLED("");

final String header;

CoepMode(String header)
{
this.header = header;
}
}

private final Set<String> exemptions = new HashSet<>();
private final CoepMode mode;

public CrossOriginEmbedderPolicyConfiguration(CoepMode mode, String... exemptions)
{
this.exemptions.addAll(Arrays.asList(exemptions));
this.mode = Args.notNull(mode, "mode");
}

public CrossOriginEmbedderPolicyConfiguration(CoepMode mode)
{
this.mode = Args.notNull(mode, "mode");
}

public Set<String> getExemptions()
{
return exemptions;
}

public CoepMode getMode()
{
return mode;
}

public String getCoepHeader()
{
return mode.header;
}

public CrossOriginEmbedderPolicyConfiguration addExemptedPath(String path)
{
exemptions.add(path);
return this;
}

public boolean isEnabled()
{
return mode != CoepMode.DISABLED;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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.wicket.coep;

import org.apache.wicket.coop.CrossOriginOpenerPolicyRequestCycleListener;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.cycle.IRequestCycleListener;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.http.WebResponse;
import org.apache.wicket.util.lang.Args;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;

/**
* Sets <a href="https://wicg.github.io/cross-origin-embedder-policy/">Cross-Origin Embedder
* Policy</a> (COEP) headers on the responses based on the mode specified by
* {@link CrossOriginEmbedderPolicyConfiguration}. COEP can be enabled in <code>REPORTING</code>
* mode which will set the headers as <code>Cross-Origin-Embedder-Policy-Report-Only</code> or
* <code>ENFORCING</code> mode which will set the header as
* <code>Cross-Origin-Embedder-Policy</code>. The header is not set for the paths that are exempted
* from COEP. The only valid value of COEP is <code>require-corp</code>, so if the listener is
* enabled the policy value will be specified as so.
*
* COEP prevents a document from loading any non-same-origin resources which don't explicitly grant
* the document permission to be loaded. Using COEP and COOP together allows developers to safely
* use powerful features such as <code>SharedArrayBuffer</code>,
* <code>performance.measureMemory()</code>, and the JS Self-Profiling API.See
* {@link CrossOriginOpenerPolicyRequestCycleListener} for instructions on how to enable COOP.
* Read more about cross-origin isolation on
* <a href="https://web.dev/why-coop-coep/">https://web.dev/why-coop-coep/</a>
*
*
* @author Santiago Diaz - saldiaz@google.com
* @author Ecenaz Jen Ozmen - ecenazo@google.com
*
* @see CrossOriginEmbedderPolicyConfiguration
* @see org.apache.wicket.settings.SecuritySettings
*/
public class CrossOriginEmbedderPolicyRequestCycleListener implements IRequestCycleListener
{
private static final Logger log = LoggerFactory.getLogger(CrossOriginEmbedderPolicyRequestCycleListener.class);

static final String REQUIRE_CORP = "require-corp";

private CrossOriginEmbedderPolicyConfiguration coepConfig;

public CrossOriginEmbedderPolicyRequestCycleListener(CrossOriginEmbedderPolicyConfiguration coepConfig)
{
this.coepConfig = Args.notNull(coepConfig, "coepConfig");
}

@Override
public void onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler)
{
final Object containerRequest = cycle.getRequest().getContainerRequest();
if (containerRequest instanceof HttpServletRequest)
{
HttpServletRequest request = (HttpServletRequest) containerRequest;
String path = request.getContextPath();
final String coepHeaderName = coepConfig.getCoepHeader();

if (coepConfig.getExemptions().contains(path))
{
log.debug("Request path {} is exempted from COEP, no '{}' header added", path, coepHeaderName);
return;
}

if (cycle.getResponse() instanceof WebResponse)
{
WebResponse webResponse = (WebResponse) cycle.getResponse();
if (webResponse.isHeaderSupported())
{
webResponse.setHeader(coepHeaderName, REQUIRE_CORP);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* 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.wicket.coop;

import org.apache.wicket.Application;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.util.lang.Args;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
* Specifies the configuration for Cross-Origin Opener Policy to be used by
* {@link CrossOriginOpenerPolicyRequestCycleListener} when adding COOP headers. Users can specify the paths that
* should be exempt from COOP and one of 4 modes
* (<code>UNSAFE_NONE, SAME_ORIGIN, SAME_ORIGIN_ALLOW_POPUPS, DISABLED</code>) for the policy. The
* config object lives in {@link org.apache.wicket.settings.SecuritySettings}, users can specify
* their COOP preferences with the following lines in their application's
* {@link WebApplication#init()} method:
*
* <pre>
* &#064;Override
* protected void init()
* {
* // ...
* getSecuritySettings().setCrossOriginOpenerPolicyConfiguration(CoopMode.SAME_ORIGIN,
* "EXEMPTED PATHS");
* // ...
* }
* </pre>
*
* The config value will be read once at startup in {@link Application#initApplication()}, changing
* the configuration at runtime will have no effect of the COOP headers set.
*
* @author Santiago Diaz - saldiaz@google.com
* @author Ecenaz Jen Ozmen - ecenazo@google.com
*
* @see CrossOriginOpenerPolicyRequestCycleListener
* @see org.apache.wicket.settings.SecuritySettings
*/
public class CrossOriginOpenerPolicyConfiguration
{
public enum CoopMode
{
UNSAFE_NONE("unsafe-none"),
SAME_ORIGIN("same-origin"),
SAME_ORIGIN_ALLOW_POPUPS("same-origin-allow-popups"),
DISABLED("");

final String keyword;

CoopMode(String keyword)
{
this.keyword = keyword;
}
}


private final Set<String> exemptions = new HashSet<>();
private final CoopMode mode;

public CrossOriginOpenerPolicyConfiguration(CoopMode mode, String... exemptions)
{
this.exemptions.addAll(Arrays.asList(exemptions));
this.mode = Args.notNull(mode, "mode");
}

public CrossOriginOpenerPolicyConfiguration(CoopMode mode)
{
this.mode = Args.notNull(mode, "mode");
}

public CrossOriginOpenerPolicyConfiguration addExemptedPath(String path)
{
exemptions.add(path);
return this;
}

public Set<String> getExemptions()
{
return exemptions;
}

public CoopMode getMode()
{
return mode;
}

public String getHeaderValue()
{
return mode.keyword;
}

public boolean isEnabled()
{
return mode != CoopMode.DISABLED;
}
}
Loading