NEGOTIATE authentication

This type of authentication is used in for example MS Windows Domains and can utilize SPNEGO, NTLM or Kerberos authentication.

The flow is the following (the same steps as are given here or here but in terms of browser / Web server interaction; also local developers please check here):

  • The user authenticates itself once he logins into the system. The system sends the credentials to authentication server and receives back the client session ticket (also called TGT), which is stored safely on the client and authenticates the client (e.g. the user).
  • Browser access a secured resource in some Web application. The Web server responds with a 401 response containing special header WWW-Authenticate: NEGOTIATE.
  • The NEGOTIATE-aware browser realizes it needs to acquire a service ticket for the given URL (service). It first tries the Kerberos authentication: it sends a request to the KDC and acquires the service ticket that will be used to authenticate the client to the service. If the browser fails on some reason (service is not registered in KDC (see below note) or user is rejected to access the service), the browser falls-back to NTLM authentication: it displays the login box (that looks like one you would see with BASIC authentication) and the entered credentials are transferred in an encrypted NTLM block.
  • The browser tries to access the same resource URL as before but this time it adds WWW-authorization: NEGOTIATE encoded-spnego-token header to the HTTP request. Here encoded-spnego-token is the SPNEGO token encoded in base64 which is basically a wrapper for the service ticket or NTLM block.
  • The authenticator on Web server unwraps the SPNEGO token and gets the service ticket. Using the secret key (shared only by Web server and KDC) it decodes the service ticket and makes sure the timestamp is close enough to the current time. Those two steps are the validation that this is the user that sent the ticket. If all passes, the user is valid to request a service.
  • The authenticator returns true, and passes control to the servlet container which sends back the requested resource. Otherwise, a 403 response is sent back to the browser.

GSS API is an standard API / Protocol for authentication and authorization. JGSSAPI is the Java implementation of this API.

JAAS is an authentication and authorization model, created by Sun. JBoss implemented their security model using JAAS model. This enables any person to plug their own authentication and authorization modules into JBoss security module. JGSS Sun's implementation is using JAAS model for accessing ADS. See When to use Java GSS-API vs. JSSE for more information.

A service secret key is created when registering the service principal in ADS (which looks like HTTP/host.fqdn.com@KERBEROS-REALM). This is done using the utility ktpass.exe. One of its arguments is the keytab file location to save the secret key to. This keytab contains the list of pairs “service principal name → secret key” (which is derived from the Kerberos password). You should place this in a secure / non-public-access location. In JBoss you define the location of the the keytab via <application-policy> in conf/login-config.xml (is implementation-specific). The authenticator searches the keytab for a pre-configured service principal and retrieves the service secret key. In Tomcat, since you don't have login-config.xml, you need to define this in a separate configuration file.

You can different approaches to implement SSO on Tomcat/JBoss here and here but:

References

2014/01/20 12:33 Dmitry Katsubo
2010/02/13 23:22  
2013/01/14 15:52 Dmitry Katsubo
2010/05/26 10:27 Dmitry Katsubo

Further reading

Questions answered

How to verify that the service ticket has OK-AS-DELEGATE flag enabled in ADS?

  • :OPT: Refresh your personal TGT:
    $ kinit
    Password for user123@REALM.COMPANY.ORG: *****
  • Populate the credentials' cache with the service ticket (the requested endpoint should be secured):
    $ curl --negotiate -u : http://service-id.company.org/status
    No resource method found for GET, return 405 with Allow header
  • The O flag reported for HTTP/service-id.company.org means that ok-as-delegate is enabled:
    $ klist -f
    Ticket cache: FILE:/tmp/krb5cc
    Default principal: user123@REALM.COMPANY.ORG
    
    Valid starting     Expires            Service principal
    02/07/17 16:02:30  02/08/17 05:02:23  HTTP/service-id.company.org@REALM.COMPANY.ORG
            renew until 02/08/17 16:02:22, Flags: FRAO

For description of flags check Kerberos ticket properties.

How to create keytab for the given user?

From Creating kerberos keytab files compatible with Active Directory:

On Linux:

user123@host:~> ktutil
ktutil:  addent -password -p USER123@REALM.COMPANY.ORG -k 1 -e RC4-HMAC
Password for USER123@REALM.COMPANY.ORG: *****
ktutil:  wkt USER123.keytab
ktutil:  q

On Windows:

C:\> ktab -a USER123@REALM.COMPANY.ORG -k USER123.keytab
Password for USER123@REALM.COMPANY.ORG:*****
Done!
Service key for USER123@REALM.COMPANY.ORG is saved in USER123.keytab

or

C:\> ktab -a USER123@REALM.COMPANY.ORG <password> -k USER123.keytab

Now this keytab can be used in KerberosRestTemplate or in login.config (to be passed to Java via -Djava.security.auth.login.config=login.config):

// Login entry for a Kerberos client (initiator of a secure Kerberos connection):
com.sun.security.jgss.krb5.initiate {
    com.sun.security.auth.module.Krb5LoginModule required
    storeKey=true
    useKeyTab=true
    doNotPrompt=true
    principal="USER123@REALM.COMPANY.ORG"
    keyTab="USER123.keytab"
    ;
};

If you get javax.security.auth.login.LoginException: No key to store exception when using the keytab, then remove your ticket cache (rm /tmp/krb5cc_nnnn).

Username can be written in lower case (user123) provided that it matches principal in login.config.

Troubleshooting NEGOTIATE authentication

  • Define -Dsun.security.krb5.debug=true
  • Define -Dsun.security.spnego.debug=true
  • Add debug=true to module configuration in login.config.

Check also:

GSSException: Defective token detected

GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
    at sun.security.jgss.GSSHeader.<init>(GSSHeader.java:80)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:287)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:267)
    at org.eclipse.jetty.security.SpnegoLoginService.login(SpnegoLoginService.java:132)
    at org.eclipse.jetty.security.authentication.SpnegoAuthenticator.validateRequest(SpnegoAuthenticator.java:80)

From here:

Make sure you are using the browser from different machine as the server.

KrbException: Cannot find key of appropriate type to decrypt AP REP - RC4 with HMAC

KrbException: Invalid argument (400) - Cannot find key of appropriate type to decrypt AP REP - RC4 with HMAC
    at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:263)
    at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:134)
    at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:79)
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:724)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:323)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:267)
    at sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(SpNegoContext.java:874)
    at sun.security.jgss.spnego.SpNegoContext.acceptSecContext(SpNegoContext.java:541)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:323)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:267)
    at org.eclipse.jetty.security.SpnegoLoginService.login(SpnegoLoginService.java:132)

AD uses rc4-hmac in Authentication Protocol (AP) reply. In order to use des-cbc-md5 one must activate the Use Kerberos DES encryption types for this account setting for server user account otherwise you get stuck in rc4-hmac mode (which apparently is default in Win2K8 R2 and later).

References:

To be sure also check that des-cbc-md5 (Kerberos encryption type 3) is the one listed in your keytab file:

$ klist -e -k service.keytab

[1] Service principal: HTTP/service-id.company.org@REALM.COMPANY.ORG
         KVNO: 3
         Key type: 3

Otherwise you need to regenerate the keytab file (see Cannot find key of appropriate type to decrypt AP REP, "Cannot find key of appropriate type to decrypt" error again on W2k8).

What is the application of javax.security.auth.useSubjectCredsOnly?

From Use of Java GSS-API for Secure Message Exchanges Without JAAS Programming:

Setting the system property javax.security.auth.useSubjectCredsOnly to false allows us to relax the usual restriction of requiring a GSS mechanism to obtain necessary credentials from an existing Subject, set up by JAAS. When this restriction is relaxed, it allows the mechanism to obtain credentials from some vendor-specific location. For example, some vendors might choose to use the operating system's cache if one exists, while others might choose to read from a protected file on disk.

When this restriction is relaxed, Sun Microsystem's Kerberos mechanism still looks for the credentials in the Subject associated with the thread's access control context, but if it doesn't find any there, it performs JAAS authentication using a Kerberos module to obtain new ones. The Kerberos module prompts you for a Kerberos principal name and password. Note that Kerberos mechanism implementations from other vendors may behave differently when this property is set to false. Consult their documentation to determine their implementation's behavior.

programming/java/spnego.txt · Last modified: 2017/03/28 23:38 by dmitry
 
 
Recent changes RSS feed Driven by DokuWiki