July 29, 2003
SecureStrutsLinkTool is a substitute for StrutsLinkTool intended for those who use the SSL Extensions with Struts 1.1. Simply switch class names in toolbox.xml and you're set.
More info on Struts SSL Extensions
Any comments are welcome on the Velocity Developer's List <velocity-dev@jakarta.apache.org>.
Marinó A. Jónsson
{ { {
package org.apache.velocity.tools.struts;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.tools.view.tools.LinkTool;
import org.apache.velocity.tools.struts.StrutsUtils;
import org.apache.struts.config.ForwardConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.action.SecurePlugIn;
import org.apache.struts.config.SecureActionConfig;
import org.apache.struts.Globals;
/**
{{{ * <p>Title: SecureStrutsLinkTool</p>
* <p>Description: Tool to be able to use Struts SSL Extensions with Velocity</p>
* <p>It has the same interface as StrutsLinkTool and can function as a substitute if Struts 1.1 and SSL Ext are installed. </p>
* @author Marinó A. Jónsson
* @version 1.0
*/ public class SecureStrutsLinkTool {{{ extends LinkTool {
- private static final String HTTP = "http"; private static final String HTTPS = "https"; private static final String STD_HTTP_PORT = "80"; private static final String STD_HTTPS_PORT = "443"; /**
<p>Returns a copy of the link with the given action name
- converted into a server-relative URI reference. This method
- does not check if the specified action really is defined.
- This method will overwrite any previous URI reference settings
but will copy the query string.</p>
- @param action an action path as defined in struts-config.xml
@return a new instance of StrutsLinkTool
- /
public SecureStrutsLinkTool setAction(String action) {
String link = StrutsUtils.getActionMappingURL(application, request, action); return (SecureStrutsLinkTool) copyWith(this.computeURL(request, application, link));
<p>Returns a copy of the link with the given global forward name
- converted into a server-relative URI reference. If the parameter
does not map to an existing global forward name, <code>null</code>
- is returned. This method will overwrite any previous URI reference
settings but will copy the query string.</p>
- @param forward a global forward name as defined in struts-config.xml
@return a new instance of StrutsLinkTool
- /
public SecureStrutsLinkTool setForward(String forward) {
ForwardConfig fc = StrutsUtils.getForwardConfig(forward, request, application); if (fc == null) {
- Velocity.warn("In method setForward(" + forward +
- "): Parameter does not map to a valid forward.");
StringBuffer url = new StringBuffer(); if (fc.getPath().startsWith("/")) {
- url.append(request.getContextPath());
url.append(StrutsUtils.getForwardURL(request, fc));
- url.append(fc.getPath());
return (SecureStrutsLinkTool) copyWith(this.computeURL(request, application, url.toString()));
- Velocity.warn("In method setForward(" + forward +
public static String computeURL(HttpServletRequest request, ServletContext app, String link) {
StringBuffer url = new StringBuffer(link); String contextPath = request.getContextPath();
if (SecurePlugIn.getAppSslExtEnable(app) &&
- url.toString().startsWith(contextPath)) { // Initialize the scheme and ports we are using String usingScheme = request.getScheme(); String usingPort = String.valueOf(request.getServerPort()); // Get the servlet context relative link URL String linkString = url.toString().substring(contextPath.length()); // See if link references an action somewhere in our app
SecureActionConfig secureConfig = getActionConfig(request, app, linkString); // If link is an action, find the desired port and scheme
if (secureConfig != null &&
SecureActionConfig.ANY.equalsIgnoreCase(secureConfig.getSecure())) { String desiredScheme = Boolean.valueOf(secureConfig.getSecure()).booleanValue() ?
- HTTPS : HTTP;
SecurePlugIn.getAppHttpsPort(app) : SecurePlugIn.getAppHttpPort(app);
if ( (!desiredScheme.equals(usingScheme) || !desiredPort.equals(usingPort))) {
- url.insert(0, startNewUrlString(request, desiredScheme, desiredPort)); // This is a hack to help us overcome the problem that some
// older browsers do not share sessions between http & https if (url.toString().indexOf(";jsessionid=") < 0) {
- // Add the session identifier
url = new StringBuffer(StrutsUtils.toEncoded(url.toString(),
- request.getSession().getId()));
- // Add the session identifier
- url.toString().startsWith(contextPath)) { // Initialize the scheme and ports we are using String usingScheme = request.getScheme(); String usingPort = String.valueOf(request.getServerPort()); // Get the servlet context relative link URL String linkString = url.toString().substring(contextPath.length()); // See if link references an action somewhere in our app
- Finds the configuration definition for the specified action link
- @param pageContext the current page context.
- @param linkString The action we are searching for, specified as a link. (i.e. may include "..")
@return The SecureActionConfig object entry for this action, or null if not found
- /
private static SecureActionConfig getActionConfig(HttpServletRequest request, ServletContext app, String linkString) {
ModuleConfig moduleConfig = StrutsUtils.selectModule(linkString, app); // Strip off the subapp path, if any linkString = linkString.substring(moduleConfig.getPrefix().length()); // Use our servlet mapping, if one is specified String servletMapping = (String) app.getAttribute(Globals.SERVLET_KEY); int starIndex = servletMapping != null ? servletMapping.indexOf('*') : -1; if (starIndex == -1) {
- return null;
if (jsession >= 0) {
- linkString = linkString.substring(0, jsession);
if (anchor >= 0) {
- linkString = linkString.substring(0, anchor);
if (question >= 0) {
- linkString = linkString.substring(0, question);
if (! (linkString.startsWith(prefix) && linkString.endsWith(suffix))) {
- return null;
- linkString = "/" + linkString;
SecureActionConfig secureConfig = (SecureActionConfig) moduleConfig.findActionConfig(linkString); return secureConfig;
- Builds the protocol, server name, and port portion of the new URL
- @param request The current request
- @param desiredScheme The scheme (http or https) to be used in the new URL
- @param desiredPort The port number to be used in th enew URL
@return The new URL as a StringBuffer
- /
private static StringBuffer startNewUrlString(HttpServletRequest request,
- String desiredScheme, String desiredPort) {
StringBuffer url = new StringBuffer(); String serverName = request.getServerName(); url.append(desiredScheme).append("://").append(serverName);
if ( (HTTP.equals(desiredScheme) && !STD_HTTP_PORT.equals(desiredPort)) ||
(HTTPS.equals(desiredScheme) && !STD_HTTPS_PORT.equals(desiredPort))) { url.append(":").append(desiredPort);
}
{{{ } } }
- }}}