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.action; 075 076import java.io.IOException; 077import java.io.InputStream; 078import java.net.URL; 079import java.util.ArrayList; 080import java.util.Collection; 081import java.util.MissingResourceException; 082import javax.servlet.ServletException; 083import javax.servlet.UnavailableException; 084import org.apache.commons.digester.Digester; 085import org.apache.commons.logging.Log; 086import org.apache.commons.logging.LogFactory; 087import org.apache.struts.action.ActionServlet; 088import org.apache.struts.config.ModuleConfig; 089import org.apache.struts.util.MessageResources; 090 091/** 092 * Implements sslext plugin functionality 093 */ 094public class SecurePlugIn implements SecurePlugInInterface { 095 096 protected String addSession = DEFAULT_ADD_SESSION; 097 protected String httpPort = DEFAULT_HTTP_PORT; 098 protected String httpsPort = DEFAULT_HTTPS_PORT; 099 protected String enable = DEFAULT_ENABLE; 100 101 private Log sLog = LogFactory.getLog(SecurePlugIn.class); 102 103 /** 104 * The {@link ActionServlet} owning this application. 105 */ 106 private ActionServlet servlet = null; 107 108 /** 109 * The servlet name under which we are registered in our web application 110 * deployment descriptor. 111 */ 112 private String servletName = null; 113 114 /** 115 * The servlet mappings for the Struts Action Servlet 116 */ 117 private Collection servletMappings = new ArrayList(); 118 119 /** 120 * The set of public identifiers, and corresponding resource names, for 121 * the versions of the configuration file DTDs that we know about. There 122 * <strong>MUST</strong> be an even number of Strings in this list! 123 */ 124 protected String registrations[] = { 125 "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", "/org/apache/struts/resources/web-app_2_2.dtd", 126 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", "/org/apache/struts/resources/web-app_2_3.dtd" 127 }; 128 129 /** 130 * The resources object for our internal resources. 131 */ 132 protected MessageResources resources = null; 133 134 135 /** 136 * The Java base name of our internal resources. 137 * @since Struts 1.1 138 */ 139 protected String resourceName = "org.apache.struts.action.SecureResources"; 140 141 /** 142 * Initialize some instance variables and 143 * the ServletContext (application) to make this PlugIn's 144 * properties accessible from the whole app. 145 * 146 * @param servlet The Struts ActionServlet instance for the whole application 147 * @param config The ApplicationConfig for our owning sub-application 148 * @exception ServletException if we cannot configure ourselves correctly 149 */ 150 @Override 151 public void init(ActionServlet servlet, ModuleConfig config) 152 throws ServletException { 153 this.servlet = servlet; 154 155 initMappings(); 156 servlet.getServletContext().setAttribute(SECURE_PLUGIN, this); 157 } 158 159 /** 160 * Remove stuff from the ServletContext (application). 161 */ 162 @Override 163 public void destroy() { 164 servlet.getServletContext().removeAttribute(SECURE_PLUGIN); 165 } 166 167 public void setHttpsPort(String s) { 168 this.httpsPort = s; 169 } 170 171 public void setHttpPort(String s) { 172 this.httpPort = s; 173 } 174 175 @Override 176 public String getHttpsPort() { 177 return this.httpsPort; 178 } 179 180 @Override 181 public String getHttpPort() { 182 return this.httpPort; 183 } 184 185 @Override 186 public Collection getServletMappings() { 187 return this.servletMappings; 188 } 189 190 @Override 191 public String getEnable() { 192 return enable; 193 } 194 195 public void setEnable(String s) { 196 enable = s; 197 } 198 199 public String getAddSession() { 200 return addSession; 201 } 202 203 public void setAddSession(String addSession) { 204 this.addSession = addSession; 205 } 206 207 @Override 208 public boolean getSslExtAddSession() { 209 return Boolean.valueOf(getAddSession()); 210 } 211 212 @Override 213 public boolean getSslExtEnable() { 214 return Boolean.valueOf(getEnable()); 215 } 216 217 /** 218 * Initialize the servlet mappings under which the Struts ActionServlet 219 * is accessed. This will be used when searching for action mappings in the 220 * Struts configuration files when creating links, etc. 221 */ 222 protected void initMappings() throws ServletException { 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", "addServletMapping", 2); 242 digester.addCallParam("web-app/servlet-mapping/servlet-name", 0); 243 digester.addCallParam("web-app/servlet-mapping/url-pattern", 1); 244 245 // Process the web application deployment descriptor 246 if(sLog.isDebugEnabled()) { 247 sLog.debug("Scanning web.xml for ActionServlet URL mappings"); 248 } 249 250 InputStream input = null; 251 try { 252 input = servlet.getServletContext().getResourceAsStream("/WEB-INF/web.xml"); 253 digester.parse(input); 254 } catch (Throwable e) { 255 sLog.error(resources.getMessage("configWebXml"), e); 256 } finally { 257 if(input != null) { 258 try { 259 input.close(); 260 } catch (IOException e) { 261 // Nothing 262 } 263 } 264 } 265 } 266 267 /** 268 * Initialize our internal MessageResources bundle. 269 * 270 * @exception ServletException if we cannot initialize these resources 271 */ 272 protected void initResources() 273 throws ServletException { 274 try { 275 resources = MessageResources.getMessageResources(resourceName); 276 } catch (MissingResourceException e) { 277 sLog.error("Cannot load internal resources from '" + resourceName + "'", e); 278 throw new UnavailableException("Cannot load internal resources from '" + resourceName + "'"); 279 } 280 } 281 282 /** 283 * Remember all servlet mapping from our web application deployment 284 * descriptor, if it is for the Struts ActionServlet. 285 * 286 * @param servletName The name of the servlet being mapped 287 * @param urlPattern The URL pattern to which this servlet is mapped 288 */ 289 public void addServletMapping(String servletName, String urlPattern) { 290 if(sLog.isDebugEnabled()) { 291 sLog.debug("Process servletName=" + servletName + ", urlPattern=" + urlPattern); 292 } 293 294 if(servletName == null) { 295 return; 296 } 297 298 if(servletName.equals(this.servletName)) { 299 this.servletMappings.add(urlPattern); 300 } 301 } 302}