mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-08 06:25:51 +01:00
Merge branch 'add-features-to-ldapauth' of https://github.com/yjkony/gitbucket into yjkony-add-features-to-ldapauth
Conflicts: src/main/scala/app/IndexController.scala src/main/scala/service/SystemSettingsService.scala src/main/scala/util/LDAPUtil.scala src/main/scala/util/Notifier.scala
This commit is contained in:
@@ -59,6 +59,10 @@ trait IndexControllerBase extends ControllerBase {
|
|||||||
session.setAttribute(Keys.Session.LoginAccount, account)
|
session.setAttribute(Keys.Session.LoginAccount, account)
|
||||||
updateLastLoginDate(account.userName)
|
updateLastLoginDate(account.userName)
|
||||||
|
|
||||||
|
if(AccountUtil.hasLdapDummyMailAddress(account)) {
|
||||||
|
redirect("/" + account.userName + "/_edit")
|
||||||
|
}
|
||||||
|
|
||||||
flash.get(Keys.Flash.Redirect).asInstanceOf[Option[String]].map { redirectUrl =>
|
flash.get(Keys.Flash.Redirect).asInstanceOf[Option[String]].map { redirectUrl =>
|
||||||
if(redirectUrl.stripSuffix("/") == request.getContextPath){
|
if(redirectUrl.stripSuffix("/") == request.getContextPath){
|
||||||
redirect("/")
|
redirect("/")
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ trait SystemSettingsControllerBase extends ControllerBase {
|
|||||||
"bindPassword" -> trim(label("Bind Password", optional(text()))),
|
"bindPassword" -> trim(label("Bind Password", optional(text()))),
|
||||||
"baseDN" -> trim(label("Base DN", 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))),
|
||||||
|
"additionalFilterCondition"-> trim(label("Additional filter condition", optional(text()))),
|
||||||
"fullNameAttribute" -> trim(label("Full name attribute", optional(text()))),
|
"fullNameAttribute" -> trim(label("Full name attribute", optional(text()))),
|
||||||
"mailAttribute" -> trim(label("Mail address attribute", text(required))),
|
"mailAttribute" -> trim(label("Mail address attribute", optional(text()))),
|
||||||
"tls" -> trim(label("Enable TLS", optional(boolean()))),
|
"tls" -> trim(label("Enable TLS", optional(boolean()))),
|
||||||
"keystore" -> trim(label("Keystore", optional(text())))
|
"keystore" -> trim(label("Keystore", optional(text())))
|
||||||
)(Ldap.apply))
|
)(Ldap.apply))
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ trait AccountService {
|
|||||||
// Create or update account by LDAP information
|
// Create or update account by LDAP information
|
||||||
getAccountByUserName(ldapUserInfo.userName, true) match {
|
getAccountByUserName(ldapUserInfo.userName, true) match {
|
||||||
case Some(x) if(!x.isRemoved) => {
|
case Some(x) if(!x.isRemoved) => {
|
||||||
|
if(settings.ldap.get.mailAttribute.getOrElse("").isEmpty) {
|
||||||
|
updateAccount(x.copy(fullName = ldapUserInfo.fullName))
|
||||||
|
} else {
|
||||||
updateAccount(x.copy(mailAddress = ldapUserInfo.mailAddress, fullName = ldapUserInfo.fullName))
|
updateAccount(x.copy(mailAddress = ldapUserInfo.mailAddress, fullName = ldapUserInfo.fullName))
|
||||||
|
}
|
||||||
getAccountByUserName(ldapUserInfo.userName)
|
getAccountByUserName(ldapUserInfo.userName)
|
||||||
}
|
}
|
||||||
case Some(x) if(x.isRemoved) => {
|
case Some(x) if(x.isRemoved) => {
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ trait SystemSettingsService {
|
|||||||
ldap.bindPassword.foreach(x => props.setProperty(LdapBindPassword, x))
|
ldap.bindPassword.foreach(x => props.setProperty(LdapBindPassword, x))
|
||||||
props.setProperty(LdapBaseDN, ldap.baseDN)
|
props.setProperty(LdapBaseDN, ldap.baseDN)
|
||||||
props.setProperty(LdapUserNameAttribute, ldap.userNameAttribute)
|
props.setProperty(LdapUserNameAttribute, ldap.userNameAttribute)
|
||||||
|
ldap.additionalFilterCondition.foreach(x => props.setProperty(LdapAdditionalFilterCondition, x))
|
||||||
ldap.fullNameAttribute.foreach(x => props.setProperty(LdapFullNameAttribute, x))
|
ldap.fullNameAttribute.foreach(x => props.setProperty(LdapFullNameAttribute, x))
|
||||||
props.setProperty(LdapMailAddressAttribute, ldap.mailAttribute)
|
ldap.mailAttribute.foreach(x => props.setProperty(LdapMailAddressAttribute, x.toString))
|
||||||
ldap.tls.foreach(x => props.setProperty(LdapTls, x.toString))
|
ldap.tls.foreach(x => props.setProperty(LdapTls, x.toString))
|
||||||
ldap.keystore.foreach(x => props.setProperty(LdapKeystore, x))
|
ldap.keystore.foreach(x => props.setProperty(LdapKeystore, x))
|
||||||
}
|
}
|
||||||
@@ -85,8 +86,9 @@ trait SystemSettingsService {
|
|||||||
getOptionValue(props, LdapBindPassword, None),
|
getOptionValue(props, LdapBindPassword, None),
|
||||||
getValue(props, LdapBaseDN, ""),
|
getValue(props, LdapBaseDN, ""),
|
||||||
getValue(props, LdapUserNameAttribute, ""),
|
getValue(props, LdapUserNameAttribute, ""),
|
||||||
|
getOptionValue(props, LdapAdditionalFilterCondition, None),
|
||||||
getOptionValue(props, LdapFullNameAttribute, None),
|
getOptionValue(props, LdapFullNameAttribute, None),
|
||||||
getValue(props, LdapMailAddressAttribute, ""),
|
getOptionValue(props, LdapMailAddressAttribute, None),
|
||||||
getOptionValue[Boolean](props, LdapTls, None),
|
getOptionValue[Boolean](props, LdapTls, None),
|
||||||
getOptionValue(props, LdapKeystore, None)))
|
getOptionValue(props, LdapKeystore, None)))
|
||||||
} else {
|
} else {
|
||||||
@@ -125,8 +127,9 @@ object SystemSettingsService {
|
|||||||
bindPassword: Option[String],
|
bindPassword: Option[String],
|
||||||
baseDN: String,
|
baseDN: String,
|
||||||
userNameAttribute: String,
|
userNameAttribute: String,
|
||||||
|
additionalFilterCondition: Option[String],
|
||||||
fullNameAttribute: Option[String],
|
fullNameAttribute: Option[String],
|
||||||
mailAttribute: String,
|
mailAttribute: Option[String],
|
||||||
tls: Option[Boolean],
|
tls: Option[Boolean],
|
||||||
keystore: Option[String])
|
keystore: Option[String])
|
||||||
|
|
||||||
@@ -163,6 +166,7 @@ object SystemSettingsService {
|
|||||||
private val LdapBindPassword = "ldap.bind_password"
|
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 LdapAdditionalFilterCondition = "ldap.additional_filter_condition"
|
||||||
private val LdapFullNameAttribute = "ldap.fullname_attribute"
|
private val LdapFullNameAttribute = "ldap.fullname_attribute"
|
||||||
private val LdapMailAddressAttribute = "ldap.mail_attribute"
|
private val LdapMailAddressAttribute = "ldap.mail_attribute"
|
||||||
private val LdapTls = "ldap.tls"
|
private val LdapTls = "ldap.tls"
|
||||||
|
|||||||
18
src/main/scala/util/AccountUtil.scala
Normal file
18
src/main/scala/util/AccountUtil.scala
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import model.Account
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility for account model.
|
||||||
|
*/
|
||||||
|
object AccountUtil {
|
||||||
|
private val LDAP_DUMMY_MAL = "@ldap-devnull"
|
||||||
|
|
||||||
|
def hasLdapDummyMailAddress(account: Account): Boolean = {
|
||||||
|
account.mailAddress.endsWith(LDAP_DUMMY_MAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
def getLdapDummyMailAddress(userName: String): String = {
|
||||||
|
userName + LDAP_DUMMY_MAL
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ object LDAPUtil {
|
|||||||
keystore = ldapSettings.keystore.getOrElse(""),
|
keystore = ldapSettings.keystore.getOrElse(""),
|
||||||
error = "System LDAP authentication failed."
|
error = "System LDAP authentication failed."
|
||||||
){ conn =>
|
){ conn =>
|
||||||
findUser(conn, userName, ldapSettings.baseDN, ldapSettings.userNameAttribute) match {
|
findUser(conn, userName, ldapSettings.baseDN, ldapSettings.userNameAttribute, ldapSettings.additionalFilterCondition) match {
|
||||||
case Some(userDN) => userAuthentication(ldapSettings, userDN, userName, password)
|
case Some(userDN) => userAuthentication(ldapSettings, userDN, userName, password)
|
||||||
case None => Left("User does not exist.")
|
case None => Left("User does not exist.")
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,15 @@ object LDAPUtil {
|
|||||||
keystore = ldapSettings.keystore.getOrElse(""),
|
keystore = ldapSettings.keystore.getOrElse(""),
|
||||||
error = "User LDAP Authentication Failed."
|
error = "User LDAP Authentication Failed."
|
||||||
){ conn =>
|
){ conn =>
|
||||||
findMailAddress(conn, userDN, ldapSettings.userNameAttribute, userName, ldapSettings.mailAttribute) match {
|
if(ldapSettings.mailAttribute.getOrElse("").isEmpty) {
|
||||||
|
Right(LDAPUserInfo(
|
||||||
|
userName = userName,
|
||||||
|
fullName = ldapSettings.fullNameAttribute.flatMap { fullNameAttribute =>
|
||||||
|
findFullName(conn, userDN, ldapSettings.userNameAttribute, userName, fullNameAttribute)
|
||||||
|
}.getOrElse(userName),
|
||||||
|
mailAddress = AccountUtil.getLdapDummyMailAddress(userName)))
|
||||||
|
} else {
|
||||||
|
findMailAddress(conn, userDN, ldapSettings.userNameAttribute, userName, ldapSettings.mailAttribute.get) match {
|
||||||
case Some(mailAddress) => Right(LDAPUserInfo(
|
case Some(mailAddress) => Right(LDAPUserInfo(
|
||||||
userName = getUserNameFromMailAddress(userName),
|
userName = getUserNameFromMailAddress(userName),
|
||||||
fullName = ldapSettings.fullNameAttribute.flatMap { fullNameAttribute =>
|
fullName = ldapSettings.fullNameAttribute.flatMap { fullNameAttribute =>
|
||||||
@@ -58,6 +66,7 @@ object LDAPUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private def getUserNameFromMailAddress(userName: String): String = {
|
private def getUserNameFromMailAddress(userName: String): String = {
|
||||||
(userName.indexOf('@') match {
|
(userName.indexOf('@') match {
|
||||||
@@ -112,7 +121,7 @@ object LDAPUtil {
|
|||||||
/**
|
/**
|
||||||
* Search a specified user and returns userDN if exists.
|
* Search a specified user and returns userDN if exists.
|
||||||
*/
|
*/
|
||||||
private def findUser(conn: LDAPConnection, userName: String, baseDN: String, userNameAttribute: String): Option[String] = {
|
private def findUser(conn: LDAPConnection, userName: String, baseDN: String, userNameAttribute: String, additionalFilterCondition: Option[String]): Option[String] = {
|
||||||
@tailrec
|
@tailrec
|
||||||
def getEntries(results: LDAPSearchResults, entries: List[Option[LDAPEntry]] = Nil): List[LDAPEntry] = {
|
def getEntries(results: LDAPSearchResults, entries: List[Option[LDAPEntry]] = Nil): List[LDAPEntry] = {
|
||||||
if(results.hasMore){
|
if(results.hasMore){
|
||||||
@@ -125,7 +134,13 @@ object LDAPUtil {
|
|||||||
entries.flatten
|
entries.flatten
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getEntries(conn.search(baseDN, LDAPConnection.SCOPE_SUB, userNameAttribute + "=" + userName, null, false)).collectFirst {
|
|
||||||
|
val filterCond = additionalFilterCondition.getOrElse("") match {
|
||||||
|
case "" => userNameAttribute + "=" + userName
|
||||||
|
case x => "(&(" + x + ")(" + userNameAttribute + "=" + userName + "))"
|
||||||
|
}
|
||||||
|
|
||||||
|
getEntries(conn.search(baseDN, LDAPConnection.SCOPE_SUB, filterCond, null, false)).collectFirst {
|
||||||
case x => x.getDN
|
case x => x.getDN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ trait Notifier extends RepositoryService with AccountService with IssuesService
|
|||||||
)
|
)
|
||||||
.distinct
|
.distinct
|
||||||
.withFilter ( _ != context.loginAccount.get.userName ) // the operation in person is excluded
|
.withFilter ( _ != context.loginAccount.get.userName ) // the operation in person is excluded
|
||||||
.foreach ( getAccountByUserName(_) filterNot (_.isGroupAccount) foreach (x => notify(x.mailAddress)) )
|
.foreach ( getAccountByUserName(_) filterNot (_.isGroupAccount) filterNot (AccountUtil.hasLdapDummyMailAddress(_)) foreach (x => notify(x.mailAddress)) )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@(account: model.Account, info: Option[Any])(implicit context: app.Context)
|
@(account: model.Account, info: Option[Any])(implicit context: app.Context)
|
||||||
@import context._
|
@import context._
|
||||||
@import view.helpers._
|
@import view.helpers._
|
||||||
|
@import util.AccountUtil
|
||||||
@html.main("Edit your profile"){
|
@html.main("Edit your profile"){
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="span9">
|
<div class="span9">
|
||||||
@helper.html.information(info)
|
@helper.html.information(info)
|
||||||
|
@if(AccountUtil.hasLdapDummyMailAddress(account)){<div class="alert alert-danger">Please register your mail address.</div>}
|
||||||
<form action="@url(account.userName)/_edit" method="POST" validate="true">
|
<form action="@url(account.userName)/_edit" method="POST" validate="true">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">Profile</div>
|
<div class="box-header">Profile</div>
|
||||||
@@ -31,7 +33,7 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="mailAddress" class="strong">Mail Address:</label>
|
<label for="mailAddress" class="strong">Mail Address:</label>
|
||||||
<input type="text" name="mailAddress" id="mailAddress" value="@account.mailAddress"/>
|
<input type="text" name="mailAddress" id="mailAddress" value="@if(!AccountUtil.hasLdapDummyMailAddress(account)){@account.mailAddress}"/>
|
||||||
<span id="error-mailAddress" class="error"></span>
|
<span id="error-mailAddress" class="error"></span>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@@ -52,7 +54,7 @@
|
|||||||
<a href="@path/@account.userName/_delete" class="btn btn-danger" id="delete">Delete account</a>
|
<a href="@path/@account.userName/_delete" class="btn btn-danger" id="delete">Delete account</a>
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" class="btn btn-success" value="Save"/>
|
<input type="submit" class="btn btn-success" value="Save"/>
|
||||||
<a href="@url(account.userName)" class="btn">Cancel</a>
|
@if(!AccountUtil.hasLdapDummyMailAddress(account)){<a href="@url(account.userName)" class="btn">Cancel</a>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -133,6 +133,13 @@
|
|||||||
<span id="error-ldap_userNameAttribute" class="error"></span>
|
<span id="error-ldap_userNameAttribute" class="error"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label" for="ldapAdditionalFilterCondition">Additional filter condition</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" id="ldapAdditionalFilterCondition" name="ldap.additionalFilterCondition" value="@settings.ldap.map(_.additionalFilterCondition)"/>
|
||||||
|
<span id="error-ldap_additionalFilterCondition" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label class="control-label" for="ldapFullNameAttribute">Full name attribute</label>
|
<label class="control-label" for="ldapFullNameAttribute">Full name attribute</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
|
|||||||
Reference in New Issue
Block a user