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