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: 565912 $ $Date: 2007-08-14 17:03:11 -0400 (Tue, 14 Aug 2007) $ 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 }