SPNEGO support part 2
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 31 Mar 2011 19:33:04 +0000 (19:33 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 31 Mar 2011 19:33:04 +0000 (19:33 +0000)
Expose the users delegated credentials through a request attribute so applications can make use of it

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1087416 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/Globals.java
java/org/apache/catalina/Realm.java
java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
java/org/apache/catalina/connector/Request.java
java/org/apache/catalina/realm/CombinedRealm.java
java/org/apache/catalina/realm/GenericPrincipal.java
java/org/apache/catalina/realm/LocalStrings.properties
java/org/apache/catalina/realm/LockOutRealm.java
java/org/apache/catalina/realm/RealmBase.java
java/org/apache/catalina/session/StandardSession.java
webapps/docs/config/valve.xml

index 1505a2b..124378c 100644 (file)
@@ -151,6 +151,10 @@ public final class Globals {
         "javax.security.auth.subject";
 
     
+    public static final String GSS_CREDENTIAL_ATTR =
+        "org.apache.catalina.realm.GSS_CREDENTIAL";
+
+
     /**
      * The master flag which controls strict servlet specification 
      * compliance.
index b9e85c1..f03f4b6 100644 (file)
@@ -111,9 +111,11 @@ 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 The gssContext processed by the {@link Authenticator}.
+     * @param gssContext The gssContext processed by the {@link Authenticator}.
+     * @param storeCreds Should the realm attempt to store the delegated
+     *                   credentials in the returned Principal?
      */
-    public Principal authenticate(GSSContext gssContext);
+    public Principal authenticate(GSSContext gssContext, boolean storeCreds);
     
     
     /**
index b30cfd3..8dc05fa 100644 (file)
@@ -77,6 +77,15 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
         this.loginConfigName = loginConfigName;
     }
 
+    private boolean storeDelegatedCredentials = true;
+    public boolean isStoreDelegatedCredentials() {
+        return storeDelegatedCredentials;
+    }
+    public void setStoreDelegatedCredentials(
+            boolean storeDelegatedCredentials) {
+        this.storeDelegatedCredentials = storeDelegatedCredentials;
+    }
+
 
     @Override
     protected String getAuthMethod() {
@@ -229,7 +238,8 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
                 return false;
             }
 
-            principal = context.getRealm().authenticate(gssContext);
+            principal = context.getRealm().authenticate(gssContext,
+                    storeDelegatedCredentials);
         } catch (GSSException e) {
             if (log.isDebugEnabled()) {
                 log.debug(sm.getString("spnegoAuthenticator.ticketValidateFail",
index e90055b..ff6283f 100644 (file)
@@ -923,6 +923,13 @@ public class Request
             return asyncSupported;
         }
 
+        if (name.equals(Globals.GSS_CREDENTIAL_ATTR)) {
+            if (userPrincipal instanceof GenericPrincipal) {
+                return ((GenericPrincipal) userPrincipal).getGssCredential();
+            }
+            return null;
+        }
+
         Object attr=attributes.get(name);
 
         if(attr!=null)
index b6cd91e..70b2e7f 100644 (file)
@@ -271,7 +271,7 @@ public class CombinedRealm extends RealmBase {
      * {@inheritDoc}
      */
     @Override
-    public Principal authenticate(GSSContext gssContext) {
+    public Principal authenticate(GSSContext gssContext, boolean storeCreds) {
         if (gssContext.isEstablished()) {
             Principal authenticatedUser = null;
             String username = null;
@@ -292,7 +292,7 @@ public class CombinedRealm extends RealmBase {
                             username, realm.getInfo()));
                 }
 
-                authenticatedUser = realm.authenticate(gssContext);
+                authenticatedUser = realm.authenticate(gssContext, storeCreds);
 
                 if (authenticatedUser == null) {
                     if (log.isDebugEnabled()) {
index 22f7536..6b45faf 100644 (file)
@@ -25,6 +25,8 @@ import java.util.List;
 
 import javax.security.auth.login.LoginContext;
 
+import org.ietf.jgss.GSSCredential;
+
 
 /**
  * Generic implementation of <strong>java.security.Principal</strong> that
@@ -98,6 +100,26 @@ public class GenericPrincipal implements Principal {
      */
     public GenericPrincipal(String name, String password, List<String> roles,
             Principal userPrincipal, LoginContext loginContext) {
+        this(name, password, roles, userPrincipal, loginContext, null);
+    }
+    
+    /**
+     * Construct a new Principal, associated with the specified Realm, for the
+     * specified username and password, with the specified role names
+     * (as Strings).
+     *
+     * @param name The username of the user represented by this Principal
+     * @param password Credentials used to authenticate this user
+     * @param roles List of roles (must be Strings) possessed by this user
+     * @param userPrincipal - the principal to be returned from the request 
+     *        getUserPrincipal call if not null; if null, this will be returned
+     * @param loginContext  - If provided, this will be used to log out the user
+     *        at the appropriate time
+     * @param gssCredential - If provided, the user&apos;s delegated credentials
+     */
+    public GenericPrincipal(String name, String password, List<String> roles,
+            Principal userPrincipal, LoginContext loginContext,
+            GSSCredential gssCredential) {
         super();
         this.name = name;
         this.password = password;
@@ -109,6 +131,7 @@ public class GenericPrincipal implements Principal {
                 Arrays.sort(this.roles);
         }
         this.loginContext = loginContext;
+        this.gssCredential = gssCredential;
     }
 
 
@@ -167,6 +190,19 @@ public class GenericPrincipal implements Principal {
      */
     protected LoginContext loginContext = null;
 
+
+    /**
+     * The user&apos;s delegated credentials.
+     */
+    protected GSSCredential gssCredential = null;
+
+    public GSSCredential getGssCredential() {
+        return this.gssCredential;
+    }
+    protected void setGssCredential(GSSCredential gssCredential) {
+        this.gssCredential = gssCredential;
+    }
+
     // --------------------------------------------------------- Public Methods
 
 
index 01fb5a8..c248501 100644 (file)
@@ -65,6 +65,7 @@ memoryRealm.readXml=Exception while reading memory database file
 memoryRealm.xmlFeatureEncoding=Exception configuring digester to permit java encoding names in XML files. Only IANA encoding names will be supported.
 realmBase.algorithm=Invalid message digest algorithm {0} specified
 realmBase.alreadyStarted=This Realm has already been started
+realmBase.delegatedCredentialFail=Unable to obtain delegated credentials for user [{0}
 realmBase.digest=Error digesting user credentials
 realmBase.forbidden=Access to the requested resource has been denied
 realmBase.hasRoleFailure=Username {0} does NOT have role {1}
index 7059a85..194e42c 100644 (file)
@@ -225,7 +225,7 @@ public class LockOutRealm extends CombinedRealm {
      * {@inheritDoc}
      */
     @Override
-    public Principal authenticate(GSSContext gssContext) {
+    public Principal authenticate(GSSContext gssContext, boolean storeCreds) {
         if (gssContext.isEstablished()) {
             String username = null;
             GSSName name = null;
@@ -246,7 +246,8 @@ public class LockOutRealm extends CombinedRealm {
                 return null;
             }
 
-            Principal authenticatedUser = super.authenticate(gssContext);
+            Principal authenticatedUser =
+                    super.authenticate(gssContext, storeCreds);
             
             if (authenticatedUser == null) {
                 registerAuthFailure(username);
index fc5ad22..323ba83 100644 (file)
@@ -55,6 +55,7 @@ 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.GSSCredential;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSName;
 
@@ -424,7 +425,7 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
      * {@inheritDoc}
      */
     @Override
-    public Principal authenticate(GSSContext gssContext) {
+    public Principal authenticate(GSSContext gssContext, boolean storeCred) {
         if (gssContext.isEstablished()) {
             GSSName name = null;
             try {
@@ -434,7 +435,20 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
             }
             
             if (name!= null) {
-                return getPrincipal(name.toString());
+                GSSCredential gssCredential = null;
+                if (storeCred && gssContext.getCredDelegState()) {
+                    try {
+                        gssCredential = gssContext.getDelegCred();
+                    } catch (GSSException e) {
+                        e.printStackTrace();
+                        if (log.isDebugEnabled()) {
+                            log.debug(sm.getString(
+                                    "realmBase.delegatedCredentialFail", name),
+                                    e);
+                        }
+                    }
+                }
+                return getPrincipal(name.toString(), gssCredential);
             }
         }
         
@@ -785,7 +799,7 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
             if (roles.length == 0 && !constraint.getAllRoles()) {
                 if(constraint.getAuthConstraint()) {
                     if( log.isDebugEnabled() )
-                        log.debug("No roles ");
+                        log.debug("No role)s ");
                     status = false; // No listed roles means no access at all
                     denyfromall = true;
                     break;
@@ -1181,6 +1195,17 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
     protected abstract Principal getPrincipal(String username);
 
 
+    protected Principal getPrincipal(String username,
+            GSSCredential gssCredential) {
+        Principal p = getPrincipal(username);
+        
+        if (p instanceof GenericPrincipal) {
+            ((GenericPrincipal) p).setGssCredential(gssCredential);
+        }
+        
+        return p;
+    }
+
     /**
      * Return the Server object that is the ultimate parent for the container
      * with which this Realm is associated. If the server cannot be found (eg
index a418ce5..626013f 100644 (file)
@@ -176,7 +176,8 @@ public class StandardSession implements HttpSession, Session, Serializable {
      * Set of attribute names which are not allowed to be persisted.
      */
     protected static final String[] excludedAttributes = {
-        Globals.SUBJECT_ATTR
+        Globals.SUBJECT_ATTR,
+        Globals.GSS_CREDENTIAL_ATTR
     };
 
 
index b3a77aa..8cd90ab 100644 (file)
         specified, the platform default provider will be used.</p>
       </attribute>
 
+      <attribute name="storeDelegatedCredentials" required="false">
+        <p>Controls if the user&apos; delegated credentials will be stored in
+        the user Principal. If available, the delegated credentials will be
+        available to applications (e.g. for onward authentication to external
+        services) via the <code>org.apache.catalina.realm.GSS_CREDENTIAL</code>
+        request attribute.If not set, the default value of <code>true</code>
+        will be used.</p>
+      </attribute>
+
     </attributes>
 
   </subsection>