package com.hwlcn.security.realm.ldap;
import com.hwlcn.security.authc.AuthenticationException;
import com.hwlcn.security.authc.AuthenticationInfo;
import com.hwlcn.security.authc.AuthenticationToken;
import com.hwlcn.security.authc.SimpleAuthenticationInfo;
import com.hwlcn.security.authc.credential.AllowAllCredentialsMatcher;
import com.hwlcn.security.authz.AuthorizationException;
import com.hwlcn.security.authz.AuthorizationInfo;
import com.hwlcn.security.ldap.UnsupportedAuthenticationMechanismException;
import com.hwlcn.security.realm.AuthorizingRealm;
import com.hwlcn.security.subject.PrincipalCollection;
import com.hwlcn.security.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.naming.AuthenticationNotSupportedException;
import javax.naming.NamingException;
import javax.naming.ldap.LdapContext;
public class JndiLdapRealm extends AuthorizingRealm {
private static final Logger log = LoggerFactory.getLogger(JndiLdapRealm.class);
private static final String USERDN_SUBSTITUTION_TOKEN = "{0}";
private String userDnPrefix;
private String userDnSuffix;
private LdapContextFactory contextFactory;
public JndiLdapRealm() {
setCredentialsMatcher(new AllowAllCredentialsMatcher());
setAuthenticationTokenClass(AuthenticationToken.class);
this.contextFactory = new JndiLdapContextFactory();
}
protected String getUserDnPrefix() {
return userDnPrefix;
}
protected String getUserDnSuffix() {
return userDnSuffix;
}
public void setUserDnTemplate(String template) throws IllegalArgumentException {
if (!StringUtils.hasText(template)) {
String msg = "User DN template cannot be null or empty.";
throw new IllegalArgumentException(msg);
}
int index = template.indexOf(USERDN_SUBSTITUTION_TOKEN);
if (index < 0) {
String msg = "User DN template must contain the '" +
USERDN_SUBSTITUTION_TOKEN + "' replacement token to understand where to " +
"insert the runtime authentication principal.";
throw new IllegalArgumentException(msg);
}
String prefix = template.substring(0, index);
String suffix = template.substring(prefix.length() + USERDN_SUBSTITUTION_TOKEN.length());
if (log.isDebugEnabled()) {
log.debug("Determined user DN prefix [{}] and suffix [{}]", prefix, suffix);
}
this.userDnPrefix = prefix;
this.userDnSuffix = suffix;
}
public String getUserDnTemplate() {
return getUserDn(USERDN_SUBSTITUTION_TOKEN);
}
protected String getUserDn(String principal) throws IllegalArgumentException, IllegalStateException {
if (!StringUtils.hasText(principal)) {
throw new IllegalArgumentException("User principal cannot be null or empty for User DN construction.");
}
String prefix = getUserDnPrefix();
String suffix = getUserDnSuffix();
if (prefix == null && suffix == null) {
log.debug("userDnTemplate property has not been configured, indicating the submitted " +
"AuthenticationToken's principal is the same as the User DN. Returning the method argument " +
"as is.");
return principal;
}
int prefixLength = prefix != null ? prefix.length() : 0;
int suffixLength = suffix != null ? suffix.length() : 0;
StringBuilder sb = new StringBuilder(prefixLength + principal.length() + suffixLength);
if (prefixLength > 0) {
sb.append(prefix);
}
sb.append(principal);
if (suffixLength > 0) {
sb.append(suffix);
}
return sb.toString();
}
public void setContextFactory(LdapContextFactory contextFactory) {
this.contextFactory = contextFactory;
}
public LdapContextFactory getContextFactory() {
return this.contextFactory;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info;
try {
info = queryForAuthenticationInfo(token, getContextFactory());
} catch (AuthenticationNotSupportedException e) {
String msg = "Unsupported configured authentication mechanism";
throw new UnsupportedAuthenticationMechanismException(msg, e);
} catch (javax.naming.AuthenticationException e) {
throw new AuthenticationException("LDAP authentication failed.", e);
} catch (NamingException e) {
String msg = "LDAP naming error while attempting to authenticate user.";
throw new AuthenticationException(msg, e);
}
return info;
}
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
AuthorizationInfo info;
try {
info = queryForAuthorizationInfo(principals, getContextFactory());
} catch (NamingException e) {
String msg = "LDAP naming error while attempting to retrieve authorization for user [" + principals + "].";
throw new AuthorizationException(msg, e);
}
return info;
}
protected Object getLdapPrincipal(AuthenticationToken token) {
Object principal = token.getPrincipal();
if (principal instanceof String) {
String sPrincipal = (String) principal;
return getUserDn(sPrincipal);
}
return principal;
}
protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token,
LdapContextFactory ldapContextFactory)
throws NamingException {
Object principal = token.getPrincipal();
Object credentials = token.getCredentials();
log.debug("Authenticating user '{}' through LDAP", principal);
principal = getLdapPrincipal(token);
LdapContext ctx = null;
try {
ctx = ldapContextFactory.getLdapContext(principal, credentials);
return createAuthenticationInfo(token, principal, credentials, ctx);
} finally {
LdapUtils.closeContext(ctx);
}
}
@SuppressWarnings({"UnusedDeclaration"})
protected AuthenticationInfo createAuthenticationInfo(AuthenticationToken token, Object ldapPrincipal,
Object ldapCredentials, LdapContext ldapContext)
throws NamingException {
return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName());
}
protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals,
LdapContextFactory ldapContextFactory) throws NamingException {
return null;
}
}