You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2009/04/17 19:37:37 UTC

svn commit: r766095 - in /wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https: ./ HttpsConfig.java HttpsRequestCycleProcessor.java RequireHttps.java SwitchProtocolRequestTarget.java

Author: ivaynberg
Date: Fri Apr 17 17:37:36 2009
New Revision: 766095

URL: http://svn.apache.org/viewvc?rev=766095&view=rev
Log:
https/http switching support, WICKET-2229
Issue: WICKET-2229

Added:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/
    wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsRequestCycleProcessor.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/RequireHttps.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/SwitchProtocolRequestTarget.java   (with props)

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java?rev=766095&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java Fri Apr 17 17:37:36 2009
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.protocol.https;
+
+/**
+ * Configuration for http-https switching
+ * 
+ * @see HttpsRequestCycleProcessor
+ */
+public class HttpsConfig
+{
+	private int httpPort = 80;
+	private int httpsPort = 443;
+
+	/**
+	 * Constructor
+	 */
+	public HttpsConfig()
+	{
+
+	}
+
+	/**
+	 * Constructor
+	 * 
+	 * @param httpPort
+	 *            http port
+	 * @param httpsPort
+	 *            https port
+	 */
+	public HttpsConfig(int httpPort, int httpsPort)
+	{
+		this.httpPort = httpPort;
+		this.httpsPort = httpsPort;
+	}
+
+
+	/**
+	 * Sets http port
+	 * 
+	 * @param httpPort
+	 */
+	public void setHttpPort(int httpPort)
+	{
+		this.httpPort = httpPort;
+	}
+
+	/**
+	 * Sets https port
+	 * 
+	 * @param httpsPort
+	 */
+	public void setHttpsPort(int httpsPort)
+	{
+		this.httpsPort = httpsPort;
+	}
+
+	/**
+	 * @return http port
+	 */
+	public int getHttpPort()
+	{
+		return httpPort;
+	}
+
+	/**
+	 * @return https port
+	 */
+	public int getHttpsPort()
+	{
+		return httpsPort;
+	}
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsRequestCycleProcessor.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsRequestCycleProcessor.java?rev=766095&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsRequestCycleProcessor.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsRequestCycleProcessor.java Fri Apr 17 17:37:36 2009
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.protocol.https;
+
+import org.apache.wicket.IRequestTarget;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.protocol.http.WebRequestCycleProcessor;
+import org.apache.wicket.protocol.https.SwitchProtocolRequestTarget.Protocol;
+import org.apache.wicket.request.RequestParameters;
+import org.apache.wicket.request.target.component.IBookmarkablePageRequestTarget;
+import org.apache.wicket.request.target.component.IPageRequestTarget;
+
+
+/**
+ * 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 SecureRequestCycleProcessor(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 HttpsRequestCycleProcessor extends WebRequestCycleProcessor
+{
+	private final HttpsConfig portConfig;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param httpsConfig
+	 *            configuration
+	 */
+	public HttpsRequestCycleProcessor(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;
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public IRequestTarget resolve(RequestCycle rc, RequestParameters rp)
+	{
+		// 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);
+		Class<?> pageClass = getPageClass(target);
+		if (pageClass != null)
+		{
+			IRequestTarget redirect = null;
+			if (hasSecureAnnotation(pageClass))
+			{
+				redirect = SwitchProtocolRequestTarget.requireProtocol(Protocol.HTTPS);
+			}
+			else
+			{
+				redirect = SwitchProtocolRequestTarget.requireProtocol(Protocol.HTTP);
+			}
+			if (redirect != null)
+			{
+				return redirect;
+			}
+
+		}
+		return target;
+	}
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/HttpsRequestCycleProcessor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/RequireHttps.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/RequireHttps.java?rev=766095&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/RequireHttps.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/RequireHttps.java Fri Apr 17 17:37:36 2009
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.protocol.https;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a page as requiring https.
+ * 
+ * @see HttpsRequestCycleProcessor
+ * 
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface RequireHttps {
+
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/RequireHttps.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/SwitchProtocolRequestTarget.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/SwitchProtocolRequestTarget.java?rev=766095&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/SwitchProtocolRequestTarget.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/SwitchProtocolRequestTarget.java Fri Apr 17 17:37:36 2009
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.protocol.https;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.wicket.IRequestTarget;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.protocol.http.WebRequest;
+import org.apache.wicket.protocol.http.WebResponse;
+
+/**
+ * Request target that performs redirects across http and https
+ */
+class SwitchProtocolRequestTarget implements IRequestTarget
+{
+	/**
+	 * Protocols
+	 */
+	public enum Protocol {
+		/*** HTTP */
+		HTTP,
+		/** HTTPS */
+		HTTPS,
+		/** CURRENT */
+		PRESERVE_CURRENT
+	}
+
+	private final Protocol protocol;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param protocol
+	 *            required protocol
+	 */
+	public SwitchProtocolRequestTarget(Protocol protocol)
+	{
+		if (protocol == null)
+		{
+			throw new IllegalArgumentException("Argument 'protocol' may not be null.");
+		}
+		if (protocol == Protocol.PRESERVE_CURRENT)
+		{
+			throw new IllegalArgumentException("Argument 'protocol' may not have value '" +
+				Protocol.PRESERVE_CURRENT.toString() + "'.");
+		}
+		this.protocol = protocol;
+	}
+
+	/** {@inheritDoc} */
+	public void detach(RequestCycle requestCycle)
+	{
+
+	}
+
+	/**
+	 * Rewrite the url using the specified protocol
+	 * 
+	 * @param protocol
+	 * @param port
+	 * @param request
+	 * @return url
+	 */
+	private String getUrl(String protocol, Integer port, HttpServletRequest request)
+	{
+		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 (request.getQueryString() != null)
+		{
+			result.append("?");
+			result.append(request.getQueryString());
+		}
+		return result.toString();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public void respond(RequestCycle requestCycle)
+	{
+		WebRequest webRequest = (WebRequest)requestCycle.getRequest();
+		HttpServletRequest request = webRequest.getHttpServletRequest();
+
+		HttpsRequestCycleProcessor processor = (HttpsRequestCycleProcessor)requestCycle.getProcessor();
+		Integer port = null;
+		if (protocol == Protocol.HTTP)
+		{
+			if (processor.getConfig().getHttpPort() != 80)
+			{
+				port = processor.getConfig().getHttpPort();
+			}
+		}
+		else if (protocol == Protocol.HTTPS)
+		{
+			if (processor.getConfig().getHttpsPort() != 443)
+			{
+				port = processor.getConfig().getHttpsPort();
+			}
+		}
+
+		String url = getUrl(protocol.toString().toLowerCase(), port, request);
+
+		WebResponse response = (WebResponse)requestCycle.getResponse();
+
+		// an attempt to rewrite a secure jsessionid into nonsecure, doesnt seem to work
+		// Session session = Session.get();
+		// if (!session.isTemporary())
+		// {
+		// response.addCookie(new Cookie("JSESSIONID", session.getId()));
+		// }
+
+		response.redirect(url);
+	}
+
+	/**
+	 * Returns a target that can be used to redirect to the specified protocol. If no change is
+	 * required null will be returned.
+	 * 
+	 * @param protocol
+	 *            required protocol
+	 * @return request target or null
+	 */
+	public static IRequestTarget requireProtocol(Protocol protocol)
+	{
+		RequestCycle requestCycle = RequestCycle.get();
+		WebRequest webRequest = (WebRequest)requestCycle.getRequest();
+		HttpServletRequest request = webRequest.getHttpServletRequest();
+		if (protocol == null || protocol == Protocol.PRESERVE_CURRENT ||
+			request.getScheme().equals(protocol.toString().toLowerCase()))
+		{
+			return null;
+		}
+		else
+		{
+			return new SwitchProtocolRequestTarget(protocol);
+		}
+	}
+
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/https/SwitchProtocolRequestTarget.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain