added support of multiple fallback suffixes

This commit is contained in:
Joern Muehlencord
2019-08-02 08:45:34 +02:00
parent 24dc927ab7
commit 119fb04520

View File

@ -16,6 +16,8 @@
package de.muehlencord.shared.account.shiro.realm; package de.muehlencord.shared.account.shiro.realm;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.naming.ldap.LdapContext; import javax.naming.ldap.LdapContext;
@ -39,7 +41,8 @@ public class UserNameActiveDirectoryRealm extends ActiveDirectoryRealm {
private static final Logger LOGGER = LoggerFactory.getLogger(UserNameActiveDirectoryRealm.class); private static final Logger LOGGER = LoggerFactory.getLogger(UserNameActiveDirectoryRealm.class);
private boolean permissionsLookupEnabled = true; private boolean permissionsLookupEnabled = true;
protected String fallbackPrincipalSuffix = null; protected List<String> fallbackPrincipalSuffixes = null;
private NamingException lastException = null;
@Override @Override
public boolean supports(AuthenticationToken token) { public boolean supports(AuthenticationToken token) {
@ -49,69 +52,54 @@ public class UserNameActiveDirectoryRealm extends ActiveDirectoryRealm {
@Override @Override
protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException { protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token; UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String userName = upToken.getUsername();
LdapContext ctx = lookupUserWithSuffix(upToken, ldapContextFactory, principalSuffix);
String userName = getUserName(upToken, principalSuffix); if (fallbackPrincipalSuffixes != null) {
LdapContext ctx = null;
try {
ctx = lookupUser(userName, upToken.getCredentials(), ldapContextFactory);
} catch (NamingException ex) {
if (fallbackPrincipalSuffix == null) {
throw ex;
}
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Lookup with principalSuffix {} failed, falling back to {}", principalSuffix, fallbackPrincipalSuffix); LOGGER.debug("Trying the fallbackSuffixes = {}", fallbackPrincipalSuffixes.toString());
}
} finally {
LdapUtils.closeContext(ctx);
} }
if ((ctx == null) && (fallbackPrincipalSuffix != null)) { Iterator<String> it = fallbackPrincipalSuffixes.iterator();
userName = getUserName(upToken, fallbackPrincipalSuffix); while ((ctx == null) && (it.hasNext())) {
try { ctx = lookupUserWithSuffix(upToken, ldapContextFactory, it.next());
ctx = lookupUser(userName, upToken.getCredentials(), ldapContextFactory);
} catch (NamingException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Lookup with fallbackSuffix {} also failed", fallbackPrincipalSuffix);
}
throw ex;
} finally {
LdapUtils.closeContext(ctx);
} }
} }
if (ctx == null) { if (ctx == null) {
if (lastException != null) {
throw lastException;
} else {
throw new NamingException("Unknown error authenticationing user " + userName + ". Context still null. Check implementation"); throw new NamingException("Unknown error authenticationing user " + userName + ". Context still null. Check implementation");
} }
}
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("User {} LDAP authenticated", userName); LOGGER.debug("User {} LDAP authenticated", userName);
}
LOGGER.debug("building authentication info"); LOGGER.debug("building authentication info");
}
AuthenticationInfo authInfo = buildAuthenticationInfo(userName, upToken.getPassword()); AuthenticationInfo authInfo = buildAuthenticationInfo(userName, upToken.getPassword());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("authentifaction info created"); LOGGER.debug("authentifaction info created");
}
return authInfo; return authInfo;
} }
/** /**
* Builds an {@link org.apache.shiro.authz.AuthorizationInfo} object by * Builds an {@link org.apache.shiro.authz.AuthorizationInfo} object by querying the active directory LDAP context for the groups that a user is a member of. The groups are then translated to role
* querying the active directory LDAP context for the groups that a user is * names by using the configured {@link #groupRolesMap}.
* a member of. The groups are then translated to role names by using the
* configured {@link #groupRolesMap}.
* <p/>
* This implementation expects the <tt>principal</tt> argument to be a
* String username.
* <p/>
* Subclasses can override this method to determine authorization data
* (roles, permissions, etc) in a more complex way. Note that this default
* implementation does not support permissions, only roles.
* *
* @param principals the principal of the Subject whose account is being * This implementation expects the <tt>principal</tt> argument to be a String username.
* retrieved. *
* Subclasses can override this method to determine authorization data (roles, permissions, etc) in a more complex way. Note that this default implementation does not support permissions, only
* roles.
*
* @param principals the principal of the Subject whose account is being retrieved.
* @param ldapContextFactory the factory used to create LDAP connections. * @param ldapContextFactory the factory used to create LDAP connections.
* @return the AuthorizationInfo for the given Subject principal. * @return the AuthorizationInfo for the given Subject principal.
* @throws NamingException if an error occurs when searching the LDAP * @throws NamingException if an error occurs when searching the LDAP server.
* server.
*/ */
@Override @Override
protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, LdapContextFactory ldapContextFactory) throws NamingException { protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, LdapContextFactory ldapContextFactory) throws NamingException {
@ -139,12 +127,12 @@ public class UserNameActiveDirectoryRealm extends ActiveDirectoryRealm {
this.permissionsLookupEnabled = permissionsLookupEnabled; this.permissionsLookupEnabled = permissionsLookupEnabled;
} }
public String getFallbackPrincipalSuffix() { public List<String> getFallbackPrincipalSuffixes() {
return fallbackPrincipalSuffix; return fallbackPrincipalSuffixes;
} }
public void setFallbackPrincipalSuffix(String fallbackPrincipalSuffix) { public void setFallbackPrincipalSuffixes(List<String> fallbackPrincipalSuffixes) {
this.fallbackPrincipalSuffix = fallbackPrincipalSuffix; this.fallbackPrincipalSuffixes = fallbackPrincipalSuffixes;
} }
private String getUserName(UsernamePasswordToken upToken, String suffix) { private String getUserName(UsernamePasswordToken upToken, String suffix) {
@ -166,4 +154,26 @@ public class UserNameActiveDirectoryRealm extends ActiveDirectoryRealm {
return ldapContextFactory.getLdapContext(userName, credentials); return ldapContextFactory.getLdapContext(userName, credentials);
} }
private LdapContext lookupUserWithSuffix(UsernamePasswordToken upToken, LdapContextFactory ldapContextFactory, String currentSuffix) {
String userName = getUserName(upToken, currentSuffix);
LdapContext ctx = null;
try {
ctx = lookupUser(userName, upToken.getCredentials(), ldapContextFactory);
} catch (NamingException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Lookup with suffix {} failed", currentSuffix);
}
if (LOGGER.isTraceEnabled()) {
LOGGER.error(ex.getMessage());
LOGGER.trace("Detailed stacktrace", new Object[]{ex});
}
lastException = ex;
return null;
} finally {
LdapUtils.closeContext(ctx);
}
return ctx;
}
} }