Naveesh Doolhur created RANGER-5774:
---------------------------------------

             Summary:  RangerAuthenticationProvider LDAP search+bind mode 
(empty ranger.ldap.user.dnpattern) bypasses password validation via anonymous 
bind
                 Key: RANGER-5774
                 URL: https://issues.apache.org/jira/browse/RANGER-5774
             Project: Ranger
          Issue Type: Bug
          Components: Ranger
    Affects Versions: 2.9.0, 2.8.0, 2.7.0, 2.6.0, 2.5.0
         Environment: Docker
            Reporter: Naveesh Doolhur


When ranger.authentication.method=LDAP is configured for search+bind mode 
(using ranger.ldap.base.dn / ranger.ldap.bind.dn / ranger.ldap.bind.password, 
with ranger.ldap.user.dnpattern left empty as documented/expected for this 
mode), any password is accepted for any existing local Ranger username — 
authentication is effectively bypassed.

 

authenticate() always tries getLdapAuthentication() (the DN-pattern method) 
before falling back to getLdapBindAuthentication() (the search+bind method):
if ("LDAP".equalsIgnoreCase(rangerAuthenticationMethod)) {
    authentication = getLdapAuthentication(authentication);
    if (authentication != null && authentication.isAuthenticated()) {
        return authentication;
    } else {
        authentication = getLdapBindAuthentication(authentication);
        ...
Inside getLdapAuthentication():

 

Secondary bug, same investigation: even after working around the above (by 
setting ranger.ldap.user.dnpattern to a deliberately non-matching placeholder 
DN, forcing correct fallthrough to getLdapBindAuthentication()), a correct 
password still failed to authenticate whenever 
ranger.ldap.group.searchfilter/ranger.ldap.group.searchbase were left empty. 
getLdapBindAuthentication(), unlike getLdapAuthentication(), has no guard 
around constructing DefaultLdapAuthoritiesPopulator, so it always performs a 
group-membership search using those values; an empty filter throws 
InvalidSearchFilterException from the JNDI layer after the real user bind 
already succeeded, and that exception is caught and treated as an 
authentication failure.

Steps to Reproduce:
1. Set ranger.authentication.method=LDAP.
2. Configure ranger.ldap.base.dn, ranger.ldap.bind.dn, 
ranger.ldap.bind.password for search+bind mode (per documentation, leave 
ranger.ldap.user.dnpattern empty).
3. Attempt to log in (UI or /service/xusers/users REST endpoint via Basic Auth) 
as any existing local Ranger username, with any incorrect password.

Expected: Login rejected.
Actual: Login succeeds.

Suggested fix: getLdapAuthentication() should check rangerLdapUserDNPattern for 
blank/empty before attempting a bind, and skip directly to 
getLdapBindAuthentication() if so, rather than constructing a pattern from an 
empty string. Separately, getLdapBindAuthentication() should guard its 
DefaultLdapAuthoritiesPopulator construction the same way 
getLdapAuthentication() already does (if 
(!StringUtil.isEmpty(rangerLdapGroupSearchBase) && 
!StringUtil.isEmpty(rangerLdapGroupSearchFilter))).


String[] userDnPatterns = rangerLdapUserDNPattern.split(";");
bindAuthenticator.setUserDnPatterns(userDnPatterns);
"".split(";") in Java returns [""] — one element, an empty string — not an 
empty array. That empty pattern becomes the LDAP bind DN for every login 
attempt regardless of username. Binding with an empty DN is a standard 
anonymous bind (RFC 4513), which most LDAP servers (including 389 Directory 
Server, tested directly) treat as always-successful, ignoring whatever password 
was supplied. getLdapAuthentication() therefore returns an "authenticated" 
result for any credentials, and getLdapBindAuthentication() — the method 
actually intended for this configuration — never runs.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to