Mar 14, 2012 at 7:14 PM
Edited Mar 14, 2012 at 8:30 PM
We have a Swing Java application that connects to a Java server that we need to support SSO with. We're able to modify the example given under the "Negotiate: single sign-on" section
here. We use Netty to pass tokens back and forth. I have split the code out into a simple example and made it available
here. A number of people have asked for this on the discussion board so hopefully others will find it useful.
This seems to work fine for us however it appears that it will fallback and use NTLM and not use Kerberos. We need to get Kerberos working since we have a customer that needs to support multiple domains.
Our network guy has done some tracing and found that it looks like we need to pass a server name as well as the SPN. I'm just not seeing where to pass anything else in the API. I'm assuming that we pass the SPN for places that require the targetName
parameter, the documentation isn't clear on what needs to be passed it states it's dependant on the security package, but even on
MSDN it's not clear what to pass:
clientContext = WindowsSecurityContextImpl.getCurrent("Negotiate", cmd.getOptionValue("s"));
clientContext.initialize(clientContext.getHandle(), continueToken, cmd.getOptionValue("s"));
Can anyone offer some insight on what we need to pass in this instance?
Here is the tracing the network guy has found:
The situation is that the Kerberos authentication is failing on the TGS-REQ from the client.
By design, the authentication mechanism fails over to NTLM, which works in certain situations, i.e. single-domain Active Directory environments.
Our client implementation, (where NTLM is not working) is a multi-domain environment.
NTLM authentication is not an acceptable option for this implementation.
This is obviously confusing because all of this happens within the wire and you cannot tell which authentication mechanism (Kerberos or NTLM) is performing the authentication without using a network monitor/analyzer (we are using
wire-shark). Most of the information below is from wire-shark.
The error on the TGS-REQ is:
- KRB Error : KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
This typically means that the SPN for the service is not registered for the service, however in this case it is (see below)
C:\Users\networkadmin>setspn -l SRV790
Registered ServicePrincipalNames for CN=SRV790,CN=Computers,DC=Company,DC=com:
When you dig a little deeper into the TGS-REQ and KRB Error packets, you see that the TGS request uses the same parameter for both the Server Name and the Service Name
- Kerberos KRB-Error
- Server Name (Principal): sso_srv_44
- Name-Type: Principal (1)
- Name: sso_srv_44
In doing some trial and error, I renamed the server (hosting the service) to be the same name as the service (sso_srv_44).
I then re-registered the service SPN under the new hostname, which effectively matches the parameters from the above error message:
C:\Users\networkadmin>setspn -l sso_srv_44
Registered ServicePrincipalNames for CN= sso_srv_44,CN=Computers,DC=Company,DC=com:
When the server name and the service name are the same in the SPN, the TGS-REQ works and the SSO over Kerberos works.
This was all verified using the network/protocol analyzer. You see the client-side TGS-REQ and successful replies and you see the successful server-side Kerberos communication/authentication between the service-host and the domain controller.