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 }