Hi,

I think I managed to solve it: at least after an hour of testing it
haven't found a "leak" on my solution. The solution is as follows:

1-Create a secure form class as follows:

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.
 *
 * @author Igor Vaynberg (ivaynberg)
 *
 */
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);
        }
                /*
         * (non-Javadoc)
         * @see 
org.apache.wicket.markup.html.form.Form#onComponentTag(org.apache.wicket.markup.ComponentTag)
         */
        @Override
        protected void onComponentTag(ComponentTag tag)
        {
                super.onComponentTag(tag);              
                String action = tag.getAttribute("action");
                action = RequestUtils.toAbsolutePath(action);
                // rewrite action to use HTTPs
                if(!action.startsWith("https"))
                        action = "https"+action.substring(4);
                tag.put("action", action);
                
        }
}

2-Make a local copy of SwitchProtocolRequestTarget (this class is only
package visible)
3-Copy SecureHttpsRequestCycleProcessor and modify it as follows:

import javax.servlet.http.HttpServletRequest;

import org.apache.wicket.Component;
import org.apache.wicket.IRequestTarget;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.Session;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.WebRequestCycleProcessor;
import org.apache.wicket.protocol.https.HttpsConfig;
import org.apache.wicket.protocol.https.RequireHttps;
import org.apache.wicket.request.RequestParameters;
import 
org.apache.wicket.request.target.component.IBookmarkablePageRequestTarget;
import org.apache.wicket.request.target.component.IPageRequestTarget;
import 
org.apache.wicket.request.target.component.listener.IListenerInterfaceRequestTarget;

import *your package*.SemiSecurePage;
import *your package*.SwitchProtocolRequestTarget.Protocol;

/**
 * Request cycle processor that can switch between http and https
protocols based on the
 * {...@link RequireHttps} annotation.
 *
 * Once this processor is installed, any page annotated with the
{...@link RequireHttps} annotation
 * will be served over https, while any page lacking the annotation
will be served over http. The
 * annotation can be placed on a super class or an interface that a
page implements.
 *
 * To install this processor:
 *
 * <pre>
 * class MyApplication extends WebApplication
 * {
 *      &#064;Override
 *      protected IRequestCycleProcessor newRequestCycleProcessor()
 *      {
 *              return new HttpsRequestCycleProcessor(config);
 *      }
 * }
 * </pre>
 *
 * <b>Notes</b>: According to servlet spec a cookie created on an
https request is marked as secure,
 * such cookies are not available for http requests. What this means
is that a session started over
 * https will not be propagated to further http calls because
JSESSIONID cookie will be marked as
 * secure and not available to http requests. This entails that unless
a session is created and
 * bound on http prior to using an https request any wicket pages or
session values stored in the
 * https session will not be available to further http requests. If
your application requires a
 * http-&gt;https-&gt;http interactions (such as the case where only a
login page and my account
 * pages are secure) you must make sure a session is created and
stored in the http request prior to
 * the first http-&gt;https redirect.
 */
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);
        }
}

-Created an annotation

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Marks a page as requiring contating a form submitted over HTTPs.
 *
 * NOTES: Adding {...@link Inherited} annotation to this annotation will
not work because we also want
 * it to work for interfaces
 *
 * @see HttpsRequestCycleProcessor
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface SemiSecurePage {

}

and use to mark "SemiSecure pages". This part might be superfluous...
but I added it as an extra check.

-Create a SecureServletWebRequest

import javax.servlet.http.HttpServletRequest;

import org.apache.wicket.protocol.http.servlet.ServletWebRequest;

/**
 * @author Ernesto Reinaldo Barreiro
 *
 */
public class SecureServletWebRequest extends ServletWebRequest {

        private boolean useAbsoluteURL = false;
        
        /**
         * @param httpServletRequest
         */
        public SecureServletWebRequest(HttpServletRequest httpServletRequest) {
                super(httpServletRequest);
        }

        public boolean isUseAbsoluteURL() {
                return useAbsoluteURL;
        }

        public void setUseAbsoluteURL(boolean useAbsoluteURL) {
                this.useAbsoluteURL = useAbsoluteURL;
        }

}

- Created SecureBufferedWebResponse

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 "your package".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.startsWith("..") ) {
                                
                        } else if(!queryString.startsWith("?"))
                                result.append("?");
                        result.append(queryString);
                }
                return result.toString();
        }

}

-On your WebApplication class override

       @Override
        protected WebResponse newWebResponse(HttpServletResponse 
servletResponse) {
                return (getRequestCycleSettings().getBufferResponse() ? new
SecureBufferedWebResponse(
                                servletResponse) : new 
WebResponse(servletResponse));
        }
        
        @Override
        protected WebRequest newWebRequest(HttpServletRequest servletRequest) {
                return new SecureServletWebRequest(servletRequest);
        }

The above seems to be working for me but the solution is "hacky" and
depends on frameworks "internals". The problem seem to be generation
of relative URLs and this is what class SecureBufferedWebResponse is
trying to "fix". Can you try it and tell me if it works for you?

Regards,

Ernesto

On Tue, Oct 19, 2010 at 10:15 AM, sonxurxo <sonxu...@gmail.com> wrote:
>
> Hi all,
> This question applies to Wicket 1.4.9.
> I have an app where I have a Sign-in component (Panel) that is shown in
> (almost) every page of the site. I'd like all the app to work over http, and
> that form to work over https. Since the @RequireHttps annotation only works
> on pages and not Components, how can I achieve that?
> I have some other pages (e.g. registration page) that is fully working over
> https with the mentioned annotation, everything is OK. But I can not get the
> sign-in form (included in quite some http-pages) work over https.
> Any ideas?
> If there's a core developer reading this, is there any plan of "extending"
> the @RequireHttps annotation to other Components rather than just pages?
> --
> View this message in context: 
> http://apache-wicket.1842946.n4.nabble.com/SSL-Links-and-buttons-tp3001634p3001634.html
> Sent from the Users forum mailing list archive at Nabble.com.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org
> For additional commands, e-mail: users-h...@wicket.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org
For additional commands, e-mail: users-h...@wicket.apache.org

Reply via email to