+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- ~
- ~ This program and the accompanying materials are made available under the
- ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
- ~ and is available at http://www.eclipse.org/legal/epl-v10.html
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.odlparent</groupId>
- <artifactId>odlparent</artifactId>
- <version>1.8.0-Carbon</version>
- <relativePath/>
- </parent>
-
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>filter-valve</artifactId>
- <version>1.9.0-SNAPSHOT</version>
- <packaging>bundle</packaging>
-
- <dependencies>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>javax.servlet</artifactId>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.catalina</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Fragment-Host>org.eclipse.gemini.web.tomcat</Fragment-Host>
- <Import-Package>javax.servlet,
- org.apache.catalina,
- org.apache.catalina.connector,
- org.apache.catalina.valves,
- org.slf4j,
- javax.xml.bind,
- javax.xml.bind.annotation,
- org.apache.commons.io,
- com.google.common.base,
- com.google.common.collect</Import-Package>
- </instructions>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
-
-</project>
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Objects;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import org.apache.catalina.connector.Request;
-import org.apache.catalina.connector.Response;
-import org.apache.catalina.valves.ValveBase;
-import org.apache.commons.io.FileUtils;
-import org.opendaylight.controller.filtervalve.cors.jaxb.Host;
-import org.opendaylight.controller.filtervalve.cors.jaxb.Parser;
-import org.opendaylight.controller.filtervalve.cors.model.FilterProcessor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Valve that allows adding filters per context. Each context can have its own filter definitions.
- * Main purpose is to allow externalizing security filters from application bundles to a single
- * file per OSGi distribution.
- */
-public class FilterValve extends ValveBase {
- private static final Logger logger = LoggerFactory.getLogger(FilterValve.class);
- private FilterProcessor filterProcessor;
-
- public void invoke(final Request request, final Response response) throws IOException, ServletException {
- if (filterProcessor == null) {
- throw new IllegalStateException("Initialization error");
- }
-
- FilterChain nextValveFilterChain = (req, resp) -> {
- boolean reqEquals = Objects.equals(request, req);
- boolean respEquals = Objects.equals(response, resp);
- if (reqEquals == false || respEquals == false) {
- logger.error("Illegal change was detected by valve - request {} or " +
- "response {} was replaced by a filter. This is not supported by this valve",
- reqEquals, respEquals);
- throw new IllegalStateException("Request or response was replaced in a filter");
- }
- getNext().invoke(request, response);
- };
- filterProcessor.process(request, response, nextValveFilterChain);
- }
-
- /**
- * Called by Tomcat when configurationFile attribute is set.
- * @param fileName path to xml file containing valve configuration
- * @throws Exception exception
- */
- public void setConfigurationFile(String fileName) throws Exception {
- File configurationFile = new File(fileName);
- if (configurationFile.exists() == false || configurationFile.canRead() == false) {
- throw new IllegalArgumentException(
- "Cannot read 'configurationFile' of this valve defined in tomcat-server.xml: " + fileName);
- }
- String xmlContent;
- try {
- xmlContent = FileUtils.readFileToString(configurationFile);
- } catch (IOException e) {
- logger.error("Cannot read {} of this valve defined in tomcat-server.xml", fileName, e);
- throw new IllegalStateException("Cannot read " + fileName, e);
- }
- Host host;
- try {
- host = Parser.parse(xmlContent, fileName);
- } catch (Exception e) {
- logger.error("Cannot parse {} of this valve defined in tomcat-server.xml", fileName, e);
- throw new IllegalStateException("Error while parsing " + fileName, e);
- }
- filterProcessor = new FilterProcessor(host);
- }
-
- /**
- * @see org.apache.catalina.valves.ValveBase#getInfo()
- */
- public String getInfo() {
- return getClass() + "/1.0";
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
-
-import com.google.common.base.Optional;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import org.opendaylight.controller.filtervalve.cors.model.UrlMatcher;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@XmlRootElement
-public class Context {
- private static final Logger logger = LoggerFactory.getLogger(Context.class);
-
- private String path;
- private List<Filter> filters = new ArrayList<>();
- private List<FilterMapping> filterMappings = new ArrayList<>();
- private boolean initialized;
- private UrlMatcher<Filter> urlMatcher;
-
-
- public synchronized void initialize(String fileName, Map<String, Filter> namesToTemplates) {
- checkState(initialized == false, "Already initialized");
- Map<String, Filter> namesToFilters = new HashMap<>();
- for (Filter filter : filters) {
- try {
- filter.initialize(fileName, Optional.fromNullable(namesToTemplates.get(filter.getFilterName())));
- } catch (Exception e) {
- throw new IllegalStateException(format("Error while processing filter %s of context %s, defined in %s",
- filter.getFilterName(), path, fileName), e);
- }
- namesToFilters.put(filter.getFilterName(), filter);
- }
- filters = Collections.unmodifiableList(new ArrayList<>(filters));
- LinkedHashMap<String, Filter> patternMap = new LinkedHashMap<>();
- for (FilterMapping filterMapping : filterMappings) {
- filterMapping.initialize();
- Filter found = namesToFilters.get(filterMapping.getFilterName());
- if (found != null) {
- patternMap.put(filterMapping.getUrlPattern(), found);
- } else {
- logger.error("Cannot find matching filter for filter-mapping {} of context {}, defined in {}",
- filterMapping.getFilterName(), path, fileName);
- throw new IllegalStateException(format(
- "Cannot find filter for filter-mapping %s of context %s, defined in %s",
- filterMapping.getFilterName(), path, fileName));
- }
- }
- filterMappings = Collections.unmodifiableList(new ArrayList<>(filterMappings));
- urlMatcher = new UrlMatcher<>(patternMap);
- initialized = true;
- }
-
- public List<Filter> findMatchingFilters(String path) {
- logger.trace("findMatchingFilters({})", path);
- checkState(initialized, "Not initialized");
- return urlMatcher.findMatchingFilters(path);
- }
-
- @XmlAttribute(name = "path")
- public String getPath() {
- return path;
- }
-
- public void setPath(String path) {
- checkArgument(initialized == false, "Already initialized");
- this.path = path;
- }
-
- @XmlElement(name = "filter")
- public List<Filter> getFilters() {
- return filters;
- }
-
- public void setFilters(List<Filter> filters) {
- checkArgument(initialized == false, "Already initialized");
- this.filters = filters;
- }
-
- @XmlElement(name = "filter-mapping")
- public List<FilterMapping> getFilterMappings() {
- return filterMappings;
- }
-
- public void setFilterMappings(List<FilterMapping> filterMappings) {
- checkArgument(initialized == false, "Already initialized");
- this.filterMappings = filterMappings;
- }
-
- @Override
- public String toString() {
- return "Context{" +
- "path='" + path + '\'' +
- '}';
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.MapDifference;
-import com.google.common.collect.Maps;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@XmlRootElement
-public class Filter implements FilterConfig {
- private static final Logger logger = LoggerFactory.getLogger(Filter.class);
-
- private String filterName;
- private String filterClass;
- private List<InitParam> initParams = new ArrayList<>();
- private javax.servlet.Filter actualFilter;
- private boolean initialized, isTemplate;
-
-
- /**
- * Called in filter-template nodes defined in <Host/> node - do not actually initialize the filter.
- * In this case filter is only used to hold values of init params to be merged with
- * filter defined in <Context/>.
- */
- public synchronized void initializeTemplate(){
- checkState(initialized == false, "Already initialized");
- for (InitParam initParam : initParams) {
- initParam.inititialize();
- }
- isTemplate = true;
- initialized = true;
- }
-
-
- public synchronized void initialize(String fileName, Optional<Filter> maybeTemplate) {
- checkState(initialized == false, "Already initialized");
- logger.trace("Initializing filter {} : {}", filterName, filterClass);
- for (InitParam initParam : initParams) {
- initParam.inititialize();
- }
- if (maybeTemplate.isPresent()) {
- // merge non conflicting init params
- Filter template = maybeTemplate.get();
- checkArgument(template.isTemplate);
- Map<String, InitParam> templateParams = template.getInitParamsMap();
- Map<String, InitParam> currentParams = getInitParamsMap();
- // add values of template that are not present in current
- MapDifference<String, InitParam> difference = Maps.difference(templateParams, currentParams);
- for (Entry<String, InitParam> templateUnique : difference.entriesOnlyOnLeft().entrySet()) {
- initParams.add(templateUnique.getValue());
- }
- // merge filterClass
- if (filterClass == null) {
- filterClass = template.filterClass;
- } else if (Objects.equals(filterClass, template.filterClass) == false) {
- logger.error("Conflict detected in filter-class of {} defined in {}, template class {}, child class {}" ,
- filterName, fileName, template.filterClass, filterClass);
- throw new IllegalStateException("Conflict detected in template/filter filter-class definitions," +
- " filter name: " + filterName + " in file " + fileName);
- }
- }
- initParams = Collections.unmodifiableList(new ArrayList<>(initParams));
- Class<?> clazz;
- try {
- clazz = Class.forName(filterClass);
- } catch (Exception e) {
- throw new IllegalStateException("Cannot instantiate class defined in filter " + filterName
- + " in file " + fileName, e);
- }
- try {
- actualFilter = (javax.servlet.Filter) clazz.newInstance();
- } catch (Exception e) {
- throw new IllegalStateException("Cannot instantiate class defined in filter " + filterName
- + " in file " + fileName, e);
- }
- logger.trace("Initializing {} with following init-params:{}", filterName, getInitParams());
- try {
- actualFilter.init(this);
- } catch (Exception e) {
- throw new IllegalStateException("Cannot initialize filter " + filterName
- + " in file " + fileName, e);
- }
- initialized = true;
- }
-
- @Override
- public ServletContext getServletContext() {
- throw new UnsupportedOperationException("Getting ServletContext is currently not supported");
- }
-
- @Override
- public String getInitParameter(String name) {
- for (InitParam initParam : initParams) {
- if (Objects.equals(name, initParam.getParamName())) {
- return initParam.getParamValue();
- }
- }
- return null;
- }
-
- @Override
- public Enumeration<String> getInitParameterNames() {
- final Iterator<InitParam> iterator = initParams.iterator();
- return new Enumeration<String>() {
- @Override
- public boolean hasMoreElements() {
- return iterator.hasNext();
- }
-
- @Override
- public String nextElement() {
- return iterator.next().getParamName();
- }
- };
- }
-
- public javax.servlet.Filter getActualFilter() {
- checkState(initialized, "Not initialized");
- return actualFilter;
- }
-
- public boolean isInitialized() {
- return initialized;
- }
-
-
- @XmlElement(name = "filter-name")
- public String getFilterName() {
- return filterName;
- }
-
- public void setFilterName(String filterName) {
- this.filterName = filterName;
- }
-
- @XmlElement(name = "filter-class")
- public String getFilterClass() {
- return filterClass;
- }
-
- public void setFilterClass(String filterClass) {
- this.filterClass = filterClass;
- }
-
- @XmlElement(name = "init-param")
- public List<InitParam> getInitParams() {
- return initParams;
- }
-
- public void setInitParams(List<InitParam> initParams) {
- this.initParams = initParams;
- }
-
-
- @Override
- public String toString() {
- return "Filter{" +
- "filterName='" + filterName + '\'' +
- '}';
- }
-
- public Map<String, InitParam> getInitParamsMap() {
- Map<String, InitParam> result = new HashMap<>();
- for (InitParam initParam : initParams) {
- checkState(initParam.isInitialized());
- result.put(initParam.getParamName(), initParam);
- }
- return result;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-
-@XmlRootElement
-public class FilterMapping {
- private String filterName;
- private String urlPattern;
- private boolean initialized;
-
- @XmlElement(name = "filter-name")
- public String getFilterName() {
- return filterName;
- }
-
- public void setFilterName(String filterName) {
- checkArgument(initialized == false, "Already initialized");
- this.filterName = filterName;
- }
-
- @XmlElement(name = "url-pattern")
- public String getUrlPattern() {
- return urlPattern;
- }
-
- public void setUrlPattern(String urlPattern) {
- checkArgument(initialized == false, "Already initialized");
- this.urlPattern = urlPattern;
- }
-
- public synchronized void initialize() {
- checkArgument(initialized == false, "Already initialized");
- initialized = true;
- }
-
- public boolean isInitialized() {
- return initialized;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.base.Optional;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-
-
-/**
- * Root element, arbitrarily named Host to match tomcat-server.xml, but does not allow specifying which host
- * name to be matched.
- */
-@XmlRootElement(name = "Host")
-public class Host {
- private List<Context> contexts = new ArrayList<>();
- private List<Filter> filterTemplates = new ArrayList<>();
- private boolean initialized;
- private Map<String, Context> contextMap;
-
-
- public synchronized void initialize(String fileName) {
- checkState(initialized == false, "Already initialized");
- Map<String, Filter> namesToTemplates = new HashMap<>();
- for (Filter template : filterTemplates) {
- template.initializeTemplate();
- namesToTemplates.put(template.getFilterName(), template);
- }
- contextMap = new HashMap<>();
- for (Context context : getContexts()) {
- checkState(contextMap.containsKey(context.getPath()) == false,
- "Context {} already defined in {}", context.getPath(), fileName);
- context.initialize(fileName, namesToTemplates);
- contextMap.put(context.getPath(), context);
- }
- contextMap = Collections.unmodifiableMap(new HashMap<>(contextMap));
- contexts = Collections.unmodifiableList(new ArrayList<>(contexts));
- initialized = true;
- }
-
- public Optional<Context> findContext(String contextPath) {
- checkState(initialized, "Not initialized");
- Context context = contextMap.get(contextPath);
- return Optional.fromNullable(context);
- }
-
- @XmlElement(name = "Context")
- public List<Context> getContexts() {
- return contexts;
- }
-
- public void setContexts(List<Context> contexts) {
- checkArgument(initialized == false, "Already initialized");
- this.contexts = contexts;
- }
-
- @XmlElement(name = "filter-template")
- public List<Filter> getFilterTemplates() {
- return filterTemplates;
- }
-
- public void setFilterTemplates(List<Filter> filterTemplates) {
- checkArgument(initialized == false, "Already initialized");
- this.filterTemplates = filterTemplates;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import static com.google.common.base.Preconditions.checkState;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-
-@XmlRootElement
-public class InitParam {
- private String paramName;
- private String paramValue;
- private boolean initialized;
-
- public synchronized void inititialize() {
- checkState(initialized == false, "Already initialized");
- initialized = true;
- }
-
- @XmlElement(name = "param-name")
- public String getParamName() {
- return paramName;
- }
-
- public void setParamName(String paramName) {
- this.paramName = paramName;
- }
-
- @XmlElement(name = "param-value")
- public String getParamValue() {
- return paramValue;
- }
-
- public void setParamValue(String paramValue) {
- this.paramValue = paramValue;
- }
-
- public boolean isInitialized() {
- return initialized;
- }
-
- @Override
- public String toString() {
- return "{" + paramName + '=' + paramValue + "}";
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import java.io.StringReader;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-
-public class Parser {
-
- public static Host parse(String xmlFileContent, String fileName) throws JAXBException {
- JAXBContext context = JAXBContext.newInstance(Host.class);
- javax.xml.bind.Unmarshaller um = context.createUnmarshaller();
- Host host = (Host) um.unmarshal(new StringReader(xmlFileContent));
- host.initialize(fileName);
- return host;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.model;
-
-import com.google.common.base.Optional;
-import java.io.IOException;
-import java.util.List;
-import java.util.ListIterator;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import org.apache.catalina.connector.Request;
-import org.apache.catalina.connector.Response;
-import org.opendaylight.controller.filtervalve.cors.jaxb.Context;
-import org.opendaylight.controller.filtervalve.cors.jaxb.Filter;
-import org.opendaylight.controller.filtervalve.cors.jaxb.Host;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class FilterProcessor {
- private static final Logger logger = LoggerFactory.getLogger(FilterProcessor.class);
-
- private final Host host;
-
- public FilterProcessor(Host host) {
- this.host = host;
- }
-
- public void process(Request request, Response response, FilterChain nextValveFilterChain)
- throws IOException, ServletException {
-
- String contextPath = request.getContext().getPath();
- String path = request.getDecodedRequestURI();
-
- Optional<Context> maybeContext = host.findContext(contextPath);
- logger.trace("Processing context {} path {}, found {}", contextPath, path, maybeContext);
- if (maybeContext.isPresent()) {
- // process filters
- Context context = maybeContext.get();
- List<Filter> matchingFilters = context.findMatchingFilters(path);
- FilterChain fromLast = nextValveFilterChain;
- ListIterator<Filter> it = matchingFilters.listIterator(matchingFilters.size());
- final boolean trace = logger.isTraceEnabled();
- while (it.hasPrevious()) {
- final Filter currentFilter = it.previous();
- final FilterChain copy = fromLast;
- fromLast = (request1, response1) -> {
- if (trace) {
- logger.trace("Applying {}", currentFilter);
- }
- javax.servlet.Filter actualFilter = currentFilter.getActualFilter();
- actualFilter.doFilter(request1, response1, copy);
- };
- }
- // call first filter
- fromLast.doFilter(request, response);
- } else {
- // move to next valve
- nextValveFilterChain.doFilter(request, response);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.model;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Maps.immutableEntry;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Match incoming URL with user defined patterns according to servlet specification.
- * In the Web application deployment descriptor, the following syntax is used to define mappings:
- * <ul>
- * <li>A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for path mapping.</li>
- * <li>A string beginning with a ‘*.’ prefix is used as an extension mapping.</li>
- * <li>All other strings are used for exact matches only.</li>
- * </ul>
- */
-public class UrlMatcher<FILTER> {
- private static final Logger logger = LoggerFactory.getLogger(UrlMatcher.class);
- // order index for each FILTER is kept as Entry.value
- private final Map<String, Entry<FILTER, Integer>> prefixMap = new HashMap<>(); // contains patterns ending with '/*', '*' is stripped from each key
- private final Map<String, Entry<FILTER, Integer>> suffixMap = new HashMap<>(); // contains patterns starting with '*.' prefix, '*' is stripped from each key
- private final Map<String, Entry<FILTER, Integer>> exactMatchMap = new HashMap<>(); // contains exact matches only
-
- /**
- * @param patternMap order preserving map containing path info pattern as key
- */
- public UrlMatcher(LinkedHashMap<String, FILTER> patternMap) {
- int idx = 0;
- for (Entry<String, FILTER> entry : patternMap.entrySet()) {
- idx++;
- String pattern = checkNotNull(entry.getKey());
- FILTER value = entry.getValue();
- Entry<FILTER, Integer> valueWithIdx = immutableEntry(value, idx);
- if (pattern.startsWith("/") && pattern.endsWith("/*")) {
- pattern = pattern.substring(0, pattern.length() - 1);
- prefixMap.put(pattern, valueWithIdx);
- } else if (pattern.startsWith("*.")) {
- pattern = pattern.substring(1);
- suffixMap.put(pattern, valueWithIdx);
- } else {
- exactMatchMap.put(pattern, valueWithIdx);
- }
- }
- }
-
- /**
- * Find filters matching path
- *
- * @param path relative and decoded path to resource
- * @return list of matching filters
- */
- public List<FILTER> findMatchingFilters(String path) {
- checkNotNull(path);
- TreeMap<Integer, FILTER> sortedMap = new TreeMap<>();
- // add matching prefixes
- for (Entry<String, Entry<FILTER, Integer>> prefixEntry : prefixMap.entrySet()) {
- if (path.startsWith(prefixEntry.getKey())) {
- put(sortedMap, prefixEntry.getValue());
- }
- }
- // add matching suffixes
- for (Entry<String, Entry<FILTER, Integer>> suffixEntry : suffixMap.entrySet()) {
- if (path.endsWith(suffixEntry.getKey())) {
- put(sortedMap, suffixEntry.getValue());
- }
- }
- // add exact match
- Entry<FILTER, Integer> exactMatch = exactMatchMap.get(path);
- if (exactMatch != null) {
- put(sortedMap, exactMatch);
- }
- ArrayList<FILTER> filters = new ArrayList<>(sortedMap.values());
- logger.trace("Matching filters for path {} are {}", path, filters);
- return filters;
- }
-
- private void put(TreeMap<Integer, FILTER> sortedMap, Entry<FILTER, Integer> entry) {
- sortedMap.put(entry.getValue(), entry.getKey());
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import java.io.IOException;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-public class DummyFilter implements javax.servlet.Filter {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void destroy() {
- throw new UnsupportedOperationException();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import java.io.IOException;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-public class MockedFilter implements javax.servlet.Filter {
- private FilterConfig filterConfig;
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- this.filterConfig = filterConfig;
- }
-
- public FilterConfig getFilterConfig() {
- return filterConfig;
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void destroy() {
- throw new UnsupportedOperationException();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.jaxb;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.google.common.base.Optional;
-import java.io.File;
-import javax.servlet.FilterConfig;
-import org.apache.commons.io.FileUtils;
-import org.junit.Test;
-
-public class ParserTest {
-
- @Test
- public void testParsing() throws Exception {
- File xmlFile = new File(getClass().getResource("/sample-cors-config.xml").getFile());
- assertThat(xmlFile.canRead(), is(true));
- String xmlFileContent = FileUtils.readFileToString(xmlFile);
- Host host = Parser.parse(xmlFileContent, "fileName");
- assertEquals(1, host.getContexts().size());
- // check that MockedFilter has init params merged/replaced
- Optional<Context> context = host.findContext("/restconf");
- assertTrue(context.isPresent());
- assertEquals(1, context.get().getFilters().size());
- MockedFilter filter = (MockedFilter) context.get().getFilters().get(0).getActualFilter();
- FilterConfig filterConfig = filter.getFilterConfig();
- assertEquals("*", filterConfig.getInitParameter("cors.allowed.origins"));
- assertEquals("11", filterConfig.getInitParameter("cors.preflight.maxage"));
- }
-
-
- @Test
- public void testParsing_NoFilterDefined() throws Exception {
- File xmlFile = new File(getClass().getResource("/no-filter-defined.xml").getFile());
- assertThat(xmlFile.canRead(), is(true));
- String xmlFileContent = FileUtils.readFileToString(xmlFile);
- try {
- Parser.parse(xmlFileContent, "fileName");
- fail();
- }catch(Exception e){
- assertThat(e.getMessage(), containsString("Cannot find filter for filter-mapping CorsFilter"));
- }
- }
-
- @Test
- public void testConflictingClass() throws Exception {
- File xmlFile = new File(getClass().getResource("/conflicting-class.xml").getFile());
- assertThat(xmlFile.canRead(), is(true));
- String xmlFileContent = FileUtils.readFileToString(xmlFile);
- try {
- Parser.parse(xmlFileContent, "fileName");
- fail();
- } catch (RuntimeException e) {
- assertThat(e.getMessage(), containsString("Error while processing filter CorsFilter of context /restconf"));
- assertThat(e.getCause().getMessage(), containsString("Conflict detected in template/filter filter-class definitions, filter name: CorsFilter"));
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.filtervalve.cors.model;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.assertEquals;
-
-import java.util.LinkedHashMap;
-import org.junit.Test;
-
-public class UrlMatcherTest {
- UrlMatcher<String> urlMatcher;
-
- @Test
- public void test() throws Exception {
- final String defaultFilter = "default";
- final String exactMatchFilter = "someFilter";
- final String jspFilter = "jspFilter";
- final String exactMatch = "/somePath";
- final String prefixFilter = "prefixFilter";
- LinkedHashMap<String, String> patternMap = new LinkedHashMap<>();
- patternMap.put(exactMatch, exactMatchFilter);
- patternMap.put("/*", defaultFilter);
- patternMap.put("*.jsp", jspFilter);
- patternMap.put("/foo/*", prefixFilter);
- urlMatcher = new UrlMatcher<>(patternMap);
- assertMatches("/abc", defaultFilter);
- assertMatches(exactMatch, exactMatchFilter, defaultFilter);
- assertMatches("/some.jsp", defaultFilter, jspFilter);
- assertMatches("/foo/bar", defaultFilter, prefixFilter);
- assertMatches("/foo/bar.jsp", defaultFilter, jspFilter, prefixFilter);
- }
-
- public void assertMatches(String testedPath, String... filters) {
- assertEquals(asList(filters), urlMatcher.findMatchingFilters(testedPath));
- }
-
-}
+++ /dev/null
-<!--
- ~ Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- ~
- ~ This program and the accompanying materials are made available under the
- ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
- ~ and is available at http://www.eclipse.org/legal/epl-v10.html
- -->
-
-<Host>
- <filter-template>
- <filter-name>CorsFilter</filter-name>
- <filter-class>org.opendaylight.controller.filtervalve.cors.jaxb.MockedFilter</filter-class>
- <init-param>
- <param-name>cors.preflight.maxage</param-name>
- <param-value>10</param-value>
- </init-param>
- <init-param>
- <param-name>cors.allowed.origins</param-name>
- <param-value>*</param-value>
- </init-param>
- </filter-template>
-
- <Context path="/restconf">
- <filter>
- <filter-name>CorsFilter</filter-name>
- <!-- conflict -->
- <filter-class>org.opendaylight.controller.filtervalve.cors.jaxb.DummyFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>CorsFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </Context>
-</Host>
+++ /dev/null
-<!--
- ~ Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- ~
- ~ This program and the accompanying materials are made available under the
- ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
- ~ and is available at http://www.eclipse.org/legal/epl-v10.html
- -->
-
-<Host>
- <!-- Filters are allowed here, only serving as a template -->
- <filter-template>
- <filter-name>CorsFilter</filter-name>
- <filter-class>org.opendaylight.controller.filtervalve.cors.jaxb.MockedFilter</filter-class>
- <init-param>
- <param-name>cors.allowed.origins</param-name>
- <param-value>*</param-value>
- </init-param>
- <init-param>
- <param-name>cors.allowed.methods</param-name>
- <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
- </init-param>
- <init-param>
- <param-name>cors.allowed.headers</param-name>
- <param-value>Content-Type,X-Requested-With,accept,authorization,
- origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers
- </param-value>
- </init-param>
- <init-param>
- <param-name>cors.exposed.headers</param-name>
- <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
- </init-param>
- <init-param>
- <param-name>cors.support.credentials</param-name>
- <param-value>true</param-value>
- </init-param>
- <init-param>
- <param-name>cors.preflight.maxage</param-name>
- <param-value>10</param-value>
- </init-param>
- </filter-template>
-
- <Context path="/restconf">
- <!-- Filters are also allowed here. -->
- <filter>
- <filter-name>CorsFilter</filter-name>
- <!-- init params can be added/overriden if template is used -->
- </filter>
- <!-- only local references are allowed -->
- <filter-mapping>
- <filter-name>CorsFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </Context>
-
- <Context path="/controller/nb/v2/connectionmanager">
- <filter-mapping>
- <filter-name>CorsFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </Context>
-</Host>
+++ /dev/null
-<!--
- ~ Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- ~
- ~ This program and the accompanying materials are made available under the
- ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
- ~ and is available at http://www.eclipse.org/legal/epl-v10.html
- -->
-
-<Host>
- <filter-template>
- <filter-name>CorsFilter</filter-name>
- <filter-class>org.opendaylight.controller.filtervalve.cors.jaxb.MockedFilter</filter-class>
- <init-param>
- <param-name>cors.preflight.maxage</param-name>
- <param-value>10</param-value>
- </init-param>
- <init-param>
- <param-name>cors.allowed.origins</param-name>
- <param-value>*</param-value>
- </init-param>
- </filter-template>
-
- <Context path="/restconf">
- <filter>
- <filter-name>CorsFilter</filter-name>
- <!-- override value -->
- <init-param>
- <param-name>cors.preflight.maxage</param-name>
- <param-value>11</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>CorsFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </Context>
-</Host>
<!-- Parents -->
<module>opendaylight/commons/protocol-framework</module>
<module>opendaylight/commons/logback_settings</module>
- <module>opendaylight/commons/filter-valve</module>
<module>opendaylight/commons/liblldp</module>
<module>benchmark</module>
<module>opendaylight/commons/jolokia</module>