[jcifs] SPNEGO NTLM/Kerberos

Eric eglass1 at comcast.net
Wed Jun 2 00:49:07 GMT 2004


Attached is a patch to 0.9.0 to provide SPNEGO Kerberos/NTLM HTTP 
authentication (as well as a lightweight "backbone" for CIFS extended 
authentication).  This is fairly bleeding edge (read: not tested very 
well) but seemed to be in demand, and I had some time to put it 
together.  This is pretty large, so will probably need to be pushed out 
to the mailing list.

This will require JDK 1.4 (it *might* work with 1.3 if you've got JGSS 
installed).  You'll also need the "ktpass" tool (part of the Windows 
2000 Support Tools package):

http://www.microsoft.com/windows2000/downloads/servicepacks/SP4/supporttools.asp

To manipulate service principals, it is also useful to get the "setspn" 
utility (although it isn't strictly required):

http://www.microsoft.com/windows2000/techinfo/reskit/tools/existing/setspn-o.asp

For testing/troubleshooting, you'll also likely want to get the 
"kerbtray" utility (one of the Resource Kit tools):

http://www.microsoft.com/windows2000/techinfo/reskit/tools/existing/kerbtray-o.asp


To set this up, you will need to do the following:

1)  Create a user in Active Directory (say, "testuser".  Doesn't matter, 
but remember the password you used).

2)  Create a service principal name with ktpass:

ktpass -princ HTTP/<servername>@<realm> -mapuser <username> -pass <password>

servername is the hostname of your HTTP server (i.e., "mybox").
realm is your Kerberos realm (AD uses the DNS domain name, uppercase).
username is the username you created previously.
password is the password you were supposed to remember.

So for HTTP server "mybox.domain.com", with user "testuser" and password 
"password", this would be:

ktpass -princ HTTP/mybox at DOMAIN.COM -mapuser testuser -pass password

Note that the username is case-sensitive.  This should come back with:

     Successfully mapped HTTP/mybox to testuser.
     Key created.
     Account has been set for DES-only encryption.

The "DES-only" is important as Sun's Kerberos implementation doesn't 
support the default rc4-hmac ticket encryption.

3)  Now set up web.xml.  There are a few options for doing this (using a 
keytab, etc.).  But for simply getting things going, try using the 
attached web.xml as a template.  The critical settings are:


jcifs.http.enableNegotiate -- Set this to true, otherwise only NTLM will 
be advertised/supported.

jcifs.spnego.servicePrincipal -- the service principal you just created. 
  Using the previous example, this would be "HTTP/mybox at DOMAIN.COM".

jcifs.spnego.servicePassword -- The password for the service principal 
account (same password as before).

java.security.krb5.realm -- The Kerberos realm (as noted above, the 
uppercase DNS domain; "DOMAIN.COM" here).

java.security.krb5.kdc -- The Kerberos KDC (your Active Directory server).


By default, it will use an internal JAAS login configuration; you can 
specify your own using the standard "java.security.auth.login.config" 
setting (specifying this as an init parameter for the filter will set 
the corresponding system property).  Likewise you can leave out the 
realm and KDC settings and use your default krb5.conf if that is set up; 
or, specify "java.security.krb5.conf" as an init parameter to set the 
system property.

Once you've got web.xml set up, you should be able to fire up your 
servlet container and access your web application.  getRemoteUser() 
should work similarly to the NTLM filter (see the attached "index.jsp" 
for testing).  I would recommend also setting the init parameter 
"sun.security.krb5.debug" to "true" (as this will enable Kerberos 
debugging and print out a bunch of useful info).

If you encounter issues, the kerbtray utility can be used on the client 
to list the active Kerberos tickets.  You can compare these to the 
expected values from the filter to troubleshoot.  There should be a 
corresponding service principal ticket listed, i.e. "HTTP/mybox"; 
service and target names should both be "HTTP/mybox at DOMAIN.COM", and 
encryption types should be "Kerberos DES-CBC-MD5" or similar (not an RC4 
variant).

You can also look at the user you created previously.  After running 
ktpass to create the SPN, the user's logon name should have been changed 
to "HTTP/mybox"; under Account Options, "Use DES encryption types for 
this account" should be checked.

The account setup process is outlined in greater detail in the 
configuration instructions for Wedgetail's product (the procedure is 
pretty much the same, except their implementation supports RC4 tickets):

http://www.wedgetail.com/jcsi/sso/doc/guide/setup-ad.html


The jcifs.spnego package contains the "meat" of the implementation.  The 
jcifs.spnego.Authentication class is where the token examination and 
processing takes place.  Although the HTTP filter just uses the 
server/accept side, the client/initiate side is implemented as well; I 
haven't tested this, but it should be moderately simple to get HTTP 
SPNEGO client authentication working.  Extended authentication for CIFS 
should also be feasible; this would also likely require a significant 
(or at least non-trivial) redesign (since you no longer have an 
NtlmPasswordAuthentication per se).

Anyways, I figured this was a significant enough milestone to slap out 
there so it could get kicked around a bit ;)  I expect significant 
changes would be needed before putting this into the baseline jCIFS 
code.  Particularly (in random order, just floating for discussion):

1)  Figuring out a "higher-level" way to represent credentials/identity. 
  Currently, NtlmPasswordAuthentication is both; ideally, you'd supply a 
set of credentials and get back an authenticated identity.  This could 
be done using a model something like:

     public interface Credentials {

         public String getUsername();

         public String getPassword();

     }

     // in NtlmPasswordAuthentication:
     public class NtlmPasswordAuthentication implements Credentials,
             Principal {
         // still implements both credentials and identity
         // (Principal), but logically separated.
     }

     // in SmbFile:
     public SmbFile(String url, Credentials credentials) {
         // still backward compatible with current jCIFS constructor,
         // but allows for alternative credential representations.
     }

2)  Implementing extended authentication for SMB connections.  This 
shouldn't be terribly difficult, but I'm not exactly sure the best 
place/way to do it.  The guts of what is needed is in the 
jcifs.spnego.Authentication class; essentially, just send blobs back and 
forth until you get an authenticated principal established.  More 
information on how this is represented over the wire is on Richard 
Sharpe's site:

     http://www.richardsharpe.com/samba-stuff.html

Attached are some packet snips I grabbed showing what Kerberos and 
"wrapped" NTLM SPNEGO handshakes look like over SMB.

3)  SMB connections would also need to obtain the session key for 
signing.  The NTLM code is already there, pretty much (subtle 
differences for extended auth).  The corresponding Kerberos derivations 
would need to be implemented.  I'm also not sure if there is a 
difference in the session key used in "raw" and "wrapped" NTLM (i.e. 
NTLM negotiated via SPNEGO).

4)  It might also be useful to do all the JDK 1.4 dependent stuff using 
reflection.  This would be god-awful ugly, but would allow it to degrade 
elegantly to wrapped-NTLM SPNEGO if Kerberos/JGSS isn't available (and 
would also allow it to build on JDK 1.3 without the JGSS classes).

5)  Testing wrapped-NTLM SPNEGO (this is included in the attached, but I 
don't know if it actually works as I've been focusing on the Kerberos 
stuff).

6)  Possibly cleaning up/trimming down the ASN.1 parsing code (this was 
just snagged from BouncyCastle, as it was readily available and has a 
compatible license).


Anyways, good stuff to look at and a good starting point for future efforts.

Eric

-------------- next part --------------
A non-text attachment was scrubbed...
Name: jcifs-spnego.tgz
Type: application/x-tar
Size: 31364 bytes
Desc: not available
Url : http://lists.samba.org/archive/jcifs/attachments/20040601/bbe67796/jcifs-spnego-0001.tar
-------------- next part --------------
A non-text attachment was scrubbed...
Name: web.xml
Type: text/xml
Size: 2120 bytes
Desc: not available
Url : http://lists.samba.org/archive/jcifs/attachments/20040601/bbe67796/web-0001.xml
-------------- next part --------------
3jÛZržžÛ®æÛyÖ§v·¦¢÷
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smbkrbext.pcap
Type: application/octet-stream
Size: 2362 bytes
Desc: not available
Url : http://lists.samba.org/archive/jcifs/attachments/20040601/bbe67796/smbkrbext-0001.obj
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smbntlmext.pcap
Type: application/octet-stream
Size: 1839 bytes
Desc: not available
Url : http://lists.samba.org/archive/jcifs/attachments/20040601/bbe67796/smbntlmext-0001.obj


More information about the jcifs mailing list