001/* 002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Arnaud Kervern 016 */ 017 018package org.nuxeo.ecm.platform.web.common.requestcontroller.service; 019 020import java.io.Serializable; 021import java.util.Dictionary; 022import java.util.Enumeration; 023import java.util.Hashtable; 024 025import javax.servlet.FilterConfig; 026import javax.servlet.ServletContext; 027import javax.servlet.http.HttpServletRequest; 028 029import org.apache.commons.lang.StringUtils; 030import org.nuxeo.common.xmap.annotation.XNode; 031import org.nuxeo.common.xmap.annotation.XObject; 032import org.nuxeo.runtime.api.Framework; 033 034import static org.apache.commons.lang.StringUtils.isEmpty; 035 036/** 037 * @author <a href="mailto:ak@nuxeo.com">Arnaud Kervern</a> 038 * @since 5.7.2 039 */ 040@XObject(value = "corsConfig") 041public class NuxeoCorsFilterDescriptor implements Serializable, Cloneable { 042 043 private static final String PROPERTIES_PREFIX = "cors."; 044 045 @XNode("@name") 046 protected String name; 047 048 @XNode("@enabled") 049 protected Boolean enabled = true; 050 051 @XNode("@allowGenericHttpRequests") 052 protected Boolean allowGenericHttpRequests = true; 053 054 @XNode("@allowOrigin") 055 protected String allowOrigin; 056 057 @XNode("@allowSubdomains") 058 protected boolean allowSubdomains = false; 059 060 @XNode("@supportedMethods") 061 protected String supportedMethods; 062 063 @XNode("@supportedHeaders") 064 protected String supportedHeaders; 065 066 @XNode("@exposedHeaders") 067 protected String exposedHeaders; 068 069 @XNode("@supportsCredentials") 070 protected Boolean supportsCredentials = true; 071 072 @XNode("@maxAge") 073 protected int maxAge = -1; 074 075 protected String pattern = ""; 076 077 @XNode("pattern") 078 public void setPattern(String pattern) { 079 this.pattern = Framework.expandVars(pattern); 080 } 081 082 public FilterConfig buildFilterConfig() { 083 final Dictionary<String, String> parameters = buildDictionary(); 084 085 return new FilterConfig() { 086 @Override 087 public String getFilterName() { 088 return "NuxeoCorsFilterDescriptor"; 089 } 090 091 @Override 092 public ServletContext getServletContext() { 093 // Not used with @see CORSFilter 094 return null; 095 } 096 097 @Override 098 public String getInitParameter(String name) { 099 return parameters.get(name); 100 } 101 102 @Override 103 public Enumeration getInitParameterNames() { 104 return parameters.keys(); 105 } 106 }; 107 } 108 109 public boolean isMatching(HttpServletRequest request) { 110 return !StringUtils.isEmpty(pattern) && request.getRequestURI().matches(pattern); 111 } 112 113 public NuxeoCorsFilterDescriptor clone() throws CloneNotSupportedException { 114 NuxeoCorsFilterDescriptor n = new NuxeoCorsFilterDescriptor(); 115 n.name = name; 116 n.allowGenericHttpRequests = allowGenericHttpRequests; 117 n.allowOrigin = allowOrigin; 118 n.allowSubdomains = allowSubdomains; 119 n.supportedMethods = supportedMethods; 120 n.supportedHeaders = supportedHeaders; 121 n.exposedHeaders = exposedHeaders; 122 n.supportsCredentials = supportsCredentials; 123 n.maxAge = maxAge; 124 n.pattern = pattern; 125 return n; 126 } 127 128 public void merge(NuxeoCorsFilterDescriptor o) { 129 allowGenericHttpRequests = o.allowGenericHttpRequests; 130 supportsCredentials = o.supportsCredentials; 131 allowSubdomains = o.allowSubdomains; 132 133 if (!StringUtils.isEmpty(o.allowOrigin)) { 134 allowOrigin = o.allowOrigin; 135 } 136 137 if (!StringUtils.isEmpty(o.supportedMethods)) { 138 supportedMethods = o.supportedMethods; 139 } 140 141 if (!StringUtils.isEmpty(o.supportedHeaders)) { 142 supportedHeaders = o.supportedHeaders; 143 } 144 145 if (!StringUtils.isEmpty(o.exposedHeaders)) { 146 exposedHeaders = o.exposedHeaders; 147 } 148 149 if (maxAge == -1) { 150 maxAge = o.maxAge; 151 } 152 153 if (!StringUtils.isEmpty(o.pattern)) { 154 pattern = o.pattern; 155 } 156 } 157 158 protected Dictionary<String, String> buildDictionary() { 159 Dictionary<String, String> params = new Hashtable<>(); 160 params.put(PROPERTIES_PREFIX + "allowGenericHttpRequests", Boolean.toString(allowGenericHttpRequests)); 161 162 if (!isEmpty(allowOrigin)) { 163 params.put(PROPERTIES_PREFIX + "allowOrigin", allowOrigin); 164 } 165 166 params.put(PROPERTIES_PREFIX + "allowSubdomains", Boolean.toString(allowSubdomains)); 167 168 if (!isEmpty(supportedMethods)) { 169 params.put(PROPERTIES_PREFIX + "supportedMethods", supportedMethods); 170 } 171 172 if (!isEmpty(supportedHeaders)) { 173 params.put(PROPERTIES_PREFIX + "supportedHeaders", supportedHeaders); 174 } 175 176 if (!isEmpty(exposedHeaders)) { 177 params.put(PROPERTIES_PREFIX + "exposedHeaders", exposedHeaders); 178 } 179 180 params.put(PROPERTIES_PREFIX + "supportsCredentials", Boolean.toString(supportsCredentials)); 181 params.put(PROPERTIES_PREFIX + "maxAge", Integer.toString(maxAge)); 182 183 return params; 184 } 185}