You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by bd...@apache.org on 2022/06/23 14:59:37 UTC

[shiro] 01/01: Apply principalSuffix only when username does NOT already contain the suffix

This is an automated email from the ASF dual-hosted git repository.

bdemers pushed a commit to branch shiro-871-19x
in repository https://gitbox.apache.org/repos/asf/shiro.git

commit 0db440a839de1f6bb263c089cdce678c1f241732
Author: Brian Demers <bd...@apache.org>
AuthorDate: Fri Mar 18 17:24:33 2022 -0400

    Apply principalSuffix only when username does NOT already contain the suffix
    
    Fixes: SHIRO-871
---
 .../activedirectory/ActiveDirectoryRealm.java      |  2 +-
 .../apache/shiro/realm/ldap/AbstractLdapRealm.java | 12 +++++
 .../activedirectory/ActiveDirectoryRealmTest.java  | 56 ++++++++++++++++++++++
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/core/src/main/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealm.java b/core/src/main/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealm.java
index 39fa4b62..3dc459cb 100644
--- a/core/src/main/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealm.java
+++ b/core/src/main/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealm.java
@@ -163,7 +163,7 @@ public class ActiveDirectoryRealm extends AbstractLdapRealm {
         searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 
         String userPrincipalName = username;
-        if (principalSuffix != null) {
+        if (principalSuffix != null && !userPrincipalName.toLowerCase(Locale.ROOT).endsWith(principalSuffix.toLowerCase(Locale.ROOT))) {
             userPrincipalName += principalSuffix;
         }
 
diff --git a/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java b/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java
index 25458c9e..36b2ec56 100644
--- a/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java
+++ b/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java
@@ -63,6 +63,18 @@ public abstract class AbstractLdapRealm extends AuthorizingRealm {
     /*--------------------------------------------
     |    I N S T A N C E   V A R I A B L E S    |
     ============================================*/
+
+    /**
+     * Defines the Suffix added to the User Principal Name when looking up groups (e.g. "memberOf")
+     * AD Example:
+     * User's Principal Name be "John.Doe"
+     * User's E-Mail Address be "John.Doe@example.com"
+     *
+     * For the example below, set:
+     *      realm.principalSuffix = @example.com
+     *
+     * Only then, "John.Doe" and also "John.Doe@example.com" can authorize against groups
+     */
     protected String principalSuffix = null;
 
     protected String searchBase = null;
diff --git a/core/src/test/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealmTest.java b/core/src/test/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealmTest.java
index 5a2ce0e7..8d4b661e 100644
--- a/core/src/test/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealmTest.java
+++ b/core/src/test/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealmTest.java
@@ -24,6 +24,7 @@ import org.apache.shiro.authc.credential.CredentialsMatcher;
 import org.apache.shiro.authz.AuthorizationInfo;
 import org.apache.shiro.authz.SimpleAuthorizationInfo;
 import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.mgt.SecurityManager;
 import org.apache.shiro.realm.AuthorizingRealm;
 import org.apache.shiro.realm.UserIdPrincipal;
 import org.apache.shiro.realm.UsernamePrincipal;
@@ -32,14 +33,29 @@ import org.apache.shiro.subject.PrincipalCollection;
 import org.apache.shiro.subject.SimplePrincipalCollection;
 import org.apache.shiro.subject.Subject;
 import org.apache.shiro.util.ThreadContext;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapContext;
 import java.util.HashSet;
 import java.util.Set;
 
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.anyString;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.assertTrue;
 
 
@@ -97,6 +113,43 @@ public class ActiveDirectoryRealmTest {
         subject.logout();
     }
 
+    @Test
+    public void testExistingUserSuffix() throws Exception {
+        assertExistingUserSuffix(USERNAME, "testuser@ExAmple.COM"); // suffix case matches configure suffix
+
+        // suffix matches user entry
+        assertExistingUserSuffix(USERNAME + "@example.com", "testuser@example.com");
+        assertExistingUserSuffix(USERNAME + "@EXAMPLE.com", "testuser@EXAMPLE.com");
+    }
+
+    public void assertExistingUserSuffix(String username, String expectedPrincipalName) throws Exception {
+
+        LdapContext ldapContext = createMock(LdapContext.class);
+        NamingEnumeration<SearchResult> results = createMock(NamingEnumeration.class);
+        Capture<Object[]> captureArgs = Capture.newInstance(CaptureType.ALL);
+        expect(ldapContext.search(anyString(), anyString(), capture(captureArgs), anyObject(SearchControls.class))).andReturn(results);
+        replay(ldapContext);
+
+        ActiveDirectoryRealm activeDirectoryRealm = new ActiveDirectoryRealm() {{
+            this.principalSuffix = "@ExAmple.COM";
+        }};
+
+        SecurityManager securityManager = new DefaultSecurityManager(activeDirectoryRealm);
+        Subject subject = new Subject.Builder(securityManager).buildSubject();
+        subject.execute(() -> {
+
+            try {
+                activeDirectoryRealm.getRoleNamesForUser(username, ldapContext);
+            } catch (NamingException e) {
+                Assert.fail("Unexpected NamingException thrown during test");
+            }
+        });
+
+        Object[] args = captureArgs.getValue();
+        assertThat(args, arrayWithSize(1));
+        assertThat(args[0], is(expectedPrincipalName));
+    }
+
     public class TestActiveDirectoryRealm extends ActiveDirectoryRealm {
 
         /*--------------------------------------------
@@ -117,6 +170,9 @@ public class ActiveDirectoryRealmTest {
             setCredentialsMatcher(credentialsMatcher);
         }
 
+        public void setPrincipalSuffix(String principalSuffix) {
+            this.principalSuffix = principalSuffix;
+        }
 
         protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
             SimpleAccount account = (SimpleAccount) super.doGetAuthenticationInfo(token);