Popular community supported LDAP Security Manager for GemFire broken by Shiro upgrade in VMware GemFire v9.9 and v9.10
search cancel

Popular community supported LDAP Security Manager for GemFire broken by Shiro upgrade in VMware GemFire v9.9 and v9.10

book

Article ID: 294411

calendar_today

Updated On:

Products

VMware Tanzu Gemfire

Issue/Introduction

Charlie Black's community supported LDAP security manager implementation for GemFire, vmware-gemfire-ldap (https://github.com/charliemblack/vmware-gemfire-ldap), is one of the most popular ways to connect GemFire authentication to LDAP or Active Directory. This implementation uses Shiro to map LDAP roles to GemFire permissions.

In order to address known security vulnerabilities, the version of Shiro used by and distributed with GemFire must be periodically upgraded. Unfortunately, Shiro 1.5.0 introduced a bug in its INI-file parser that can cause issues with the mapping of LDAP group names to GemFire roles and this bug is present in GemFire versions starting with 9.9.3 and 9.10.1.

Note: As of the time this article was written, the fix is not yet available in any Shiro release and is not included in any GemFire release.

This issue manifests itself as an AuthenticationException due to missing GemFire roles and messages like the following are found in the logs:
[error 2021/04/01 12:00:00.135 PDT <RMI TCP Connection(4)-10.0.0.5> tid=0x5a] Could not authenticate : 
org.apache.shiro.authc.AuthenticationException: User has been authenticated, however doesn't have any GemFire roles
       at io.pivotal.gemfire.ldap.GemFireLDAPRealm.queryForAuthenticationInfo(GemFireLDAPRealm.java:147)
       at org.apache.shiro.realm.ldap.AbstractLdapRealm.doGetAuthenticationInfo(AbstractLdapRealm.java:200)
       at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571)
       ...
The error indicates that although the user account successfully authenticated against the LDAP server, the module was unable to match any of that accounts groups to GemFire roles. In turn, this is a result of the broken Shiro INI parser mishandling escaped equals, "\=", in the groups' distinguished names in the configuration file.

Environment

Product Version: 9.10

Resolution

Short of switching to another Security Manager implementation, the only resolution presently available is to build your own custom version of the shiro-core JAR with the fix applied and replace the jar distributed with GemFire (in the GemFire lib directory) with this modified JAR.


Custom shiro-core JAR

1. Clone the shiro repository from GitHub:
  $ git clone https://github.com/apache/shiro.git
2. Change into the resulting shiro directory and checkout the appropriate version (e.g. v1.7.1 for GemFire 9.10.6, v1.6.0 for GemFire 9.10.5, etc.):
  $ cd shiro
  $ git checkout shiro-root-1.7.1
3. Make the fix to the Ini.java and remove one test from IniTest.groovy that validates the "bad" behavior. (A .diff with the necessary changes is included at the bottom of this section):
  $ patch -p1 < shiro-ini-fix.diff
4. Build the JAR:
  $ mvn -am -pl :shiro-core package
5. Copy the resulting JAR over the one distributed with GemFire:
  $ cp core/target/shiro-core-1.7.1.jar <PATH TO GEMFIRE LIB DIR>
6. Make sure your LDAP Security Manager is built against the correct version of Shiro.

Shiro-Ini-Fix.diff
diff --git a/config/core/src/main/java/org/apache/shiro/config/Ini.java b/config/core/src/main/java/org/apache/shiro/config/Ini.java
index 79936190..6e01fbe4 100644
--- a/config/core/src/main/java/org/apache/shiro/config/Ini.java
+++ b/config/core/src/main/java/org/apache/shiro/config/Ini.java
@@ -579,7 +579,7 @@ public class Ini implements Map<String, Ini.Section> {
                 char c = line.charAt(i);
 
                 if (buildingKey) {
-                    if (isKeyValueSeparatorChar(c) && !isCharEscaped(line, i)) {
+                    if (isKeyValueSeparatorChar(c) && !isCharEscaped(line, i-1)) {
                         buildingKey = false;//now start building the value
                     } else if (!isCharEscaped(line, i)){
                         keyBuffer.append(c);
diff --git a/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy b/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
index cf9ee12b..c0f9f686 100644
--- a/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
+++ b/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
@@ -161,17 +161,6 @@ public class IniTest {
         assertEquals("\\ Beauty\\", kv[1]);
     }
 
-    /**
-     * Tests if an escaped separator char will not be recognized as such.
-     */
-    @Test
-    public void testSplitKeyValueEscapedEquals()  {
-        String test = "Truth\\=Beauty";
-        String[] kv = Ini.Section.splitKeyValue(test);
-        assertEquals("Truth", kv[0]);
-        assertEquals("Beauty", kv[1]);
-    }
-
     @Test(expected = IllegalArgumentException.class)
     public void testSplitKeyValueNoValue() {
         String test = "  Truth  ";


Attachments

shiro-ini-fix get_app