Pure Java Waffle SSO problem

1,738 views
Skip to first unread message

Greg

unread,
Jan 9, 2013, 5:09:37 PM1/9/13
to waffle...@googlegroups.com
I am trying to using Waffle 1.5 to implement single sign on for a service (not a web service) using pure java and waffle-jna.
I'm running this on Windows Server 2008R2 with ActiveDirectory configured to use Kerberos.

I looked at the method codetestAcceptSecurityToken() in WindowsAuthProviderTests.java for clues on how to do this.
What it looks like is that I need to send enough information to reconstruct the clientContext on the server side.
Sending the principal name and the token should be enough. However, I cannot get it to work.
Below is my code for the client and server.

Client Code:

// Get the identity and credentials of the current user.
String spn = "HOST/xyz.domain.com:8999";
IWindowsSecurityContext clientContext = WindowsSecurityContextImpl.getCurrent("Negotiate", spn);
String principalName = clientContext.getPrincipalName();
byte[] token = clientContext.getToken();
// Send principalName and token to remote server for SSO authentication...


Server Code:
============
// Have received principalName and token from client...
// Reconstruct client context.
String securityPackage = "Negotiate";
String spn = "HOST/xyz.domain.com:8999";
IWindowsCredentialsHandle credHandle = new WindowsCredentialsHandleImpl(
                    principalName,
                    Sspi.SECPKG_CRED_OUTBOUND,
                    securityPackage
                );
credHandle.initialize();
WindowsSecurityContextImpl clientContext = new WindowsSecurityContextImpl();
clientContext.setPrincipalName(principalName);
clientContext.setCredentialsHandle(credHandle.getHandle());
clientContext.setSecurityPackage(securityPackage);
clientContext.initialize(null, new SecBufferDesc(Sspi.SECBUFFER_TOKEN, credential.getToken()), spn);

// Create the Auth Provider
WindowsAuthProviderImpl provider = new WindowsAuthProviderImpl();
IWindowsSecurityContext serverContext = null;
String connectionId = principalName + Thread.currentThread().getId();
do {           
    serverContext = provider.acceptSecurityToken(connectionId, clientContext.getToken(), securityPackage);
    if (serverContext != null && serverContext.isContinue()) {
        SecBufferDesc continueToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, serverContext.getToken());
        clientContext.initialize(clientContext.getHandle(), continueToken, spn);
    }
} while (clientContext.isContinue() || serverContext.isContinue());

When I run this code, the sever goes through the do/while loop ok the first time. At the end, clientContext.isContinue() is true and serverContext.isContinue() is true.
On the next pass through the loop, the call to provider.acceptSecurityToken() calls Secur32.INSTANCE.acceptSecurityToken(), which returns 0. At the end of the loop, clientContext.isContinue() is false but serverContext.isContinue() is still true. So it goes around the loop again.
Then on the third call to provider.acceptSecurityToken it throws a Win32Exception with rc = -2146893048 which is SEC_E_INVALID_TOKEN.
Can somebody please tell me what I'm doing wrong?

Greg

unread,
Jan 9, 2013, 5:31:48 PM1/9/13
to waffle...@googlegroups.com

Oops. A correction to the last paragraph. After the second pass through the do/while loop, clientContext.isContinue() is still true and serverContext.isContinue is false.

Daniel Doubrovkine

unread,
Jan 9, 2013, 6:41:55 PM1/9/13
to waffle...@googlegroups.com
So this code is for both client and server. 

What you should be seinding is those opaque buffers: from client send clientContext.getToken(), then from server send back serverContext.getToken(), etc, until done.

Someone actually wrote what you're trying to accomplish: https://github.com/gschrader/ssoexample-waffle

cheers
dB.



On Wed, Jan 9, 2013 at 5:31 PM, Greg <greg.s...@gmail.com> wrote:

Oops. A correction to the last paragraph. After the second pass through the do/while loop, clientContext.isContinue() is still true and serverContext.isContinue is false.




Greg

unread,
Jan 10, 2013, 10:56:23 AM1/10/13
to waffle...@googlegroups.com


On Wednesday, January 9, 2013 6:41:55 PM UTC-5, Daniel Doubrovkine wrote:
So this code is for both client and server. 

What you should be seinding is those opaque buffers: from client send clientContext.getToken(), then from server send back serverContext.getToken(), etc, until done.


I don't have a way to keep sending tokens back and forth. My customer expects me to send the service a valid credential the first time. They have a single login method in their service interface. I can add some code to the login implementation on the server side to accept a "waffle credential", but I have only a single call to login and no way to add methods to the service interface. Is there some way to do this in one shot?

Daniel Doubrovkine

unread,
Jan 10, 2013, 11:04:49 AM1/10/13
to waffle...@googlegroups.com
Now I am confused. If you don't control both the client and the server, you can't establish a secure scheme between the two. You can't just have a client decide "I authenticated Bob" and then tell the server "trust me, it's Bob", someone else would be able to do the same. 

Unless you already have another secure mechanism to authenticate with the service? If so, why do you need Waffle at all? Don't you just need to know the username of the currently logged in Windows user (which is trivial)?


Greg

unread,
Jan 10, 2013, 12:52:45 PM1/10/13
to waffle...@googlegroups.com
The customer has a service written in Java. In the past, it supported kerberos-based SSO authentication using GSSAPI talking to Active Directory. The service interface has a single login method that accepts a username and a credential (a byte array). The client interface sent a Kerberos service ticket as the credential. This doesn't work with Windows Server 2008R2, apparently, although it did work with Windows Server 2003. They can't get a service ticket out of Active Directory on WinSvr 2008R2.

So I thought we might be able to use .NET via waffle to get a token/ticket.  My question is, does waffle have a way of sending a single credential to the server to authenticate the client. Or does it have to engage in the token handshaking?  (And is that the change that broke their GSSAPI code)?

If somebody knows how to get a service ticket using GSSAPI with Windows Server 2008R2, that would also be a solution. Searching the web has only revealed a host of people who couldn't get it to work.

 

Daniel Doubrovkine

unread,
Jan 10, 2013, 12:56:32 PM1/10/13
to waffle...@googlegroups.com
You're asking the right question. See if @gschrader implemented this in https://github.com/gschrader/ssoexample-gss, I believe he did.
Reply all
Reply to author
Forward
0 new messages