Skip to content

Commit

Permalink
Add experimental CORS server support
Browse files Browse the repository at this point in the history
Include org.apache.cxf.rs.security.cors.CrossOriginResourceSharing implementation
  • Loading branch information
bostko committed Jan 18, 2017
1 parent fabfcdb commit 57cccbb
Show file tree
Hide file tree
Showing 10 changed files with 333 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,25 @@ public class BrooklynFeatureEnablement {
/** whether feeds are automatically registered when set on entities, so that they are persisted */
public static final String FEATURE_FEED_REGISTRATION_PROPERTY = FEATURE_PROPERTY_PREFIX+".feedRegistration";

/**
* <p>
* Enables support for Cross Origin Resource Sharing (CORS) filtering on requests in BrooklynWebServer.
* If enabled, the allowed origins for the CORS headers should be configured
* using the <code>brooklyn.experimental.feature.corsCxfFeature.allowedOrigins=[]</code> property.
* </p>
* <p>
* If <code>brooklyn.experimental.feature.corsCxfFeature.allowedOrigins</code> is not is not supplied then allowedOrigins will be a wildcard on all domains.<br>
* Not specifying <code>allowedOrigins</code> is strongly discouraged.
* </p>
* <p>
* Currently there is no support for varying these headers on a per-API-resource basis, that is, the same configured headers are applied to all requests.
* </p>
* <p>
* Apache Brooklyn API requests should be exposed to third party web apps with great attention.
* </p>
*/
public static final String FEATURE_CORS_CXF_PROPERTY = FEATURE_PROPERTY_PREFIX + ".corsCxfFeature";

public static final String FEATURE_CATALOG_PERSISTENCE_PROPERTY = FEATURE_PROPERTY_PREFIX+".catalogPersistence";

/** whether the default standby mode is {@link HighAvailabilityMode#HOT_STANDBY} or falling back to the traditional
Expand Down
1 change: 1 addition & 0 deletions karaf/features/src/main/feature/feature.xml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@
<feature>brooklyn-camp-base</feature>

<feature>cxf-jaxrs</feature>
<bundle dependency="true">mvn:org.apache.cxf/cxf-rt-rs-security-cors/${cxf.version}</bundle>

<bundle dependency="true">mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${fasterxml.jackson.version}</bundle>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import javax.annotation.Nullable;
import javax.security.auth.spi.LoginModule;

import com.google.common.collect.ImmutableList;
import org.apache.brooklyn.core.BrooklynFeatureEnablement;
import org.apache.brooklyn.rest.NopSecurityHandler;
import org.apache.brooklyn.api.location.PortRange;
import org.apache.brooklyn.api.mgmt.ManagementContext;
Expand All @@ -52,6 +54,7 @@
import org.apache.brooklyn.rest.RestApiSetup;
import org.apache.brooklyn.rest.filter.CsrfTokenFilter;
import org.apache.brooklyn.rest.filter.EntitlementContextFilter;
import org.apache.brooklyn.rest.filter.CorsImplSupplierFilter;
import org.apache.brooklyn.rest.filter.HaHotCheckResourceFilter;
import org.apache.brooklyn.rest.filter.LoggingFilter;
import org.apache.brooklyn.rest.filter.NoCacheFilter;
Expand Down Expand Up @@ -455,14 +458,21 @@ public synchronized void start() throws Exception {
}

private WebAppContext deployRestApi(WebAppContext context) {
RestApiSetup.installRest(context,
ImmutableList.Builder<Object> providersListBuilder = ImmutableList.builder();
providersListBuilder.add(
new ManagementContextProvider(),
new ShutdownHandlerProvider(shutdownHandler),
new RequestTaggingRsFilter(),
new NoCacheFilter(),
new HaHotCheckResourceFilter(),
new EntitlementContextFilter(),
new CsrfTokenFilter());
if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_CORS_CXF_PROPERTY)) {
providersListBuilder.add(new CorsImplSupplierFilter(managementContext));
}

RestApiSetup.installRest(context,
providersListBuilder.build().toArray());
RestApiSetup.installServletFilters(context,
RequestTaggingFilter.class,
LoggingFilter.class);
Expand Down
5 changes: 5 additions & 0 deletions rest/rest-resources/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-security-cors</artifactId>
<version>${cxf.version}</version>
</dependency>

<dependency>
<groupId>org.apache.brooklyn</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* 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.brooklyn.rest.filter;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.reflect.TypeToken;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.BrooklynFeatureEnablement;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.util.JavaGroovyEquivalents;
import org.apache.cxf.rs.security.cors.CrossOriginResourceSharingFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.ext.Provider;
import java.util.Collections;
import java.util.List;

/**
* @see BrooklynFeatureEnablement#FEATURE_CORS_CXF_PROPERTY
*/
@Provider
public class CorsImplSupplierFilter extends CrossOriginResourceSharingFilter {
public static final ConfigKey<List<String>> ALLOWED_ORIGINS = ConfigKeys.newConfigKey(new TypeToken<List<String>>() {},
BrooklynFeatureEnablement.FEATURE_CORS_CXF_PROPERTY + ".allowedOrigins",
"List of allowed origins. Access-Control-Allow-Origin header will be returned to client if Origin header in request is matching exactly a value among the list allowed origins. " +
"If AllowedOrigins is empty or not specified then all origins are allowed. " +
"No wildcard allowed origins are supported.",
Collections.<String>emptyList());
private static final Logger LOGGER = LoggerFactory.getLogger(CorsImplSupplierFilter.class);

private static final boolean brooklynFeatureEnabled = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_CORS_CXF_PROPERTY);
static {
if (brooklynFeatureEnabled) {
LOGGER.info("CORS brooklyn feature enabled.");
}
}

@VisibleForTesting
public CorsImplSupplierFilter(@Nullable ManagementContext mgmt) {
setFindResourceMethod(false);
Preconditions.checkNotNull(mgmt,"ManagementContext should be suppplied to CORS filter.");
setAllowOrigins(JavaGroovyEquivalents.<List<String>>elvis(
mgmt.getConfig().getConfig(ALLOWED_ORIGINS), Collections.<String>emptyList()));
}

@Override
public void filter(ContainerRequestContext requestContext) {
if (brooklynFeatureEnabled) {
super.filter(requestContext);
}
}

@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
if (brooklynFeatureEnabled) {
super.filter(requestContext, responseContext);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ limitations under the License.
<bean class="org.apache.brooklyn.rest.util.ShutdownHandlerProvider">
<argument ref="shutdownHandler" />
</bean>
<bean class="org.apache.brooklyn.rest.filter.CorsImplSupplierFilter" >
<argument ref="localManagementContext" />
</bean>
</jaxrs:providers>

<jaxrs:properties>
Expand Down
1 change: 1 addition & 0 deletions rest/rest-server/src/main/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
org.apache.brooklyn.rest.filter.EntitlementContextFilter,
org.apache.brooklyn.rest.filter.CsrfTokenFilter,
org.apache.brooklyn.rest.util.ManagementContextProvider
<!-- org.apache.brooklyn.rest.filter.CorsImplSupplierFilter does not support ManagementContext injection in WEB_XML mode -->
<!-- org.apache.brooklyn.rest.util.ShutdownHandlerProvider -->
</param-value>
</init-param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.brooklyn.rest;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.brooklyn.rest.filter.CorsImplSupplierFilter.ALLOWED_ORIGINS;

import java.io.File;
import java.io.FilenameFilter;
Expand All @@ -27,15 +28,18 @@
import java.util.List;

import javax.servlet.Filter;
import javax.ws.rs.ext.ContextResolver;

import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherAbstract;
import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
import org.apache.brooklyn.core.BrooklynFeatureEnablement;
import org.apache.brooklyn.core.internal.BrooklynProperties;
import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.core.server.BrooklynServerConfig;
import org.apache.brooklyn.core.server.BrooklynServiceAttributes;
import org.apache.brooklyn.rest.filter.CorsImplSupplierFilter;
import org.apache.brooklyn.rest.filter.CsrfTokenFilter;
import org.apache.brooklyn.rest.filter.EntitlementContextFilter;
import org.apache.brooklyn.rest.filter.HaHotCheckResourceFilter;
Expand All @@ -56,6 +60,7 @@
import org.apache.brooklyn.util.net.Networking;
import org.apache.brooklyn.util.os.Os;
import org.apache.brooklyn.util.text.WildcardGlobs;
import org.apache.cxf.rs.security.cors.CrossOriginResourceSharingFilter;
import org.eclipse.jetty.jaas.JAASLoginService;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
Expand Down Expand Up @@ -232,14 +237,21 @@ private WebAppContext servletContextHandler(ManagementContext managementContext)
context.setAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT, managementContext);

installWar(context);
RestApiSetup.installRest(context,
ImmutableList.Builder<Object> providersListBuilder = ImmutableList.builder();
providersListBuilder.add(
new ManagementContextProvider(),
new ShutdownHandlerProvider(shutdownListener),
new RequestTaggingRsFilter(),
new NoCacheFilter(),
new HaHotCheckResourceFilter(),
new EntitlementContextFilter(),
new CsrfTokenFilter());
if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_CORS_CXF_PROPERTY)) {
providersListBuilder.add(new CorsImplSupplierFilter(managementContext));
}
RestApiSetup.installRest(context,
providersListBuilder.build().toArray());

RestApiSetup.installServletFilters(context, this.filters);

context.setContextPath("/");
Expand Down

0 comments on commit 57cccbb

Please sign in to comment.