Windows Environment SSO and Java
In windows based enterprise environment, most applications are integrated using single sign-on(SSO) functionality. What is single sign-on,
According to wikipedia:
Single sign-on (SSO) is a property of access control of multiple related, but independent software systems. With this property a user logs in once and gains access to all systems without being prompted to log in again at each of them.
Simply, single sign-on allows enterprise users to access different range of applications using their same domain credentials.
Recently I was facing a scenario where I need to access some resources programmatically using Java. Its a HTTP based resource, its protected based on windows authentication and I was using Oracle Java 6. According to following guide http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-auth.html, built in http handler handles the http authentication.
I ran into problem, where I was running the developer environment using my domain account (senthadev\dev) and I have to use a different domain account(senthavde\qatest) to access the resource. It wasn't possible since java always used my developer domain account to authenticate and my account does not have access. How to solve this?
While searching for an solution, I ran into some suggestions such as to override the default library, bytecode patching etc..
Then I found an interesting project called Waffle https://github.com/dblock/waffle
Its a 100% java library which uses Windows SSPI to provide SSO funcationality. I used it to impersonate the java threads as a senthadev\qatest user and then access the http resource.
Here is the maven code to include the waffle library:
<dependency>
<groupId>com.github.dblock.waffle</groupId>
<artifactId>waffle-jna</artifactId>
<version>1.5</version>
</dependency>
And the sample java code:
package com.senthadev.winlogon;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinBase;
import waffle.windows.auth.IWindowsAuthProvider;
import waffle.windows.auth.IWindowsIdentity;
import waffle.windows.auth.IWindowsImpersonationContext;
import waffle.windows.auth.impl.WindowsAuthProviderImpl;
public class WinLoginAuth {
public static void main(String [] args){
String username = "qatest";
String password = "change_me";
String domain = "senthadev";
int logonType = WinBase.LOGON32_LOGON_INTERACTIVE;
int logonProvider = WinBase.LOGON32_PROVIDER_DEFAULT;
IWindowsAuthProvider authProvider = new WindowsAuthProviderImpl();
IWindowsIdentity userIdentity = null;
IWindowsImpersonationContext impoContext = null;
try{
userIdentity = authProvider.logonDomainUserEx(username, domain, password, logonType, logonProvider);
System.out.println("Welcome :" + userIdentity.getFqn());
impoContext = userIdentity.impersonate();
System.out.println("Current thread is running as :" + Advapi32Util.getUserName());
//Access the resource behind SSO
URL url = new URL("https://win.senthadev.com/protected/report");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
//do the job as senthadev\qates
conn.disconnect();
}
catch(Win32Exception winEx){
System.out.println("Oops!! " + winEx.getMessage());
}
catch(Exception ex){
System.out.println("Main Oops!! " + ex.getMessage());
}
finally{
if (impoContext != null)
impoContext.revertToSelf();
if (userIdentity != null)
userIdentity.dispose();
authProvider = null;
}
}
}