When I first started out with Kerberos and Java, time was running out on a project at work, and it got thrown upon me out of the blue (dreaded scope creep!). At that point I didn't have a clue about how even the Kerberos algorithm worked. The client put me on the spot and said "Can you do Kerberos interop with .NET SOAP services?" - I never back down from a challenge - in fact the satisfaction in completing something like that is one of the best parts of my job. It was like "Yeah, that should take 4-6 days. I'll just write it myself". Underneath this calm exterior I was looking for a big hole to open up and swallow me!
Firstly, I checked the web services framework we were using and found that there was no Kerberos support. The best answer I got from the Axis 2 community was "No, this is not supported and we don't know of anyone doing it in Axis 2". So this meant doing everything from the ground on up. The first step was to work out how the heck Kerberos worked, and how to authenticate with it in Java.
The first place people end up when on such a quest is usually the Sun tutorial on JAAS and GSS. While this tutorial kind've explains the concepts and how to do it, it is hard to get a complete picture of what you're doing. Secondly, the code is a socket based client/server which is not useful at all, as only a lunatic would be writing their own server communications layer in these days of NIO and SOA. The second place is the Sun Java forum for Kerberos, which has a couple of smart people who answer a lot of questions, but I found their responses more often than not ended up confusing me.
This article is my take on a Kerberos "Hello World" client/server in a more applicable way to modern systems. I changed the concept slightly to suit my needs - that is, it needed to be the foundation for a SOAP inter-operable system. Instead of using socket communications, my code base-64 encodes the Kerberos service ticket and writes it to a file. Subsequently, when the server is run, it opens that file, reads the base-64 string and decodes it to a service ticket which is then used to initiate the Kerberos context/session. When sending Kerberos tickets over SOAP they are base-64 encoded, hence my implementation. Once the security context has been initialised, the server determines the client who made the request and prints "Hello World
An intended 'feature' of my blogs is that I will include fully working projects and code with them, that should run straight out of the box. Below you can find a downloadable source distribution of my NetBeans project, that includes compiled classes, and .bat files for running the client and server. All that needs to be done before running, is to re-configure the properties files to work with your domain/KDC.
The code is fairly straight-forward, and I've commented it heavily. Points to note for newbies are:
1. JAAS is used to login at both the client and server sides. Once you have successfully logged in via JAAS, you get a subject which contains all your secret keys that the KDC gave you after logging in. These keys are used to encrypt and decrypt tickets that are only meant for you. Only you and the KDC know your secret keys, hence only you can decrypt tokens meant for you.
2. When the JAAS login is performed in the client, the ticket that is retrieved (and placed into your subject) is the TGT (ticket granting ticket). This is required to then subsequently request a service ticket for accessing a service. Additionally, when the server logs in, it gets its own TGT and a set of keys which are used to decode the incoming service ticket.
3. The call to initSecContext() in the Client is the act of requesting a service ticket. The raw byte array that this returns is the service ticket. This contains the client principal user name and a session key that only the client, server and KDC know about. The ticket is encrypted by the KDC so that only the server can decode it.
4. The security context initation and acceptance are privileged actions. This means that they can only be performed by the identity with the correct credentials/keys to do so. In the examples, the code subject.doAs() is how this is implemented. The subject that is passed in as a parameter is used to decode whatever token is being accepted or used.
5. The code:
krb5Oid = new Oid( "1.2.840.113554.1.2.2");instructs the Java APIs that the security mechanism you are wanting to use is Kerberos version 5.
6. In my examples, requestMutualAuth is always turned off, so that there is only one token sent from client to server to initiate and accept a security context. This is different from the Sun tutorial in that many passes can be made. In web service security, it is a big hassle if more than one pass is required to initiate the context, as the SOAP message may be asynchronous or atomic.
7. The GSS API that you will often see mentioned is the best means of doing Kerberos authentication in Java. GSS stands for Generic Security Services API. It provides a generic way of performing security/authentication services, that does not tie you down to a specific implementation (e.g. Kerberos). The benefit of using it here, other than being able to use a different security mechanism is that it makes interoperability with .NET extremely simple because .NET also uses GSS. A GSS token (service ticket) generated in Java, can be easily understood by a .NET program, and vice-versa. Web service Kerberos security uses GSS tokens when initiating secured sessions. Note that it is possible to use the actual Kerberos libraries in Java to do authentication, but there is no benefit at all to doing so.
Configuring the example project
Before running the project, it needs to be configured to use your domain and KDC correctly. The settings in the included config files are specific to running on my laptop against Apache Directory Server. I have also tested it against a Windows 2003 domain running Active Directory.
Firstly, I am assuming that your KDC has been setup correctly. That is, you have a user account, a server account and the latter has a Kerberos service principal setup (see my previous blog on how to do this in Active Directory).
The file jaas.conf has to be changed to put the correct service principal in the Server configuration section. This is the Kerberos principal that your service account is mapped to. My example is set to principal="webserver/bully@EXAMPLE.COM"; bully is my laptop computer name, and webserver is the name of the service account.
The client.properties file needs to be changed to include your realm name (which HAS to be capitalised), the ip address of your KDC, your client account login details and the service account name. The service account name gets converted into a Kerberos principal by the Java libraries, so you don't need to specify it as a Kerberos name here.
The server.properties file needs to be changed to specify your KDC, your realm and the password of your service account.
You can now run client.bat and then server.bat and see if your Kerberos Hello World application is working. Note that you should be running with at least Java 1.5.07 and it needs to be the Sun JVM. Older JVMs don't support all the encryption types that Kerberos v5 uses, and the Sun JVM specific base-64 libraries are used in my demo.
Error Messages
Identifier doesn't match expected value (906) - this is because your password is wrong, so you couldn't be authenticated against the KDC.
Server not found in Kerberos database - this is either because the service account doesn't exist in your database OR the Kerberos service principal name wasn't recognised by your KDC. Try another SPN mapping or modify the config file to have a different service principal name. If you are using Apache Directory, you can check the server logs for what SPN is actually getting passed through to the KDC.
Integrity check on decrypted field failed - this generally means that (a) your password failed during the JAAS login to the KDC, or (b) the ticket you are trying to decode couldn't be decrypted. This is because the ticket is not meant for your server, so it doesn't have the key for decrypting it. In this case, change the service principal that your server is logging in as to resolve this.
Encryption type not supported by KDC - this is generally due to using Active Directory on a Windows 2003 domain. This requires setting a registry entry on both your client and domain machines, allowTGTSessionKey. See the section in the following Sun document for the complete guide to doing this. Note that I also have had this error while using Apache Directory server, which was due to my JDK 1.5 not being past version 7 (or thereabouts).
Download the NetBeans project and source/binaries here. |
![]() | Client.java |
package javamonkey.app.gss;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.security.PrivilegedAction;
import java.util.Properties;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
import sun.misc.BASE64Encoder;
/**
* <p>Client logs in to a Key Distribution Center (KDC) using JAAS and then
* requests a service ticket for the server, base 64 encodes it and writes it
* to the file <i>service-ticket.txt</i>.</p>
* <p>This class, in combination with the <i>Server</i> class illustrates the
* use of the JAAS and GSS APIs for initiating a security context using the
* Kerberos protocol.</p>
* <p>This requires a KDC/domain controller such as Active Directory or Apache
* Directory. The KDC configuration details are stored in the
* <i>client.properties</i> file, while the JAAS details are stored in the
* file <i>jaas.conf</i>.</p>
* @author Ants
*/
public class Client {
public static void main( String[] args) {
try {
// Setup up the Kerberos properties.
Properties props = new Properties();
props.load( new FileInputStream( "client.properties"));
System.setProperty( "sun.security.krb5.debug", "true");
System.setProperty( "java.security.krb5.realm", props.getProperty( "realm"));
System.setProperty( "java.security.krb5.kdc", props.getProperty( "kdc"));
System.setProperty( "java.security.auth.login.config", "./jaas.conf");
System.setProperty( "javax.security.auth.useSubjectCredsOnly", "true");
String username = props.getProperty( "client.principal.name");
String password = props.getProperty( "client.password");
// Oid mechanism = use Kerberos V5 as the security mechanism.
krb5Oid = new Oid( "1.2.840.113554.1.2.2");
Client client = new Client();
// Login to the KDC.
client.login( username, password);
// Request the service ticket.
client.initiateSecurityContext( props.getProperty( "service.principal.name"));
// Write the ticket to disk for the server to read.
encodeAndWriteTicketToDisk( client.serviceTicket, "./security.token");
System.out.println( "Service ticket encoded to disk successfully");
}
catch ( LoginException e) {
e.printStackTrace();
System.err.println( "There was an error during the JAAS login");
System.exit( -1);
}
catch ( GSSException e) {
e.printStackTrace();
System.err.println( "There was an error during the security context initiation");
System.exit( -1);
}
catch ( IOException e) {
e.printStackTrace();
System.err.println( "There was an IO error");
System.exit( -1);
}
}
public Client() {
super();
}
private static Oid krb5Oid;
private Subject subject;
private byte[] serviceTicket;
// Authenticate against the KDC using JAAS.
private void login( String username, String password) throws LoginException {
LoginContext loginCtx = null;
// "Client" references the JAAS configuration in the jaas.conf file.
loginCtx = new LoginContext( "Client",
new LoginCallbackHandler( username, password));
loginCtx.login();
this.subject = loginCtx.getSubject();
}
// Begin the initiation of a security context with the target service.
private void initiateSecurityContext( String servicePrincipalName)
throws GSSException {
GSSManager manager = GSSManager.getInstance();
GSSName serverName = manager.createName( servicePrincipalName,
GSSName.NT_HOSTBASED_SERVICE);
final GSSContext context = manager.createContext( serverName, krb5Oid, null,
GSSContext.DEFAULT_LIFETIME);
// The GSS context initiation has to be performed as a privileged action.
this.serviceTicket = Subject.doAs( subject, new PrivilegedAction<byte[]>() {
public byte[] run() {
try {
byte[] token = new byte[0];
// This is a one pass context initialisation.
context.requestMutualAuth( false);
context.requestCredDeleg( false);
return context.initSecContext( token, 0, token.length);
}
catch ( GSSException e) {
e.printStackTrace();
return null;
}
}
});
}
// Base64 encode the raw ticket and write it to the given file.
private static void encodeAndWriteTicketToDisk( byte[] ticket, String filepath)
throws IOException {
BASE64Encoder encoder = new BASE64Encoder();
FileWriter writer = new FileWriter( new File( filepath));
String encodedToken = encoder.encode( ticket);
writer.write( encodedToken);
writer.close();
}
}
![]() | LoginCallbackHandler.java |
package javamonkey.app.gss;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
/**
* Password callback handler for resolving password/usernames for a JAAS login.
* @author Ants
*/
public class LoginCallbackHandler implements CallbackHandler {
public LoginCallbackHandler() {
super();
}
public LoginCallbackHandler( String name, String password) {
super();
this.username = name;
this.password = password;
}
public LoginCallbackHandler( String password) {
super();
this.password = password;
}
private String password;
private String username;
/**
* Handles the callbacks, and sets the user/password detail.
* @param callbacks the callbacks to handle
* @throws IOException if an input or output error occurs.
*/
public void handle( Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
for ( int i=0; i<callbacks.length; i++) {
if ( callbacks[i] instanceof NameCallback && username != null) {
NameCallback nc = (NameCallback) callbacks[i];
nc.setName( username);
}
else if ( callbacks[i] instanceof PasswordCallback) {
PasswordCallback pc = (PasswordCallback) callbacks[i];
pc.setPassword( password.toCharArray());
}
else {
/*throw new UnsupportedCallbackException(
callbacks[i], "Unrecognized Callback");*/
}
}
}
}
![]() | Server.java |
package javamonkey.app.gss;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.security.PrivilegedAction;
import java.util.Properties;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
import sun.misc.BASE64Decoder;
/**
* <p>Server logs in to a Key Distribution Center (KDC) using JAAS and then
* reads the encoded service ticket from the file <i>service-ticket.txt</i>.
* This ticket is decoded into a byte array and the security context is
* attempted to be accepted, using the GSS API.</p>
* <p>This class, in combination with the <i>Client</i> class illustrates the
* use of the JAAS and GSS APIs for initiating a security context using the
* Kerberos protocol.</p>
* <p>This requires a KDC/domain controller such as Active Directory or Apache
* Directory. The KDC configuration details are stored in the
* <i>server.properties</i> file, while the JAAS details are stored in the
* file <i>jaas.conf</i>.</p>
* @author Ants
*/
public class Server {
public static void main( String[] args) {
try {
// Setup up the Kerberos properties.
Properties props = new Properties();
props.load( new FileInputStream( "server.properties"));
System.setProperty( "sun.security.krb5.debug", "true");
System.setProperty( "java.security.krb5.realm", props.getProperty( "realm"));
System.setProperty( "java.security.krb5.kdc", props.getProperty( "kdc"));
System.setProperty( "java.security.auth.login.config", "./jaas.conf");
System.setProperty( "javax.security.auth.useSubjectCredsOnly", "true");
String password = props.getProperty( "service.password");
// Oid mechanism = use Kerberos V5 as the security mechanism.
krb5Oid = new Oid( "1.2.840.113554.1.2.2");
Server server = new Server();
// Login to the KDC.
server.login( password);
byte serviceTicket[] = loadTokenFromDisk();
// Request the service ticket.
String clientName = server.acceptSecurityContext( serviceTicket);
System.out.println( "\nSecurity context successfully initialised!");
System.out.println( "\nHello World " + clientName + "!");
}
catch ( LoginException e) {
e.printStackTrace();
System.err.println( "There was an error during the JAAS login");
System.exit( -1);
}
catch ( GSSException e) {
e.printStackTrace();
System.err.println( "There was an error during the security context acceptance");
System.exit( -1);
}
catch ( IOException e) {
e.printStackTrace();
System.err.println( "There was an IO error");
System.exit( -1);
}
}
// Load the security token from disk and decode it. Return the raw GSS token.
private static byte[] loadTokenFromDisk() throws IOException {
BufferedReader in = new BufferedReader( new FileReader( "security.token"));
System.out.println( new File( "security.token").getAbsolutePath());
String str;
StringBuffer buffer = new StringBuffer();
while ((str = in.readLine()) != null) {
buffer.append( str + "\n");
}
in.close();
//System.out.println( buffer.toString());
BASE64Decoder decoder = new BASE64Decoder();
return decoder.decodeBuffer( buffer.toString());
}
private static Oid krb5Oid;
private Subject subject;
// Authenticate against the KDC using JAAS.
private void login( String password) throws LoginException {
LoginContext loginCtx = null;
// "Client" references the JAAS configuration in the jaas.conf file.
loginCtx = new LoginContext( "Server",
new LoginCallbackHandler( password));
loginCtx.login();
this.subject = loginCtx.getSubject();
}
// Completes the security context initialisation and returns the client name.
private String acceptSecurityContext( final byte[] serviceTicket)
throws GSSException {
krb5Oid = new Oid( "1.2.840.113554.1.2.2");
// Accept the context and return the client principal name.
return Subject.doAs( subject, new PrivilegedAction<String>() {
public String run() {
try {
// Identify the server that communications are being made to.
GSSManager manager = GSSManager.getInstance();
GSSContext context = manager.createContext( (GSSCredential) null);
context.acceptSecContext( serviceTicket, 0, serviceTicket.length);
return context.getSrcName().toString();
}
catch ( Exception e) {
e.printStackTrace();
return null;
}
}
});
}
}
![]() | jaas.conf |
Client {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=false;
};
Server {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=false
storeKey=true
useTicketCache=false
principal="webserver/bully@EXAMPLE.COM";
};
![]() | client.properties |
realm=EXAMPLE.COM
kdc=127.0.0.1
client.principal.name=anthony
client.password=Password99
service.principal.name=webserver
![]() | server.properties |
realm=EXAMPLE.COM
kdc=localhost
service.password=Password99
Download the NetBeans project and source/binaries here.
Thanks for great blog posts on Kerberos and the Java side of it.
Could you please give some input of how you setup the Apache Directory Server, i.e. what version, what you needed to configure, an ldif file for creating a user and a service in the directory and so on.
Best regards
Jimmy
Hi Jimmy, I've posted a new blog on using Apache Directory Server as a KDC - http://thejavamonkey.blogspot.com/2008/07/using-apache-directory-server-as-kdc.html
Have a look and let me know what you think.
Thanks mate, you are a legend, The explanation helped me clear all my doubts. Appreciate the effort
Thank you very much! It looks really good and will help a lot of people.
Small note:
Client.java uses username "anthony" (see client.properties), but the LDIF file (in other blog) contains user named "monkey" ;-)
Thanks you!
It helps me a lot and ends waste of time searching something clear on Kerberos java client.
Damned Google!
Thanks for such a detailed tutorial. Helped me to clear some facts regarding using Kerberos with web services
Thank you for the wonderful hands-on tutorial on Kerberos.
I am getting 'Server not found in the Kerberos Database (7) error.
Have a basic doubt - My machine name is GC57DG1-SEC.r1-core.r1.xyz.net - with r1-core.r1.xyz.net is the domain name.
In the JAAS.conf - the server principal="webserver/GC57DG1-SEC.r1-core.r1.xyz.net@EXAMPLE.COM";
Is there a way for me to check whether this is correct? For some reasons, I am not able to run the DS in debug mode. Have been banging my head over this :-) Would greatly appreciate any help.
Thanks
It worked for me once I changed the Oid to GSSName.NT_USER_NAME instead of NT_HOSTBASED_SERVICE.
Thanks
Thank you so much for this sample code. I was having a hard time understanding the Sun tutorial and this helped make things clearer. Honestly, the hardest part was the Active Directory stuff to make sure I mapped a user to an SPN properly.
Thanks again.
I have the client work. However, when I run the server, I got the following exception. Thank you for your help.
Entered Krb5Context.acceptSecContext with state=STATE_NEW
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
Checksum failed !
GSSException: Failure unspecified at GSS-API level (Mechanism level: Checksum failed)
at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
at javamonkey.app.gss.Server$1.run(Server.java:118)
at javamonkey.app.gss.Server$1.run(Server.java:113)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Unknown Source)
at javamonkey.app.gss.Server.acceptSecurityContext(Server.java:112)
at javamonkey.app.gss.Server.main(Server.java:56)
Here is SPN in the client.properties:
service.principal.name=HOST/BCIDCVM01.bci.sas.com
Hey, there are two things you should try:
1. If you are using a version of the JDK that is less than 1.5.0_07 then, update to a newer version of Java.
2. On the Active Directory accounts on your domain server, make sure you check the box "use DES encryption type" for the client and service accounts.
That solved my problem. Thank you very much.
Thanks for the example monkey boy, it was a great starting point. I did run into some problems, however. Here's how I resolved them ...
When starting server you may get error "Client not found in Kerberos database." Here's why ...
When server "logs in" via JAAS, it attempts to retrieve a TGT and uses value of jaas 'principal' attribute as user name (along w/ password supplied by callback.) Because this value represents the SPN and not the client name, the login fails.
Server should be passive, i.e. no TGT required. The fix is add isInitiator=false to jaas.conf 'Server' app entry. Jaas login then simply creates a Kerberos principal (using SPN) and Kerberos key using password supplied by callback. No UDP message to AD required.
When initiating security context within Client, you may get error "Server not found in Kerberos database." Here's why ...
The service principal name is "assembled" via the GSS api and MUST exactly match value registered within KDC. To fix:
1. assuming SPN mapped to service name on KDC is
'myservice/my.host.name'
2. service.principal.name in Client.properties must match the above name exactly - DO NOT SURROUND WITH QUOTES
3. you must append domain name to principal attribute in Server entry in jaas.conf (THE DOMAIN NAME MUST BE ALL CAPS and value MUST BE SURROUNDED BY QUOTES), e.g.
principal="myservice/my.host.name@MY.DOMAIN"
4. Modify example code which assembles the SPN to use Kerberos formatted name:
Oid krb5PrincipalNameType = new Oid("1.2.840.113554.1.2.2.1");
GSSName serverName = manager.createName(servicePrincipalName, krb5PrincipalNameType);
Hope this helps someone.
Thanks for a good example.
Still wondering, is there some way to use the logged on Windows users Kerberos with these newer Windows versions without having to set this "allowTGTSessionKey" cause I don't feel so comfortable with messing with clients registry settings...
you have nice site. thanks for sharing this site. various kinds of ebooks are available here
http://feboook.blogspot.com
Hi This article has been great for my classes. I am new to this technology and im getting the following error when i run your application
javax.security.auth.login.LoginException: Integrity check on decrypted field failed (31)
I am providing the correct password for the server still it keeps coming. Also i have got the client to work. Stuck up with server now..
Please help me with this.
Regards,
Sushant
Hi your articles are very useful, thanks for the contribution!
Btw, in this article you mentioned that ".NET also uses GSS", are you refering to SSPI?. My client app will be written in C# .Net and the server app will be written in Java. I'm now doing the research on the interoperability between .Net client and Java server, appreciate if you are able to share your experience with me if any. Thanks! :)
Regards,
DJ, Singapore
Hello.
Thanks for this article, its very usefull. However, I need to know how to set up the kerberos port. IT is 88 by default, but i NEED to make que client connect to port 60088. How can I set this up?
Thanks in advance
Hey, have you tried changing the client.properties file to the following:
kdc=127.0.0.1:60088
(and obviously change localhost IP to your server IP if its on a different machine)
I had a quick look at the Java Virtual Machine source and it looks like they may have a serious issue in there that this will not get passed (as they use the ":" to specify multiple kdc's.). Hopefully they have sorted this out in the latest virtual machines!
Yeah, I already tried that. And it doesn't really work. It seems that the ":" characters is used to separate multiple hosts, rather than separate a host and a port.
I think this is a little big failure in their part. They should really fix this.
Ugly workaround for that problem, put all your KDCs in the local hostfile as mungekdc.some.domain and reference that.
PS. Yes, I know, I've already said it's ugly.
Hi, thanks for the code.
However I get the following error when running the server:
GSSException: Failure unspecified at GSS-API level (Mechanism level: Encryption type AES256 CTS mode with HMAC SHA1-96 is not supported/enabled)
at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
at test.krb.Server$1.run(Server.java:116)
at test.krb.Server$1.run(Server.java:1)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Unknown Source)
at test.krb.Server.acceptSecurityContext(Server.java:110)
at test.krb.Server.main(Server.java:55)
Caused by: KrbException: Encryption type AES256 CTS mode with HMAC SHA1-96 is not supported/enabled
at sun.security.krb5.EncryptionKey.findKey(Unknown Source)
at sun.security.krb5.KrbApReq.authenticate(Unknown Source)
at sun.security.krb5.KrbApReq.(Unknown Source)
at sun.security.jgss.krb5.InitSecContextToken.(Unknown Source)
... 9 more
I use a copy of MIT kerberos for the KDC.
I get following error.. please help.
KDC Apache DS..
sTime is Mon Aug 09 21:43:22 IST 2010 1281370402000
suSec is 0
error code is 7
error Message is Server not found in Kerberos database
realm is EXAMPLE.COM
sname is krbtgt/EXAMPLE.COM
msgType is 30
KrbException: Server not found in Kerberos database (7) - Server not found in Ke
rberos database
at sun.security.krb5.KrbTgsRep.(Unknown Source)
at sun.security.krb5.KrbTgsReq.getReply(Unknown Source)
at sun.security.krb5.internal.CredentialsUtil.serviceCreds(Unknown Sourc
e)
at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(Unknow
n Source)
at sun.security.krb5.Credentials.acquireServiceCreds(Unknown Source)
at sun.security.jgss.krb5.Krb5Context.initSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.initSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.initSecContext(Unknown Source)
at javamonkey.app.gss.Client$1.run(Client.java:109)
at javamonkey.app.gss.Client$1.run(Client.java:102)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Unknown Source)
at javamonkey.app.gss.Client.initiateSecurityContext(Client.java:102)
at javamonkey.app.gss.Client.main(Client.java:52)
Caused by: KrbException: Identifier doesn't match expected value (906)
at sun.security.krb5.internal.KDCRep.init(Unknown Source)
at sun.security.krb5.internal.TGSRep.init(Unknown Source)
at sun.security.krb5.internal.TGSRep.(Unknown Source)
... 14 more
GSSException: No valid credentials provided (Mechanism level: Server not found i
n Kerberos database (7) - Server not found in Kerberos database)
at sun.security.jgss.krb5.Krb5Context.initSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.initSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.initSecContext(Unknown Source)
at javamonkey.app.gss.Client$1.run(Client.java:109)
at javamonkey.app.gss.Client$1.run(Client.java:102)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Unknown Source)
at javamonkey.app.gss.Client.initiateSecurityContext(Client.java:102)
at javamonkey.app.gss.Client.main(Client.java:52)
Caused by: KrbException: Server not found in Kerberos database (7) - Server not
found in Kerberos database
at sun.security.krb5.KrbTgsRep.(Unknown Source)
at sun.security.krb5.KrbTgsReq.getReply(Unknown Source)
at sun.security.krb5.internal.CredentialsUtil.serviceCreds(Unknown Sourc
e)
at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(Unknow
n Source)
at sun.security.krb5.Credentials.acquireServiceCreds(Unknown Source)
... 9 more
Caused by: KrbException: Identifier doesn't match expected value (906)
at sun.security.krb5.internal.KDCRep.init(Unknown Source)
at sun.security.krb5.internal.TGSRep.init(Unknown Source)
at sun.security.krb5.internal.TGSRep.(Unknown Source)
... 14 more
Exception in thread "main" java.lang.NullPointerException
at java.io.ByteArrayInputStream.(Unknown Source)
at sun.misc.CharacterEncoder.encode(Unknown Source)
at javamonkey.app.gss.Client.encodeAndWriteTicketToDisk(Client.java:125)
at javamonkey.app.gss.Client.main(Client.java:54)
C:\NeoWork\Kerboros\PlainKerboros\kerberos-gss-getting-started>pause
Press any key to continue . . .
C:\NeoWork\Kerboros\PlainKerboros\kerberos-gss-getting-started>
sorry please ignore my previous post..
please help me..
I get following error
>>> KrbKdcReq send: kdc=localhost UDP:88, timeout=30000, number of retries =3, #
bytes=235
>>> KDCCommunication: kdc=localhost UDP:88, timeout=30000,Attempt =1, #bytes=235
>>> KrbKdcReq send: #bytes read=529
>>> KrbKdcReq send: #bytes read=529
>>> EType: sun.security.krb5.internal.crypto.DesCbcMd5EType
>>> KrbAsRep cons in KrbAsReq.getReply webserver/inenvasudrl3c
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 3 1 23 16 17.
C:\NeoWork\Kerboros\PlainKerboros\kerberos-gss-getting-started\security.token
GSSException: Defective token detected (Mechanism level: GSSHeader did not find
the right tag)
at sun.security.jgss.GSSHeader.(Unknown Source)
at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source)
at javamonkey.app.gss.Server$1.run(Server.java:117)
at javamonkey.app.gss.Server$1.run(Server.java:111)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Unknown Source)
at javamonkey.app.gss.Server.acceptSecurityContext(Server.java:111)
at javamonkey.app.gss.Server.main(Server.java:55)
I hope my previous comment came through!
I got Single Sign-On to work for a newly created non-administrator user. This client does have a nonzero sessionkey in it's TGT.
BTW I love your Monkey Island references. Funny parallel with the three-headed monkey (Kerberos is a three-headed dog).
Blogspot is having real trouble. Here is what I wanted to say in the hope it helps someone else spare some time.
My only requirement was to have our client Java app securely authenticate the currently logged-in Windows user to our server Java app without having the user retype its password. This simple requirement took me 3 working days to figure out and get it working in an example program.
I am running as a user with admin rights on Windows 7 with a Windows 2008 Active Directory. I also had the "Encryption type not supported by KDC (14)" problem and added the allowtgtsessionkey registry setting, but I still had this problem. Instead of using DES on the clients I decided to use rc4-hmac as this is preferred by Windows by using the following krb5.conf
[libdefaults]
default_tkt_enctypes = rc4-hmac
default_tgs_enctypes = rc4-hmac
permitted_enctypes = rc4-hmac
In fact the error goes away if I disallow only the aes128-cts protocol.
With this I got both your example and the GSS-API example from oracle to work, but without single sign on, it still needs a plain text password at the client side. To turn on Single Sign-On for the clients I set useTicketCache=false in the JAAS config for the client.
In both your and Oracle's example, logging in to the KDC seems to work fine but initializing the security context fails with the error "Integrity check on decrypted field failed (31)". (Purely on Client.java, even before starting Server.java).
This seems to be a known bug/feature(with Sun bugs and on a Microsoft technet forum post) in Windows where local administrators get a zero session key in the TGT even if they have allowtgtsessionkey set to 1.
Getting following exception on running client.java
javax.security.auth.login.LoginException: Client not found in Kerberos database
(6) - Client not found in Kerberos database
at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Un
known Source)
at com.sun.security.auth.module.Krb5LoginModule.login(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at javax.security.auth.login.LoginContext.invoke(Unknown Source)
at javax.security.auth.login.LoginContext.access$000(Unknown Source)
at javax.security.auth.login.LoginContext$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(Unknown Source)
at javax.security.auth.login.LoginContext.login(Unknown Source)
at javamonkey.app.gss.Client.login(Client.java:89)
at javamonkey.app.gss.Client.main(Client.java:50)
Caused by: KrbException: Client not found in Kerberos database (6) - Client not
found in Kerberos database
at sun.security.krb5.KrbAsRep.(Unknown Source)
at sun.security.krb5.KrbAsReq.getReply(Unknown Source)
at sun.security.krb5.Credentials.sendASRequest(Unknown Source)
at sun.security.krb5.Credentials.acquireTGT(Unknown Source)
... 14 more
Caused by: KrbException: Identifier doesn't match expected value (906)
at sun.security.krb5.internal.KDCRep.init(Unknown Source)
at sun.security.krb5.internal.ASRep.init(Unknown Source)
at sun.security.krb5.internal.ASRep.(Unknown Source)
... 18 more
There was an error during the JAAS login
I read your article, and it's great. Now I have a service Calculator with 4 function "add", "subtract", "multiple", "divide". I want to use Kerberos ticket to authenticate client who want to use my service. So how to do this?
I also do that follow this article but It does not work.
ntegrity check on decrypted field failed - this generally means that (a) your password failed during the JAAS login to the KDC, or (b) the
We are getting the error - "Integrity check on decrypted field failed "
Your suggestion is -
ticket you are trying to decode couldn't be decrypted. This is because the ticket is not meant for your server, so it doesn't have the key for decrypting it. In this case, change the service principal that your server is logging in as to resolve this.
Our code is running fine for client.java but it is failing in server.java. Our client box is windows and the KDC is linux and App server is linux.Rather than apache directory we have ftp and telnet installed. Is that ok ? Any help on this error is very much appreciated
I got things working. However, when I want to use the ticket cache on the client side to get SSO I get the following error
Exception in thread "main" java.lang.RuntimeException: GSSException: No valid cr
edentials provided (Mechanism level: Integrity check on decrypted field failed (
31))
at Client$1.run(Client.java:111)
at Client$1.run(Client.java:1)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Unknown Source)
at Client.initiateSecurityContext(Client.java:100)
at Client.main(Client.java:50)
Caused by: GSSException: No valid credentials provided (Mechanism level: Integri
ty check on decrypted field failed (31))
at sun.security.jgss.krb5.Krb5Context.initSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.initSecContext(Unknown Source)
at sun.security.jgss.GSSContextImpl.initSecContext(Unknown Source)
at Client$1.run(Client.java:107)
... 5 more
Caused by: KrbException: Integrity check on decrypted field failed (31)
at sun.security.krb5.KrbTgsRep.(Unknown Source)
at sun.security.krb5.KrbTgsReq.getReply(Unknown Source)
at sun.security.krb5.internal.CredentialsUtil.serviceCreds(Unknown Sourc
e)
at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(Unknow
n Source)
at sun.security.krb5.Credentials.acquireServiceCreds(Unknown Source)
... 9 more
Caused by: KrbException: Identifier doesn't match expected value (906)
at sun.security.krb5.internal.KDCRep.init(Unknown Source)
at sun.security.krb5.internal.TGSRep.init(Unknown Source)
at sun.security.krb5.internal.TGSRep.(Unknown Source)
... 14 more
Exactly what i was looking for on KBC and Java. Thanks for the post. It was very useful.
Can a GSSCredential class be used to handle credential elements for more than one prinicipals, the way it can handle credential elements for multiple mechanisms?
thanks
In the above somebody wrote
<quote>
Still wondering, is there some way to use the logged on Windows users Kerberos with these newer Windows versions without having to set this "allowTGTSessionKey" cause I don't feel so comfortable with messing with clients registry settings...
</quote>
I think this is the problem that most of us are facing when trying to use Kerberos from Java SE on Windows. This restriction pretty much makes the Java SE implementation of Kerberos unusable on Windows in a real life corportate LAN scenario. There's no way a typical company will allow this registry setting to be changed on all their workstations, especially in a situation where Microsoft recommends it to be off by default.
So what is the real problem and how does other non-MS applications solve it ? One good example could be Firefox which has no problems with this unlike Java SE. Why is this so? I think it is because an application like Firefox use the platform's native GSS library while Java SE uses it's own - at least on Windows.
You can read more about it here: http://download.oracle.com/javase/6/docs/technotes/guides/security/jgss/jgss-features.html in section "Native platform GSS integration". I think that if Java SE had supported native GSS platform integration on Windows the problem would not exist. I bet the Java Bug database contains an enhancement request on this topic, but I haven't checked.
Unfortunately as long as the problem exist the combination of Kerberos from Java SE on Windows will get very little takeup in the corporate world.
Really useful tutorial, thanks! I ran into a couple of problems above:
GSSException: Failure unspecified at GSS-API level (Mechanism level: Encryption type AES256 CTS mode with HMAC SHA1-96 is not supported/enabled)
I fixed this exception by installing the JCE jar libraries at http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
And I fixed this exception:
KrbException: Server not found in Kerberos database (7) - Server not found in Kerberos database
by correcting my /etc/hosts file on the KDC server.
Hi,
I wonder if following is possible using Java Kerberos implementations.
Is it possible to let Java generate a service ticket (like the KDC would do) and send it to the server app. I have access to the keytab file to encrypt the ticket.
This example could be described as impersonating the KDC which generates Service Tickets.
Thanks for the info.
Kind regards
Bart
This is a great blog! Any advice on how to integrate Kerberos authentication with Javamail (IMAP)?
class java.lang.NullPointerException, null Wrapper integrity check failed...
I am stuck with it. Can you provide any info that when this happens?