1 /* 2 * Copyright (c) 2010, University of Kent 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * 1. Neither the name of the University of Kent nor the names of its 16 * contributors may be used to endorse or promote products derived from this 17 * software without specific prior written permission. 18 * 19 * 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. 23 * 24 * 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * 4. YOU AGREE THAT THE EXCLUSIONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE 34 * IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS 35 * SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS 36 * SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH 37 * GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH 38 * TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY 39 * IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE 40 * SERIOUS FAULTS, IN THIS SOFTWARE. 41 * 42 * 5. This license is governed, except to the extent that local laws 43 * necessarily apply, by the laws of England and Wales. 44 */ 45 package org.zxid; 46 47 import java.io.IOException; 48 49 import javax.servlet.Filter; 50 import javax.servlet.FilterChain; 51 import javax.servlet.FilterConfig; 52 import javax.servlet.ServletException; 53 import javax.servlet.ServletRequest; 54 import javax.servlet.ServletResponse; 55 import javax.servlet.http.HttpServletRequest; 56 import javax.servlet.http.HttpServletResponse; 57 import javax.servlet.http.HttpSession; 58 59 /** 60 * Checks whether a session has been established yet. If not the 61 * user will be redirected to the SSO servlet, requesting it to 62 * authenticate the user. 63 * 64 * @author Stijn Lievens 65 * 66 */ 67 public class ZxidSSOFilter implements Filter { 68 69 /** 70 * The location of the ZXID SSO servlet. 71 * Can be set with an init-parameter. 72 */ 73 private String ssoServletLocation = "sso"; 74 75 // @Override // commented out for Java 1.5 destroy()76 public void destroy() { 77 } 78 79 /** 80 * Checks whether a session is already established. If it is then the filter does 81 * nothing but call the next one in the chain. Otherwise, the user is redirected 82 * to the ZXID SSO servlet. 83 */ 84 //@Override // commented out for Java 1.5 doFilter(ServletRequest request, ServletResponse response, FilterChain chain)85 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 86 throws IOException, ServletException { 87 HttpServletRequest req = (HttpServletRequest) request; 88 HttpSession ses = req.getSession(false); // Important: do not allow automatic session. 89 if (ses != null) { // user was logged in. Continue 90 chain.doFilter(request, response); 91 return; 92 } else { 93 // No session was established yet, redirect to SSO servlet 94 ((HttpServletResponse) response).sendRedirect(ssoServletLocation + "?o=E&fr=" 95 + getReturnURL(req)); 96 } 97 } 98 99 /** 100 * Sets the location of the SSO servlet. 101 */ 102 //@Override // commented out for Java 1.5 init(FilterConfig config)103 public void init(FilterConfig config) throws ServletException { 104 if (config.getInitParameter("sso-servlet-location") != null) { 105 ssoServletLocation = config.getInitParameter("sso-servlet-location"); 106 } 107 } 108 109 /** 110 * Recreates the full URL that originally got the web client to the given 111 * request. This takes into account changes to the request due to request 112 * dispatching. 113 * 114 * <p>Note that if the protocol is HTTP and the port number is 80 or if the 115 * protocol is HTTPS and the port number is 443, then the port number is not 116 * added to the return string as a convenience.</p> 117 */ 118 // taken from: https://issues.apache.org/bugzilla/show_bug.cgi?id=28222 getReturnURL(HttpServletRequest request)119 private final static String getReturnURL(HttpServletRequest request) { 120 if (request == null){ 121 throw new IllegalArgumentException("Cannot take null parameters."); 122 } 123 124 String scheme = request.getScheme(); 125 String serverName = request.getServerName(); 126 int serverPort = request.getServerPort(); 127 128 /* 129 * Try to get the forwarder value first, only if it's empty fall back to the 130 * current value 131 */ 132 String requestUri = (String) request.getAttribute("javax.servlet.forward.request_uri"); 133 requestUri = (requestUri == null) ? request.getRequestURI() : requestUri; 134 135 /* 136 * Try to get the forwarder value first, only if it's empty fall back to the 137 * current value. 138 */ 139 String queryString = (String) request.getAttribute("javax.servlet.forward.query_string"); 140 queryString = (queryString == null) ? request.getQueryString() : queryString; 141 142 StringBuffer buffer = new StringBuffer(); 143 buffer.append(scheme); 144 buffer.append("://"); 145 buffer.append(serverName); 146 147 //if not http:80 or https:443, then add the port number 148 if (!(scheme.equalsIgnoreCase("http") && serverPort == 80) && 149 !(scheme.equalsIgnoreCase("https") && serverPort == 443)) { 150 buffer.append(":").append(String.valueOf(serverPort)); 151 } 152 153 buffer.append(requestUri); 154 155 if (queryString != null) { 156 buffer.append("?"); 157 buffer.append(queryString); 158 } 159 160 return buffer.toString(); 161 } 162 163 } 164