Author: markt Date: Tue Mar 29 20:05:04 2011 New Revision: 1086706 URL: http://svn.apache.org/viewvc?rev=1086706&view=rev Log: Part 2 of SPNEGO/Windows authentication support. Authorisation support. Works essentially the same way as CLIENT-CERT, i.e. the Realm doesn't actually authenticate the user but it does create the Principal and add the roles.
Modified: tomcat/trunk/java/org/apache/catalina/Realm.java tomcat/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java tomcat/trunk/java/org/apache/catalina/realm/CombinedRealm.java tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java Modified: tomcat/trunk/java/org/apache/catalina/Realm.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Realm.java?rev=1086706&r1=1086705&r2=1086706&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/Realm.java (original) +++ tomcat/trunk/java/org/apache/catalina/Realm.java Tue Mar 29 20:05:04 2011 @@ -26,6 +26,7 @@ import java.security.cert.X509Certificat import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.deploy.SecurityConstraint; +import org.ietf.jgss.GSSContext; /** * A <b>Realm</b> is a read-only facade for an underlying security realm * used to authenticate individual users, and identify the security roles @@ -110,7 +111,16 @@ public interface Realm { * Return the Principal associated with the specified chain of X509 * client certificates. If there is none, return <code>null</code>. * - * @param certs Array of client certificates, with the first one in + * @param certs The gssContext processed by the {@link Authenticator}. + */ + public Principal authenticate(GSSContext gssContext); + + + /** + * Return the Principal associated with the specified {@link GSSContext}. + * If there is none, return <code>null</code>. + * + * @param gssContext Array of client certificates, with the first one in * the array being the certificate of the client itself. */ public Principal authenticate(X509Certificate certs[]); Modified: tomcat/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java?rev=1086706&r1=1086705&r2=1086706&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java (original) +++ tomcat/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java Tue Mar 29 20:05:04 2011 @@ -33,10 +33,10 @@ import javax.security.auth.login.LoginCo import javax.security.auth.login.LoginException; import javax.servlet.http.HttpServletResponse; +import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; -import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.startup.Bootstrap; import org.apache.catalina.util.Base64; import org.apache.juli.logging.Log; @@ -47,7 +47,7 @@ import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSManager; -import org.ietf.jgss.GSSName; + /** * A SPNEGO authenticator that uses the SPENGO/Kerberos support built in to Java @@ -208,7 +208,8 @@ public class SpnegoAuthenticator extends try { principal = Subject.doAs(serviceSubject, - new KerberosAuthAction(decoded.getBytes(), response)); + new KerberosAuthAction(decoded.getBytes(), + response, context)); } catch (PrivilegedActionException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -235,10 +236,13 @@ public class SpnegoAuthenticator extends private byte[] inToken; private HttpServletResponse resp; + private Context context; - public KerberosAuthAction(byte[] inToken, HttpServletResponse resp) { + public KerberosAuthAction(byte[] inToken, HttpServletResponse resp, + Context context) { this.inToken = inToken; this.resp = resp; + this.context = context; } @Override @@ -246,7 +250,7 @@ public class SpnegoAuthenticator extends // Assume the GSSContext is stateless // TODO: Confirm this assumption - GSSContext context = + GSSContext gssContext = GSSManager.getInstance().createContext((GSSCredential) null); Principal principal = null; @@ -256,26 +260,19 @@ public class SpnegoAuthenticator extends } byte[] outToken = - context.acceptSecContext(inToken, 0, inToken.length); + gssContext.acceptSecContext(inToken, 0, inToken.length); if (outToken == null) { throw new GSSException(GSSException.DEFECTIVE_TOKEN); } - GSSName initiatorName = context.getSrcName(); - - if (context.isEstablished()) { - // TODO This (and a lot of the surrounding code) needs to move - // to RealmBase so authorisation will work. This is just a quick - // hack to get authentication working. - principal = new GenericPrincipal(initiatorName.toString(), null); - } + principal = context.getRealm().authenticate(gssContext); // Send response token on success and failure resp.setHeader("WWW-Authenticate", "Negotiate " + Base64.encode(outToken)); - context.dispose(); + gssContext.dispose(); return principal; } } Modified: tomcat/trunk/java/org/apache/catalina/realm/CombinedRealm.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/CombinedRealm.java?rev=1086706&r1=1086705&r2=1086706&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/realm/CombinedRealm.java (original) +++ tomcat/trunk/java/org/apache/catalina/realm/CombinedRealm.java Tue Mar 29 20:05:04 2011 @@ -31,6 +31,9 @@ import org.apache.catalina.LifecycleExce import org.apache.catalina.Realm; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSException; +import org.ietf.jgss.GSSName; /** * Realm implementation that contains one or more realms. Authentication is @@ -264,6 +267,53 @@ public class CombinedRealm extends Realm return authenticatedUser; } + /** + * {@inheritDoc} + */ + @Override + public Principal authenticate(GSSContext gssContext) { + if (gssContext.isEstablished()) { + Principal authenticatedUser = null; + String username = null; + + GSSName name = null; + try { + name = gssContext.getSrcName(); + } catch (GSSException e) { + log.warn(sm.getString("realmBase.gssNameFail"), e); + return null; + } + + username = name.toString(); + + for (Realm realm : realms) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("combinedRealm.authStart", + username, realm.getInfo())); + } + + authenticatedUser = realm.authenticate(gssContext); + + if (authenticatedUser == null) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("combinedRealm.authFail", + username, realm.getInfo())); + } + } else { + if (log.isDebugEnabled()) { + log.debug(sm.getString("combinedRealm.authSucess", + username, realm.getInfo())); + } + break; + } + } + return authenticatedUser; + } + + // Fail in all other cases + return null; + } + @Override protected String getName() { return name; Modified: tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties?rev=1086706&r1=1086705&r2=1086706&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties Tue Mar 29 20:05:04 2011 @@ -73,6 +73,7 @@ realmBase.notAuthenticated=Configuration realmBase.notStarted=This Realm has not yet been started realmBase.authenticateFailure=Username {0} NOT successfully authenticated realmBase.authenticateSuccess=Username {0} successfully authenticated +realmBase.gssNameFail=Failed to extract name from established GSSContext userDatabaseRealm.authenticateError=Login configuration error authenticating username {0} userDatabaseRealm.lookup=Exception looking up UserDatabase under key {0} userDatabaseRealm.noDatabase=No UserDatabase component found under key {0} Modified: tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java?rev=1086706&r1=1086705&r2=1086706&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java (original) +++ tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java Tue Mar 29 20:05:04 2011 @@ -26,6 +26,9 @@ import java.util.concurrent.atomic.Atomi import org.apache.catalina.LifecycleException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSException; +import org.ietf.jgss.GSSName; /** * This class extends the CombinedRealm (hence it can wrap other Realms) to @@ -219,6 +222,46 @@ public class LockOutRealm extends Combin /** + * {@inheritDoc} + */ + @Override + public Principal authenticate(GSSContext gssContext) { + if (gssContext.isEstablished()) { + String username = null; + GSSName name = null; + try { + name = gssContext.getSrcName(); + } catch (GSSException e) { + log.warn(sm.getString("realmBase.gssNameFail"), e); + return null; + } + + username = name.toString(); + + if (isLocked(username)) { + // Trying to authenticate a locked user is an automatic failure + registerAuthFailure(username); + + log.warn(sm.getString("lockOutRealm.authLockedUser", username)); + return null; + } + + Principal authenticatedUser = super.authenticate(gssContext); + + if (authenticatedUser == null) { + registerAuthFailure(username); + } else { + registerAuthSuccess(username); + } + return authenticatedUser; + } + + // Fail in all other cases + return null; + } + + + /** * Unlock the specified username. This will remove all records of * authentication failures for this user. * Modified: tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java?rev=1086706&r1=1086705&r2=1086706&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java (original) +++ tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java Tue Mar 29 20:05:04 2011 @@ -54,6 +54,9 @@ import org.apache.catalina.util.MD5Encod import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSException; +import org.ietf.jgss.GSSName; /** * Simple implementation of <b>Realm</b> that reads an XML file to configure @@ -418,6 +421,29 @@ public abstract class RealmBase extends /** + * {@inheritDoc} + */ + @Override + public Principal authenticate(GSSContext gssContext) { + if (gssContext.isEstablished()) { + GSSName name = null; + try { + name = gssContext.getSrcName(); + } catch (GSSException e) { + log.warn(sm.getString("realmBase.gssNameFail"), e); + } + + if (name!= null) { + return getPrincipal(name.toString()); + } + } + + // Fail in all other cases + return null; + } + + + /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org