[jitsi-dev] GSSAPI support for LDAP directory


#1

Hello,

I'm sending two patches adding support for GSSAPI (Kerberos)
authentication when accessing LDAP directories.

The first patch adds GSSAPI SASL method. Unfortunately, when the method
is tried without valid Kerberos ticket, Java by default asks for login
and password on the console. This behaviour is worked around in the
second patch, using some (Apache 2.0-licensed, hope that's OK) code
borrowed from Spark.

Due to how JAAS works, the code touches some global state. It shouldn't
be a problem, as the plugin is the only GSS-aware piece of code. If
anyone wishes to implement GSSAPI support in other areas in future, some
code (GSSAPIConfiguration and calls to System.setProperty and
Configuration.setConfiguration) might be moved to some shared location.

The patches have been tested in the following configuration:
* Debian testing
* OpenJDK 7u55-2.4.7-1
* ActiveDirectory LDAP and Kerberos

···

--
pozdr(); // Jarek


#2

#3

Needed to avoid user/password prompts *on the console* when the
credentials are not present.

···

From: Jarek Kami�ski <jarek@vilo.eu.org>
---
.../impl/ldap/GSSAPIConfiguration.java | 100 +++++++++++++++++++++
.../communicator/impl/ldap/LdapDirectoryImpl.java | 19 ++--
.../sip/communicator/impl/ldap/ldap.manifest.mf | 1 +
3 files changed, 115 insertions(+), 5 deletions(-)
create mode 100644 src/net/java/sip/communicator/impl/ldap/GSSAPIConfiguration.java

diff --git a/src/net/java/sip/communicator/impl/ldap/GSSAPIConfiguration.java b/src/net/java/sip/communicator/impl/ldap/GSSAPIConfiguration.java
new file mode 100644
index 0000000..13127d9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/ldap/GSSAPIConfiguration.java
@@ -0,0 +1,100 @@
+/*
+ * The following file is copied from the Spark project
+ *
+ * Copyright (C) 2004-2011 Jive Software. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.sip.communicator.impl.ldap;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+
+@SuppressWarnings("UseOfObsoleteCollectionType")
+class GSSAPIConfiguration extends Configuration {
+
+ Map<String, Vector<AppConfigurationEntry>> configs;
+
+ GSSAPIConfiguration() {
+ super();
+ init(true);
+ }
+
+ GSSAPIConfiguration(boolean config_from_file) {
+ super();
+ init(config_from_file);
+ }
+
+
+ private void init(boolean config_from_file) {
+
+ configs = new HashMap<String, Vector<AppConfigurationEntry>>();
+
+ //The structure of the options is not well documented in terms of
+ //data types. Since the file version of the Configuration object
+ //puts things in quotes, String is assumed. But boolean options
+ //do not have quotes, and my represent different types internally.
+ HashMap<String, String> c_options = new HashMap<String, String>();
+
+ //If Kerberos config is not from a file, it's not possible to (re-)read the config file.
+ //So don't set refreshKrb5Config
+ if (config_from_file) {
+ c_options.put("refreshKrb5Config", "true");
+ }
+ c_options.put("doNotPrompt", "true");
+ c_options.put("useTicketCache", "true");
+ //c_options.put("debug", "true");
+
+
+ putAppConfigurationEntry("com.sun.security.jgss.initiate", "com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, c_options);
+ putAppConfigurationEntry("com.sun.security.jgss.krb5.initiate", "com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, c_options);
+
+ }
+
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ AppConfigurationEntry[] a = new AppConfigurationEntry[1];
+ if (configs.containsKey(name)) {
+ Vector<AppConfigurationEntry> v = configs.get(name);
+ a = v.toArray(a);
+ return a;
+ }
+ else {
+ return null;
+ }
+ }
+
+ public boolean putAppConfigurationEntry(String name, String module, AppConfigurationEntry.LoginModuleControlFlag controlFlag, Map<String,String> options) {
+ Vector<AppConfigurationEntry> v;
+ if (configs.containsKey(name)) {
+ v = configs.get(name);
+ }
+ else {
+ v = new Vector<AppConfigurationEntry>();
+ configs.put(name, v);
+ }
+
+ return v.add(new AppConfigurationEntry(module, controlFlag, options));
+ }
+
+
+ public void refresh() {
+ }
+
+
+}
diff --git a/src/net/java/sip/communicator/impl/ldap/LdapDirectoryImpl.java b/src/net/java/sip/communicator/impl/ldap/LdapDirectoryImpl.java
index 611ec34..a3341c7 100644
--- a/src/net/java/sip/communicator/impl/ldap/LdapDirectoryImpl.java
+++ b/src/net/java/sip/communicator/impl/ldap/LdapDirectoryImpl.java
@@ -10,6 +10,7 @@ import java.util.*;

import javax.naming.*;
import javax.naming.directory.*;
+import javax.security.auth.login.Configuration;

import net.java.sip.communicator.service.ldap.*;
import net.java.sip.communicator.service.ldap.event.*;
@@ -204,6 +205,12 @@ public class LdapDirectoryImpl
                 // Allow usage of system-provided Kerberos ticket.
                 System.setProperty("javax.security.auth.useSubjectCredsOnly",
                         "false");
+ /*
+ * Use custom JAAS configuration, with doNotPrompt set to true.
+ * This is needed to avoid user/password prompts
+ * *on the console* when the credentials are not present.
+ */
+ Configuration.setConfiguration(new GSSAPIConfiguration());
                 this.env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
                 // Request mutual authentication
                 this.env.put("javax.security.sasl.server.authentication",
@@ -451,11 +458,13 @@ public class LdapDirectoryImpl
                             filter + "\" (initial query: \"" +
                             query.toString() + "\") on directory \"" +
                             LdapDirectoryImpl.this + "\": " + e);
- endEvent = new LdapEvent(
- LdapDirectoryImpl.this,
- LdapEvent.LdapEventCause.SEARCH_AUTH_ERROR,
- query
- );
+ // Ignore auth errors for GSSAPI
+ final LdapEvent.LdapEventCause eventCause
+ = settings.getAuth() != Auth.GSSAPI
+ ? LdapEvent.LdapEventCause.SEARCH_AUTH_ERROR
+ : LdapEvent.LdapEventCause.SEARCH_ERROR;
+ endEvent = new LdapEvent(LdapDirectoryImpl.this, eventCause,
+ query);
                 }
                 catch(NamingException e)
                 {
diff --git a/src/net/java/sip/communicator/impl/ldap/ldap.manifest.mf b/src/net/java/sip/communicator/impl/ldap/ldap.manifest.mf
index d5fdc71..31f59b5 100644
--- a/src/net/java/sip/communicator/impl/ldap/ldap.manifest.mf
+++ b/src/net/java/sip/communicator/impl/ldap/ldap.manifest.mf
@@ -10,6 +10,7 @@ Import-Package: org.osgi.framework,
  javax.naming.event,
  javax.net,
  javax.net.ssl,
+ javax.security.auth.login,
  net.java.sip.communicator.util,
  net.java.sip.communicator.service.certificate,
  org.jitsi.service.configuration,
--
1.9.2


#4

said it
yourself - Spark can use GSSAPI to connect to XMPP server. I'm using it!
(My whole company is using it). For us to get it to work, we needed to put
a "gss.conf"
file in /usr/share/jitsi containing:

com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true;
};

Did you need anything like this at all?

···

On May 1, 2014 3:50 AM, "Jarek Kamiński" <jarek@vilo.eu.org> wrote:

Hello,

I'm sending two patches adding support for GSSAPI (Kerberos)
authentication when accessing LDAP directories.

The first patch adds GSSAPI SASL method. Unfortunately, when the method
is tried without valid Kerberos ticket, Java by default asks for login
and password on the console. This behaviour is worked around in the
second patch, using some (Apache 2.0-licensed, hope that's OK) code
borrowed from Spark.

Due to how JAAS works, the code touches some global state. It shouldn't
be a problem, as the plugin is the only GSS-aware piece of code. If
anyone wishes to implement GSSAPI support in other areas in future, some
code (GSSAPIConfiguration and calls to System.setProperty and
Configuration.setConfiguration) might be moved to some shared location.

The plugin is not the only GSS-aware piece of code, actually. In fact you

--
Thanks,
David Mansfield
Cobite, INC.


#5

Hi

I'm sending two patches adding support for GSSAPI (Kerberos)
authentication when accessing LDAP directories.

Thank you for your work!

The first patch adds GSSAPI SASL method. Unfortunately, when the method
is tried without valid Kerberos ticket, Java by default asks for login
and password on the console. This behaviour is worked around in the
second patch, using some (Apache 2.0-licensed, hope that's OK) code
borrowed from Spark.

The code borrowed from Spark is relatively simple and while the license is
compatible with the LGPL, it cannot go into our source repository in this
form. The code style is the most obvious problem, but I'd also prefer to
avoid using obsolete types that don't seem to be necessary.

Due to how JAAS works, the code touches some global state. It shouldn't
be a problem, as the plugin is the only GSS-aware piece of code. If
anyone wishes to implement GSSAPI support in other areas in future, some
code (GSSAPIConfiguration and calls to System.setProperty and
Configuration.setConfiguration) might be moved to some shared location.

That is okay for the time being.

The patches have been tested in the following configuration:
* Debian testing
* OpenJDK 7u55-2.4.7-1
* ActiveDirectory LDAP and Kerberos

That's unfortunately a problem: I already did some proof of concept a while
back, and it won't work on Windows. Java relies on accessing the TGT session
key, something that Windows doesn't allow by default. You'd need to deploy a
registry key to allow that, weakening the security and only working when the
user is not a local administrator anyway. So: Java+Kerberos+Windows = broken
because Oracle just doesn't seem to care at all.

So for this patch, it means it must filter the platform and not provide
GSSAPI on Windows (and possibly Mac, AFAIK there it's only possible since
JRE 8 which we don't support yet) OR provide some means to let the user
enter his login credentials in a popup window OR just let it be until the
JRE is finally fixed.

Regards,
Ingo

PS: Before you consider working any further on this, please sign the
contributor agreement (bluejimp.com/bca.pdf) and send it to emcho@jitsi.org
if you haven't already done so.


#6

Just FYI: Spark (and Jitsi) GSSAPI DOES work on windows with the registry
tweaks you mentioned. We are using it in our company.

create c:\Program Files\Jitsi\gss.conf (same as I sent in a previous email).

Then with regedit:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos
Value Name: AllowTgtSessionKey
Value Type: REG_DWORD
Value: 0x01

This it itself doesn't weaken security IMHO. It allows applications

to request service tickets - same as what we get on Linux by default.
It does seem

however to not work if user is local administrator.

···

On Thu, May 1, 2014 at 6:04 AM, Ingo Bauersachs <ingo@jitsi.org> wrote:

Hi

> I'm sending two patches adding support for GSSAPI (Kerberos)
> authentication when accessing LDAP directories.

Thank you for your work!

> The first patch adds GSSAPI SASL method. Unfortunately, when the method
> is tried without valid Kerberos ticket, Java by default asks for login
> and password on the console. This behaviour is worked around in the
> second patch, using some (Apache 2.0-licensed, hope that's OK) code
> borrowed from Spark.

The code borrowed from Spark is relatively simple and while the license is
compatible with the LGPL, it cannot go into our source repository in this
form. The code style is the most obvious problem, but I'd also prefer to
avoid using obsolete types that don't seem to be necessary.

> Due to how JAAS works, the code touches some global state. It shouldn't
> be a problem, as the plugin is the only GSS-aware piece of code. If
> anyone wishes to implement GSSAPI support in other areas in future, some
> code (GSSAPIConfiguration and calls to System.setProperty and
> Configuration.setConfiguration) might be moved to some shared location.

That is okay for the time being.

> The patches have been tested in the following configuration:
> * Debian testing
> * OpenJDK 7u55-2.4.7-1
> * ActiveDirectory LDAP and Kerberos

That's unfortunately a problem: I already did some proof of concept a while
back, and it won't work on Windows. Java relies on accessing the TGT
session
key, something that Windows doesn't allow by default. You'd need to deploy
a
registry key to allow that, weakening the security and only working when
the
user is not a local administrator anyway. So: Java+Kerberos+Windows =
broken
because Oracle just doesn't seem to care at all.

--
Thanks,
David Mansfield
Cobite, INC.