Author: markt
Date: Fri Apr 1 00:34:45 2011
New Revision: 1087524
URL: http://svn.apache.org/viewvc?rev=1087524&view=rev
Log:
SPNEGP part 3 - the final part for 7.0.12
Integrate with JNDI realm so delegated credentials are used by default.
Modified:
tomcat/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java
tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/docs/config/realm.xml
tomcat/trunk/webapps/docs/windows-auth-howto.xml
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=1087524&r1=1087523&r2=1087524&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
(original)
+++
tomcat/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
Fri Apr 1 00:34:45 2011
@@ -46,24 +46,6 @@ import org.ietf.jgss.Oid;
* multiple components. If the configuration is invalid, the error messages are
* often cryptic although a Google search will usually point you in the right
* direction.
- * <p>
- * TODO:
- * <ul>
- * <li>Add support for delegating credentials? Need this if we want to
- * authenticate to a realm as the user. This is likely to result in a fair
- * amount of internal refactoring.</li>
- * </ul>
- * <p>
- * TBDs:
- * <ul>
- * <li>Does the domain name have to be in upper case?</li>
- * <li>Does the SPN have to start with HTTP/...?</li>
- * <li>Can a port number be appended to the end of the host in the SPN?</li>
- * <li>Can the domain be left off the user in the ktpass command?</li>
- * <li>What are the limitations on the account that Tomcat can run as? SPN
- * associated account works, domain admin works, local admin doesn't
- * work</li>
- * </ul>
*/
public class SpnegoAuthenticator extends AuthenticatorBase {
Modified: tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java?rev=1087524&r1=1087523&r2=1087524&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java Fri Apr 1
00:34:45 2011
@@ -56,6 +56,7 @@ import org.apache.catalina.LifecycleExce
import org.apache.catalina.util.Base64;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.CharChunk;
+import org.ietf.jgss.GSSCredential;
/**
* <p>Implementation of <strong>Realm</strong> that works with a directory
@@ -415,6 +416,14 @@ public class JNDIRealm extends RealmBase
*/
protected int timeLimit = 0;
+
+ /**
+ * Should delegated credentials from the SPNEGO authenticator be used if
+ * available
+ */
+ protected boolean useDelegatedCredential = true;
+
+
// ------------------------------------------------------------- Properties
/**
@@ -950,6 +959,15 @@ public class JNDIRealm extends RealmBase
}
+
+ public boolean isUseDelegatedCredential() {
+ return useDelegatedCredential;
+ }
+
+ public void setUseDelegatedCredential(boolean useDelegatedCredential) {
+ this.useDelegatedCredential = useDelegatedCredential;
+ }
+
/**
* Return descriptive information about this Realm implementation and
* the corresponding version number, in the format
@@ -1935,6 +1953,12 @@ public class JNDIRealm extends RealmBase
*/
@Override
protected Principal getPrincipal(String username) {
+ return getPrincipal(username, null);
+ }
+
+ @Override
+ protected Principal getPrincipal(String username,
+ GSSCredential gssCredential) {
DirContext context = null;
Principal principal = null;
@@ -1949,7 +1973,7 @@ public class JNDIRealm extends RealmBase
try {
// Authenticate the specified username if possible
- principal = getPrincipal(context, username);
+ principal = getPrincipal(context, username, gssCredential);
} catch (CommunicationException e) {
@@ -1964,7 +1988,7 @@ public class JNDIRealm extends RealmBase
context = open();
// Try the authentication again.
- principal = getPrincipal(context, username);
+ principal = getPrincipal(context, username, gssCredential);
} catch (ServiceUnavailableException e) {
@@ -1979,7 +2003,7 @@ public class JNDIRealm extends RealmBase
context = open();
// Try the authentication again.
- principal = getPrincipal(context, username);
+ principal = getPrincipal(context, username, gssCredential);
}
@@ -2012,14 +2036,52 @@ public class JNDIRealm extends RealmBase
* Return the Principal associated with the given user name.
*/
protected synchronized Principal getPrincipal(DirContext context,
- String username)
+ String username, GSSCredential gssCredential)
throws NamingException {
- User user = getUser(context, username);
+ User user = null;
+ List<String> roles = null;
+
+ try {
+ if (gssCredential != null && isUseDelegatedCredential()) {
+ // Set up context
+ context.addToEnvironment(
+ Context.SECURITY_AUTHENTICATION, "GSSAPI");
+ context.addToEnvironment(
+ "javax.security.sasl.server.authentication", "true");
+ context.addToEnvironment(
+ "javax.security.sasl.qop", "auth-conf");
+ // Note: Subject already set in SPNEGO authenticator so no need
+ // for Subject.doAs() here
+ }
+ user = getUser(context, username);
+ if (user != null) {
+ roles = getRoles(context, user);
+ }
+ } finally {
+ try {
+ context.removeFromEnvironment(
+ Context.SECURITY_AUTHENTICATION);
+ } catch (NamingException e) {
+ // Ignore
+ }
+ try {
+ context.removeFromEnvironment(
+ "javax.security.sasl.server.authentication");
+ } catch (NamingException e) {
+ // Ignore
+ }
+ try {
+ context.removeFromEnvironment(
+ "javax.security.sasl.qop");
+ } catch (NamingException e) {
+ // Ignore
+ }
+ }
if (user != null) {
return new GenericPrincipal(user.getUserName(), user.getPassword(),
- getRoles(context, user));
+ roles, null, null, gssCredential);
}
return null;
@@ -2303,45 +2365,45 @@ public class JNDIRealm extends RealmBase
}
- // ------------------------------------------------------ Private Classes
-
- /**
- * A protected class representing a User
- */
- protected static class User {
+ // ------------------------------------------------------ Private Classes
+
+ /**
+ * A protected class representing a User
+ */
+ protected static class User {
- private final String username;
- private final String dn;
- private final String password;
- private final List<String> roles;
-
- public User(String username, String dn, String password,
- List<String> roles) {
- this.username = username;
- this.dn = dn;
- this.password = password;
- if (roles == null) {
- this.roles = Collections.emptyList();
- } else {
- this.roles = Collections.unmodifiableList(roles);
- }
- }
+ private final String username;
+ private final String dn;
+ private final String password;
+ private final List<String> roles;
+
+ public User(String username, String dn, String password,
+ List<String> roles) {
+ this.username = username;
+ this.dn = dn;
+ this.password = password;
+ if (roles == null) {
+ this.roles = Collections.emptyList();
+ } else {
+ this.roles = Collections.unmodifiableList(roles);
+ }
+ }
- public String getUserName() {
- return username;
- }
-
- public String getDN() {
- return dn;
- }
+ public String getUserName() {
+ return username;
+ }
- public String getPassword() {
- return password;
- }
+ public String getDN() {
+ return dn;
+ }
+
+ public String getPassword() {
+ return password;
+ }
- public List<String> getRoles() {
- return roles;
- }
- }
+ public List<String> getRoles() {
+ return roles;
+ }
+ }
}
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=1087524&r1=1087523&r2=1087524&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java Fri Apr 1
00:34:45 2011
@@ -151,6 +151,13 @@ public abstract class RealmBase extends
protected AllRolesMode allRolesMode = AllRolesMode.STRICT_MODE;
+ /**
+ * When processing users authenticated via the GSS-API, should any
+ * "@..." be stripped from the end of the user name?
+ */
+ protected boolean stripAtForGss = true;
+
+
// ------------------------------------------------------------- Properties
@@ -272,6 +279,16 @@ public abstract class RealmBase extends
}
+ public boolean isStripAtForGss() {
+ return stripAtForGss;
+ }
+
+
+ public void setStripAtForGss(boolean stripAtForGss) {
+ this.stripAtForGss = stripAtForGss;
+ }
+
+
// --------------------------------------------------------- Public Methods
@@ -427,14 +444,23 @@ public abstract class RealmBase extends
@Override
public Principal authenticate(GSSContext gssContext, boolean storeCred) {
if (gssContext.isEstablished()) {
- GSSName name = null;
+ GSSName gssName = null;
try {
- name = gssContext.getSrcName();
+ gssName = gssContext.getSrcName();
} catch (GSSException e) {
log.warn(sm.getString("realmBase.gssNameFail"), e);
}
- if (name!= null) {
+ if (gssName!= null) {
+ String name = gssName.toString();
+
+ if (isStripAtForGss()) {
+ int i = name.indexOf('@');
+ if (i > 0) {
+ // Zero so we don;t leave a zero length name
+ name = name.substring(0, i);
+ }
+ }
GSSCredential gssCredential = null;
if (storeCred && gssContext.getCredDelegState()) {
try {
@@ -448,7 +474,7 @@ public abstract class RealmBase extends
}
}
}
- return getPrincipal(name.toString(), gssCredential);
+ return getPrincipal(name, gssCredential);
}
}
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1087524&r1=1087523&r2=1087524&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Apr 1 00:34:45 2011
@@ -95,9 +95,13 @@
Don't register Contexts that fail to start with the Mapper.
(markt)
</fix>
<add>
- Add initial support for SPNEGO/Kerberos authentication also referred to
- as integrated Windows authentication. This is a work in progress. See
- the documentation for details. (markt)
+ <bug>48685</bug>: Add initial support for SPNEGO/Kerberos
authentication
+ also referred to as integrated Windows authentication. This includes
+ user authentication, authorisation via the directory using the
+ user's delegated credentials and exposing the user's
delegated
+ credentials via a request attribute so applications can make use of the
+ to impersonate the current user when accessing third-party systems that
+ use a compatible authentication mechanism. (markt)
</add>
<fix>
HTTP range requests cannot be reliably served when a Writer is in use
so
Modified: tomcat/trunk/webapps/docs/config/realm.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/realm.xml?rev=1087524&r1=1087523&r2=1087524&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/realm.xml (original)
+++ tomcat/trunk/webapps/docs/config/realm.xml Fri Apr 1 00:34:45 2011
@@ -143,6 +143,12 @@
a role name assigned to the corresponding user.</p>
</attribute>
+ <attribute name="stripAtForGss" required="false">
+ <p>When processing users authenticated via the GSS-API, this attribute
+ controls if any "@..." is removed from the end of the user
+ name. If not specified, the default is <code>true</code>.</p>
+ </attribute>
+
<attribute name="userCredCol" required="true">
<p>Name of the column, in the "users" table, which contains
the user's credentials (i.e. password(. If a value for the
@@ -224,6 +230,12 @@
a role name assigned to the corresponding user.</p>
</attribute>
+ <attribute name="stripAtForGss" required="false">
+ <p>When processing users authenticated via the GSS-API, this attribute
+ controls if any "@..." is removed from the end of the user
+ name. If not specified, the default is <code>true</code>.</p>
+ </attribute>
+
<attribute name="userCredCol" required="true">
<p>Name of the column, in the "users" table, which contains
the user's credentials (i.e. password(. If a value for the
@@ -420,7 +432,9 @@
user currently being authenticated? If false,
<code>connectionName</code>} and <code>connectionPassword</code> will
be
used if specified, else an anonymous. If not specified, the default
- value of <code>false</code> is used.</p>
+ value of <code>false</code> is used. Note that when accessing the
+ directory using delegated credentials, this attribute is always ignored
+ and the search is performed using the delegated credentials.</p>
</attribute>
<attribute name="roleSubtree" required="false">
@@ -437,6 +451,12 @@
<code>0</code> is used which indicates no limit.</p>
</attribute>
+ <attribute name="stripAtForGss" required="false">
+ <p>When processing users authenticated via the GSS-API, this attribute
+ controls if any "@..." is removed from the end of the user
+ name. If not specified, the default is <code>true</code>.</p>
+ </attribute>
+
<attribute name="timeLimit" required="false">
<p>Specifies the time (in milliseconds) to wait for records to be
returned when using the <code>userSearch</code> attribute. If not
@@ -444,6 +464,14 @@
limit.</p>
</attribute>
+ <attribute name="useDelegatedCredential" required="false">
+ <p>When the JNIRealm is used with the SPNEGO authenticator, delegated
+ credentials for the user may be available. If such credentials are
+ present, this attribute controls whether are not they are used to
+ connect to the directory. If not specified, the default value of
+ <code>true</code> is used.</p>
+ </attribute>
+
<attribute name="userBase" required="false">
<p>The base element for user searches performed using the
<code>userSearch</code> expression. Not used if you are using
@@ -471,7 +499,11 @@
actual username should be inserted. You can use this property
instead of <code>userSearch</code>, <code>userSubtree</code>
and <code>userBase</code> when the distinguished name contains
- the username and is otherwise the same for all users.</p>
+ the username and is otherwise the same for all users. Note that
+ when accessing the directory using delegated credentials, this
+ attribute is always ignored and <code>userSearch</code>,
+ <code>userSubtree</code> and <code>userBase</code> are always
+ used instead.</p>
</attribute>
<attribute name="userRoleName" required="false">
@@ -565,6 +597,12 @@
default value is <code>conf/tomcat-users.xml</code>.</p>
</attribute>
+ <attribute name="stripAtForGss" required="false">
+ <p>When processing users authenticated via the GSS-API, this attribute
+ controls if any "@..." is removed from the end of the user
+ name. If not specified, the default is <code>true</code>.</p>
+ </attribute>
+
</attributes>
<p>The XML document referenced by the <code>pathname</code> attribute must
@@ -634,6 +672,12 @@
for your role <code>Principals</code>.</p>
</attribute>
+ <attribute name="stripAtForGss" required="false">
+ <p>When processing users authenticated via the GSS-API, this attribute
+ controls if any "@..." is removed from the end of the user
+ name. If not specified, the default is <code>true</code>.</p>
+ </attribute>
+
<attribute name="useContextClassLoader" required="false">
<p>Instructs JAASRealm to use the context class loader for loading the
user-specified <code>LoginModule</code> class and associated
Modified: tomcat/trunk/webapps/docs/windows-auth-howto.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/windows-auth-howto.xml?rev=1087524&r1=1087523&r2=1087524&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/windows-auth-howto.xml (original)
+++ tomcat/trunk/webapps/docs/windows-auth-howto.xml Fri Apr 1 00:34:45 2011
@@ -51,10 +51,18 @@ sections.</p>
</section>
<section name="Built-in Tomcat support">
-<p><strong>This is a work in progress. This warning should be removed once the
-various questions and TODOs (see the Javadoc and implementation class) have
been
-resolved.</strong> In particular, onwards delegation is not yet supported and
-roles are not retrieved from the domain controller.</p>
+<p><strong>This is a work in progress. There are a number of outstanding
+questions that require further testing.</strong> These include:
+<ul>
+<li>Does the domain name have to be in upper case?</li>
+<li>Does the SPN have to start with HTTP/...?</li>
+<li>Can a port number be appended to the end of the host in the SPN?</li>
+<li>Can the domain be left off the user in the ktpass command?</li>
+<li>What are the limitations on the account that Tomcat can run as? SPN
+ associated account works, domain admin works, local admin doesn't
+ work</li>
+</ul>
+</p>
<p>There are four components to the configuration of the built-in Tomcat
support for Windows authentication. The domain controller, the server hosting
Tomcat, the web application wishing to use Windows authentication and the
client
@@ -156,6 +164,10 @@ com.sun.security.jgss.krb5.accept {
is automatically set to the required value of false if a web application is
configured to use the SPNEGO authentication method.</li>
</p>
+ <p>The SPNEGO authenticator will work with any <a href="config/realm.html">
+ Realm</a> but if used with the JNDI Realm, by default the JNDI Realm will use
+ the user's delegated credentials to connect to the Active Directory.
+ </p>
<p>The above steps have been tested on a Tomcat server running Windows Server
2008 R2 64-bit Standard with an Oracle 1.6.0_24 64-bit JDK.</p>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]