001// -------------------------------------------------------------------------------- 002// Copyright 2002-2024 Echo Three, LLC 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 017/* 018 * ==================================================================== 019 * 020 * The Apache Software License, Version 1.1 021 * 022 * Copyright (c) 1999-2003 The Apache Software Foundation. All rights 023 * reserved. 024 * 025 * Redistribution and use in source and binary forms, with or without 026 * modification, are permitted provided that the following conditions 027 * are met: 028 * 029 * 1. Redistributions of source code must retain the above copyright 030 * notice, this list of conditions and the following disclaimer. 031 * 032 * 2. Redistributions in binary form must reproduce the above copyright 033 * notice, this list of conditions and the following disclaimer in 034 * the documentation and/or other materials provided with the 035 * distribution. 036 * 037 * 3. The end-user documentation included with the redistribution, if 038 * any, must include the following acknowlegement: 039 * "This product includes software developed by the 040 * Apache Software Foundation (http://www.apache.org/)." 041 * Alternately, this acknowlegement may appear in the software itself, 042 * if and wherever such third-party acknowlegements normally appear. 043 * 044 * 4. The names "The Jakarta Project", "Struts", and "Apache Software 045 * Foundation" must not be used to endorse or promote products derived 046 * from this software without prior written permission. For written 047 * permission, please contact apache@apache.org. 048 * 049 * 5. Products derived from this software may not be called "Apache" 050 * nor may "Apache" appear in their names without prior written 051 * permission of the Apache Group. 052 * 053 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 054 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 055 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 056 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 057 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 058 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 059 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 060 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 061 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 062 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 063 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 064 * SUCH DAMAGE. 065 * ==================================================================== 066 * 067 * This software consists of voluntary contributions made by many 068 * individuals on behalf of the Apache Software Foundation. For more 069 * information on the Apache Software Foundation, please see 070 * <http://www.apache.org/>. 071 * 072 */ 073 074package com.echothree.view.client.web.struts.sslext.tiles; 075 076import com.echothree.view.client.web.struts.sslext.action.SecurePlugInInterface; 077import com.echothree.view.client.web.struts.sslext.action.SecureTilesRequestProcessor; 078import java.io.IOException; 079import java.io.InputStream; 080import java.net.URL; 081import java.util.ArrayList; 082import java.util.Collection; 083import java.util.MissingResourceException; 084import javax.servlet.ServletException; 085import javax.servlet.UnavailableException; 086import org.apache.commons.digester.Digester; 087import org.apache.commons.logging.Log; 088import org.apache.commons.logging.LogFactory; 089import org.apache.struts.action.ActionServlet; 090import org.apache.struts.action.RequestProcessor; 091import org.apache.struts.config.ControllerConfig; 092import org.apache.struts.config.ModuleConfig; 093import org.apache.struts.tiles.TilesPlugin; 094import org.apache.struts.util.MessageResources; 095import org.apache.struts.util.RequestUtils; 096 097/** 098 * Implements sslext plugin functionality for use with Tiles. 099 */ 100public class SecureTilesPlugin 101 extends TilesPlugin implements SecurePlugInInterface { 102 103 protected String addSession = DEFAULT_ADD_SESSION; 104 protected String httpPort = DEFAULT_HTTP_PORT; 105 protected String httpsPort = DEFAULT_HTTPS_PORT; 106 protected String enable = DEFAULT_ENABLE; 107 108 protected String resourceName = "org.apache.struts.action.SecureResources"; 109 protected MessageResources resources = null; 110 protected String registrations[] = { 111 "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", 112 "/org/apache/struts/resources/web-app_2_2.dtd", 113 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", 114 "/org/apache/struts/resources/web-app_2_3.dtd" 115 }; 116 117 protected Log log = LogFactory.getLog(SecureTilesPlugin.class); 118 protected ModuleConfig config = null; 119 protected ActionServlet servlet = null; 120 protected String servletName = null; 121 protected Collection servletMappings = new ArrayList(); 122 123 @Override 124 public void destroy() { 125 super.destroy(); 126 servlet.getServletContext().removeAttribute(SECURE_PLUGIN); 127 } 128 129 public void setHttpsPort(String s) { 130 this.httpsPort = s; 131 } 132 133 public void setHttpPort(String s) { 134 this.httpPort = s; 135 } 136 137 @Override 138 public String getHttpsPort() { 139 return this.httpsPort; 140 } 141 142 @Override 143 public String getHttpPort() { 144 return this.httpPort; 145 } 146 147 @Override 148 public Collection getServletMappings() { 149 return this.servletMappings; 150 } 151 152 @Override 153 public String getEnable() { 154 return enable; 155 } 156 157 public void setEnable(String s) { 158 enable = s; 159 } 160 161 public String getAddSession() { 162 return addSession; 163 } 164 165 public void setAddSession(String addSession) { 166 this.addSession = addSession; 167 } 168 169 @Override 170 public boolean getSslExtAddSession() { 171 172 return Boolean.valueOf(getAddSession()); 173 } 174 175 @Override 176 public boolean getSslExtEnable() { 177 178 return Boolean.valueOf(getEnable()); 179 } 180 181 @Override 182 public void init(ActionServlet servlet, ModuleConfig moduleConfig) 183 throws ServletException { 184 185 this.config = moduleConfig; 186 this.servlet = servlet; 187 initMappings(); 188 servlet.getServletContext().setAttribute(SECURE_PLUGIN, this); 189 super.init(servlet, moduleConfig); 190 } 191 192 @Override 193 protected void initRequestProcessorClass(ModuleConfig config) throws ServletException { 194 String tilesProcessorClassname = SecureTilesRequestProcessor.class.getName(); 195 ControllerConfig ctrlConfig = config.getControllerConfig(); 196 String configProcessorClassname = ctrlConfig.getProcessorClass(); 197 Class configProcessorClass; 198 try { 199 configProcessorClass = RequestUtils.applicationClass(configProcessorClassname); 200 } catch (java.lang.ClassNotFoundException ex) { 201 log.fatal("Can't set TilesRequestProcessor: bad class name '" 202 + configProcessorClassname 203 + "'."); 204 throw new ServletException(ex); 205 } 206 if (configProcessorClassname.equals(RequestProcessor.class.getName()) 207 || configProcessorClassname.endsWith(tilesProcessorClassname)) { 208 ctrlConfig.setProcessorClass(tilesProcessorClassname); 209 return; 210 } 211 Class tilesProcessorClass = SecureTilesRequestProcessor.class; 212 if (!tilesProcessorClass.isAssignableFrom(configProcessorClass)) { // Not compatible 213 String msg = "TilesPlugin : Specified RequestProcessor not compatible with TilesRequestProcessor"; 214 if (log.isFatalEnabled()) { 215 log.fatal(msg); 216 } 217 throw new ServletException(msg); 218 } // end if 219 } 220 221 protected void initMappings() throws ServletException { 222 223 // Get the action servlet name 224 this.servletName = servlet.getServletConfig().getServletName(); 225 226 // Prepare a Digester to scan the web application deployment descriptor 227 Digester digester = new Digester(); 228 digester.push(this); 229 digester.setNamespaceAware(true); 230 digester.setValidating(false); 231 232 // Register our local copy of the DTDs that we can find 233 for(int i = 0; i < registrations.length; i += 2) { 234 URL url = this.getClass().getResource(registrations[i + 1]); 235 if (url != null) { 236 digester.register(registrations[i], url.toString()); 237 } 238 } 239 240 // Configure the processing rules that we need 241 digester.addCallMethod("web-app/servlet-mapping", 242 "addServletMapping", 2); 243 digester.addCallParam("web-app/servlet-mapping/servlet-name", 0); 244 digester.addCallParam("web-app/servlet-mapping/url-pattern", 1); 245 246 // Process the web application deployment descriptor 247 if (log.isDebugEnabled()) { 248 log.debug("Scanning web.xml for ActionServlet URL mappings"); 249 } 250 InputStream input = null; 251 try { 252 input = 253 servlet.getServletContext().getResourceAsStream("/WEB-INF/web.xml"); 254 digester.parse(input); 255 } catch (Throwable e) { 256 log.error(resources.getMessage("configWebXml"), e); 257 } finally { 258 if (input != null) { 259 try { 260 input.close(); 261 } catch (IOException e) { 262 ; 263 } 264 } 265 } 266 } 267 268 protected void initResources() throws ServletException { 269 270 try { 271 resources = MessageResources.getMessageResources(resourceName); 272 } catch (MissingResourceException e) { 273 log.error("Cannot load internal resources from '" + resourceName + "'", 274 e); 275 throw new UnavailableException 276 ("Cannot load internal resources from '" + resourceName + "'"); 277 } 278 } 279 280 public void addServletMapping(String servletName, String urlPattern) { 281 282 if (log.isDebugEnabled()) { 283 log.debug("Process servletName=" + servletName + 284 ", urlPattern=" + urlPattern); 285 } 286 if (servletName == null) { 287 return; 288 } 289 if (servletName.equals(this.servletName)) { 290 this.servletMappings.add(urlPattern); 291 } 292 } 293}