Friday, January 18. 2013
SPNEGO/Kerberos in JavaEE
In the previous entry a Samba 4 DC was setup and a Windows 2008R2 client was successfully joined to it. I was thinking how to extend or use the domain (in order to test a bit deeper the Samba version) when I found an article about integrating SPNEGO/Kerberos security in weblogic. It was a elegant idea for the blog but, as always, I prefer to do it with opensource software.
SPENEGO is a generic mechanism that let a server and a client negotiate one of a number of possible real mechanisms for some purpose. Microsoft added this idea to the web for HTTP authentication, browser and server look for a common mechanism of authentication. Obviously NTLM and Kerberos, both are techniques supported by AD, are possible choices. This entry deals with Kerberos which is an authentication protocol based on tickets and cryptography and intimately related to AD.
Using SPNEGO/Kerberos a web application can authenticate the users previously logged in the domain (Samba4 domain in our case). This way any employee logged in his working Windows computer will not need to re-authenticate again to use the application. It can be said that it is a Single SignOn (SSO) for Windows environments. In a very brief explanation SPNEGO/Kerberos works in the following way:
- Client browser does HTTP GET/POST for a resource.
- Web server returns HTTP 401 status (unauthorized) but with a header that marks it wants SPNEGO negotiation (WWW-Authenticate: Negotiate).
- Client generates a Kerberos token, base64 encodes it, and resubmits the request with an Authorization header with the token (Authorization: Negotiate <base64 token>).
- Server decodes the token, extracts the information and authenticates it against the Kerberos Key Distribution Center (KDC).
- Once the client has been authenticated the Web server returns the HTTP 200 status (OK), a final WWW-Authenticate header and the page content.
Searching over the internet I found a very interesting project SPNEGO. This project is a Java filter that implements SPNEGO/Kerberos authentication. The filter after performing the commented algorithm injects the kerberos principal as the Servlet Request Principal. Although the project seems to have not been modified in the last two years it will save me a lot of implementation in this little PoC.
In summary today's entry explains how to add the SPNEGO filter to a Java web application in order to transparently authenticate users against a Samba4 domain. I decided to use a glassfish v3 server in the same machine where Samba DC was installed. I have to admit that all the configuration is very tricky and I was completely lost until I found this useful howto from Documentum DAA blog.
As I have to use some windows tools to configure the Samba domain (nice, isn't it?) the Remote Administration tools were installed in the windows 2008R2 member.
- Start→Computer→Manage.
- Select Features on the left tree.
- Click Add Features at the right.
- In the Remote Administration Tools select the following items:
- Active Directory Certificate Service Tools.
- AD DS and AD LDS Tools.
- DNS Server Tools.
I added a lot, probably more than needed but forgive me, I am not a Windows sysadmin.
A service account was created in the AD (account name glassfishserver). This account supports AES 128 bit encryption and password never expires options were checked (I am not really sure if the first check is really needed).
Then some Service Principal Names (SPN) were added to the account in order to be a valid HTTP server (again the commands were executed from a cmd console in the windows machine). Cos the glassfish server is going to be installed in the samba machine both names (fully qualified and the short one) were added to the service account.
> setspn -A HTTP/samba glassfishserver Registering ServicePrincipalNames for CN=glassfishserver,CN=Users,DC=kvm,DC=test HTTP/samba Updated object > setspn -A HTTP/samba.kvm.test glassfishserver Registering ServicePrincipalNames for CN=glassfishserver,CN=Users,DC=kvm,DC=test HTTP/samba.kvm.test Updated object > setspn -l glassfishserver Registered ServicePrincipalNames for CN=glassfishserver,CN=Users,DC=kvm,DC=test: HTTP/samba HTTP/samba.kvm.test
Finally, to finish with the account, the keytab was generated:
> ktab.exe -a HTTP/samba.kvm.test <password> -k glassfishserver.keytab Done! Service key for HTTP/samba.kvm.test is saved in glassfishserver.keytab
The file was generated using ktab command from Java Windows machine (I have read that generating keytabs with other commands can produce further problems, but I am not sure again).
Once the service account was ready a glassfish 3.1.2.2 was installed in the samba machine (default installation using wheezy openjdk-6). The kerberos configuration file was added in ${GLASSFISH_DIR}/glassfish/domains/domain1/config/krb5.conf.
[libdefaults] default_tkt_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc default_tgs_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc permitted_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc default_realm = KVM.TEST [realms] KVM.TEST = { kdc = samba.kvm.test default_domain = KVM.TEST } [domain_realm] .KVM.TEST = KVM.TEST
And two login modules for the SPNEGO filter were added to the ${GLASSFISH_DIR}/glassfish/domains/domain1/config/login.conf configuration.
spnego-client { com.sun.security.auth.module.Krb5LoginModule required; }; spnego-server { com.sun.security.auth.module.Krb5LoginModule required useKeyTab=true storeKey=true keyTab=glassfishserver.keytab principal="HTTP/samba.kvm.test" isInitiator=false; };
Obviously the keytab file previously generated was also located in the glassfish domain config directory. At this point all the java examples that the DMDAA entry comments about were executed obtaining the expected results.
With all the Kerberos configuration finished a hello-spnego.war file was created with the SPNEGO filter configuration in the web.xml and the spnego-r7.jar file in the lib directory. Here I present the relevant configuration for the filter.
<filter> <description>SPNEGO filter</description> <filter-name>SpnegoHttpFilter</filter-name> <filter-class>net.sourceforge.spnego.SpnegoHttpFilter</filter-class> <init-param> <param-name>spnego.allow.basic</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>spnego.allow.localhost</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>spnego.allow.unsecure.basic</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>spnego.login.client.module</param-name> <param-value>spnego-client</param-value> </init-param> <init-param> <param-name>spnego.krb5.conf</param-name> <param-value>krb5.conf</param-value> </init-param> <init-param> <param-name>spnego.login.conf</param-name> <param-value>login.conf</param-value> </init-param> <init-param> <param-name>spnego.login.server.module</param-name> <param-value>spnego-server</param-value> </init-param> <init-param> <param-name>spnego.prompt.ntlm</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>spnego.logger.level</param-name> <param-value>1</param-value> </init-param> </filter> <filter-mapping> <filter-name>SpnegoHttpFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
The WAR was deployed to the glassfish server.
Finally just the testing remains but the browser should be configured before in order to send the authentication token. I just tested with two different clients although all common browsers supports it:
Firefox (18.0): In the about:config page the samba URI should be added as trusted.
Set network.negotiate-auth.trusted-uris to http://samba.kvm.test:8080/hello-spnego
IE8: Tools→Internet Options→Security Tab→Select Local Intranet.
Add the server http://samba.kvm.test.
Check that in Advanced tab Enable Integrated Windows Authetincation is enabled.
And that's all. You can see a video were I do a transparent login using both browsers:
The SPNEGO filter is working perfectly in a Samba4 domain inside a glassfish server. As you see in this entry I just reused some code from another project and, as usual, it is not very complicated if you follow the steps one by one (I have to say again that I found myself walking in circles until I followed the DMDAA entry). The SPNEGO filter project has some things I do not like too much but, it is clear, it works. This solution has only one problem for me, the user group membership information is not present to the server/application and that means no authorization is possible in JavaEE (custom or standard)... I am working on it.
Negotiated regards!
Comments