package be.neutrinet.ispng.external;
import be.neutrinet.ispng.config.Config;
import be.neutrinet.ispng.util.AuthenticationMigrationAutomationIntegration;
import com.unboundid.ldap.sdk.*;
import com.unboundid.ldap.sdk.controls.PasswordExpiredControl;
import com.unboundid.ldap.sdk.controls.PasswordExpiringControl;
import com.unboundid.ldap.sdk.persist.LDAPField;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;
import org.apache.log4j.Logger;
import javax.net.SocketFactory;
import java.lang.reflect.Field;
import java.util.Optional;
/**
* Created by wannes on 27/05/15.
*/
public class LDAP {
private final static LDAP instance = new LDAP();
private LDAPConnection connection;
private Logger logger = Logger.getLogger(getClass());
private SocketFactory socketFactory = null;
private Optional<String> host = null;
private LDAP() {
}
public static LDAP get() {
return instance;
}
public static String findAttributeName(Class clazz, String fieldName) {
assert clazz != null;
assert fieldName != null;
try {
for (Field f : clazz.getDeclaredFields()) {
if (f.getName().equals(fieldName)) {
LDAPField field = f.getAnnotation(LDAPField.class);
if (field != null) {
return field.attribute();
} else {
return fieldName;
}
}
}
} catch (Exception ex) {
Logger.getLogger(LDAP.class).error("Failed to find LDAP attribute for field " + fieldName, ex);
}
return fieldName;
}
public static LDAPConnection connection() {
return instance.connection;
}
public static String escapeDN(String name) {
StringBuilder sb = new StringBuilder();
if ((name.length() > 0) && ((name.charAt(0) == ' ') || (name.charAt(0) == '#'))) {
sb.append('\\'); // add the leading backslash if needed
}
for (int i = 0; i < name.length(); i++) {
char curChar = name.charAt(i);
switch (curChar) {
case '\\':
sb.append("\\\\");
break;
case ',':
sb.append("\\,");
break;
case '+':
sb.append("\\+");
break;
case '"':
sb.append("\\\"");
break;
case '<':
sb.append("\\<");
break;
case '>':
sb.append("\\>");
break;
case ';':
sb.append("\\;");
break;
default:
sb.append(curChar);
}
}
if ((name.length() > 1) && (name.charAt(name.length() - 1) == ' ')) {
sb.insert(sb.length() - 1, '\\'); // add the trailing backslash if needed
}
return sb.toString();
}
public void boot() {
host = Config.get("ldap/host");
if (host.isPresent()) {
try {
SSLUtil sslUtil = new SSLUtil(null, new TrustAllTrustManager());
socketFactory = sslUtil.createSSLSocketFactory();
connection = new LDAPConnection(socketFactory, host.get(), Integer.parseInt(Config.get("ldap/port", "636")));
Optional<String> dn = Config.get("ldap/bind/dn");
Optional<String> password = Config.get("ldap/bind/password");
if (!dn.isPresent() || !password.isPresent()) {
throw new IllegalArgumentException("LDAP bind DN and/or password not present");
}
BindRequest bindRequest = new SimpleBindRequest(dn.get(), password.get());
BindResult bindResult = connection.bind(bindRequest);
PasswordExpiredControl pwdExpired = PasswordExpiredControl.get(bindResult);
if (pwdExpired == null) {
logger.debug("The password expired control was not included in " +
"the LDAP BIND response.");
} else {
logger.error("You must change your LDAP password " +
"before you will be allowed to perform any other operations.");
}
PasswordExpiringControl pwdExpiring = PasswordExpiringControl.get(bindResult);
if (pwdExpiring == null) {
logger.debug("The password expiring control was not included in" +
" the LDAP BIND response.");
} else {
logger.warn("Your LDAP password will expire in " +
pwdExpiring.getSecondsUntilExpiration() + " seconds.");
}
logger.info("Connected to LDAP");
} catch (Exception ex) {
logger.error("Failed to connect to LDAP server", ex);
System.exit(666);
}
}
}
public boolean auth(String dn, String password) {
try {
// Handle migration from old password hash format
int result = AuthenticationMigrationAutomationIntegration.intercept(dn, password);
if (result == -1) return false;
if (result == 1) return true;
LDAPConnection connection = new LDAPConnection(socketFactory, host.get(), Integer.parseInt(Config.get("ldap/port", "636")));
BindResult bind = connection.bind(dn, password);
boolean success = bind.getResultCode().equals(ResultCode.SUCCESS);
connection.close();
return success;
} catch (Exception ex) {
Logger.getLogger(getClass()).debug("Failed to auth user " + dn, ex);
}
return false;
}
}