001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.adapters.cas;
017:
018: import edu.yale.its.tp.cas.auth.PasswordHandler;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022:
023: import org.springframework.context.ApplicationContext;
024:
025: import org.springframework.web.context.support.WebApplicationContextUtils;
026:
027: import java.util.Map;
028:
029: import javax.servlet.ServletRequest;
030: import javax.servlet.http.HttpServletRequest;
031:
032: /**
033: * Enables CAS to use the Acegi Security System for authentication.<P>This class works along with {@link
034: * CasPasswordHandler} to enable users to easily migrate from stand-alone Acegi Security System deployments to
035: * enterprise-wide CAS deployments.</p>
036: * <p>It should be noted that the Acegi Security System will operate as a CAS client irrespective of the
037: * <code>PasswordHandler</code> used on the CAS server. In other words, this class need <B>not</B> be used on the CAS
038: * server if not desired. It exists solely for the convenience of users wishing have CAS delegate to an Acegi Security
039: * System-based <code>AuthenticationManager</code>.</p>
040: * <p>This class works requires a properly configured <code>CasPasswordHandler</code>. On the first authentication
041: * request, the class will use Spring's {@link WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)}
042: * method to obtain an <code>ApplicationContext</code> instance, inside which must be a configured
043: * <code>CasPasswordHandler</code> instance. The <code>CasPasswordHandlerProxy</code> will then delegate
044: * authentication requests to that instance.</p>
045: * <p>To configure CAS to use this class, edit CAS' <code>web.xml</code> and define the
046: * <code>edu.yale.its.tp.cas.authHandler</code> context parameter with the value
047: * <code>org.acegisecurity.adapters.cas.CasPasswordHandlerProxy</code>.</p>
048: *
049: * @author Ben Alex
050: * @version $Id: CasPasswordHandlerProxy.java 1496 2006-05-23 13:38:33Z benalex $
051: */
052: public class CasPasswordHandlerProxy implements PasswordHandler {
053: //~ Static fields/initializers =====================================================================================
054:
055: private static final Log logger = LogFactory
056: .getLog(CasPasswordHandlerProxy.class);
057:
058: //~ Instance fields ================================================================================================
059:
060: private ApplicationContext ctx;
061: private CasPasswordHandler handler;
062:
063: //~ Methods ========================================================================================================
064:
065: /**
066: * Called by CAS when authentication is required.<P>Delegates to the <code>CasPasswordHandler</code>.</p>
067: *
068: * @param request as provided by CAS
069: * @param username provided to CAS
070: * @param password provided to CAS
071: *
072: * @return whether authentication was successful or not
073: *
074: * @throws IllegalArgumentException if the application context does not contain a <code>CasPasswordHandler</code>
075: * or the <code>ServletRequest</code> was not of type <code>HttpServletRequest</code>
076: */
077: public boolean authenticate(ServletRequest request,
078: String username, String password) {
079: if (ctx == null) {
080: if (!(request instanceof HttpServletRequest)) {
081: throw new IllegalArgumentException(
082: "Can only process HttpServletRequest");
083: }
084:
085: HttpServletRequest httpRequest = (HttpServletRequest) request;
086:
087: ctx = this .getContext(httpRequest);
088: }
089:
090: if (handler == null) {
091: Map beans = ctx.getBeansOfType(CasPasswordHandler.class,
092: true, true);
093:
094: if (beans.size() == 0) {
095: throw new IllegalArgumentException(
096: "Bean context must contain at least one bean of type CasPasswordHandler");
097: }
098:
099: String beanName = (String) beans.keySet().iterator().next();
100: handler = (CasPasswordHandler) beans.get(beanName);
101: }
102:
103: return handler.authenticate(request, username, password);
104: }
105:
106: /**
107: * Allows test cases to override where application context obtained from.
108: *
109: * @param httpRequest which can be used to find the <code>ServletContext</code>
110: *
111: * @return the Spring application context
112: */
113: protected ApplicationContext getContext(
114: HttpServletRequest httpRequest) {
115: return WebApplicationContextUtils
116: .getRequiredWebApplicationContext(httpRequest
117: .getSession().getServletContext());
118: }
119: }
|