View Javadoc

1   /**
2    *
3    * Copyright 2003-2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.geronimo.tomcat.realm;
18  
19  import org.apache.catalina.realm.JAASCallbackHandler;
20  import org.apache.catalina.realm.JAASRealm;
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.geronimo.security.ContextManager;
24  import org.apache.geronimo.tomcat.JAASTomcatPrincipal;
25  
26  import javax.security.auth.Subject;
27  import javax.security.auth.login.*;
28  import java.security.Principal;
29  import java.util.ArrayList;
30  import java.util.Iterator;
31  import java.util.List;
32  
33  
34  /**
35   * @version $Rev: 355877 $ $Date: 2005-12-10 18:48:27 -0800 (Sat, 10 Dec 2005) $
36   */
37  public class TomcatJAASRealm extends JAASRealm implements Cloneable {
38      private static final Log log = LogFactory.getLog(TomcatJAASRealm.class);
39  
40      private static final String DEFAULT_NAME = "tomcat";
41  
42      /**
43       * Descriptive information about this <code>Realm</code> implementation.
44       */
45      protected static final String info = "org.apache.geronimo.tomcat.realm.TomcatJAASRealm/1.0";
46  
47      /**
48       * Descriptive information about this <code>Realm</code> implementation.
49       */
50      protected static final String name = "TomcatJAASRealm";
51  
52      public TomcatJAASRealm() {
53          super();
54      }
55  
56  
57      /**
58       * Return the <code>Principal</code> associated with the specified
59       * username and credentials, if there is one; otherwise return
60       * <code>null</code>.
61       * <p/>
62       * If there are any errors with the JDBC connection, executing the query or
63       * anything we return null (don't authenticate). This event is also logged,
64       * and the connection will be closed so that a subsequent request will
65       * automatically re-open it.
66       *
67       * @param username    Username of the <code>Principal</code> to look up
68       * @param credentials Password or other credentials to use in authenticating this
69       *                    username
70       */
71      public Principal authenticate(String username, String credentials) {
72  
73          // Establish a LoginContext to use for authentication
74          try {
75              LoginContext loginContext = null;
76              if (appName == null)
77                  appName = DEFAULT_NAME;
78  
79              if (log.isDebugEnabled())
80                  log.debug(sm.getString("jaasRealm.beginLogin", username, appName));
81  
82              // What if the LoginModule is in the container class loader ?
83              ClassLoader ocl = null;
84  
85              if (isUseContextClassLoader()) {
86                  ocl = Thread.currentThread().getContextClassLoader();
87                  Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
88              }
89  
90              try {
91                  loginContext = new LoginContext(appName, new JAASCallbackHandler(this, username, credentials));
92              } catch (Throwable e) {
93                  log.error(sm.getString("jaasRealm.unexpectedError"), e);
94                  return (null);
95              } finally {
96                  if (isUseContextClassLoader()) {
97                      Thread.currentThread().setContextClassLoader(ocl);
98                  }
99              }
100 
101             if (log.isDebugEnabled())
102                 log.debug("Login context created " + username);
103 
104             // Negotiate a login via this LoginContext
105             Subject subject = null;
106             try {
107                 loginContext.login();
108                 Subject tempSubject = loginContext.getSubject();
109                 if (tempSubject == null) {
110                     if (log.isDebugEnabled())
111                         log.debug(sm.getString("jaasRealm.failedLogin", username));
112                     return (null);
113                 }
114 
115                 subject = ContextManager.getServerSideSubject(tempSubject);
116                 if (subject == null) {
117                     if (log.isDebugEnabled())
118                         log.debug(sm.getString("jaasRealm.failedLogin", username));
119                     return (null);
120                 }
121 
122             } catch (AccountExpiredException e) {
123                 if (log.isDebugEnabled())
124                     log.debug(sm.getString("jaasRealm.accountExpired", username));
125                 return (null);
126             } catch (CredentialExpiredException e) {
127                 if (log.isDebugEnabled())
128                     log.debug(sm.getString("jaasRealm.credentialExpired", username));
129                 return (null);
130             } catch (FailedLoginException e) {
131                 if (log.isDebugEnabled())
132                     log.debug(sm.getString("jaasRealm.failedLogin", username));
133                 return (null);
134             } catch (LoginException e) {
135                 log.warn(sm.getString("jaasRealm.loginException", username), e);
136                 return (null);
137             } catch (Throwable e) {
138                 log.error(sm.getString("jaasRealm.unexpectedError"), e);
139                 return (null);
140             }
141 
142             if (log.isDebugEnabled())
143                 log.debug(sm.getString("jaasRealm.loginContextCreated", username));
144 
145             // Return the appropriate Principal for this authenticated Subject
146             Principal principal = createPrincipal(username, subject);
147             if (principal == null) {
148                 log.debug(sm.getString("jaasRealm.authenticateFailure", username));
149                 return (null);
150             }
151             if (log.isDebugEnabled()) {
152                 log.debug(sm.getString("jaasRealm.authenticateSuccess", username));
153             }
154 
155             return (principal);
156 
157         } catch (Throwable t) {
158             log.error("error ", t);
159             return null;
160         }
161     }
162 
163     protected Principal createPrincipal(String username, Subject subject) {
164         // Prepare to scan the Principals for this Subject
165         String password = null; // Will not be carried forward
166 
167         List roles = new ArrayList();
168         Principal userPrincipal = null;
169 
170         // Scan the Principals for this Subject
171         Iterator principals = subject.getPrincipals().iterator();
172         while (principals.hasNext()) {
173             Principal principal = (Principal) principals.next();
174 
175             String principalClass = principal.getClass().getName();
176 
177             if( log.isDebugEnabled() ) {
178                 log.debug(sm.getString("jaasRealm.checkPrincipal", principal, principalClass));
179             }
180 
181             if (userPrincipal == null && userClasses.contains(principalClass)) {
182                 userPrincipal = principal;
183                 if( log.isDebugEnabled() ) {
184                     log.debug(sm.getString("jaasRealm.userPrincipalSuccess", principal.getName()));
185                 }
186             }
187 
188             if (roleClasses.contains(principalClass)) {
189                 roles.add(principal.getName());
190                 if( log.isDebugEnabled() ) {
191                     log.debug(sm.getString("jaasRealm.rolePrincipalAdd", principal.getName()));
192                 }
193             }
194         }
195 
196         // Print failure message if needed
197         if (userPrincipal == null) {
198             if (log.isDebugEnabled()) {
199                 log.debug(sm.getString("jaasRealm.userPrincipalFailure"));
200                 log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
201             }
202         } else {
203             if (roles.size() == 0) {
204                 if (log.isDebugEnabled()) {
205                     log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
206                 }
207             }
208         }
209 
210         JAASTomcatPrincipal jaasPrincipal = new JAASTomcatPrincipal(username);
211         jaasPrincipal.setSubject(subject);
212         jaasPrincipal.setRoles(roles);
213 
214         // Return the resulting Principal for our authenticated user
215         return jaasPrincipal;
216     }
217 
218 
219     public Object clone() throws CloneNotSupportedException{
220         return super.clone();
221     }
222 
223 
224     public boolean hasRole(Principal principal, String role) {
225 
226         if ((principal == null) || (role == null) ||
227             !(principal instanceof JAASTomcatPrincipal))
228             return (false);
229 
230         JAASTomcatPrincipal jtp = (JAASTomcatPrincipal) principal;
231         if (jtp.getRoles().contains(role))
232             return true;
233 
234         return false;
235     }
236 
237 }