Adding LDAP StartTLS support

Some LDAP server do not allow authenticate with unencrypted password.
This patch is adding the StartTLS support which takes care of the
encryption.

In order to enable the StartTLS, go to "System Settings" and select the
"Enable StartTLS" in the Authentication section. Then make sure that you
add your LDAP certificate into the Java keystore:

$ keytool -import \
          -file /etc/pki/tls/certs/cacert.pem \
          -alias myName \
          -keystore /var/lib/gitbucket/keystore

You can list all keys from the keystore like this:

$ keytool -list -keystore /var/lib/gitbucket/keystore
This commit is contained in:
Jiri Tyr
2013-11-01 15:44:19 +00:00
parent 34853d0322
commit f311339786
6 changed files with 52 additions and 9 deletions

View File

@@ -16,5 +16,8 @@
# URL prefix for the GitBucket page (http://<host>:<port>/<prefix>/)
#GITBUCKET_PREFIX=
# Java keystore (for LDAP StartTLS)
#GITBUCKET_KEYSTORE=/var/lib/gitbucket/keystore
# Other Java option
#GITBUCKET_JVM_OPTS=

View File

@@ -14,6 +14,7 @@
# Default values
GITBUCKET_HOME=/var/lib/gitbucket
GITBUCKET_WAR_FILE=/usr/share/gitbucket/lib/gitbucket.war
GITBUCKET_KEYSTORE=/var/lib/gitbucket/keystore
# Pull in cq settings
[ -f /etc/sysconfig/gitbucket ] && . /etc/sysconfig/gitbucket
@@ -29,6 +30,8 @@ RETVAL=0
start() {
echo -n $"Starting GitBucket server: "
GITBUCKET_JVM_OPTS="${GITBUCKET_JVM_OPTS} -Djavax.net.ssl.trustStore=${GITBUCKET_KEYSTORE}"
# Compile statup parameters
if [ $GITBUCKET_PORT ]; then
START_OPTS="${START_OPTS} --port=${GITBUCKET_PORT}"

View File

@@ -33,7 +33,8 @@ trait SystemSettingsControllerBase extends ControllerBase with FlashMapSupport {
"bindPassword" -> trim(label("Bind Password", optional(text()))),
"baseDN" -> trim(label("Base DN", 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))),
"tls" -> trim(label("Enable StartTLS", optional(boolean())))
)(Ldap.apply))
)(SystemSettings.apply)

View File

@@ -32,6 +32,7 @@ trait SystemSettingsService {
props.setProperty(LdapBaseDN, ldap.baseDN)
props.setProperty(LdapUserNameAttribute, ldap.userNameAttribute)
props.setProperty(LdapMailAddressAttribute, ldap.mailAttribute)
ldap.tls.foreach(x => props.setProperty(LdapTls, x.toString))
}
}
props.store(new java.io.FileOutputStream(GitBucketConf), null)
@@ -69,7 +70,8 @@ trait SystemSettingsService {
getOptionValue(props, LdapBindPassword, None),
getValue(props, LdapBaseDN, ""),
getValue(props, LdapUserNameAttribute, ""),
getValue(props, LdapMailAddressAttribute, "")))
getValue(props, LdapMailAddressAttribute, ""),
getOptionValue[Boolean](props, LdapTls, None)))
} else {
None
}
@@ -97,7 +99,8 @@ object SystemSettingsService {
bindPassword: Option[String],
baseDN: String,
userNameAttribute: String,
mailAttribute: String)
mailAttribute: String,
tls: Option[Boolean])
case class Smtp(
host: String,
@@ -129,6 +132,7 @@ object SystemSettingsService {
private val LdapBaseDN = "ldap.baseDN"
private val LdapUserNameAttribute = "ldap.username_attribute"
private val LdapMailAddressAttribute = "ldap.mail_attribute"
private val LdapTls = "ldap.tls"
private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A =
defining(props.getProperty(key)){ value =>

View File

@@ -3,6 +3,8 @@ package util
import util.ControlUtil._
import service.SystemSettingsService
import com.novell.ldap._
import java.security.Security
import org.slf4j.LoggerFactory
import service.SystemSettingsService.Ldap
import scala.annotation.tailrec
@@ -11,7 +13,8 @@ import scala.annotation.tailrec
*/
object LDAPUtil {
private val LDAP_VERSION: Int = 3
private val LDAP_VERSION: Int = LDAPConnection.LDAP_V3
private val logger = LoggerFactory.getLogger("LDAPUtil")
/**
* Try authentication by LDAP using given configuration.
@@ -22,7 +25,8 @@ object LDAPUtil {
ldapSettings.host,
ldapSettings.port.getOrElse(SystemSettingsService.DefaultLdapPort),
ldapSettings.bindDN.getOrElse(""),
ldapSettings.bindPassword.getOrElse("")
ldapSettings.bindPassword.getOrElse(""),
ldapSettings.tls.getOrElse(false)
) match {
case Some(conn) => {
withConnection(conn) { conn =>
@@ -41,7 +45,8 @@ object LDAPUtil {
ldapSettings.host,
ldapSettings.port.getOrElse(SystemSettingsService.DefaultLdapPort),
userDN,
password
password,
ldapSettings.tls.getOrElse(false)
) match {
case Some(conn) => {
withConnection(conn) { conn =>
@@ -55,15 +60,35 @@ object LDAPUtil {
}
}
private def bind(host: String, port: Int, dn: String, password: String): Option[LDAPConnection] = {
val conn: LDAPConnection = new LDAPConnection
private def bind(host: String, port: Int, dn: String, password: String, tls: Boolean): Option[LDAPConnection] = {
if (tls) {
// Dynamically set Sun as the security provider
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider())
}
val conn: LDAPConnection = new LDAPConnection(new LDAPJSSEStartTLSFactory())
try {
// Connect to the server
conn.connect(host, port)
if (tls) {
// Secure the connection
conn.startTLS()
}
// Bind to the server
conn.bind(LDAP_VERSION, dn, password.getBytes)
Some(conn)
} catch {
case e: Exception => {
if (conn.isConnected) conn.disconnect()
// Provide more information if something goes wrong
logger.info("" + e)
if (conn.isConnected) {
conn.disconnect()
}
None
}
}

View File

@@ -94,6 +94,13 @@
<span id="error-ldap_mailAttribute" class="error"></span>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" name="ldap.tls"@if(settings.ldap.flatMap(_.tls).getOrElse(false)){ checked}/> Enable StartTLS
</label>
</div>
</div>
</div>
<!--====================================================================-->
<!-- Notification email -->