View Javadoc

1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.acegisecurity.adapters.catalina;
17  
18  import org.acegisecurity.Authentication;
19  import org.acegisecurity.AuthenticationException;
20  import org.acegisecurity.AuthenticationManager;
21  
22  import org.acegisecurity.adapters.PrincipalAcegiUserToken;
23  
24  import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
25  
26  import org.apache.catalina.Container;
27  import org.apache.catalina.LifecycleException;
28  import org.apache.catalina.realm.RealmBase;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  import org.springframework.context.support.FileSystemXmlApplicationContext;
34  
35  import java.io.File;
36  
37  import java.security.Principal;
38  import java.security.cert.X509Certificate;
39  
40  import java.util.Map;
41  
42  
43  /***
44   * Adapter to enable Catalina (Tomcat) to authenticate via the Acegi Security
45   * System for Spring.
46   * 
47   * <p>
48   * Returns a {@link PrincipalAcegiUserToken} to Catalina's authentication
49   * system, which is subsequently available via
50   * <code>HttpServletRequest.getUserPrincipal()</code>.
51   * </p>
52   *
53   * @author Ben Alex
54   * @version $Id: CatalinaAcegiUserRealm.java,v 1.9 2005/11/25 00:26:30 benalex Exp $
55   */
56  public class CatalinaAcegiUserRealm extends RealmBase {
57      //~ Static fields/initializers =============================================
58  
59      private static final Log logger = LogFactory.getLog(CatalinaAcegiUserRealm.class);
60  
61      //~ Instance fields ========================================================
62  
63      protected final String name = "CatalinaSpringUserRealm / $Id: CatalinaAcegiUserRealm.java,v 1.9 2005/11/25 00:26:30 benalex Exp $";
64      private AuthenticationManager authenticationManager;
65      private Container container;
66      private String appContextLocation;
67      private String key;
68  
69      //~ Methods ================================================================
70  
71      public void setAppContextLocation(String appContextLocation) {
72          this.appContextLocation = appContextLocation;
73      }
74  
75      public String getAppContextLocation() {
76          return appContextLocation;
77      }
78  
79      public void setKey(String key) {
80          this.key = key;
81      }
82  
83      public String getKey() {
84          return key;
85      }
86  
87      public Principal authenticate(String username, String credentials) {
88          if (username == null) {
89              return null;
90          }
91  
92          if (credentials == null) {
93              credentials = "";
94          }
95  
96          Authentication request = new UsernamePasswordAuthenticationToken(username,
97                  credentials);
98          Authentication response = null;
99  
100         try {
101             response = authenticationManager.authenticate(request);
102         } catch (AuthenticationException failed) {
103             if (logger.isDebugEnabled()) {
104                 logger.debug("Authentication request for user: " + username
105                     + " failed: " + failed.toString());
106             }
107 
108             return null;
109         }
110 
111         return new PrincipalAcegiUserToken(this.key,
112             response.getPrincipal().toString(),
113             response.getCredentials().toString(), response.getAuthorities(),
114             response.getPrincipal());
115     }
116 
117     public Principal authenticate(String username, byte[] credentials) {
118         return authenticate(username, new String(credentials));
119     }
120 
121     /***
122      * Not supported, returns null
123      *
124      * @param username DOCUMENT ME!
125      * @param digest DOCUMENT ME!
126      * @param nonce DOCUMENT ME!
127      * @param nc DOCUMENT ME!
128      * @param cnonce DOCUMENT ME!
129      * @param qop DOCUMENT ME!
130      * @param realm DOCUMENT ME!
131      * @param md5a2 DOCUMENT ME!
132      *
133      * @return DOCUMENT ME!
134      */
135     public java.security.Principal authenticate(java.lang.String username,
136         java.lang.String digest, java.lang.String nonce, java.lang.String nc,
137         java.lang.String cnonce, java.lang.String qop, java.lang.String realm,
138         java.lang.String md5a2) {
139         return null;
140     }
141 
142     /***
143      * Not supported, returns null
144      *
145      * @param x509Certificates DOCUMENT ME!
146      *
147      * @return DOCUMENT ME!
148      */
149     public Principal authenticate(X509Certificate[] x509Certificates) {
150         return null;
151     }
152 
153     public boolean hasRole(Principal principal, String role) {
154         if ((principal == null) || (role == null)) {
155             return false;
156         }
157 
158         if (!(principal instanceof PrincipalAcegiUserToken)) {
159             logger.warn(
160                 "Expected passed principal to be of type PrincipalAcegiUserToken but was "
161                 + principal.getClass().getName());
162 
163             return false;
164         }
165 
166         PrincipalAcegiUserToken test = (PrincipalAcegiUserToken) principal;
167 
168         return test.isUserInRole(role);
169     }
170 
171     /***
172      * Provides the method that Catalina will use to start the container.
173      *
174      * @throws LifecycleException if a problem is detected
175      */
176     public void start() throws LifecycleException {
177         this.start(true);
178     }
179 
180     protected String getName() {
181         return this.name;
182     }
183 
184     /***
185      * Always returns null (we override authenticate methods)
186      *
187      * @param arg0 DOCUMENT ME!
188      *
189      * @return DOCUMENT ME!
190      */
191     protected String getPassword(String arg0) {
192         return null;
193     }
194 
195     /***
196      * Always returns null (we override authenticate methods)
197      *
198      * @param arg0 DOCUMENT ME!
199      *
200      * @return DOCUMENT ME!
201      */
202     protected Principal getPrincipal(String arg0) {
203         return null;
204     }
205 
206     /***
207      * Provides a method to load the container adapter without delegating to
208      * the superclass, which cannot operate outside the Catalina container.
209      *
210      * @throws LifecycleException if a problem is detected
211      */
212     protected void startForTest() throws LifecycleException {
213         this.start(false);
214     }
215 
216     private void start(boolean startParent) throws LifecycleException {
217         if (startParent) {
218             super.start();
219         }
220 
221         if ((appContextLocation == null) || "".equals(appContextLocation)) {
222             throw new LifecycleException("appContextLocation must be defined");
223         }
224 
225         if ((key == null) || "".equals(key)) {
226             throw new LifecycleException("key must be defined");
227         }
228 
229         File xml = new File(System.getProperty("catalina.base"),
230                 appContextLocation);
231 
232         if (!xml.exists()) {
233             throw new LifecycleException(
234                 "appContextLocation does not seem to exist in "
235                 + xml.toString());
236         }
237 
238         FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(
239                 "file:" + xml.getAbsolutePath());
240         Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
241 
242         if (beans.size() == 0) {
243             throw new IllegalArgumentException(
244                 "Bean context must contain at least one bean of type AuthenticationManager");
245         }
246 
247         String beanName = (String) beans.keySet().iterator().next();
248         authenticationManager = (AuthenticationManager) beans.get(beanName);
249         logger.info("CatalinaAcegiUserRealm Started");
250     }
251 }