001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal;
007:
008: import java.io.IOException;
009: import java.io.UnsupportedEncodingException;
010: import java.util.Enumeration;
011: import java.util.HashMap;
012: import java.util.Iterator;
013: import java.util.Properties;
014:
015: import javax.servlet.ServletException;
016: import javax.servlet.http.HttpServlet;
017: import javax.servlet.http.HttpServletRequest;
018: import javax.servlet.http.HttpServletResponse;
019: import javax.servlet.http.HttpSession;
020:
021: import org.jasig.portal.security.IPerson;
022: import org.jasig.portal.security.PersonManagerFactory;
023: import org.jasig.portal.services.Authentication;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.jasig.portal.utils.ResourceLoader;
027: import org.jasig.portal.utils.CommonUtils;
028:
029: /**
030: * Receives the username and password and tries to authenticate the user.
031: * The form presented by org.jasig.portal.channels.CLogin is typically used
032: * to generate the post to this servlet.
033: * @author Bernie Durfee (bdurfee@interactivebusiness.com)
034: * @version $Revision: 42042 $
035: * @author Don Fracapane (df7@columbia.edu)
036: * Added properties in the security properties file that hold the tokens used to
037: * represent the principal and credential for each security context.
038: */
039: public class LoginServlet extends HttpServlet {
040: private static final Log log = LogFactory
041: .getLog(LoginServlet.class);
042: private static final String redirectString;
043: private static HashMap credentialTokens;
044: private static HashMap principalTokens;
045: protected Authentication m_authenticationService = null;
046:
047: static {
048: String upFile = UPFileSpec.RENDER_URL_ELEMENT
049: + UPFileSpec.PORTAL_URL_SEPARATOR
050: + UserInstance.USER_LAYOUT_ROOT_NODE
051: + UPFileSpec.PORTAL_URL_SEPARATOR
052: + UPFileSpec.PORTAL_URL_SUFFIX;
053: HashMap cHash = new HashMap(1);
054: HashMap pHash = new HashMap(1);
055: try {
056: upFile = UPFileSpec.buildUPFile(null,
057: UPFileSpec.RENDER_METHOD,
058: UserInstance.USER_LAYOUT_ROOT_NODE, null, null);
059: String key;
060: // We retrieve the tokens representing the credential and principal
061: // parameters from the security properties file.
062: Properties props = ResourceLoader.getResourceAsProperties(
063: LoginServlet.class,
064: "/properties/security.properties");
065: Enumeration propNames = props.propertyNames();
066: while (propNames.hasMoreElements()) {
067: String propName = (String) propNames.nextElement();
068: String propValue = props.getProperty(propName);
069: if (propName.startsWith("credentialToken.")) {
070: key = propName.substring(16);
071: cHash.put(key, propValue);
072: }
073: if (propName.startsWith("principalToken.")) {
074: key = propName.substring(15);
075: pHash.put(key, propValue);
076: }
077: }
078: } catch (PortalException pe) {
079: log.error("LoginServlet::static ", pe);
080: } catch (IOException ioe) {
081: log.error("LoginServlet::static ", ioe);
082: }
083: redirectString = upFile;
084: credentialTokens = cHash;
085: principalTokens = pHash;
086: }
087:
088: /**
089: * Initializes the servlet
090: * @exception ServletException
091: */
092: public void init() throws ServletException {
093: m_authenticationService = new Authentication();
094:
095: }
096:
097: /**
098: * Process the incoming HttpServletRequest
099: * @param request
100: * @param response
101: * @exception ServletException
102: * @exception IOException
103: */
104: public void service(HttpServletRequest request,
105: HttpServletResponse response) throws ServletException,
106: IOException {
107: CommonUtils.setNoCache(response);
108:
109: // Call to setCharacterEncoding method should be done before any call to req.getParameter() method.
110: try {
111: request.setCharacterEncoding("UTF-8");
112: } catch (UnsupportedEncodingException uee) {
113: log.error("Unable to set UTF-8 character encoding!", uee);
114: }
115:
116: /* Grab the target functional name, if any, off the login request.
117: * Also any arguments for the target
118: * We will pass them along after authentication.
119: */
120: String targetFname = request.getParameter("uP_fname");
121: String targetArgs = request.getParameter("uP_args");
122:
123: // Clear out the existing session for the user if they have one
124: final HttpSession s = request.getSession(false);
125: if (s != null) {
126: try {
127: s.invalidate();
128: } catch (IllegalStateException ise) {
129: // ISE indicates session was already invalidated.
130: // This is fine. This servlet trying to guarantee that the session has been invalidated;
131: // it doesn't have to insist that it is the one that invalidated it.
132: if (log.isTraceEnabled()) {
133: log
134: .trace(
135: "LoginServlet attempted to invalidate an already invalid session.",
136: ise);
137: }
138: }
139: }
140:
141: // Create the user's session
142: request.getSession(true);
143: IPerson person = null;
144: try {
145: // Get the person object associated with the request
146: person = PersonManagerFactory.getPersonManagerInstance()
147: .getPerson(request);
148: // WE grab all of the principals and credentials from the request and load
149: // them into their respective HashMaps.
150: HashMap principals = getPropertyFromRequest(
151: principalTokens, request);
152: HashMap credentials = getPropertyFromRequest(
153: credentialTokens, request);
154:
155: // Attempt to authenticate using the incoming request
156: m_authenticationService.authenticate(principals,
157: credentials, person);
158: } catch (Exception e) {
159: // Log the exception
160: log.error("Exception authenticating the request", e);
161: // Reset everything
162: request.getSession(false).invalidate();
163: // Add the authentication failure
164: request.getSession(true).setAttribute(
165: "up_authenticationError", "true");
166: person = null;
167: }
168: // Check to see if the person has been authenticated
169: if (person != null
170: && person.getSecurityContext().isAuthenticated()) {
171: // Send the now authenticated user back to the PortalSessionManager servlet
172: String redirectTarget = null;
173:
174: if (targetFname == null) {
175: redirectTarget = request.getContextPath() + "/"
176: + redirectString;
177: } else {
178: redirectTarget = request.getContextPath() + "/"
179: + "tag.idempotent." + redirectString
180: + "?uP_fname=" + targetFname;
181: if (targetArgs != null) {
182: redirectTarget = redirectTarget + "&uP_args="
183: + targetArgs;
184: }
185: }
186:
187: response.sendRedirect(redirectTarget);
188: } else {
189: if (request.getMethod().equals("POST"))
190: request.getSession(false).setAttribute(
191: "up_authenticationAttempted", "true");
192: // Preserve the attempted username so it can be redisplayed to the user by CLogin
193: String attemptedUserName = request.getParameter("userName");
194: if (attemptedUserName != null)
195: request.getSession(false).setAttribute(
196: "up_attemptedUserName",
197: request.getParameter("userName"));
198: // Send the unauthenticated user back to the PortalSessionManager servlet
199: response.sendRedirect(request.getContextPath() + '/'
200: + redirectString);
201: }
202: }
203:
204: /**
205: * Get the values represented by each token from the request and load them into a
206: * HashMap that is returned.
207: * @param tokens
208: * @param request
209: * @return HashMap of properties
210: */
211: private HashMap getPropertyFromRequest(HashMap tokens,
212: HttpServletRequest request) {
213: // Iterate through all of the other property keys looking for the first property
214: // named like propname that has a value in the request
215: HashMap retHash = new HashMap(1);
216: Iterator tokenItr = tokens.keySet().iterator();
217: while (tokenItr.hasNext()) {
218: String ctxName = (String) tokenItr.next();
219: String parmName = (String) tokens.get(ctxName);
220: String parmValue = null;
221: if (request.getAttribute(parmName) != null) {
222: // Upstream components (like servlet filters) may supply information
223: // for the authentication process using request attributes.
224: try {
225: parmValue = (String) request.getAttribute(parmName);
226: } catch (ClassCastException cce) {
227: String msg = "The request attribute '" + parmName
228: + "' must be a String.";
229: throw new RuntimeException(msg, cce);
230: }
231: } else {
232: // If a configured parameter isn't provided by a request attribute,
233: // check request parameters (i.e. querystring, form fields).
234: parmValue = request.getParameter(parmName);
235: }
236: // null value causes exception in context.authentication
237: // alternately we could just not set parm if value is null
238: parmValue = (parmValue == null ? "" : parmValue).trim();
239: // The relationship between the way the properties are stored and the way
240: // the subcontexts are named has to be closely looked at to make this work.
241: // The keys are either "root" or the subcontext name that follows "root.". As
242: // as example, the contexts ["root", "root.simple", "root.cas"] are represented
243: // as ["root", "simple", "cas"].
244: String key = (ctxName.startsWith("root.") ? ctxName
245: .substring(5) : ctxName);
246: retHash.put(key, parmValue);
247: }
248: return (retHash);
249: }
250: }
|