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

Reply via email to