fb
WSO2 Identity Server 6 min

WSO2 Identity Server & Integrated Windows Authentication on Linux

Joris Jansen
Joris Jansen
Consultant
wso2 is
Scroll

wso2-is.pngAs you might know, WSO2 Identity Server does support Integrated Windows Authentication (IWA) out of the box, as long as you run WSO2IS on a Windows server, if you want to run WSO2IS on a Linux server, you have to figure it out yourself.

For everybody who wants IWA on a Linux server, I managed to get IWA for WSO2IS 5.0.0 working in a proof of concept (POC) on a Linux VM using the SPNEGO library and some custom components. I will explain what I did during the POC in this blog.

Prerequisites

Besides a linux server, you also need two Windows machines/nodes. I used two VirtualBox VM’s connected to each other and my host (a linux laptop) using a ‘Host Only adapter’ with host IP-address 192.168.56.1 and net mask 255.255.255.0:

  • One domain server (I used a Windows 2012 Server R2):
    • Hostame: dc.root.testdomain
    • Domain: DN: DC=root, DC=testdomain
    • Fixed IP address: 192.168.56.102
      Default Gateway: 192.168.56.1
  • One Windows desktop which has joined the domain (I used Windows7):
    • Hostname client.root.testdomain
    • Included in the domain: DN: DC=root, DC=testdomain
    • Use DHCP to get an IP address.

The details of setting up the MS Windows cluster is not in the scope of this blog, to be honest, I needed the help of a co worker myself to get this working. (I am much more comfortable on a linux/unix system.)

Testing the Domain setup / SPNEGO configuration

To test if your setup is working correctly, check if you can pass the spnego pre flight check.
See http://spnego.sourceforge.net/pre_flight.html for this pre flight check.
During this pre flight check, you will create a krb5.conf file and a login.conf with the values from your environment.
 

The content of my krb5.conf:

[libdefaults]
        default_realm = ROOT.TESTDOMAIN
        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

[realms]
        ROOT.TESTDOMAIN  = {
                kdc = dc.root.testdomain
                default_domain = ROOT.TESTDOMAIN

[domain_realm]
        .ROOT.TESTDOMAIN = ROOT.TESTDOMAIN

The content of my login.conf:

spnego-client {
        com.sun.security.auth.module.Krb5LoginModule required;
}; 
spnego-server {
        com.sun.security.auth.module.Krb5LoginModule required
        storeKey=true
        isInitiator=false;
};

Some background information

A SPNEGO authentication scenario typically includes two HTTP Requests:

  • When the first request is sent without an authorization header, a 401 is returned by the SPNEGO library with a ‘WWW-Authenticate: Negotiate’ header to inform the browser to try again with a Kerberos token.
    (Instead of Negotiate, the headers value can also be set to ‘Basic’ allowing the browser to pass credentials using Basic authentication instead of Kerberos.)
  • The browser will react with a new request in which it passes its Kerberos token in the authorization header.

This scenario differs from the scenarios described in the custom authenticator examples given by WSO2 and caused me some troubles during the development. I don’t think I would have been able to figure out what I had to do without a) the sources and b) remote debugging of the IS server using an IDE like IntelliJ. That’s why I love open source!

Implementing the Authenticator

While implementing a custom authenticator for the Identity Server, one has to implement the ApplicationAuthenticator interface. This can easily be done by extending the AbstractApplicationAuthenticator provided by WSO2. For the proof of concept I implemented the following methods: 

public AuthenticatorFlowStatus process(…)
In this method the authentication and logout requests are processed. For the POC I return SUCCESS_COMPLETED for a logout request. For a login request, the process method of the super class is called. The parent’s process method calls several methods of the custom authenticator, like canHandle, processAuthenticationResponse, initiateAuthenticationRequest, …

public boolean canHandle(…)
When this method is called, the authenticator must tell if it can or cannot handle the request. For the POC, I just return true when the spnegoAuthenticator property is not null. In a more complete implementation one can check the origin of the request to determine if the authenticator should/can handle the request or not.

protected void initiateAuthenticationRequest(…)
In this method an extra property is set in the AuthenticationContext. The purpose of this extra property to tell the KerberosRequestCoordinator not to remove the authentication request from the cache when the Spnego library does not authenticate the user in the first call.

protected abstract void processAuthenticationResponse(…)
In this method, the SPNEGO library is used to authenticate the user. When the user is authenticated successfully, properties of the returned Principal object are used to fill a Subject object. This Subject is placed in the AuthenticationContext.

protected boolean retryAuthenticationEnabled ()
This method is called by the Identity Server to determine if it should try to authenticate a user again or not. I introduced the variable retryAuthentication to indicate if the server should or not. This variable is set in the authenticate method, called by the processAuthenticationResponse method.

public String getContextIdentifier(HttpServletRequest httpServletRequest)
This method returns a unique identifier that maps the authentication request and the response.

public String getName()
This method must return the Authenticators name.

public String getFriendlyName()
This method must return the Authenticators friendly name.

Explanation

As mentioned earlier, when the first request does not include an authorization  header, a rewrite is returned with by the authenticator. The DefaultRequestCoordinator does remove the AuthenticationRequest from its cache when the (first) request doe not lead to a successful authentication. To keep all information in the cache after the first request does not result in a successful authentication I had to implement my own RequestCoordinator, the KerberosRequestCoordinator:

In this class, which extends the DefaultRequestCoordinator, I added one global variable yenloKerberosKeepAuthenticationRequest added a few lines of code to the method public void handle(…)

The whole trick here is keep the authenticationRequest in the cache when the SPNEGO library asks the browser to add the  authorization header in a new request. Without this slight modification, the RequestCoordinator removes the authenticationRequest from the cache. This is done by adding an if statement around the line:

FrameworkUtils.removeAuthenticationRequestFromCache(request.getParameter(“sessionDataKey”));

Without this modification, when the SPNEGO library does return a Principal when the second request (with authentication header) is posted the  RequestCoordinator could not find the authenticationRequest, and as a result, the user was not redirected to the protected resource.

Configuring IE on the Windows client machine

When you specify a server by a fqdn or ip address, even when the machine is in the same subnet as the machine IE runs on, the browser treats the server as aone belonging to the Internet zone instead of in the Local intranet zone. Therefore the browser will not send it’s authentication token to the server. In my setup I had to explicitly add my server (in fact my own laptop) to the local Intranet zone. See link below for more information.

Next step(s)

  • As mentioned, this POC was done with WSO2IS 5.0.0. I have not tested it on 5.1.0 yet.
  • The KerberosAuthenticator does not get the Roles from the AD server. When you want to use the IWA for real, you definitely want to get the Roles from AD too.

Links:
http://spnego.sourceforge.net/
https://support.microsoft.com/en-us/kb/303650 

If you have any questions about this blogpost contact us via the comments section of this blog. View also our WSO2 Tutorialswebinars or white papers for more technical information. Need support? We do deliver WSO2 Product Support, WSO2 Development SupportWSO2 Operational Support and WSO2 Training Programs.

{{cta(‘669e39b2-a865-478e-b9f1-7c247102bf01’)}}

Full API lifecycle Management Selection Guide

WHITEPAPER

smartmockups l0qqucke