/**
* 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.hadoop.gateway.deploy.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.hadoop.gateway.config.GatewayConfig;
import org.apache.hadoop.gateway.config.impl.GatewayConfigImpl;
import org.apache.hadoop.gateway.deploy.DeploymentContext;
import org.apache.hadoop.gateway.deploy.DeploymentException;
import org.apache.hadoop.gateway.deploy.ServiceDeploymentContributorBase;
import org.apache.hadoop.gateway.descriptor.FilterDescriptor;
import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
import org.apache.hadoop.gateway.filter.XForwardedHeaderFilter;
import org.apache.hadoop.gateway.filter.rewrite.api.CookieScopeServletFilter;
import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
import org.apache.hadoop.gateway.service.definition.Policy;
import org.apache.hadoop.gateway.service.definition.Rewrite;
import org.apache.hadoop.gateway.service.definition.Route;
import org.apache.hadoop.gateway.service.definition.ServiceDefinition;
import org.apache.hadoop.gateway.topology.Application;
import org.apache.hadoop.gateway.topology.Service;
import org.apache.hadoop.gateway.topology.Version;
public class ApplicationDeploymentContributor extends ServiceDeploymentContributorBase {
private static final String SERVICE_DEFINITION_FILE_NAME = "service.xml";
private static final String REWRITE_RULES_FILE_NAME = "rewrite.xml";
private static final String XFORWARDED_FILTER_NAME = "XForwardedHeaderFilter";
private static final String XFORWARDED_FILTER_ROLE = "xforwardedheaders";
private static final String COOKIE_SCOPING_FILTER_NAME = "CookieScopeServletFilter";
private static final String COOKIE_SCOPING_FILTER_ROLE = "cookiescopef";
private ServiceDefinition serviceDefinition;
private UrlRewriteRulesDescriptor serviceRules;
private static ServiceDefinition loadServiceDefinition( Application application, File file ) throws JAXBException, FileNotFoundException, IOException {
ServiceDefinition definition;
if( !file.exists() ) {
definition = new ServiceDefinition();
definition.setName( application.getName() );
List<Route> routes = new ArrayList<Route>(1);
Route route;
route = new Route();
route.setPath( "/?**" );
routes.add( route );
route = new Route();
route.setPath( "/**?**" );
routes.add( route );
definition.setRoutes( routes );
} else {
JAXBContext context = JAXBContext.newInstance( ServiceDefinition.class );
Unmarshaller unmarshaller = context.createUnmarshaller();
try( FileInputStream inputStream = new FileInputStream( file ) ) {
definition = (ServiceDefinition) unmarshaller.unmarshal( inputStream );
}
}
return definition;
}
private static UrlRewriteRulesDescriptor loadRewriteRules( Application application, File file ) throws IOException {
UrlRewriteRulesDescriptor rules;
if( !file.exists() ) {
rules = UrlRewriteRulesDescriptorFactory.load( "xml", new StringReader( "<rules/>" ) );
} else {
FileReader reader = new FileReader( file );
rules = UrlRewriteRulesDescriptorFactory.load( "xml", reader );
reader.close();
}
return rules;
}
public ApplicationDeploymentContributor( GatewayConfig config, Application application ) throws DeploymentException {
try {
File appsDir = new File( config.getGatewayApplicationsDir() );
File appDir = new File( appsDir, application.getName() );
File serviceFile = new File( appDir, SERVICE_DEFINITION_FILE_NAME );
File rewriteFile = new File( appDir, REWRITE_RULES_FILE_NAME );
serviceDefinition = loadServiceDefinition( application, serviceFile );
serviceRules = loadRewriteRules( application, rewriteFile );
} catch ( IOException e ) {
throw new DeploymentException( "Failed to deploy application: " + application.getName(), e );
} catch ( JAXBException e ){
throw new DeploymentException( "Failed to deploy application: " + application.getName(), e );
}
}
@Override
public String getRole() {
return serviceDefinition.getRole();
}
@Override
public String getName() {
return serviceDefinition.getName();
}
@Override
public Version getVersion() {
return new Version(serviceDefinition.getVersion());
}
@Override
public void contributeService(DeploymentContext context, Service service) throws Exception {
contributeRewriteRules(context, service);
contributeResources(context, service);
}
private void contributeRewriteRules(DeploymentContext context, Service service) {
if ( serviceRules != null ) {
UrlRewriteRulesDescriptor clusterRules = context.getDescriptor("rewrite");
// Coverity CID 1352312
if( clusterRules != null ) {
clusterRules.addRules( serviceRules );
}
}
}
private void contributeResources(DeploymentContext context, Service service) {
Map<String, String> filterParams = new HashMap<String, String>();
List<Route> bindings = serviceDefinition.getRoutes();
for ( Route binding : bindings ) {
List<Rewrite> filters = binding.getRewrites();
if ( filters != null && !filters.isEmpty() ) {
filterParams.clear();
for ( Rewrite filter : filters ) {
filterParams.put(filter.getTo(), filter.getApply());
}
}
try {
contributeResource(context, service, binding, filterParams);
} catch ( URISyntaxException e ) {
e.printStackTrace();
}
}
}
private void contributeResource( DeploymentContext context, Service service, Route binding, Map<String, String> filterParams) throws URISyntaxException {
List<FilterParamDescriptor> params = new ArrayList<FilterParamDescriptor>();
ResourceDescriptor resource = context.getGatewayDescriptor().addResource();
resource.role(service.getRole());
resource.pattern(binding.getPath());
//add x-forwarded filter if enabled in config
if (context.getGatewayConfig().isXForwardedEnabled()) {
resource.addFilter().name(XFORWARDED_FILTER_NAME).role(XFORWARDED_FILTER_ROLE).impl(XForwardedHeaderFilter.class);
}
if (context.getGatewayConfig().isCookieScopingToPathEnabled()) {
FilterDescriptor filter = resource.addFilter().name(COOKIE_SCOPING_FILTER_NAME).role(COOKIE_SCOPING_FILTER_ROLE).impl(CookieScopeServletFilter.class);
filter.param().name(GatewayConfigImpl.HTTP_PATH).value(context.getGatewayConfig().getGatewayPath());
}
List<Policy> policyBindings = binding.getPolicies();
if ( policyBindings == null ) {
policyBindings = serviceDefinition.getPolicies();
}
if ( policyBindings == null ) {
//add default set
addDefaultPolicies(context, service, filterParams, params, resource);
} else {
addPolicies(context, service, filterParams, params, resource, policyBindings);
}
}
private void addPolicies( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource, List<Policy> policyBindings) throws URISyntaxException {
for ( Policy policyBinding : policyBindings ) {
String role = policyBinding.getRole();
if ( role == null ) {
throw new IllegalArgumentException("Policy defined has no role for service " + service.getName());
}
role = role.trim().toLowerCase();
if ( role.equals("rewrite") ) {
addRewriteFilter(context, service, filterParams, params, resource);
} else if ( topologyContainsProviderType(context, role) ) {
context.contributeFilter(service, resource, role, policyBinding.getName(), null);
}
}
}
private void addDefaultPolicies( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource) throws URISyntaxException {
addWebAppSecFilters(context, service, resource);
addAuthenticationFilter(context, service, resource);
addRewriteFilter(context, service, filterParams, params, resource);
addIdentityAssertionFilter(context, service, resource);
addAuthorizationFilter(context, service, resource);
}
private void addRewriteFilter( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource) throws URISyntaxException {
if ( !filterParams.isEmpty() ) {
for ( Map.Entry<String, String> filterParam : filterParams.entrySet() ) {
params.add(resource.createFilterParam().name(filterParam.getKey()).value(filterParam.getValue()));
}
}
addRewriteFilter(context, service, resource, params);
}
}