Is there an implementation of the MIT Kerberos admin protocol in Java which i can use to create an kerberos administration client written in Java?
My application should be able to:
1.) authenticate with MIT Kerberos Server
2.) add/delete user/service principals
No kadmin.local calls. JNI Bindings would work, too.
Alternative:
Since kerberos credentials are saved in ldap it is possible to change those information. This might be an easy alternative. But this would mean editing KDCs database itself. This bypasses the kadmin protocol and requires knowledge of how this database is created. This method should not be favored over a kadmin protocol interface.
Use Apache Directory Studio, a very nice tool.
Related
I have Kerberos and have enabled Hadoop cluster. I need to perform HDFS operations using Java code.
I have keytab file and username.
Can someone please suggest how can I authenticate Kerberos using Java code?
Thanks.
If you just want to use the HDFS Java API for a short-lived connection, then UserGroupInformation has a loginUserFromKeytab method.
If you want a durable connection (i.e. longer than the lifetime of the initial Kerberos TGT) then have a look at that post.
If you are interested in the dark side of Kerberos (well, there is no other side anyway) then have a look at the "Madness beyond the Gate" online book -- at your own risk.
~~~~~~
BTW there is an alternative to the Java API: the WebHDFS REST service. But on Windows you still need some Java code to create the Kerberos TGT (using GSSAPI i.e. the Linux way, not SSPI i.e. the Microsoft way!!!), run the SPNEGO initial authentication, and retrieve the delegation token. At this point any HTTPS library will be able to handle the file operations using that token.
There are standard Java API's for LDAP from Sun.
now i use these to operate Active Directory.
now i can create user account、create computer with java api.
But how can I grant authorization user&group to join a computer to an AD domain when i new a computer account?
i know openLDAP can do it :Access Control
but how can i do with java api?
Granting authorization is not discrib in any LDAP RFC. This part is proprietary.
In OpenLDAP Access Control List (ACL) is established by a kind of filter.
In SUN Directory (Nowdays Oracle one) ACLs are established by attributes.
In Active Directory granting authorization is done using internal in the same proprietary maner as in the NFTS file system.
The thing you can do is to execute an external program like DSACLS.EXE see Dsacls Examples
Another solution should be to map COM ADSI objects into Java this may help you (or not).
JNDI LDAP auth requires a cleartext password to be passed (Context.SECURITY_CREDENTIALS) to almost all security mechanisms (or at least how I understand it). It looks like to be designed in a way, that the password originates from the current JVM. But what about a password, that has to be sent from another machine? This approach forces it to be sent in a recoverable fashion (the most simple is cleartext) with little security.
To be more specific, let's consider a 3-tier setup: client, java server and an LDAP server. The user enters the username and password in the client which is sent to the java server. Then the java server communicates with an LDAP server in order to authorize these credentials. Is there a way to make the transmission from the client to the java server secure?
I understand, that we can use SSL or another way to secure the channel itself, but it's still no good that we have to send the password in a recoverable fashion through this (even secure) channel.
I tried to search for an answer, but it looks like most of them consider a 2-tier setup. There were also some 3d party java libraries recommendations (instead of JNDI), but it wasn't clear, if that they can handle my task. If they actually do so, could you please give an example utilizing them for my task?
My target platforms are Delphi XE3 Client, Java SE 6 Server and an AD LDAP. But I'm also interested in a more theoretical discussion not restricted to these concrete client and LDAP.
This approach forces it to be sent in a recoverable fashion (the most simple is cleartext) with little security.
The approach requires you to use SSL. It's as simple as that.
We found the answer and actually made it work on a production system.
The correct path is to use the Kerberos protocol http://en.wikipedia.org/wiki/Kerberos_(protocol).
In my setup the following happens:
1) The client obtains a ticket to the server service in the AD and sends it to the server. This is done via classes near TSSPIWinNTCredentials class in Indy, but I think it's quite possible to do so without difficulties using Windows functions directly.
2) The server logins to the AD as a service. This is done via LoginContext class using correct AppConfigurationEntry with keys.
3) The server authenticates the client in the AD using client's ticket, obtaining client's username. This is done via Subject.doAs method and classes near GSSManager class.
4) The server performs additional business level checks and grants the client a business session. This is business-specific of course.
At no point in this scenario any insecure communication is made, including sending passwords in a recoverable fashion, because it is the design goal of the Kerberos protocol itself.
I want to implement Single Sign On with Kerberos in Java and have successfully managed to create a ticket for the Service using the ticket from the Windows logon. Unfortunately, I can only create that ticket when the Registry Key "allowtgtsessionkey" is enabled. I am receiving an exception with the message "Identifier doesn't match expected value (906)" as soon as I disable it. The registry key is documented on http://java.sun.com/j2se/1.5.0/docs/guide/security/jgss/tutorials/Troubleshooting.html and http://support.microsoft.com/kb/308339.
Unfortunately I do not have access to the registry on the computers where my application will be used, so I am looking for a way to do this without having to modify it. When I do Single Sign On over SPNEGO in Internet Explorer or Mozilla Firefox, they create a Service ticket in my ticket cache, so there definitely has to be a way to do this without setting the registry key. Does anyone have an idea how to do this in Java?
Thanks for your help,
memminger
Update: I am giving up on this issue. The Windows registry key prevents the access to the Ticket (more exactly: the Subject) inside the Ticket cache. Java on Windows uses its own GSSAPI implementation, and I suppose that needs access to the Ticket to create a Service Ticket. The SSPI Windows API though has full access to the Ticket cache and can thus create Service tickets. This API is used by the web browsers, but it is not used by Java (according to http://java.sun.com/developer/technicalArticles/J2SE/security/#3). When I disable SSPI in Firefox after having accessed a web page once (so a service ticket has been created), I can still access the page, so maybe a command-line util would be sufficient that creates a service ticket using the SPPI API.
For us, this means now that we can either abandon Single Sign On (which is unacceptable for us) or that we do the authentification on the client side of our application (because we can only read out the username but not verify the ticket on the server), which is a major security risk. Another example of how stronger security constraints lead to bigger security holes because they become too complicated to use.
Forgive me if I am misunderstanding you problem, but...
The point of SSO type systems is that the client authenticates directly to the (separate) authentication server, and obtains a ticket from it. It then passes the ticket to the target server(s) it wants to use, each of which verify that the ticket is valid with the authentication server. If the ticket is validated, it can be assumed by the server that the client only obtained it by presenting the (trusted) Kerberos server with acceptable credentials.
Nowhere in the process, should any server authenticate on behalf of the client. In such a system, the only server that needs to know and validate the client's credentials is the authentication server - no other server need have access to this information. This way the client can authenticate for many servers with just one authentication exchange, and credentials are not put at risk by being stored on, or accessible to, multiple servers.
It sounds like your implementation is working just as it should - the authentication should occur on the client side of the application, and this is correct and not a security risk.
Have you tried setting sun.security.jgss.native in Java 6? Wouldn't SSPI be the "native" interface for windows?
You can access the native SSPI API via JNA. See the WindowsAuthProviderImpl in WAFFLE or WindowsNegotiateScheme from the Apache HC library for an example.
Native support for Windows SSPI was introduced into JDK 13 and later backported to JDK 11 too. You'll need to use at least Java 11.0.10. When the JDK's support for SSPI is used then there's no longer a need to fiddle with the allowtgtsessionkey registry key, nor any need to use JNA or Waffle.
You need to set
-Dsun.security.jgss.native=true
to make it work.
You can recognize if your JDK version for Windows has support for SSPI if it includes a file named sspi_bridge.dll in the bin directory.
Refs:
JDK-6722928
we are using JAAS to enable Single Sign On in a Java application using the Windows Kerberos ticket cache. Our jaas.conf config file looks like this:
LoginJaas {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=true
doNotPrompt=true
debug=true;
};
With this, we can create a Jaas LoginContext and successfully get the user's Kerberos ticket. We send this ticket to out server application using JMI. What we don't manage to do though is to verify on the server that the Kerberos ticket was in fact created by our Active Directory.
At the moment, we do a very insecure validation of the ticket by simply checking if the Server Principal (KerberosTicket.getServer()) name has our domain name in the realm part. But of course, anyone could set up an own Kerberos server with the same realm name and use that ticket to start the application.
One idea I have found was to authenticate against the Active Directory LDAP using the Kerberos ticket. Unfortunately, we use Windows 7 and re-using the Kerberos ticket to authenticate against the LDAP only works when setting a Registry entry (see http://java.sun.com/j2se/1.5.0/docs/guide/security/jgss/tutorials/Troubleshooting.html, search for allowtgtsessionkey). This is unacceptable for our users.
Is there any way to validate the ticket against our Active Directory server? I suspect there is a way to check if the KerberosTicket.getServer() ticket equals the ticket of our server, but I have no idea how to do that. UPDATE: KerberosTicket().getServer() only returns a KerberosPrincipal that contains nothing but the server ticket name and realm, so it is not suitable for validation.
Thanks for your help,
memminger
As you mentioned, the proper way to solve this is by kerberizing your service, which is the whole point of the Kerberos protocol (authenticating clients against servers). Ticket reuse doesn't work exactly because it'd be a security problem if it did.
A Kerberos service does not need to "log into Active Directory", it just needs to have a shared key with AD.
BTW, to get SSO using JAAS requires having that allowtgtsessionkey set, there's no way around that on Windows.
As no one seems to really know an answer to this, I suppose we have to make a proper Kerberos service out of our server application. One that logs in to the Active Directory itself and that has the ServicePrincipalName attribute set properly. Kind of like SPNEGO does for HTTP. A good starting point how to do that will be the SPNEGO Servlet filter on SourceForge (http://spnego.sourceforge.net/). http://thejavamonkey.blogspot.com/2008/04/clientserver-hello-world-in-kerberos.html is also a very good example of how to do Service logon.
Unfortunately, this leads to the same problem with the registry key, so I posted a new question on Is there a way in Java or a command-line util to obtain a Kerberos ticket for a service using the native SSPI API?.