001 /**
002 *
003 * Copyright 2003-2004 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * 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: 355877 $ $Date: 2005-12-10 18:48:27 -0800 (Sat, 10 Dec 2005) $
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 = new LoginContext(appName, new JAASCallbackHandler(this, username, credentials));
092 } catch (Throwable e) {
093 log.error(sm.getString("jaasRealm.unexpectedError"), e);
094 return (null);
095 } finally {
096 if (isUseContextClassLoader()) {
097 Thread.currentThread().setContextClassLoader(ocl);
098 }
099 }
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 }