Kerberos / SPNEGO based SSO (Single Sign-On) in Weblogic

This blog is about enabling SSO (Single Sign-On  Kerberos/ SPNEGO) on  a java web application running on a weblogic 12c. The end user is a windows PC, and the application server is Weblogic running on UNIX. User group information is looked up in Active Directory.

SSO implementation using Kerberos/SPNEGO requires a good understanding of Kerberos/ SPNEGO protocol and also a bit of patience. Getting it to work the first time could get very frustrating, specially figuring out why it's not working and debugging kerberos error messages. However, when it works, it works like a charm.

What is Kerberos?

Kerberos is an industry standard authentication protocol for client-server systems. It is used to identify and validate the identity of  a user requesting a service. The Following diagram and subsequent explanation describe sequence of events (high level) that take place in a Kerberos/SPNEGO authentication:


  1. A user requests a secured Web Resource. 
  2. The server responds with 401 unauthorized; challenge header “Authenticate: Negotiate”.
  3. The browser recognizes the negotiate header because it is configured to support Integrated Windows Authentication (described later in blog).The browser parses the requested URL for the host name and uses the host name as an attribute to request a valid Kerberos service ticket from the Ticket Granting Service (TGS) in Active Directory.
  4. If the user is identified, the TGS responds with a Service Ticket.
  5. The browser puts this Kerberos ticket in an SPNEGO token and includes SPNEGO token in the request HTTP header and resend's the request for the web resource to server.
  6. The server sees the HTTP header with the SPNEGO token. It extracts the Kerberos ticket and validates the ticket. After validation, the server checks authorization.
  7. If authorized, the server serves the requested secured resource. Otherwise, it responds with access denied.

Setting up Kerberos


Kerberos SPNEGO authentication setup process is a bit complex; to simplify things, I have broken it down into 5 different steps, and at the end of every step included a verification process; hopefully following the step-wise instruction and verification makes -  weblogic Kerberos /SPNEGO setup easy for you. Here are the steps:
  1. Register Service - Configure Service Principal Name and Service Account in Domain Controller
  2. Create Kerberos artifacts like keytab file & krb5.config file.
  3. Weblogic Kerberos setup.
  4. Kerberos Security setup in the application.
  5. SPPNEGO/Kerberos setup on client machine. 

Step 1) Register Service - Create Service Account and configure Service Principal Name in Domain Controller

Create logon/service user account:

Log into AD and create a user account (for your service). You can create a user by any name, but generally the machine/domain name of Application Server is used. For example, if the Application Server is running on a machine with domain name krba01.incept.lab, then the user in Active Directory is called "krba01" or "service_krba01". So onto creating a user account,
  • Launch Programs/Administrative Tools/Active Directory Users and Computers tool.
  • Right click on the Users node and select New/User. (Do not select Machine.)
  • Type in the user “service_krba01” in the "Full Name" field and in the "Logon Name" field.
  • Click Next, and enter a password (note it down, you will need it)
  • Enable "Password never expires"
  • Disable "User must change password at next logon".
  • Click Finish.
Now configure the User account to comply with the Kerberos Protocol

  • Reopen the user account and go to the "Account" tab.
  • On the "Account" tab, make sure at-least following encryption suites are checked
             1) This account supports AES 128 bit encryption is checked
             2) This account supports AES 256 bit encryption is checked
             3) This account supportsRC4-HMAC-NT is checked.
  • Click OK.
This user account will be used later while creating a SPN and  keytab; Now, on to creating SPN:

What is SPN?

An SPN (Service Principal Name) is a unique name that identifies a service i.e. it is an unique identifier for the service/ web application (in our case) which is running on the server. A SPN is associated with a service account. The SPN is used in the process of mutual authentication between the client and the server hosting a particular service. 

A service principal name (SPN) is of the form:
service/machine@realm
where:
"service" indicates the name of the software service (HTTP)
"machine" indicates the name of the server machine. It must match the URL that the user enters in the browser.
"realm" indicates the Kerberos security realm {optional}

example:HTTP/web.somedomain.com



Create SPN

On the Active Directory, open up command prompt and type following command (assuming you have admin rights)

setspn -s HTTP/krba01.incept.lab  service_krba01

where krba01.incept.lab is the domain name of my application and service_krba01 is the service account under which this service runs.


Note:
Setspn also has an –A option that you can use to add SPNs, but you should use Setspn -S instead because -S will verify that there are no duplicate SPNs. However, if you are using Windows Server 2003 or earlier, you will not be able to use the -S switch because it is not available for that platform. 



Verify

To verify that the SPN is correct; run following command on a command prompt.
setspn -l service-account-name
Output of the command is the SPN that you just created.

C:\>setspn -l service_krba01
Registered ServicePrincipalNames for CN=Service_KRBA01,OU=USR,OU=Services,OU=E
nterprise Resources,DC=incept,DC=lab:                                                                                        
        host/krba01.incept.lab                                                                                                         
        HTTP/krba01.incept.lab                                                                                                      


Note:
SETSPN command line utility might not be available in your OS and you can download it from Microsoft site here.

This completes the step 1 i.e.  registration of service. Now onto next step.


Step 2) Create Keytab and Kerberos configuration file


A keytab is a file containing pairs of Kerberos principals and encrypted keys (which are derived from the user credentials). The user account and SPN we created in Step 1 will go into this key tab file.Your application server will use credential from this file to communicate with Active Directory.  



Create keytab

To create a keytab file, you can use either ktpass (windows) or ktutil (unix) or ktab java utility.

The format for creating keytab using Ktutil is
add_entry  -password  -p SPN  -k KVNO(key version number)  -e encryption

-bash-3.2$ ktutil
ktutiladd_entry -password -p HTTP/krba01.incept.lab -k 3 -e rc4-hmac

you will be prompted for password
Password for HTTP/krba01.incept.lab@INCEPT.LAB:  XXXXX (enter user account password, that you created in step 1)
ktutil: wkt krba01.keytab
ktutil: exit

The above process creates a keytab file “krba01.keytab” containing SPN information in the current directory. Now lets add user account information to the keytab file as well.

-bash-3.2$ ktutil
ktutilrkt krba01.keytab
ktutiladd_entry -password -p service_krba01 -k 3 -e rc4-hmac
you will be prompted for password
Password for service_krba01@INCEPT.LAB:  XXXXX (enter user account password, that you created in step 1)
ktutil: wkt krba01.keytab
ktutil: exit

The above command updates keytab file with service account credential.
Note: you can also use java command for creating keytab file as follows:
java sun.security.krb5.internal.tools.Ktab -a HTTP/krba01.incept.lab password -n 3 -k c:\krba01.keytab



Verify

lets verify that keytab file contains all correct information.You can verify the contents of keytab file using either Unix/linux ktutil or klist commands or java ktab utility.

Here is how to verify using ktutil ( to verify using klist or ktab command click here).

-bash-3.2$ ktutil
ktutil:  rkt krba01.keytab
ktutil:  list

slot KVNO Principal
---- ---- ------------------------------------------------------------------------------------------------
   1    3    HTTP/krba01.incept.lab@INCEPT.LAB                                                                        
   2    3    service_krba01@INCEPT.LAB                                                                                        



Setup krb5.conf

Java GSS requires a Kerberos configuration file. The default name and location of the Kerberos configuration file depends on the operating system being used. Java GSS uses the following order to search for the default configuration file:
  1. The file referenced by the Java property java.security.krb5.conf.
  2. ${java.home}/lib/security/krb5.conf.
  3. %WINDIR%\krb5.ini on Microsoft Windows platforms. (where %WINDIR% is the location of your Windows directory. for example, C:\Windows\krb5.ini)
  4. /etc/krb5/krb5.conf on Solaris platforms.
  5. /etc/krb5.conf on other Unix platforms.
Copy the below contents (make appropriate changes) and save file in your weblogic domain folder. 

Sample krb5.conf File



Verify keytab and config file setup

You can do a basic Kerberos check using kinit tool. With the help of keytab and krb5.conf file created, you should be able to get a TGT from KDC.
Open a shell /cmd  promt and run the following command.

-bash-3.2kinit -k -t krba01.keytab service_krba01@INCEPT.LAB
If everything is ok, the above command will get a Kerberos ticket granting ticket and store in cache, which you can check using command klist
-bash-3.2$ klist -e
Ticket cache: FILE:/tmp/krb5cc_1117                                                                                            
Default principal: service_krba01@INCEPT.LAB                                                                     
Valid starting               Expires               Service principal                                                              
10/12/2013 10:29  10/12/2013 20:29  krbtgt/INCEPT.LAB@INCEPT.LAB                             
        renew until 17/12/2013 10:29, Etype(skey, tkt): ArcFour with HMAC/md5, ArcFour with   HMAC/md5                                                                                                                                      

If you get error, verify that that you had used correct service account credentials during keytab file creation.

If you do not have kinit tool, then you can use the one that comes with java
C:\Users\bhalepr> java -Dsun.security.krb5.debug=true -                      Djava.security.krb5.conf=c:\windows\krb5.ini                               sun.security.krb5.internal.tools.Kinit Service_krba01                       

Important: At this stage, it is imperative that you get the kinit command working with keytab file. No use going forward if this dosen't work. (see debug section for more info).

Note: krb5.conf is NOT required by weblogic, we created it to verify kinit command. In weblogic, the preferred way of providing configuration parameters (REALM and KDC) is through startup parameters - java.security.krb5.realm and java.security.krb5.kdc.
If you set values for these properties, then they override the default realm and KDC values specified in krb5.conf (if such a file is found).

Now onto Step 3.

Step 3) Weblogic Kerberos setup

In weblogic we first need to add a authentication provider - Kerberos Authenticator, which is done as follows:


Configure weblogic security Realm

We need to add Negotiation Identity Assertor as one of the Authentication provider and we will add it to the default security realm.  To do this, on the weblogic console, go to Security Realms -> myRealm -> Providers.
Add a new provider(“lock and edit” -> click on new), give it a name “SPPNEGO” and select “NegotiateIdentityAsserter”  as type.click OK. Then on myrealm page, click the newly created provider;  on the common tab, make sure both www-Authenticate.Negotiate and Authorization.Negotiate are in the  “choosen”  block; click on the ProviderSpecific tag and unselect “Form Based Negotiation Enabled”. Click save.
Restart your managed server.


Setup krb5login.conf in domain directory

create krb5login.conf file at the root of your domain with following contents ( make changes as per your domain setup)



Startup parameters

add following startup parameters to your weblogic server  (needless to say, make changes as per your domain setup)

-Dsun.security.krb5.debug=true
-Djava.security.krb5.realm=INCEPT.LAB
-Djava.security.krb5.kdc=AD.INCEPT.LAB
-Djavax.security.auth.useSubjectCredsOnly=false
-Djava.security.auth.login.config=krb5Login.conf  -Djava.security.krb5.conf=krb5.conf


Configure weblogic to lookup Users and Groups in LDAP

Once after a user is successfully authenticated by SPNEGO, Weblogic tries to find group information for the user by sequentially going through all the registered Authentication Providers. There are many different providers that you can add; In this blog, we will see how to add a user in weblogic internal LDAP and secondly to lookup a user in Active Directory.


Lookup user and Groups in Weblogic internal LDAP

 Weblogic has internal LDAP, you can configure a user account and group, by going to security realms -> myrealm-> Users and group tab. Create users and groups and then associate users with group. Just make sure that the “name” of the user is same as your domain id(minus the domain name  i.e. @abc.com)


Lookup user and Groups in Active Directory

go to Security Realms -> myRealm -> Providers.
Add a new provider(“lock and edit” -> click on new), give it a name “ActiveDirectoryAuthenticator” and select “ActiveDirectoryAuthenticator ”  as type and then click OK. Then on myrealm page, click the newly created provider;  on the common tab, make sure control flag is set to SUFFICIENT or REQUIRED. On the ProviderSpecific tag fill in information about your AD setup.

Host: host name of your AD
Principal: Service account you created for weblogic in step 1;
User Base DN: OU=USR,OU=LDC,DC=incept,DC=lab
User From Name Filter: (&(sAMAccountName=%u)(objectclass=user))
User Name Attribute: sAMAccountName
User Object Class: user
Group Base DN: OU=Dev,OU=LegalServices,OU=ES-Roles,DC=incept,DC=lab
Group From Name Filter: (&(sAMAccountName=%g)(objectclass=group))
Static Group Name Attribute: cn
Static Group Object Class: group
Static Member DN Attribute: member
Static Group DNs from Member DN Filter: (&(member=%M)(objectclass=group))

 Click save. Restart server. go to Security Realms -> myRealm ->Users And Groups, you should see all users and groups from AD.

Step 4) Kerberos Security setup in the application

To add kerberos security to your application, edit web.xml and add security constraint and security realm information; here is a snippet of web.xml from my sample application (which can download from here), make changes to your web.xml accordingly; As you can see there is nothing specific to Kerberos in web.xml, just general jee6 security information (you may also want to refer jee6 security blog for more information on general jee6 security).

web.xml

<security-constraint>
        <web-resource-collection>
            <web-resource-name>SampleTestServlet</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
        <user-data-constraint>
            <description>no description</description>
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <security-role>
        <role-name>admin</role-name>
    </security-role>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>myrealm</realm-name>
    </login-config>


And ROLE mapping in weblogic.xml

  <security-role-assignment>
    <role-name>admin</role-name>
    <principal-name>admin</principal-name>
  </security-role-assignment>


Step 5) SPPNEGO/Kerberos setup on client machine


Browser on client machine need to be setup to perform SPNEGO/Kerberos authentication mechanism. Here is how to configure Mozilla Firefox Browser

To configure a Firefox browser to use Windows Integrated authentication, complete the following steps:
Start Firefox.
Enter about:config in the Location Bar.
Enter the filter string network.negotiate.
Append http://, to settings for “network.negotiate-auth.delegation-uris”

Append http://, to settings for “network.negotiate-auth.trusted-uris”



All Done

Deploy your application and test it out.
You can download a sample application from here.
In case your Kerberos setup is not working, check out some debugging tips mentioned below.


Debugging

Here are some debugging tips: 

Debug Kinit

If kinit  command with keytab file does not work. As mentioned earlier, you should recheck credentials and recreate keytab file. You can also verify the credential of service account without using keytab file by:

-bash-3.2kinit service_krba01@INCEPT.LAB
Password for service_krba01@INCEPT.LAB:
kinit:  no ktkt_warnd warning possible

If everything is ok, the command will ask you for your domain password and terminates without an error message. This command will show you the initial ticket you got from the KDC if you execute it without any argument.
The above command will get a Kerberos ticket granting ticket and store in cache, which you can check using command klist
-bash-3.2$ klist -e
Ticket cache: FILE:/tmp/krb5cc_1117                                                                                          
Default principal: service_krba01@INCEPT.LAB                                                                    
Valid starting               Expires               Service principal                                                             
10/12/2013 10:29  10/12/2013 20:29  krbtgt/INCEPT.LAB@INCEPT.LAB                            


        renew until 17/12/2013 10:29, Etype(skey, tkt): ArcFour with HMAC/md5, ArcFour with  HMAC/md5

Note: Use kdestroy to purge cached tickets
-bash-3.2$ kdestroy


Weblogic debug settings

This probably you should do anyways, irrespective weather you are having difficulties getting kerberos working or not.

1) Logging level
Log into weblogic console->server->logging
Set the Severity level: to "Debug"

2) Debug Setting
Enabled debug for authentication & authorization via WebLogic Console — Servers -> [Server Name] -> Debug -> WebLogic -> Security -> atn (for Authentication) and atz (for Authorization) and click Enable


Active Directory access from Weblogic server
One of the reason's for kerberos authentication problem could be that Active directory is NOT accessible from the server hosting weblogic (application server) or could be that Port is blocked. Use telnet command from the server to ensure that AD & KDC is accessible

-bash-3.2$ telnet ad.incept.lab 88                                                                                               


Network Sniffing
Use Wireshark or similar tool to verify that kerberos token is being exchanged between the 3 parties.

Firefox 

In firefox( v 25 +), on the tools menu-> web developer ->Developers Tool.
On the bottom right corner in firefox, press on "spanner" icon and select "Network" tab. Now you can see all http header exchanges.

Some common errors 

Here is a list of some common errors (and solutions) that you might get setting up SSO.


>> wkt: error writing to key table while writing keytab
you may encounter this error while creating keytab file using ktutil; a quick check is to make sure that you are using correct SPN and password.

Here is some more reference for various kerberos errors -  Kerberos Errors.

If you have any question or suggestion, please post your comment.

Prasanna Bhale 

3 comments:

  1. Hej,
    What about this:

    The server sees the HTTP header with the SPNEGO token. It extracts the Kerberos ticket and validates the ticket. After validation, the server checks authorization.

    Where ticket is sending, am I able to use this ticket ( received by spnego ) with another application deployed on the Server ?

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. When creating a keytab with windows' ktpass or java's ktab, neither will add an entry for the user account but only for the service principal. Do we really need the user account entry in the keytab? My experience so far says no..

    ReplyDelete