001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.tomcat.realm;
018
019 import org.apache.catalina.realm.JAASCallbackHandler;
020 import org.apache.catalina.realm.JAASRealm;
021 import org.apache.commons.logging.Log;
022 import org.apache.commons.logging.LogFactory;
023 import org.apache.geronimo.security.ContextManager;
024 import org.apache.geronimo.tomcat.JAASTomcatPrincipal;
025
026 import javax.security.auth.Subject;
027 import javax.security.auth.login.*;
028 import java.security.Principal;
029 import java.util.ArrayList;
030 import java.util.Iterator;
031 import java.util.List;
032
033
034 /**
035 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
036 */
037 public class TomcatJAASRealm extends JAASRealm implements Cloneable {
038 private static final Log log = LogFactory.getLog(TomcatJAASRealm.class);
039
040 private static final String DEFAULT_NAME = "tomcat";
041
042 /**
043 * Descriptive information about this <code>Realm</code> implementation.
044 */
045 protected static final String info = "org.apache.geronimo.tomcat.realm.TomcatJAASRealm/1.0";
046
047 /**
048 * Descriptive information about this <code>Realm</code> implementation.
049 */
050 protected static final String name = "TomcatJAASRealm";
051
052 public TomcatJAASRealm() {
053 super();
054 }
055
056
057 /**
058 * Return the <code>Principal</code> associated with the specified
059 * username and credentials, if there is one; otherwise return
060 * <code>null</code>.
061 * <p/>
062 * If there are any errors with the JDBC connection, executing the query or
063 * anything we return null (don't authenticate). This event is also logged,
064 * and the connection will be closed so that a subsequent request will
065 * automatically re-open it.
066 *
067 * @param username Username of the <code>Principal</code> to look up
068 * @param credentials Password or other credentials to use in authenticating this
069 * username
070 */
071 public Principal authenticate(String username, String credentials) {
072
073 // Establish a LoginContext to use for authentication
074 try {
075 LoginContext loginContext = null;
076 if (appName == null)
077 appName = DEFAULT_NAME;
078
079 if (log.isDebugEnabled())
080 log.debug(sm.getString("jaasRealm.beginLogin", username, appName));
081
082 // What if the LoginModule is in the container class loader ?
083 ClassLoader ocl = null;
084
085 if (isUseContextClassLoader()) {
086 ocl = Thread.currentThread().getContextClassLoader();
087 Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
088 }
089
090 try {
091 loginContext = ContextManager.login(appName, new JAASCallbackHandler(this, username, credentials));
092 } catch (AccountExpiredException e) {
093 if (log.isDebugEnabled())
094 log.debug(sm.getString("jaasRealm.accountExpired", username));
095 return (null);
096 } catch (CredentialExpiredException e) {
097 if (log.isDebugEnabled())
098 log.debug(sm.getString("jaasRealm.credentialExpired", username));
099 return (null);
100 } catch (FailedLoginException e) {
101 if (log.isDebugEnabled())
102 log.debug(sm.getString("jaasRealm.failedLogin", username));
103 return (null);
104 } catch (LoginException e) {
105 log.warn(sm.getString("jaasRealm.loginException", username), e);
106 return (null);
107 } catch (Throwable e) {
108 log.error(sm.getString("jaasRealm.unexpectedError"), e);
109 return (null);
110 } finally {
111 if (isUseContextClassLoader()) {
112 Thread.currentThread().setContextClassLoader(ocl);
113 }
114 }
115
116 if (log.isDebugEnabled())
117 log.debug("Login context created " + username);
118
119 // Negotiate a login via this LoginContext
120 Subject subject = loginContext.getSubject();
121 ContextManager.setCallers(subject, subject);
122 if (log.isDebugEnabled())
123 log.debug(sm.getString("jaasRealm.loginContextCreated", username));
124
125 // Return the appropriate Principal for this authenticated Subject
126 Principal principal = createPrincipal(username, subject);
127 if (principal == null) {
128 log.debug(sm.getString("jaasRealm.authenticateFailure", username));
129 return (null);
130 }
131 if (log.isDebugEnabled()) {
132 log.debug(sm.getString("jaasRealm.authenticateSuccess", username));
133 }
134
135 return (principal);
136
137 } catch (Throwable t) {
138 log.error("error ", t);
139 return null;
140 }
141 }
142
143 protected Principal createPrincipal(String username, Subject subject) {
144 // Prepare to scan the Principals for this Subject
145 //String password = null; // Will not be carried forward
146
147 List roles = new ArrayList();
148 Principal userPrincipal = null;
149
150 // Scan the Principals for this Subject
151 Iterator principals = subject.getPrincipals().iterator();
152 while (principals.hasNext()) {
153 Principal principal = (Principal) principals.next();
154
155 String principalClass = principal.getClass().getName();
156
157 if( log.isDebugEnabled() ) {
158 log.debug(sm.getString("jaasRealm.checkPrincipal", principal, principalClass));
159 }
160
161 if (userPrincipal == null && userClasses.contains(principalClass)) {
162 userPrincipal = principal;
163 if( log.isDebugEnabled() ) {
164 log.debug(sm.getString("jaasRealm.userPrincipalSuccess", principal.getName()));
165 }
166 }
167
168 if (roleClasses.contains(principalClass)) {
169 roles.add(principal.getName());
170 if( log.isDebugEnabled() ) {
171 log.debug(sm.getString("jaasRealm.rolePrincipalAdd", principal.getName()));
172 }
173 }
174 }
175
176 // Print failure message if needed
177 if (userPrincipal == null) {
178 if (log.isDebugEnabled()) {
179 log.debug(sm.getString("jaasRealm.userPrincipalFailure"));
180 log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
181 }
182 } else {
183 if (roles.size() == 0) {
184 if (log.isDebugEnabled()) {
185 log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
186 }
187 }
188 }
189
190 JAASTomcatPrincipal jaasPrincipal = new JAASTomcatPrincipal(username);
191 jaasPrincipal.setSubject(subject);
192 jaasPrincipal.setRoles(roles);
193
194 // Return the resulting Principal for our authenticated user
195 return jaasPrincipal;
196 }
197
198
199 public Object clone() throws CloneNotSupportedException{
200 return super.clone();
201 }
202
203
204 public boolean hasRole(Principal principal, String role) {
205
206 if ((principal == null) || (role == null) ||
207 !(principal instanceof JAASTomcatPrincipal))
208 return (false);
209
210 JAASTomcatPrincipal jtp = (JAASTomcatPrincipal) principal;
211 if (jtp.getRoles().contains(role))
212 return true;
213
214 return false;
215 }
216
217 }