001/* 002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Arnaud Kervern 018 */ 019 020package org.nuxeo.ecm.platform.web.common.requestcontroller.service; 021 022import java.io.Serializable; 023import java.util.Dictionary; 024import java.util.Enumeration; 025import java.util.Hashtable; 026 027import javax.servlet.FilterConfig; 028import javax.servlet.ServletContext; 029import javax.servlet.http.HttpServletRequest; 030 031import org.apache.commons.lang.StringUtils; 032import org.nuxeo.common.xmap.annotation.XNode; 033import org.nuxeo.common.xmap.annotation.XObject; 034import org.nuxeo.runtime.api.Framework; 035 036import static org.apache.commons.lang.StringUtils.isEmpty; 037 038/** 039 * @author <a href="mailto:ak@nuxeo.com">Arnaud Kervern</a> 040 * @since 5.7.2 041 */ 042@XObject(value = "corsConfig") 043public class NuxeoCorsFilterDescriptor implements Serializable, Cloneable { 044 045 private static final String PROPERTIES_PREFIX = "cors."; 046 047 @XNode("@name") 048 protected String name; 049 050 @XNode("@enabled") 051 protected Boolean enabled = true; 052 053 @XNode("@allowGenericHttpRequests") 054 protected Boolean allowGenericHttpRequests = true; 055 056 @XNode("@allowOrigin") 057 protected String allowOrigin; 058 059 @XNode("@allowSubdomains") 060 protected boolean allowSubdomains = false; 061 062 @XNode("@supportedMethods") 063 protected String supportedMethods; 064 065 @XNode("@supportedHeaders") 066 protected String supportedHeaders; 067 068 @XNode("@exposedHeaders") 069 protected String exposedHeaders; 070 071 @XNode("@supportsCredentials") 072 protected Boolean supportsCredentials = true; 073 074 @XNode("@maxAge") 075 protected int maxAge = -1; 076 077 protected String pattern = ""; 078 079 @XNode("pattern") 080 public void setPattern(String pattern) { 081 this.pattern = Framework.expandVars(pattern); 082 } 083 084 public FilterConfig buildFilterConfig() { 085 final Dictionary<String, String> parameters = buildDictionary(); 086 087 return new FilterConfig() { 088 @Override 089 public String getFilterName() { 090 return "NuxeoCorsFilterDescriptor"; 091 } 092 093 @Override 094 public ServletContext getServletContext() { 095 // Not used with @see CORSFilter 096 return null; 097 } 098 099 @Override 100 public String getInitParameter(String name) { 101 return parameters.get(name); 102 } 103 104 @Override 105 public Enumeration getInitParameterNames() { 106 return parameters.keys(); 107 } 108 }; 109 } 110 111 public boolean isMatching(HttpServletRequest request) { 112 return !StringUtils.isEmpty(pattern) && request.getRequestURI().matches(pattern); 113 } 114 115 public NuxeoCorsFilterDescriptor clone() throws CloneNotSupportedException { 116 NuxeoCorsFilterDescriptor n = new NuxeoCorsFilterDescriptor(); 117 n.name = name; 118 n.allowGenericHttpRequests = allowGenericHttpRequests; 119 n.allowOrigin = allowOrigin; 120 n.allowSubdomains = allowSubdomains; 121 n.supportedMethods = supportedMethods; 122 n.supportedHeaders = supportedHeaders; 123 n.exposedHeaders = exposedHeaders; 124 n.supportsCredentials = supportsCredentials; 125 n.maxAge = maxAge; 126 n.pattern = pattern; 127 return n; 128 } 129 130 public void merge(NuxeoCorsFilterDescriptor o) { 131 allowGenericHttpRequests = o.allowGenericHttpRequests; 132 supportsCredentials = o.supportsCredentials; 133 allowSubdomains = o.allowSubdomains; 134 135 if (!StringUtils.isEmpty(o.allowOrigin)) { 136 allowOrigin = o.allowOrigin; 137 } 138 139 if (!StringUtils.isEmpty(o.supportedMethods)) { 140 supportedMethods = o.supportedMethods; 141 } 142 143 if (!StringUtils.isEmpty(o.supportedHeaders)) { 144 supportedHeaders = o.supportedHeaders; 145 } 146 147 if (!StringUtils.isEmpty(o.exposedHeaders)) { 148 exposedHeaders = o.exposedHeaders; 149 } 150 151 if (maxAge == -1) { 152 maxAge = o.maxAge; 153 } 154 155 if (!StringUtils.isEmpty(o.pattern)) { 156 pattern = o.pattern; 157 } 158 } 159 160 protected Dictionary<String, String> buildDictionary() { 161 Dictionary<String, String> params = new Hashtable<>(); 162 params.put(PROPERTIES_PREFIX + "allowGenericHttpRequests", Boolean.toString(allowGenericHttpRequests)); 163 164 if (!isEmpty(allowOrigin)) { 165 params.put(PROPERTIES_PREFIX + "allowOrigin", allowOrigin); 166 } 167 168 params.put(PROPERTIES_PREFIX + "allowSubdomains", Boolean.toString(allowSubdomains)); 169 170 if (!isEmpty(supportedMethods)) { 171 params.put(PROPERTIES_PREFIX + "supportedMethods", supportedMethods); 172 } 173 174 if (!isEmpty(supportedHeaders)) { 175 params.put(PROPERTIES_PREFIX + "supportedHeaders", supportedHeaders); 176 } 177 178 if (!isEmpty(exposedHeaders)) { 179 params.put(PROPERTIES_PREFIX + "exposedHeaders", exposedHeaders); 180 } 181 182 params.put(PROPERTIES_PREFIX + "supportsCredentials", Boolean.toString(supportsCredentials)); 183 params.put(PROPERTIES_PREFIX + "maxAge", Integer.toString(maxAge)); 184 185 return params; 186 } 187}