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.catalina;
017:
018: import org.acegisecurity.Authentication;
019: import org.acegisecurity.AuthenticationException;
020: import org.acegisecurity.AuthenticationManager;
021:
022: import org.acegisecurity.adapters.PrincipalAcegiUserToken;
023:
024: import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
025:
026: import org.apache.catalina.Container;
027: import org.apache.catalina.LifecycleException;
028: import org.apache.catalina.realm.RealmBase;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032:
033: import org.springframework.context.support.FileSystemXmlApplicationContext;
034:
035: import java.io.File;
036:
037: import java.security.Principal;
038: import java.security.cert.X509Certificate;
039:
040: import java.util.Map;
041:
042: /**
043: * Adapter to enable Catalina (Tomcat) to authenticate via the Acegi Security System for Spring.<p>Returns a {@link
044: * PrincipalAcegiUserToken} to Catalina's authentication system, which is subsequently available via
045: * <code>HttpServletRequest.getUserPrincipal()</code>.</p>
046: *
047: * @author Ben Alex
048: * @version $Id: CatalinaAcegiUserRealm.java 1496 2006-05-23 13:38:33Z benalex $
049: */
050: public class CatalinaAcegiUserRealm extends RealmBase {
051: //~ Static fields/initializers =====================================================================================
052:
053: private static final Log logger = LogFactory
054: .getLog(CatalinaAcegiUserRealm.class);
055:
056: //~ Instance fields ================================================================================================
057:
058: private AuthenticationManager authenticationManager;
059: private Container container;
060: private String appContextLocation;
061: private String key;
062: protected final String name = "CatalinaSpringUserRealm / $Id: CatalinaAcegiUserRealm.java 1496 2006-05-23 13:38:33Z benalex $";
063:
064: //~ Methods ========================================================================================================
065:
066: public Principal authenticate(String username, String credentials) {
067: if (username == null) {
068: return null;
069: }
070:
071: if (credentials == null) {
072: credentials = "";
073: }
074:
075: Authentication request = new UsernamePasswordAuthenticationToken(
076: username, credentials);
077: Authentication response = null;
078:
079: try {
080: response = authenticationManager.authenticate(request);
081: } catch (AuthenticationException failed) {
082: if (logger.isDebugEnabled()) {
083: logger.debug("Authentication request for user: "
084: + username + " failed: " + failed.toString());
085: }
086:
087: return null;
088: }
089:
090: return new PrincipalAcegiUserToken(this .key, response
091: .getPrincipal().toString(), response.getCredentials()
092: .toString(), response.getAuthorities(), response
093: .getPrincipal());
094: }
095:
096: public Principal authenticate(String username, byte[] credentials) {
097: return authenticate(username, new String(credentials));
098: }
099:
100: /**
101: * Not supported, returns null
102: *
103: * @param username DOCUMENT ME!
104: * @param digest DOCUMENT ME!
105: * @param nonce DOCUMENT ME!
106: * @param nc DOCUMENT ME!
107: * @param cnonce DOCUMENT ME!
108: * @param qop DOCUMENT ME!
109: * @param realm DOCUMENT ME!
110: * @param md5a2 DOCUMENT ME!
111: *
112: * @return DOCUMENT ME!
113: */
114: public java.security.Principal authenticate(
115: java.lang.String username, java.lang.String digest,
116: java.lang.String nonce, java.lang.String nc,
117: java.lang.String cnonce, java.lang.String qop,
118: java.lang.String realm, java.lang.String md5a2) {
119: return null;
120: }
121:
122: /**
123: * Not supported, returns null
124: *
125: * @param x509Certificates DOCUMENT ME!
126: *
127: * @return DOCUMENT ME!
128: */
129: public Principal authenticate(X509Certificate[] x509Certificates) {
130: return null;
131: }
132:
133: public String getAppContextLocation() {
134: return appContextLocation;
135: }
136:
137: public String getKey() {
138: return key;
139: }
140:
141: protected String getName() {
142: return this .name;
143: }
144:
145: /**
146: * Always returns null (we override authenticate methods)
147: *
148: * @param arg0 DOCUMENT ME!
149: *
150: * @return DOCUMENT ME!
151: */
152: protected String getPassword(String arg0) {
153: return null;
154: }
155:
156: /**
157: * Always returns null (we override authenticate methods)
158: *
159: * @param arg0 DOCUMENT ME!
160: *
161: * @return DOCUMENT ME!
162: */
163: protected Principal getPrincipal(String arg0) {
164: return null;
165: }
166:
167: public boolean hasRole(Principal principal, String role) {
168: if ((principal == null) || (role == null)) {
169: return false;
170: }
171:
172: if (!(principal instanceof PrincipalAcegiUserToken)) {
173: logger
174: .warn("Expected passed principal to be of type PrincipalAcegiUserToken but was "
175: + principal.getClass().getName());
176:
177: return false;
178: }
179:
180: PrincipalAcegiUserToken test = (PrincipalAcegiUserToken) principal;
181:
182: return test.isUserInRole(role);
183: }
184:
185: public void setAppContextLocation(String appContextLocation) {
186: this .appContextLocation = appContextLocation;
187: }
188:
189: public void setKey(String key) {
190: this .key = key;
191: }
192:
193: /**
194: * Provides the method that Catalina will use to start the container.
195: *
196: * @throws LifecycleException if a problem is detected
197: */
198: public void start() throws LifecycleException {
199: this .start(true);
200: }
201:
202: private void start(boolean startParent) throws LifecycleException {
203: if (startParent) {
204: super .start();
205: }
206:
207: if ((appContextLocation == null)
208: || "".equals(appContextLocation)) {
209: throw new LifecycleException(
210: "appContextLocation must be defined");
211: }
212:
213: if ((key == null) || "".equals(key)) {
214: throw new LifecycleException("key must be defined");
215: }
216:
217: File xml = new File(System.getProperty("catalina.base"),
218: appContextLocation);
219:
220: if (!xml.exists()) {
221: throw new LifecycleException(
222: "appContextLocation does not seem to exist in "
223: + xml.toString());
224: }
225:
226: FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(
227: "file:" + xml.getAbsolutePath());
228: Map beans = ctx.getBeansOfType(AuthenticationManager.class,
229: true, true);
230:
231: if (beans.size() == 0) {
232: throw new IllegalArgumentException(
233: "Bean context must contain at least one bean of type AuthenticationManager");
234: }
235:
236: String beanName = (String) beans.keySet().iterator().next();
237: authenticationManager = (AuthenticationManager) beans
238: .get(beanName);
239: logger.info("CatalinaAcegiUserRealm Started");
240: }
241:
242: /**
243: * Provides a method to load the container adapter without delegating to the superclass, which cannot
244: * operate outside the Catalina container.
245: *
246: * @throws LifecycleException if a problem is detected
247: */
248: protected void startForTest() throws LifecycleException {
249: this .start(false);
250: }
251: }
|