Java GSSAPI Credentials with Active Directory - java

Apologies in advance - I'm pretty new to Kerberos/GSSAPI, so I've probably got something really simple stuffed up.
I'm trying to run what is essentially the sample client code from the GSSAPI tutorials.
I have two VMs set up. One is named KDC-TESTING. It's a Domain Controller with Active Directory installed and a user named "testuser". It's running on the KDC.COM domain.
The second is running an IIS server named IIS-WEB that runs on the KDC.COM domain.
I also have my computer (windows 7). It's on a different domain, but it's currently using the domain controller's IP as its DNS. I'm trying to run the Basic GSSAPI client from eclipse on here.
When you go to iis-web.kdc.com (from either the domain controller vm or my computer), you're prompted for a username/password combo. You can log in using testuser (with its password, obviously).
When I run the client program, I get the following error:
org.ietf.jgss.GSSException, major code: 13, minor code: 0
major string: Invalid credentials
minor string: SubjectCredFinder: no JAAS Subject
It's thrown from this line:
GSSContext context = manager.createContext(clientName, krb5Mechanism, null, GSSContext.DEFAULT_LIFETIME);
Since it says the credentials are invalid, I added in the following (and tried creating the context with creds rather than null):
GSSCredential creds = manager.createCredential(clientName, GSSContext.DEFAULT_LIFETIME, krb5Mechanism, GSSCredential.INITIATE_ONLY);
That changed literally nothing (except for the stack trace).
Looking at this question and a bunch of docs/blogs, I think the problem is somewhat related to configuration, but I'm not sure what configuration needs to be done exactly.
I've got a krb5.conf file set up, and I'm running it with the command line arguments shown here.
I haven't done any Kerberos setup on my computer, but I've an SPN to testuser and maybe set up a keytab on the VMs (but I'm almost certain that that's not the cause).
EDIT/UPDATE:
I ran it from a new VM that was both on the KDC.COM domain and used KDC-TESTING.KDC.COM as its DNS and it seemed to work as expected (there was another error, this time with authenticating - progress! I think I know what's wrong with this one though).
I ran it as a JAR (as opposed to from inside eclipse) and, as expected, I was prompted in the command window for a username and password. Could this have been an issue (as in, is eclipse not able to take input, so it just crashes or something)?
I also hadn't been seeing any of the security debugging logs in eclipse (I'd been using -Djava.security.debug=all), but on the the VM it was all there (there was a lot of it).

Related

LDAP Entry Poisoning Fixed in jdk-8u191?

Fortify has reported an LDAP Entry Poisoning vulnerability in one of my Spring applications. You can get additional information on this vulnerability from the following links:
https://www.youtube.com/watch?v=Y8a5nB-vy78&feature=youtu.be&t=2111
https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf
https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE-wp.pdf
I decided to try and prove for myself if this was still a vulnerability. I did this by using Spring Tool Suite:
file -> new -> import spring getting started content
searched for ldap
and imported the Authenticating Ldap -> complete code set
https://spring.io/guides/gs/authenticating-ldap/
I then added the following lines to the included test-server.ldif file to the entry for bob as well as the entry for developers:
javaFactory: PayloadObject
objectClass: javaNamingReference
javaCodebase: http://127.0.0.1:9999/
javaClassName: PayloadObject
In order to run this, I needed to add the following line to application.properties:
spring.ldap.embedded.validation.enabled=false
I started up Wireshark and ran the Spring sample app, and sure enough, when I logged in with bob, I got a hit in Wireshark on port 9999.
When I asked a co-worker to test the same thing, he was unable to reproduce. After some research, we discovered that he had a newer jdk than I, and after I updated my jdk, I, too, was unable to reproduce the issue.
We narrowed it down to jdk-8u191 was the version that introduced "the fix", but I can't find anything that explains why or how it was fixed in the java release notes.
My question is - is LDAP Entry Poisoning now a false/positive if we're running jdk-8u191 or newer? Or is there some configuration option that can be set to override this "fix"?
8u191 closed a remote class loading vulnerability in LDAP, though research is ongoing. Whenever you are turning a stream of bytes into an Object in Java, you want to think about class loading (what 8u191 addressed), but also insecure deserialization.
When CVEs are addressed, they are not typically in the release notes.
As for whether or not the alert from Fortify is a false positive, I think it is more important to assess the risk relative to your application.
To leverage this vulnerability, for example, the attacker would at least need direct access to your LDAP instance (see pg 31), which likely indicates a larger security issue. 8u191 and after, the attacker would additionally need to find a class in your classpath that is vulnerable to insecure deserialization to reproduce what the BH talk demonstrates.

Connection with TN5250j works while IBMi access v1r1 (and JT400 library) does not

Few days ago my correctly working java application stated to throw "General security error" while connecting to AS400. I use JT400 library for connect. After some debugging I also find out I cannot connect with IBMi access v1r1 (5250 emulator from IBM). System i Navigator also does not work. This is print screen from login (errors are same for java application):
But connecting with TN5250J emulator works! I guess problem is with "Not authorized to object /QSYS.LIB/EN_US.LOCALE". I tried connecting with two users. One is my programming user and it works normally when connected through TN5250J. Other one is database access user that I cannot check because it has disabled access through terminal. Using same application on different system (V5R4) works correctly. Looking into job log I found nothing.
Why is /QSYS.LIB/EN_US.LOCALE accessed during signon (and it is not accessed from TN5250J)? What could affect signon process so that it no longer works with IBM emulator/library while it still works with TN5250J? Are there some connection properties in JT400 library that could affect what happens during signon so I could connect like with TN5250J?
Also please someone create tag TN5250J. I think it should be here and I have no reputation to create it!
Solution in article suggested by JamesA works. Our admin did it and I have my access back. But our admin has no idea how issue was created in the first place.
Solution from article:
Execute the Work with Object Links command (WRKLNK) to view the Root (/) directory of the AS/400 IFS.
WRKLNK OBJ('/')
In front of the AS/400 IFS directory object (specified by a single '/'), enter a '9' to work with the Root (/) object's authority.
If *PUBLIC authority is equal to *EXCLUDE, place a '2' in front of the *PUBLIC entry, press enter and add the following authorities for the *PUBLIC user:
Under the New Data Authorities parameter (DTAAUT), enter *RWX so that the user has read, write, and execute in the Root (/) directory.
Under the New Object Authorities parameter (OBJAUT), enter the following authorities:
*OBJMGT: Object management authority
*OBJEXIST: Object existence authority
*OBJALTER: Object alter authority
*OBJREF: Object reference authority
Press Enter and save your changes.
TN5250J worked because error does not happen during login (for example through green screen) but instead it happens during initialization - when you start IBMi Access and GUI window will sometimes prompt for login. Since TN5250j does not do this it works. In IBMi Access when in first prompt I specify user with *ALLOBJ authority I can then login through green screen normally with my normal user. JT400 library probably just combines logic for initialization and login!

Malformed PAC logon info on new KerberosToken

I'm using the code here to get authentication information from a Kerberos token. In there I've configured the domainUsername and domainUserPassword and just ran it as specified in the readme.md.
Then, from a browser that is in the AD domain, I connect to http://server:8080/spnego and I see on the opened page my username#domain. The page should also contain the SID of the AD groups to which my user belongs.
Looking at the server logs, I see:
org.jaaslounge.decoding.DecodingException: Malformed PAC logon info.
at org.jaaslounge.decoding.pac.PacLogonInfo.<init>(PacLogonInfo.java:209)
at org.jaaslounge.decoding.pac.Pac.<init>(Pac.java:45)
at org.jaaslounge.decoding.kerberos.KerberosPacAuthData.<init>(KerberosPacAuthData.java:13)
at org.jaaslounge.decoding.kerberos.KerberosAuthData.parse(KerberosAuthData.java:21)
at org.jaaslounge.decoding.kerberos.KerberosRelevantAuthData.<init>(KerberosRelevantAuthData.java:41)
at org.jaaslounge.decoding.kerberos.KerberosAuthData.parse(KerberosAuthData.java:18)
at org.jaaslounge.decoding.kerberos.KerberosEncData.<init>(KerberosEncData.java:136)
at org.jaaslounge.decoding.kerberos.KerberosTicket.<init>(KerberosTicket.java:103)
at org.jaaslounge.decoding.kerberos.KerberosApRequest.<init>(KerberosApRequest.java:62)
at org.jaaslounge.decoding.kerberos.KerberosToken.<init>(KerberosToken.java:52)
at com.example.ManualSpnegoNegotiateServlet.attemptNegotiation(ManualSpnegoNegotiateServlet.java:271)
Line 271 is the following
KerberosToken token = new KerberosToken(kerberosTokenData, keys);
That error message is too vague. I've no idea how to continue and I get the same error from different clients.
Does anyone have any tip about this?
I've figured this one out myself. It turns out that the message "Malformed PAC logon info" is actually correct. The code failed when it was trying to get the "Resource groups data".
Initially I thought that the PAC_LOGON_INFO structure has changed since the last jaaslounge implementation was written (somewhere in 2010). I thought that because the MS-PAC specification does not mention it at all.
Actually, the problem is coming from a completely different place: the KDC. It's running on a Win Server 2012, version in which Microsoft added by default resource SID Compression.
There you have it, if you turn off resource SID Compression on the KDC, everything will start working (no need to touch anything else, i.e. the version of jaaslounge or to patch hava with an unlimited JCE policy).

PAM "pam_unix.so" authentication sometimes fails

I'm having some trouble with PAM. I have a tomcat webapp that uses PAM to authenticate. During install we make a symbolic link in /etc/pam.d to the /etc/pam.d/sshd file. This has always worked.
Recently I added a way for users to authenticate each request (rather than using a JSESSIONID cookie). This was added because we need to batch load some data into a monitoring application periodically and using Basic Auth was easy.
If I curl my webservice repeatedly (like 10 times a second), then every once in a while PAM will fail. This happens around once every 500 times, though my client claims that it happens once every couple of times (note that they are running remotely, though i don't see why that matters).
I have replaced my sym-linked pam config with a minimal config of:
#%PAM-1.0
auth sufficient pam_unix.so audit
auth required pam_deny.so
I have also added this to my /etc/syslog.conf
*.debug /var/log/debug.log
The only applicable log messages can be found in the debug.log:
Mar 12 09:49:32 arques java: pam_unix(foo:auth): unable to obtain a password
Mar 12 09:49:32 arques java: pam_unix(foo:auth): auth could not identify password for [root]
How do I debug this further? I have tried:
Using different hosts. One which is a brand new install
I've turned off the nscd service
I'm having a similar problem with a Java application that uses PAM for authentication. For now, I'm guessing the problem is within the distributed Java PAM binding implementation on CentOS 6.4. I no longer have access to that system (but I'm still trying to solve this problem) so I cannot provide specifics such as JDK version, etc.
My solution ultimately was to harshly kludge PAM:
#%PAM-
auth sufficient pam_debug.so
To make this more explicit, you could use "pam_permit.so" instead.
That's it, basically. Any valid user would then be authenticated, with or without password. Ugh.
I'm continuing to research better answers.

Impersonating a user from a Java Servlet

Given a Java Servlet (running on a Windows server) which creates a new process via ProcessBuilder, what are my options for having that new process run as the user who invoked the original web request to the servlet?
To clarify, what I want is that something like
ProcessBuilder pb = new ProcessBuilder("whoami");
Process p = pb.start();
// p.getOutputStream() should contain the name of the remote user,
// not the user running the app server
And the real goal is to perform some security checks (say, to see if the user if able to open a file, or view such-and-such record in an internal enterprise system).
Clearly the user will need to be authenticated somehow, either by the app server or the java code - Ideally I'd like that to be in some way that works with single sign on (i.e. without the user entering a password), and it's fine if the solution works only from Windows clients who are already logged onto a domain (though even better if that's not a restriction). I'm currently using Jetty as the app server, but switching to something else would certainly be a viable option if necessary.
(If it helps to clarify, I'm basically looking to replace a CGI script which currently uses IIS's impersonation features to run in the context of the user making the request)
Project Waffle will get you (almost) there. It has SSO and impersonation implemented.
Your only option is going to be JNI, or some wrapper around JNI like JNA. You will need to call O/S APIs to change your effective credentials, which will also require the application server to run as administrator - which is itself a significant security consideration.
I don't know specifically about Windows APIs, but most O/S's have the ability for a sufficiently powerful profile (admin/root) to assume the identity of any user profile without needing the password. Otherwise, usually the only way to acquire a user profile token is to present legitimate authentication credentials for that profile.
One thing to be careful of is to ensure that you change the credentials for the thread, not the entire process.

Categories