Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

Wicket 6.x, using HttpsMapper

Inside of the Application.init() method add the following.

Note

It is extemtely important that when setting the rootRequestMapper it is done AFTER you have added any bookmarkable links otherwise they will not be switched over to Secure mode.

Code Block


mountPage("/somepage", MyPage.class);

// notice that in most cases this should be done as the
// last mounting-related operation because it replaces the root mapper
setRootRequestMapper(new HttpsMapper(getRootRequestMapper(), new HttpsConfig()));

As with previous versions of Wicket, now all you need to do is include the @RequireHttps attribute on your Pages or Components.

Using other methods to determine if Https should be use:

Referencing the example above, override the getDesiredSchemeFor method.

Code Block
setRootRequestMapper(new HttpsMapper(getRootRequestMapper(), new HttpsConfig()){
      @Override
      protected Scheme getDesiredSchemeFor(Class pageClass) {
         if (getConfigurationType()==RuntimeConfigurationType.DEVELOPMENT) {
         log.debug("Dev mode, always use HTTP");
         return Scheme.HTTP;
      } else {
         log.debug("not in development mode, letting the mapper decide, or roll you own solution");
         return super.getDesiredSchemeFor(pageClass);
      }
   }
});

Using HttpsRequestCycleProcessor (after 1.4--rc3)

By replacing the default WebRequestCycleProcessor with the HttpsRequestCycleProcessor, you are able to specify secure pages using the @RequireHttps annotation on your pages. If you wanted a little more control... lets say for development you did not want your annotated pages to use https, you could bypass the Switch Protocol code like this. As of 1.4-rc3 Wicket provides built in support for http/https switching via org.apache.wicket.protocol.https.HttpsRequestCycleProcessor. Please see the javadoc of this class for details

Code Block

@Override
protected IRequestCycleProcessor newRequestCycleProcessor()
{
    HttpsConfig config = new HttpsConfig(80,443);
    return new HttpsRequestCycleProcessor(config)
    {

        @Override
        protected IRequestTarget checkSecureIncoming(IRequestTarget target)
        {
            if (getConfigurationType().equals(Application.DEVELOPMENT))
            {
	        return target;
            }
            else
            {
                return super.checkSecureIncoming(target);
            }
        }

        @Override
        protected IRequestTarget checkSecureOutgoing(IRequestTarget target)
        {
            if (getConfigurationType().equals(Application.DEVELOPMENT))
            {
                return target;
            }
            else
            {
                return super.checkSecureOutgoing(target);
            }
        }

    };
}

For The Entire Application

Code Block
xml
xml
titleweb.xml

<web-app ...>
   <security-constraint>
      <user-data-constraint>
         <transport-guarantee>CONFIDENTIAL</transport-guarantee>
      </user-data-constraint>
   </security-constraint>
</web-app>

Quote from web-app_2_3.dtd:

The transport-guarantee element specifies that the communication
between client and server should be NONE, INTEGRAL, or
CONFIDENTIAL. NONE means that the application does not require any
transport guarantees. A value of INTEGRAL means that the application
requires that the data sent between the client and server be sent in
such a way that it can't be changed in transit. CONFIDENTIAL means
that the application requires that the data be transmitted in a
fashion that prevents other entities from observing the contents of
the transmission. In most cases, the presence of the INTEGRAL or
CONFIDENTIAL flag will indicate that the use of SSL is required.

For Particular Pages

Excerpt

An explanation of how to transparently switch from http to https.

...

Change the rendering strategy in your application.

Code Block
 getRequestCycleSettings().setRenderStrategy(Settings.ONE_PASS_RENDER);

...

Create an annotation.

Code Block
 @Retention(RetentionPolicy.RUNTIME))
@Inherited //For a "BasePage" strategy
 public @interface RequiredSSL { }

...

The following goes in your extended Application class.

Code Block
 @Override
 protected IRequestCycleProcessor newRequestCycleProcessor() {
 	                return new DefaultWebRequestCycleProcessor() {
 	                        @Override
 	                        protected IResponseStrategy newResponseStrategy() {
 	                                return new IResponseStrategy() {
 	                                        public void respond(RequestCycle requestCycle) {
 	                                                IRequestTarget requestTarget = requestCycle
 	                                                                .getRequestTarget();
 	                                                if (requestTarget != null) {
 	                                                        Application.get().logResponseTarget(requestTarget);
 	
 	                                                        WebRequest webRequest = (WebRequest) requestCycle
 	                                                                        .getRequest();
 	                                                        WebResponse webResponse = (WebResponse) requestCycle
 	                                                                        .getResponse();
 	
 	                                                        HttpServletRequest httpServletRequest = webRequest
 	                                                                        .getHttpServletRequest();
 	
 	                                                        Class pageClass = null;
 	
 	                                                        if (requestTarget instanceof IPageRequestTarget) {
 	                                                                IPageRequestTarget pageTarget = 
                                                                                     (IPageRequestTarget) requestTarget;
 	                                                                pageClass = pageTarget.getPage().getClass();
 	                                                        } else if (requestTarget instanceof IBookmarkablePageRequestTarget) {
 	                                                                IBookmarkablePageRequestTarget bookmarkableTarget = 
                                                                                     (IBookmarkablePageRequestTarget) requestTarget;
 	                                                                pageClass = bookmarkableTarget.getPageClass();
 	                                                        }
                                                                if (pageClass != null
 	                                                                        && !httpServletRequest.isSecure()
 	                                                                        && pageClass.isAnnotationPresent(RequiredSSL.class)) {
 	                                                                StringBuffer url = new StringBuffer("https://"
 	                                                                                + httpServletRequest.getServerName());
 	
 	                                                                url.append(":" + MyApplication.get().getSslPort());
                                                                        String q = RequestCycle.get().urlFor(
 	                                                                                requestTarget).toString();
 	                                                                url.append(q);
 	                                                                webResponse.redirect(url.toString());
 	                                                        }
                                                                else /* else added */
 	                                                                requestTarget.respond(requestCycle);
 	                                                }
                                                 }
 	                                };
 	                        }
 	                };
 	        }

...

Add @RequiredSSL to any Page that requires SSL !or to your BasePage, in case of use @Inherited annotation in RequiredSSL class.

Edit:

I tried to apply this but I think there was a bug (at least it didn't work for me). A else was missing before the requestTarget.respond(requestCycle); (see else added in the code).
Additionally, a switch back to non-ssl mode should/could be added by adding a if clause, more ore less like this:

Code Block

Code Block

                                                                else if (pageClass != null
 	                                                                        && httpServletRequest.isSecure()
 	                                                                        && !pageClass.isAnnotationPresent(RequiredSSL.class)) {
 	                                                                StringBuffer url = new StringBuffer("http://"
 	                                                                                + httpServletRequest.getServerName());
 	
                                                                        String q = RequestCycle.get().urlFor(
 	                                                                                requestTarget).toString();
 	                                                                url.append(q);
 	                                                                webResponse.redirect(url.toString());
 	                                                        }

Edit (Wicket 1.3.x):

I was not able to get the above to work with 1.3. However, with a few tweaks, I was able to get the proper URL generation. I followed the RequiredSSL annotation requirement. Removed the One Pass Through Render Strategy suggestion. I then copied the WebRequestCycleProcessor locally. Modified the

Code Block

encode(final RequestCycle requestCycle, final IRequestTarget requestTarget) 

and added a

Code Block

doPostEncode() 
Code Block
	public final CharSequence encode(final RequestCycle requestCycle,
			final IRequestTarget requestTarget)
	{
		// First check to see whether the target is mounted
		CharSequence url = pathForTarget(requestTarget);

		if (url != null)
		{
			// Do nothing - we've found the URL and it's mounted.
		}
		else if (requestTarget instanceof IBookmarkablePageRequestTarget)
		{
			url = encode(requestCycle, (IBookmarkablePageRequestTarget)requestTarget);
		}
		else if (requestTarget instanceof ISharedResourceRequestTarget)
		{
			url = encode(requestCycle, (ISharedResourceRequestTarget)requestTarget);
		}
		else if (requestTarget instanceof IListenerInterfaceRequestTarget)
		{
			url = encode(requestCycle, (IListenerInterfaceRequestTarget)requestTarget);
		}
		else if (requestTarget instanceof IPageRequestTarget)
		{
			// This calls page.urlFor(IRedirectListener.INTERFACE), which calls
			// the function we're in again. We therefore need to jump out here
			// and return the url immediately, otherwise we end up prefixing it
			// with relative path or absolute prefixes twice.
			return encode(requestCycle, (IPageRequestTarget)requestTarget);
		}
		// fallthough for non-default request targets
		else
		{
			url = doEncode(requestCycle, requestTarget);
		}

		if (url != null)
		{
			// Add the actual URL. This will be relative to the Wicket
			// Servlet/Filter, with no leading '/'.
			PrependingStringBuffer prepender = new PrependingStringBuffer(url.toString());

			// Prepend prefix to the URL to make it relative to the current
			// request.
			prepender.prepend(requestCycle.getRequest().getRelativePathPrefixToWicketHandler());

// CHANGES vvvvv
			// We need to special-case links to the home page if we're at the
			// same level.
			if (prepender.toString().length() == 0)
			{
				prepender.prepend("./");
			}			
			
			String result = prepender.toString();			

			return doPostEncode( requestCycle, requestTarget, requestCycle.getOriginalResponse().encodeURL(result) );

// CHANGES ^^^^^
			
		}

		// Just return null intead of throwing an exception. So that it can be
		// handled better
		return null;
	}

// CHANGES vvvvv	
	protected CharSequence doPostEncode( final RequestCycle requestCycle,
			final IRequestTarget requestTarget, CharSequence result ) {
		
		return result;
	}
	
// CHANGES ^^^^^

Then used the following SecureWebRequestCycleProcessor

Code Block
public class SecureWebRequestCodingStrategy extends WebRequestCodingStrategy {
	private int httpPort = 80;
	private int httpsPort = 443;

	public SecureWebRequestCodingStrategy(int httpPort, int httpsPort ) {
		this.httpPort = httpPort;
		this.httpsPort = httpsPort ;
	}

	@Override
	protected CharSequence doPostEncode(final RequestCycle requestCycle,
			final IRequestTarget requestTarget, final CharSequence result) {
		PrependingStringBuffer buf = new PrependingStringBuffer(
				stripWicketPath(result.toString()));
		if (requestTarget != null) {
			WebRequest webRequest = (WebRequest) requestCycle.getRequest();

			HttpServletRequest httpServletRequest = webRequest
					.getHttpServletRequest();

			Class targetClass = null;

			if (requestTarget instanceof IBookmarkablePageRequestTarget) {
				targetClass = ((IBookmarkablePageRequestTarget) requestTarget)
						.getPageClass();
			} else if (requestTarget instanceof ISharedResourceRequestTarget) {
				targetClass = ((ISharedResourceRequestTarget) requestTarget)
						.getClass();
			} else if (requestTarget instanceof IListenerInterfaceRequestTarget) {
				targetClass = ((IListenerInterfaceRequestTarget) requestTarget)
						.getTarget().getClass();
			} else if (requestTarget instanceof IPageRequestTarget) {
				targetClass = ((IPageRequestTarget) requestTarget).getPage()
						.getClass();
			}

			if (targetClass != null && !httpServletRequest.isSecure()
					&& targetClass.isAnnotationPresent(RequiredSSL.class)) {
				StringBuffer url = new StringBuffer("https://"
						+ httpServletRequest.getServerName());

				if (443 != httpsPort ) {
					url.append(":" + httpsPort );
				}
				url.append(httpServletRequest.getContextPath());

				url
						.append(stripServletPath(httpServletRequest
								.getServletPath()));

				buf.prepend(url.toString());
			} else if (targetClass != null && httpServletRequest.isSecure()
					&& !targetClass.isAnnotationPresent(RequiredSSL.class)) {
				StringBuffer url = new StringBuffer("http://");
				url.append(httpServletRequest.getServerName());
				if (80 != httpPort ) {
					url.append(":" + httpPort );
				}
				url.append(httpServletRequest.getContextPath());
				url
						.append(stripServletPath(httpServletRequest
								.getServletPath()));

				buf.prepend(url.toString());
			} else {
				if (!buf.toString().startsWith("/")) {
					buf.prepend("/");
				}
				buf.prepend(stripServletPath(httpServletRequest
						.getServletPath()));
				buf.prepend(httpServletRequest.getContextPath());
			}
		}

		return buf.toString();
	}

	private String stripServletPath(String fullPath) {
		int idx = fullPath.indexOf("/", 1);

		return (idx == -1) ? fullPath : fullPath.substring(0, idx);
	}

	private String stripWicketPath(String fullPath) {
		String tmp = fullPath;

		int idx = -1;

		if ((idx = tmp.indexOf("?wicket")) != -1) {
			tmp = "/" + tmp.substring(idx);
		} else if ((idx = tmp.lastIndexOf("../")) != -1) {
			tmp = "/" + tmp.substring(idx + 3);
		}
		else if ( !tmp.startsWith( "/") ) {
			tmp = "/" + tmp;
		}

		return tmp;
	}
}

In my application class, I did the following:

Code Block

	protected IRequestCycleProcessor newRequestCycleProcessor() {
		return new WebRequestCycleProcessor() {
			@Override
			protected IRequestCodingStrategy newRequestCodingStrategy() {
				
				String httpPort = MyApplication.this.getPublicPort();
				int httpPortVal = 80;
				
				if ( httpPort != null && !httpPort.equals( "" )) {
					httpPortVal = new Integer( httpPort ).intValue();
				}
				String httpsPort = MyApplication.this.getSslPort();
				
				if ( httpsPort == null || httpsPort.equals( "" )) {
					return super.newRequestCodingStrategy();
				}
				return new SecureWebRequestCodingStrategy( httpsPortVal, new Integer( httpsPort).intValue() );
			}
		};
	}

By using the above solution, anytime I placed a @RequiredSSL on a Form, Link, Button declaration, the proper URL will be generated (https for secured items and http for non-secure items).

...

Code Block
@Override
protected IRequestCycleProcessor newRequestCycleProcessor() {
    return new WebRequestCycleProcessor() {
        public void respond(RequestCycle requestCycle) {
            IRequestTarget requestTarget = requestCycle.getRequestTarget();
            if (requestTarget != null) {
                WebRequest webRequest = (WebRequest) requestCycle .getRequest();
                WebResponse webResponse = (WebResponse) requestCycle .getResponse();
                HttpServletRequest httpServletRequest = webRequest.getHttpServletRequest();

                Class pageClass = null;
                if (requestTarget instanceof IPageRequestTarget) {
                    IPageRequestTarget pageTarget = (IPageRequestTarget) requestTarget;
                    pageClass = pageTarget.getPage().getClass();
                } else if (requestTarget instanceof IBookmarkablePageRequestTarget) {
                    IBookmarkablePageRequestTarget bookmarkableTarget = (IBookmarkablePageRequestTarget) requestTarget;
                    pageClass = bookmarkableTarget.getPageClass();
                }

                if (pageClass != null && !httpServletRequest.isSecure() &&
                        pageClass.isAnnotationPresent(RequiredSSL.class)) {
                    // We should switch to https
                    StringBuffer url = new StringBuffer("https://");
                    url.append(httpServletRequest.getServerName());
                    url.append(":" + MyApplication.get().getHttpsPort());

                    url.append(webRequest.getHttpServletRequest().getContextPath());
                    url.append(webRequest.getServletPath());
                    webResponse.redirect(url.toString());
                } else if (pageClass != null && httpServletRequest.isSecure() &&
                        !pageClass.isAnnotationPresent(RequiredSSL.class)) {
                    // We should switch to http
                    StringBuffer url = new StringBuffer("http://");
                    url.append(httpServletRequest.getServerName());
                    url.append(":" + MyApplication.get().getHttpPort());

                    url.append(webRequest.getHttpServletRequest().getContextPath());
                    url.append(webRequest.getServletPath());
                    webResponse.redirect(url.toString());
                } else {
                    // We should just respond!
                    requestTarget.respond(requestCycle);
                }
            }
        }
    };
}