mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-06 21:45:50 +01:00
LDAP authentication by using bind account
This commit is contained in:
committed by
Tomofumi Tanaka
parent
b9aa6a234b
commit
bfc1d1d6b0
@@ -27,7 +27,9 @@ trait SystemSettingsControllerBase extends ControllerBase with FlashMapSupport {
|
|||||||
"ldap" -> optionalIfNotChecked("ldapAuthentication", mapping(
|
"ldap" -> optionalIfNotChecked("ldapAuthentication", mapping(
|
||||||
"host" -> trim(label("LDAP host", text(required))),
|
"host" -> trim(label("LDAP host", text(required))),
|
||||||
"port" -> trim(label("LDAP port", optional(number()))),
|
"port" -> trim(label("LDAP port", optional(number()))),
|
||||||
"baseDN" -> trim(label("BaseDN", text(required))),
|
"bindDN" -> trim(label("Bind DN", text(required))),
|
||||||
|
"bindPassword" -> trim(label("Bind Password", text(required))),
|
||||||
|
"baseDN" -> trim(label("Base DN", text(required))),
|
||||||
"userNameAttribute" -> trim(label("User name attribute", text(required))),
|
"userNameAttribute" -> trim(label("User name attribute", text(required))),
|
||||||
"mailAttribute" -> trim(label("Mail address attribute", text(required)))
|
"mailAttribute" -> trim(label("Mail address attribute", text(required)))
|
||||||
)(Ldap.apply))
|
)(Ldap.apply))
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ trait SystemSettingsService {
|
|||||||
settings.ldap.map { ldap =>
|
settings.ldap.map { ldap =>
|
||||||
props.setProperty(LdapHost, ldap.host)
|
props.setProperty(LdapHost, ldap.host)
|
||||||
ldap.port.foreach(x => props.setProperty(LdapPort, x.toString))
|
ldap.port.foreach(x => props.setProperty(LdapPort, x.toString))
|
||||||
|
props.setProperty(LdapBindDN, ldap.bindDN)
|
||||||
|
props.setProperty(LdapBindPassword, ldap.bindPassword)
|
||||||
props.setProperty(LdapBaseDN, ldap.baseDN)
|
props.setProperty(LdapBaseDN, ldap.baseDN)
|
||||||
props.setProperty(LdapUserNameAttribute, ldap.userNameAttribute)
|
props.setProperty(LdapUserNameAttribute, ldap.userNameAttribute)
|
||||||
props.setProperty(LdapMailAddressAttribute, ldap.mailAttribute)
|
props.setProperty(LdapMailAddressAttribute, ldap.mailAttribute)
|
||||||
@@ -57,6 +59,8 @@ trait SystemSettingsService {
|
|||||||
Some(Ldap(
|
Some(Ldap(
|
||||||
getValue(props, LdapHost, ""),
|
getValue(props, LdapHost, ""),
|
||||||
getOptionValue(props, LdapPort, Some(DefaultLdapPort)),
|
getOptionValue(props, LdapPort, Some(DefaultLdapPort)),
|
||||||
|
getValue(props, LdapBindDN, ""),
|
||||||
|
getValue(props, LdapBindPassword, ""),
|
||||||
getValue(props, LdapBaseDN, ""),
|
getValue(props, LdapBaseDN, ""),
|
||||||
getValue(props, LdapUserNameAttribute, ""),
|
getValue(props, LdapUserNameAttribute, ""),
|
||||||
getValue(props, LdapMailAddressAttribute, "")))
|
getValue(props, LdapMailAddressAttribute, "")))
|
||||||
@@ -82,6 +86,8 @@ object SystemSettingsService {
|
|||||||
case class Ldap(
|
case class Ldap(
|
||||||
host: String,
|
host: String,
|
||||||
port: Option[Int],
|
port: Option[Int],
|
||||||
|
bindDN: String,
|
||||||
|
bindPassword: String,
|
||||||
baseDN: String,
|
baseDN: String,
|
||||||
userNameAttribute: String,
|
userNameAttribute: String,
|
||||||
mailAttribute: String)
|
mailAttribute: String)
|
||||||
@@ -106,6 +112,8 @@ object SystemSettingsService {
|
|||||||
private val LdapAuthentication = "ldap_authentication"
|
private val LdapAuthentication = "ldap_authentication"
|
||||||
private val LdapHost = "ldap.host"
|
private val LdapHost = "ldap.host"
|
||||||
private val LdapPort = "ldap.port"
|
private val LdapPort = "ldap.port"
|
||||||
|
private val LdapBindDN = "ldap.bindDN"
|
||||||
|
private val LdapBindPassword = "ldap.bind_password"
|
||||||
private val LdapBaseDN = "ldap.baseDN"
|
private val LdapBaseDN = "ldap.baseDN"
|
||||||
private val LdapUserNameAttribute = "ldap.username_attribute"
|
private val LdapUserNameAttribute = "ldap.username_attribute"
|
||||||
private val LdapMailAddressAttribute = "ldap.mail_attribute"
|
private val LdapMailAddressAttribute = "ldap.mail_attribute"
|
||||||
|
|||||||
@@ -2,49 +2,107 @@ package util
|
|||||||
|
|
||||||
import service.SystemSettingsService.Ldap
|
import service.SystemSettingsService.Ldap
|
||||||
import service.SystemSettingsService
|
import service.SystemSettingsService
|
||||||
import com.novell.ldap.LDAPConnection
|
import com.novell.ldap.{LDAPReferralException, LDAPEntry, LDAPConnection}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility for LDAP authentication.
|
* Utility for LDAP authentication.
|
||||||
*/
|
*/
|
||||||
object LDAPUtil extends App {
|
object LDAPUtil {
|
||||||
|
|
||||||
|
private val LDAP_VERSION: Int = 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try authentication by LDAP using given configuration.
|
* Try authentication by LDAP using given configuration.
|
||||||
* Returns Right(mailAddress) if authentication is successful, otherwise Left(errorMessage).
|
* Returns Right(mailAddress) if authentication is successful, otherwise Left(errorMessage).
|
||||||
*/
|
*/
|
||||||
def authenticate(ldapSettings: Ldap, userName: String, password: String): Either[String, String] = {
|
def authenticate(ldapSettings: Ldap, userName: String, password: String): Either[String, String] = {
|
||||||
var conn: LDAPConnection = null
|
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 {
|
try {
|
||||||
conn = new LDAPConnection()
|
conn.connect(host, port)
|
||||||
conn.connect(ldapSettings.host, ldapSettings.port.getOrElse(SystemSettingsService.DefaultLdapPort))
|
conn.bind(LDAP_VERSION, dn, password.getBytes)
|
||||||
val userDN = ldapSettings.userNameAttribute + "=" + userName + ",ou=Users," + ldapSettings.baseDN
|
Some(conn)
|
||||||
conn.bind(3, userDN, password.getBytes)
|
|
||||||
if(conn.isBound){
|
|
||||||
val results = conn.search(userDN, LDAPConnection.SCOPE_BASE, "", Array[String](ldapSettings.mailAttribute), false)
|
|
||||||
var mailAddress: String = null
|
|
||||||
while(results.hasMore){
|
|
||||||
mailAddress = results.next.getAttribute(ldapSettings.mailAttribute).getStringValue
|
|
||||||
}
|
|
||||||
if(mailAddress != null){
|
|
||||||
Right(mailAddress)
|
|
||||||
} else {
|
|
||||||
Left("Can't find mail address.")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Left("Authentication failed.")
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
case ex: Exception => Left(ex.getMessage)
|
case e: Exception => {
|
||||||
|
if (conn.isConnected) conn.disconnect()
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def withConnection[T](conn: LDAPConnection)(f: LDAPConnection => T): T = {
|
||||||
|
try {
|
||||||
|
f(conn)
|
||||||
} finally {
|
} finally {
|
||||||
if(conn != null){
|
|
||||||
conn.disconnect()
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// val ldapSettings = Ldap("192.168.159.128", 389, "dc=unix-power,dc=net", "uid", "mail")
|
private def findMailAddress(conn: LDAPConnection, userDN: String, mailAttribute: String): Option[String] = {
|
||||||
//
|
val attributes = Array[String](mailAttribute)
|
||||||
// println(authenticate(ldapSettings, "tanaka", "password"))
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label class="control-label" for="ldapBaseDN">BaseDN</label>
|
<label class="control-label" for="ldapBindDN">Bind DN</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="ldapBindDN" name="ldap.bindDN" value="@settings.ldap.map(_.bindDN)"/>
|
||||||
|
<span id="error-ldap_bindDN" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="ldapBindPassword">Bind Password</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="password" id="ldapBindPassword" name="ldap.bindPassword" value="@settings.ldap.map(_.bindPassword)"/>
|
||||||
|
<span id="error-ldap_bindPassword" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="ldapBaseDN">Base DN</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<input type="text" id="ldapBaseDN" name="ldap.baseDN" value="@settings.ldap.map(_.baseDN)"/>
|
<input type="text" id="ldapBaseDN" name="ldap.baseDN" value="@settings.ldap.map(_.baseDN)"/>
|
||||||
<span id="error-ldap_baseDN" class="error"></span>
|
<span id="error-ldap_baseDN" class="error"></span>
|
||||||
|
|||||||
Reference in New Issue
Block a user