Adding a sign-in page served over HTTP but authenticating using HTTPSPage edited by Ernesto Reinaldo BarreiroChanges (3)
Full ContentAdding a sign-in page served over HTTP but authenticating using HTTPSOn this wiki page we explain how to create a page (e.g. a public page of a site) served over HTTP but containing a sign in form that uses HTTPs for authentication. The code we show is valid for 1.4.x branch. We start creating a subclass of Form import org.apache.wicket.RequestCycle; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.model.IModel; import org.apache.wicket.protocol.http.RequestUtils; /** * * Form that does submit via HTTPs. * */ public class SecureForm<T> extends Form<T> { private static final long serialVersionUID = 1L; /** * Constructor. * * @param id See Component */ public SecureForm(String id) { super(id); } /** * @param id See Component * @param model See Component * * @see org.apache.wicket.Component#Component(String, IModel) */ public SecureForm(String id, IModel<T> model) { super(id, model); } @Override protected void onComponentTag(ComponentTag tag) { super.onComponentTag(tag); String action = "" class="code-quote">"action"); if(!action.startsWith("http")) action = "" // rewrite action to use HTTPs if(!action.startsWith("https")) action = "" class="code-quote">"https"+action.substring(4)); tag.put("action", action); } private String replacePort(String action) { RequestCycle requestCycle = RequestCycle.get(); SecureHttpsRequestCycleProcessor processor = (SecureHttpsRequestCycleProcessor)requestCycle.getProcessor(); Integer port = processor.getConfig().getHttpPort(); Integer httpsPort = processor.getConfig().getHttpsPort(); action.replace(":"+Integer.toString(port)+"/", ":"+Integer.toString(httpsPort)+"/"); return action; } } This form rewrite the action to do submition via HTTPs. We create an annotation to mark pages Semi secure pages... that is pages served over HTTP but containing a secure form. @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface SemiSecurePage { } We modify default HttpsRequestCycleProcessor to take care of "Semi-secure" pages, i.e. pages containing a secure form and marked with @SemiSecurePage annotation. public class SecureHttpsRequestCycleProcessor extends WebRequestCycleProcessor { private final HttpsConfig portConfig; /** * Constructor * * @param httpsConfig * configuration */ public SecureHttpsRequestCycleProcessor(HttpsConfig httpsConfig) { portConfig = httpsConfig; } /** * @return configuration */ public HttpsConfig getConfig() { return portConfig; } /** * Checks if the class has a {@link RequireHttps} annotation * * @param klass * @return true if klass has the annotation */ private boolean hasSecureAnnotation(Class<?> klass) { for (Class<?> c : klass.getInterfaces()) { if (hasSecureAnnotation(c)) { return true; } } if (klass.getAnnotation(RequireHttps.class) != null) { return true; } if (klass.getSuperclass() != null) { return hasSecureAnnotation(klass.getSuperclass()); } else { return false; } } /** * Gets page class from a request target * * @param target * @return page class if there is one, null otherwise */ private Class<?> getPageClass(IRequestTarget target) { if (target instanceof IPageRequestTarget) { return ((IPageRequestTarget)target).getPage().getClass(); } else if (target instanceof IBookmarkablePageRequestTarget) { return ((IBookmarkablePageRequestTarget)target).getPageClass(); } else { return null; } } /** @deprecated use checkSecureIncoming */ @Deprecated protected IRequestTarget checkSecure(IRequestTarget target) { return checkSecureIncoming(target); } /** * Checks if the class has a {@link RequireHttps} annotation * * @param klass * @return true if klass has the annotation */ private boolean hasSecureSemiSecureAnnotation(Class<?> klass) { if(klass == null) return false; for (Class<?> c : klass.getInterfaces()) { if (hasSecureAnnotation(c)) { return true; } } if (klass.getAnnotation(SemiSecurePage.class) != null) { return true; } if (klass.getSuperclass() != null) { return hasSecureSemiSecureAnnotation(klass.getSuperclass()); } else { return false; } } protected IRequestTarget checkSecureIncoming(IRequestTarget target) { if (target != null && target instanceof SwitchProtocolRequestTarget) { return target; } if (portConfig == null) { return target; } Class<?> pageClass = getPageClass(target); if (pageClass != null) { if(hasSecureSemiSecureAnnotation(pageClass)) { if (target instanceof IListenerInterfaceRequestTarget) { Component c = ((IListenerInterfaceRequestTarget) target).getTarget(); if(SecureForm.class.isAssignableFrom(c.getClass())) { return target; } } } IRequestTarget redirect = null; if (hasSecureAnnotation(pageClass)) { redirect = SwitchProtocolRequestTarget.requireProtocol(Protocol.HTTPS); } else { redirect = SwitchProtocolRequestTarget.requireProtocol(Protocol.HTTP); } if (redirect != null) { return redirect; } } return target; } protected IRequestTarget checkSecureOutgoing(IRequestTarget target) { if (target != null && target instanceof SwitchProtocolRequestTarget) { return target; } if (portConfig == null) { return target; } Class<?> pageClass = getPageClass(target); if (pageClass != null) { if(hasSecureSemiSecureAnnotation(pageClass)) { if (target instanceof IListenerInterfaceRequestTarget) { IListenerInterfaceRequestTarget interfaceRequestTarget = (IListenerInterfaceRequestTarget) target; Component c = interfaceRequestTarget.getTarget(); if(SecureForm.class.isAssignableFrom(c.getClass())) { RequestCycle requestCycle = RequestCycle.get(); WebRequest webRequest = (WebRequest)requestCycle.getRequest(); HttpServletRequest request = webRequest.getHttpServletRequest(); boolean isHTTPS =request.getScheme().equals(Protocol.HTTPS.name().toLowerCase()); if(isHTTPS) { if(webRequest instanceof SecureServletWebRequest) { ((SecureServletWebRequest)webRequest).setUseAbsoluteURL(true); } return target; } else { return target; } } } } IRequestTarget redirect = null; if (hasSecureAnnotation(pageClass)) { redirect = SwitchProtocolRequestTarget.requireProtocol(Protocol.HTTPS, target); } else { redirect = SwitchProtocolRequestTarget.requireProtocol(Protocol.HTTP, target); } if (redirect != null) { return redirect; } } return target; } /** {@inheritDoc} */ @Override public IRequestTarget resolve(RequestCycle rc, RequestParameters rp) { if (portConfig.isPreferStateful()) { // we need to persist the session before a redirect to https so the session lasts across // both http and https calls. Session.get().bind(); } IRequestTarget target = super.resolve(rc, rp); return checkSecure(target); } /** {@inheritDoc} */ @Override public void respond(RequestCycle requestCycle) { IRequestTarget requestTarget = requestCycle.getRequestTarget(); if (requestTarget != null) { IRequestTarget secured = checkSecureOutgoing(requestTarget); if (secured != requestTarget) { requestCycle.setRequestTarget(secured); // respond will be called again because we called setrequesttarget(), so we do not // process it this time return; } } super.respond(requestCycle); } } import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.wicket.RequestCycle; import org.apache.wicket.protocol.http.BufferedWebResponse; import org.apache.wicket.protocol.http.WebRequest; import org.apache.wicket.util.string.Strings; import es.liberty.paneuropeo.web.https.SwitchProtocolRequestTarget.Protocol; /** * @author Ernesto Reinaldo Barreiro * */ public class SecureBufferedWebResponse extends BufferedWebResponse { /** * @param httpServletResponse */ public SecureBufferedWebResponse(HttpServletResponse httpServletResponse) { super(httpServletResponse); } @Override public CharSequence encodeURL(CharSequence url) { RequestCycle requestCycle = RequestCycle.get(); WebRequest webRequest = (WebRequest)requestCycle.getRequest(); if((webRequest instanceof SecureServletWebRequest) && ((SecureServletWebRequest)webRequest).isUseAbsoluteURL()) { HttpServletRequest request = webRequest.getHttpServletRequest(); boolean isHTTPS =request.getScheme().equals(Protocol.HTTPS.name().toLowerCase()); if(isHTTPS) { SecureHttpsRequestCycleProcessor processor = (SecureHttpsRequestCycleProcessor)requestCycle.getProcessor(); Integer port = null; if (processor.getConfig().getHttpPort() != 80) { port = processor.getConfig().getHttpPort(); } String absUrl = getUrl("http", port, request, url.toString()); return super.encodeURL(absUrl); } } return super.encodeURL(url); } /** * Rewrite the url using the specified protocol * * @param protocol * @param port * @param request * @return url */ protected String getUrl(String protocol, Integer port, HttpServletRequest request, String queryString) { if(queryString.startsWith("http") || queryString.startsWith("https")) return queryString; StringBuilder result = new StringBuilder(); result.append(protocol); result.append("://"); result.append(request.getServerName()); if (port != null) { result.append(":"); result.append(port); } result.append(request.getRequestURI()); if (queryString != null) { if(queryString.indexOf("../")>=0) { queryString = Strings.replaceAll(queryString, "../", "").toString(); } else if(!queryString.startsWith("?")) result.append("?"); result.append(queryString); } return result.toString(); } }
Change Notification Preferences
View Online
|
View Changes
|
Add Comment
|
- [CONF] Apache Wicket > Adding a sign-in page served over HTT... confluence
- [CONF] Apache Wicket > Adding a sign-in page served ove... confluence
- [CONF] Apache Wicket > Adding a sign-in page served ove... confluence
- [CONF] Apache Wicket > Adding a sign-in page served ove... confluence
- [CONF] Apache Wicket > Adding a sign-in page served ove... confluence
- [CONF] Apache Wicket > Adding a sign-in page served ove... confluence
- [CONF] Apache Wicket > Adding a sign-in page served ove... confluence
