diff --git a/src/main/scala/app/SystemSettingsController.scala b/src/main/scala/app/SystemSettingsController.scala index 9466a83..68efda5 100644 --- a/src/main/scala/app/SystemSettingsController.scala +++ b/src/main/scala/app/SystemSettingsController.scala @@ -33,7 +33,9 @@ "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 TLS", optional(boolean()))), + "keystore" -> trim(label("Keystore", optional(text()))) )(Ldap.apply)) )(SystemSettings.apply) diff --git a/src/main/scala/service/SystemSettingsService.scala b/src/main/scala/service/SystemSettingsService.scala index 5ed9eb3..85e94f7 100644 --- a/src/main/scala/service/SystemSettingsService.scala +++ b/src/main/scala/service/SystemSettingsService.scala @@ -32,6 +32,8 @@ props.setProperty(LdapBaseDN, ldap.baseDN) props.setProperty(LdapUserNameAttribute, ldap.userNameAttribute) props.setProperty(LdapMailAddressAttribute, ldap.mailAttribute) + ldap.tls.foreach(x => props.setProperty(LdapTls, x.toString)) + ldap.keystore.foreach(x => props.setProperty(LdapKeystore, x)) } } props.store(new java.io.FileOutputStream(GitBucketConf), null) @@ -69,7 +71,9 @@ getOptionValue(props, LdapBindPassword, None), getValue(props, LdapBaseDN, ""), getValue(props, LdapUserNameAttribute, ""), - getValue(props, LdapMailAddressAttribute, ""))) + getValue(props, LdapMailAddressAttribute, ""), + getOptionValue[Boolean](props, LdapTls, None), + getOptionValue(props, LdapKeystore, None))) } else { None } @@ -97,7 +101,9 @@ bindPassword: Option[String], baseDN: String, userNameAttribute: String, - mailAttribute: String) + mailAttribute: String, + tls: Option[Boolean], + keystore: Option[String]) case class Smtp( host: String, @@ -129,6 +135,8 @@ private val LdapBaseDN = "ldap.baseDN" private val LdapUserNameAttribute = "ldap.username_attribute" private val LdapMailAddressAttribute = "ldap.mail_attribute" + private val LdapTls = "ldap.tls" + private val LdapKeystore = "ldap.keystore" private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A = defining(props.getProperty(key)){ value => diff --git a/src/main/scala/util/LDAPUtil.scala b/src/main/scala/util/LDAPUtil.scala index 4c6347c..3f19b28 100644 --- a/src/main/scala/util/LDAPUtil.scala +++ b/src/main/scala/util/LDAPUtil.scala @@ -3,6 +3,8 @@ 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 @@ */ object LDAPUtil { - private val LDAP_VERSION: Int = 3 + private val LDAP_VERSION: Int = LDAPConnection.LDAP_V3 + private val logger = LoggerFactory.getLogger(getClass().getName()) /** * Try authentication by LDAP using given configuration. @@ -22,7 +25,9 @@ ldapSettings.host, ldapSettings.port.getOrElse(SystemSettingsService.DefaultLdapPort), ldapSettings.bindDN.getOrElse(""), - ldapSettings.bindPassword.getOrElse("") + ldapSettings.bindPassword.getOrElse(""), + ldapSettings.tls.getOrElse(false), + ldapSettings.keystore.getOrElse("") ) match { case Some(conn) => { withConnection(conn) { conn => @@ -41,7 +46,9 @@ ldapSettings.host, ldapSettings.port.getOrElse(SystemSettingsService.DefaultLdapPort), userDN, - password + password, + ldapSettings.tls.getOrElse(false), + ldapSettings.keystore.getOrElse("") ) match { case Some(conn) => { withConnection(conn) { conn => @@ -55,15 +62,41 @@ } } - 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, keystore: String): Option[LDAPConnection] = { + if (tls) { + // Dynamically set Sun as the security provider + Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()) + + if (keystore.compareTo("") != 0) { + // Dynamically set the property that JSSE uses to identify + // the keystore that holds trusted root certificates + System.setProperty("javax.net.ssl.trustStore", keystore) + } + } + + 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 } } diff --git a/src/main/twirl/admin/system.scala.html b/src/main/twirl/admin/system.scala.html index 361138d..9a02cb5 100644 --- a/src/main/twirl/admin/system.scala.html +++ b/src/main/twirl/admin/system.scala.html @@ -94,6 +94,20 @@ +
+
+ +
+
+
+ +
+ + +
+