by Abhijit Patil - Published May 2012
Oracle WebLogic Server offers a complete solution for single sign-on with Microsoft clients using Kerberos.
This article describes how to enable Microsoft clients (browsers in this case), authenticated in a Windows domain, using Kerberos, to be transparently authenticated in a Oracle WebLogic Server (Oracle WebLogic Server) domain, based on the same credentials, and without the need to type in a password again.
The purpose of this feature is to enable a client browser to access a protected resource on Oracle WebLogic Server, and to transparently provide Oracle WebLogic Server with authentication information from the Kerberos database via a SPNEGO ticket. Note that this feature also works for Java SE clients. Oracle WebLogic Server will be able to recognize the ticket, and extract the information from it. The server will then use the information for authentication and grant access to the resource if the authenticated user is authorized to access it. (Kerberos is responsible for authentication only; authorization is still handled by Oracle WebLogic Server.)
Following configuration is used to demonstrate this scenario:
Note that although above configuration is used for this scenario, SPNEGO should work for older versions of browsers, Oracle WebLogic Server, JDK, and so on.
The following list of steps are a detailed breakdown of the cross-platform authentication design shown above.
A Windows 2008 Server domain controller can serve as the Kerberos Key Distribution Center (KDC) server for Kerberos-based client and host systems.
Create an Account for Oracle WebLogic Server ServerIn this step, a Kerberos Principal representing Oracle WebLogic Server is created on the Active Directory. The principal name would be something like name@REALM.NAME, while the REALM.NAME is the administrative name of the realm. In our example, the principal name will be negotiatetestserver@SECURITYQA.COM. The machine hosting Oracle WebLogic Server doesn't have to be part of SECURITYQA.com domain. In this case it’s part of OTHERDOM.DOM domain. The account type should be "User", not a "Computer" in the AD.
Create a User “negotiatetestserver” in Active Directory for Your Oracle WebLogic Server instance
An SPN (Service Principal Name) is a unique name that identifies an instance of a service and is associated with the logon account under which the service instance runs. The SPN is used in the process of mutual authentication between the client and the server hosting a particular service. The client finds a computer account based on the SPN of the service to which it is trying to connect.
The ktpass command-line tool enables an administrator to configure a non-Windows Server Kerberos service as a security principal in the Windows Server Active Directory. Ktpass configures the server principal name for the service in Active Directory and generates an MIT-style Kerberos "keytab" file containing the shared secret key of the service. The tool allows UNIX-based services that support Kerberos authentication to use the interoperability features provided by the Windows Server Kerberos KDC service.
Use the following command to configure SPN (for AES128 cipher strength) and generate keytab file:
C:\Users\bt>ktpass -out negotiatetestserver_keytab -princ negotiatetestserver@SECURITYQA.COM -mapUser negotiatetestserver -kvno 0 -crypto AES128-SHA1 -pass -p type KRB5_NT_PRINCIPAL
Save generated keytab file (negotiatetestserver_keytab) in a secure location, and export it to the domain directory of your Oracle WebLogic Server. (In our example, we will transfer this file to MachineB.) This file is reference by a JAAS (Java Authentication and Authorization Service) configuration file explained later.
The important requirements for the configuration of this server are:
JAAS allows dynamic configuration of login modules. We need to specify a JAAS configuration file that specifies the login modules to use.
Create a file namedkrb5Login.confin the Oracle WebLogic Server domain directory with the following contents:
For Oracle WebLogic Server using Oracle JDK:
com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required principal="negotiatetestserver@SECURITYQA.COM"
useKeyTab=true keyTab=negotiatetestserver_keytab
storeKey=true debug=true;
};
com.sun.security.jgss.krb5.accept {
com.sun.security.auth.module.Krb5LoginModule required principal="negotiatetestserver@SECURITYQA.COM"
useKeyTab=true keyTab=negotiatetestserver_keytab
storeKey=true debug=true;
};
com.ibm.security.jgss.initiate {
com.ibm.security.auth.module.Krb5LoginModule required principal="negotiatetestserver@SECURITYQA.COM"
useKeyTab=true keyTab=negotiatetestserver_keytab storeKey=true debug=true;
};
com.ibm.security.jgss.accept {
com.ibm.security.auth.module.Krb5LoginModule required principal="negotiatetestserver@SECURITYQA.COM"
useKeyTab=true keyTab=negotiatetestserver_keytab storeKey=true debug=true;
};
This assumes you have transferred the keytab file “negotiatetestserver_keytab” generated in step 2 to your domain directory on Oracle WebLogic Server. If Oracle WebLogic Server is using Oracle JDK, specify following options in the Oracle WebLogic Server java command line:
-Dcom.ibm.security.jgss.debug=all -Djava.security.krb5.realm=SECURITYQA.COM -Djava.security.krb5.kdc=MACHINEC -Djava.security.auth.login.config= krb5Login.conf -Djavax.security.auth.useSubjectCredsOnly=false
WebLogic Server includes a security provider, the Negotiate Identity Assertion provider, to support single sign-on (SSO) with Microsoft clients. This identity assertion provider decodes Simple and Protected Negotiate (SPNEGO) tokens to obtain Kerberos tokens, validates the Kerberos tokens, and maps Kerberos tokens to WebLogic users. You need to configure a Negotiate Identity Assertion provider in your WebLogic security realm in order to enable SSO with Microsoft clients. See Configuring a Negotiate Identity Assertion Provider .
Install Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files(This step is applicable only if you plan to use AES256-SHA1 cipher strength. Skip this step for all other cipher strengths). You need to download and install this bundle which provides "unlimited strength" policy files which contain no restrictions on cryptographic strengths.
In order for authentication to take place, the resource (JSP or Servlet) being accessed must be protected, and for the web application to participate in Single Sign On with the client.
Here’s the servlet code used in our case (SimpleTestServlet.java):
package wlstest.functional.security.negotiate.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
public class SimpleTestServlet extends HttpServlet
{
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("
");
out.println("
Simple Test Servlet
");
out.println("
");
out.println("
Requested URL:
");
out.println("
");
out.println(HttpUtils.getRequestURL(req).toString());
out.println("
");
Enumeration theEnum = getServletConfig().getInitParameterNames();
if (theEnum != null)
{
boolean first = true;
while (theEnum.hasMoreElements())
{
if (first)
{
out.println("
Init Parameters
");
out.println("
");
first = false;
}
String param = (String) theEnum.nextElement();
out.println(" "+param+": "+getInitParameter(param));
}
out.println("
");
}
out.println("
Request information:
");
out.println("
");
print(out, "Request method", req.getMethod());
print(out, "Request URI", req.getRequestURI());
print(out, "Request protocol", req.getProtocol());
print(out, "Servlet path", req.getServletPath());
print(out, "Path info", req.getPathInfo());
print(out, "Path translated", req.getPathTranslated());
print(out, "Query string", req.getQueryString());
print(out, "Content length", req.getContentLength());
print(out, "Content type", req.getContentType());
print(out, "Server name", req.getServerName());
print(out, "Server port", req.getServerPort());
print(out, "Remote user", req.getRemoteUser());
print(out, "Remote address", req.getRemoteAddr());
print(out, "Remote host", req.getRemoteHost());
print(out, "Scheme", req.getScheme());
print(out, "Authorization scheme", req.getAuthType());
print(out, "Request scheme", req.getScheme());
out.println("
");
Enumeration e = req.getHeaderNames();
if (e.hasMoreElements())
{
out.println("
Request headers:
");
out.println("
");
while (e.hasMoreElements())
{
String name = (String)e.nextElement();
out.println(" " + name + ": " + req.getHeader(name));
}
out.println("
");
}
e = req.getParameterNames();
if (e.hasMoreElements())
{
out.println("
Servlet parameters (Single Value style):
");
out.println("
");
while (e.hasMoreElements())
{
String name = (String)e.nextElement();
out.println(" " + name + " = " + req.getParameter(name));
}
out.println("
");
}
e = req.getParameterNames();
if (e.hasMoreElements())
{
out.println("
Servlet parameters (Multiple Value style):
");
out.println("
");
while (e.hasMoreElements())
{
String name = (String)e.nextElement();
String vals[] = (String []) req.getParameterValues(name);
if (vals != null)
{
out.print(" " + name + " = ");
out.println(vals[0]);
for (int i = 1; i");
}
out.println("
");
}
out.println("
Request Attributes:
");
e = req.getAttributeNames();
if (e.hasMoreElements())
{
out.println("
");
while (e.hasMoreElements())
{
String name = (String)e.nextElement();
Object o = req.getAttribute(name);
if (o == null) continue;
out.println(" " + name + ": type=" + o.getClass().getName() + " str='" + o.toString() + "'");
}
out.println("
");
}
out.println("
");
}
private void print (PrintWriter out, String name, String value)
{
out.print(" " + name + ": ");
out.println(value == null ? "<none>" : value);
}
private void print (PrintWriter out, String name, int value)
{
out.print(" " + name + ": ");
if (value == -1)
out.println("<none>");
else
out.println(value);
}
}
Simple Test Servlet (Basic Auth)
BasicAuthSimpleTestServlet
/*
/
POST
GET
negotiateAdminRole
no description
NONE
negotiateAdminRole
BASIC
default
BasicAuthSimpleTestServlet
wlstest.functional.security.negotiate.servlet.SimpleTestServlet
/BasicAuthSimpleTestServlet
BasicAuthSimpleTestServlet
/
negotiateAdminRole
negotiateAdmin
Administrators
For Single Sign On to occur you will need an authenticated Microsoft client, belonging to the domain controlled by your realm, and requesting access to the Oracle WebLogic Server service
Configuring Internet Explorer BrowserTo configure an Internet Explorer browser to use Windows authentication, follow these procedures in Internet Explorer.
Configure Local Intranet DomainsIf you have a proxy server enabled:
To configure a Firefox browser to use Windows Integrated authentication, complete the following steps:
Configuring Google Chrome Browser
No special configuration needed for Chrome Browser.
Verifying Configuration
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Authorization: Negotiate YIIGzQYGKwYBBQUCoIIGwTCCBr2gMDAuBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHgYKKwYBBAGCNwICCqKCB
ocEggaDYIIGfwYJKoZIhvcSAQICAQBuggZuMIIGaqADAgEFoQMCAQ6iBwMFACAAAACjggUCYYIE/jCCBPqgAwIBBaEQGw5TRUNVUklUWVFBLkNPTaIrMCmgAwIBA
qEiMCAbBEhUVFAbGGFkYzIxNzA3MTkudXMub3JhY2xlLmNvbaOCBLIwggSuoAMCARGhAwIBJKKCBKAEggSc8v4RphGvP7CinPf4mhiBzyfZWQG …
>>>Pre-Authentication Data:
PA-DATA type = 19
PA-ETYPE-INFO2 etype = 17
>>>Pre-Authentication Data:
PA-DATA type = 2
PA-ENC-TIMESTAMP
>>>Pre-Authentication Data:
PA-DATA type = 16
>>>Pre-Authentication Data:
PA-DATA type = 15
AcquireTGT: PREAUTH FAILED/REQUIRED, re-send AS-REQ
Updated salt from pre-auth = SECURITYQA.COMnegotiatetestserver
>>>KrbAsReq salt is SECURITYQA.COMnegotiatetestserver
Pre-Authenticaton: find key for etype = 17
AS-REQ: Add PA_ENC_TIMESTAMP now
>>> EType: sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType
>>> KrbAsReq calling createMessage
>>> KrbAsReq in createMessage
>>> KrbKdcReq send: kdc=rno05089 UDP:88, timeout=30000, number of retries =3, #bytes=241
>>> KDCCommunication: kdc=rno05089 UDP:88, timeout=30000,Attempt =1, #bytes=241
>>> KrbKdcReq send: #bytes read=100
>>> KrbKdcReq send: #bytes read=100
>>> KdcAccessibility: remove rno05089
>>> KDCRep: init() encoding tag is 126 req type is 11
JGSS_DBG_PROV] getMechs: Mechanism(s) supported by provider IBMJGSSProvider
[JGSS_DBG_PROV] 1.3.6.1.5.5.2
[JGSS_DBG_PROV] getMechs: Mechanism(s) supported by provider IBMJGSSProvider
[JGSS_DBG_PROV] 1.2.840.113554.1.2.2
[JGSS_DBG_PROV] getMechs: Mechanism(s) supported by provider IBMSPNEGO
[JGSS_DBG_PROV] 1.3.6.1.5.5.2
[JGSS_DBG_PROV] getMechs: 2 unique mechanism(s) found
[JGSS_DBG_PROV] [0]: 1.3.6.1.5.5.2
[JGSS_DBG_PROV] [1]: 1.2.840.113554.1.2.2
[JGSS_DBG_CTX] Default list of negotiable mechs:
1.2.840.113554.1.2.2
[JGSS_DBG_CTX] AuthenticatorCache, scope of bucket122
[JGSS_DBG_CTX] ticket enc type = rc4-hmac
[JGSS_DBG_CTX] Successfully decrypted ticket
[JGSS_DBG_CTX] Put authz info in cache
[JGSS_DBG_CTX] Session key type = rc4-hmac
[JGSS_DBG_CTX] Successfully decrypted authenticator
[JGSS_DBG_CTX] Remote subkey type = rc4-hmac
[JGSS_DBG_CTX] No delegated creds from peer
[JGSS_DBG_CTX] Received channel binding checksum
Here are typical exceptions you might encounter during SPNEGO setup along with solutions:
SSO Cross-platform authentication is achieved by emulating the negotiate behavior of native Windows-to-Windows authentication services that use the Kerberos protocol. In order for cross-platform authentication to work, Oracle WebLogic Server can be used to parse SPNEGO tokens in order to extract Kerberos tokens which are then used for authentication thus providing transparent authentication to the end user.