package util
import service.SystemSettingsService.Ldap
import service.SystemSettingsService
import com.novell.ldap.{LDAPReferralException, LDAPEntry, LDAPConnection}
/**
* Utility for LDAP authentication.
*/
object LDAPUtil {
private val LDAP_VERSION: Int = 3
/**
* Try authentication by LDAP using given configuration.
* Returns Right(mailAddress) if authentication is successful, otherwise Left(errorMessage).
*/
def authenticate(ldapSettings: Ldap, userName: String, password: String): Either[String, String] = {
bind(
ldapSettings.host,
ldapSettings.port.getOrElse(SystemSettingsService.DefaultLdapPort),
ldapSettings.bindDN,
ldapSettings.bindPassword
) match {
case Some(conn) => {
withConnection(conn) { conn =>
findUser(conn, userName, ldapSettings.baseDN, ldapSettings.userNameAttribute) match {
case Some(userDN) => userAuthentication(ldapSettings, userDN, password)
case None => Left("User does not exist")
}
}
}
case None => Left("System LDAP authentication failed.")
}
}
private def userAuthentication(ldapSettings: Ldap, userDN: String, password: String): Either[String, String] = {
bind(
ldapSettings.host,
ldapSettings.port.getOrElse(SystemSettingsService.DefaultLdapPort),
userDN,
password
) match {
case Some(conn) => {
withConnection(conn) { conn =>
findMailAddress(conn, userDN, ldapSettings.mailAttribute) match {
case Some(mailAddress) => Right(mailAddress)
case None => Left("Can't find mail address.")
}
}
}
case None => Left("User LDAP Authentication Failed.")
}
}
private def bind(host: String, port: Int, dn: String, password: String): Option[LDAPConnection] = {
val conn: LDAPConnection = new LDAPConnection
try {
conn.connect(host, port)
conn.bind(LDAP_VERSION, dn, password.getBytes)
Some(conn)
} catch {
case e: Exception => {
if (conn.isConnected) conn.disconnect()
None
}
}
}
private def withConnection[T](conn: LDAPConnection)(f: LDAPConnection => T): T = {
try {
f(conn)
} finally {
conn.disconnect()
}
}
private def findUser(conn: LDAPConnection, userName: String, baseDN: String, userNameAttribute: String): Option[String] = {
val results = conn.search(baseDN, LDAPConnection.SCOPE_SUB, userNameAttribute + "=" + userName, null, false)
while (results.hasMore) {
var entry: LDAPEntry = null
try {
entry = results.next
} catch {
case lre: LDAPReferralException => // NOTE(tanacasino): Referral follow is off. so ignores it.(for AD)
}
if (entry != null) {
return Some(entry.getDN)
}
}
None
}
private def findMailAddress(conn: LDAPConnection, userDN: String, mailAttribute: String): Option[String] = {
val attributes = Array[String](mailAttribute)
val results = conn.search(userDN, LDAPConnection.SCOPE_BASE, null, attributes, false)
if (results.hasMore) {
val attr = results.next.getAttribute(mailAttribute)
if (attr != null) {
Some(attr.getStringValue)
} else {
None
}
} else {
None
}
}
}