diff --git a/build.sbt b/build.sbt index f9c3084..f686835 100644 --- a/build.sbt +++ b/build.sbt @@ -7,34 +7,33 @@ organization := "net.liftmodules" version := "1.6.0-SNAPSHOT" -liftVersion := "2.6.3" +liftVersion := "3.5.0-SNAPSHOT" liftEdition := (liftVersion apply { _.substring(0,3) }).value moduleName := name.value + "_" + liftEdition.value -crossScalaVersions := Seq("2.11.12") +crossScalaVersions := Seq("2.13.3", "2.12.11", "2.11.12") scalaVersion := crossScalaVersions.value.head scalacOptions ++= Seq("-unchecked", "-deprecation") resolvers ++= Seq( - "CB Central Mirror" at "http://repo.cloudbees.com/content/groups/public", - "Java.net Maven2 Repository" at "http://download.java.net/maven/2/" + DefaultMavenRepository, + Resolver.sonatypeRepo("public") ) libraryDependencies ++= Seq( - "net.liftweb" %% "lift-mapper" % liftVersion.value % "provided", - "ch.qos.logback" % "logback-classic" % "1.2.3" % "provided", - "log4j" % "log4j" % "1.2.17" % "provided" + "net.liftweb" %% "lift-mapper" % liftVersion.value % Provided, + "ch.qos.logback" % "logback-classic" % "1.2.3" % Provided, + "log4j" % "log4j" % "1.2.17" % Provided ) libraryDependencies ++= Seq( - "org.specs2" %% "specs2-core" % "3.9.1" % "test", -// "org.scalacheck" %% "scalacheck" % "1.8" % "test", - "org.apache.directory.server" % "apacheds-core" % "2.0.0-M24" % "test", - "org.apache.directory.server" % "apacheds-server-integ" % "2.0.0-M24" % "test", - "org.apache.directory.server" % "apacheds-core-integ" % "2.0.0-M24" % "test" + "org.specs2" %% "specs2-core" % "4.9.4" % Test, + "org.apache.directory.server" % "apacheds-core" % "2.0.0.AM26" % Test, + "org.apache.directory.server" % "apacheds-server-integ" % "2.0.0.AM26" % Test, + "org.apache.directory.server" % "apacheds-core-integ" % "2.0.0.AM26" % Test ) -fork in Test := true \ No newline at end of file +fork in Test := true diff --git a/project/build.properties b/project/build.properties index a31be40..0837f7a 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.0.4 \ No newline at end of file +sbt.version=1.3.13 diff --git a/src/main/scala/net/liftweb/ldap/LDAP.scala b/src/main/scala/net/liftweb/ldap/LDAP.scala index 44b3fbb..c9d0394 100644 --- a/src/main/scala/net/liftweb/ldap/LDAP.scala +++ b/src/main/scala/net/liftweb/ldap/LDAP.scala @@ -14,18 +14,16 @@ * limitations under the License. */ -package net.liftweb { -package ldap { +package net.liftweb.ldap import java.io.{InputStream, FileInputStream} -import java.util.{Hashtable, Properties} +import java.util.Properties import javax.naming.{AuthenticationException, CommunicationException, Context} import javax.naming.directory.{Attributes, SearchControls} import javax.naming.ldap.InitialLdapContext import scala.collection.mutable.ListBuffer -import scala.collection.JavaConversions._ import _root_.net.liftweb.util.{ControlHelpers, Props, SimpleInjector, ThreadGlobal} import _root_.net.liftweb.common.{Box, Empty, Full, Loggable} @@ -57,7 +55,7 @@ object SimpleLDAPVendor extends LDAPVendor { } @deprecated("Use the configure() method") - def setupFromBoot = configure() + def setupFromBoot(): Unit = configure() } /** @@ -313,7 +311,9 @@ class LDAPVendor extends Loggable with SimpleInjector { } protected def propertiesToMap(props: Properties) : Map[String,String] = { - Map.empty ++ props + val builder = Map.newBuilder[String, String] + props.forEach((k,v) => builder.addOne((k.toString, v.toString))) + builder.result() } // =========== Code ==================== @@ -444,6 +444,3 @@ class LDAPVendor extends Loggable with SimpleInjector { new InitialLdapContext(env, null) } } - -}} // Close nested packages - diff --git a/src/main/scala/net/liftweb/ldap/LDAPProtoUser.scala b/src/main/scala/net/liftweb/ldap/LDAPProtoUser.scala index c27f7cc..3616454 100644 --- a/src/main/scala/net/liftweb/ldap/LDAPProtoUser.scala +++ b/src/main/scala/net/liftweb/ldap/LDAPProtoUser.scala @@ -14,185 +14,187 @@ * limitations under the License. */ -package net.liftweb { -package ldap { +package net.liftweb.ldap import javax.naming.directory.Attributes + import net.liftweb.http.{S, SessionVar} import net.liftweb.http.js.JsCmds -import net.liftweb.mapper.{MappedString, - MetaMegaProtoUser, - MegaProtoUser} +import net.liftweb.mapper.{MappedString, MegaProtoUser, MetaMegaProtoUser} import net.liftweb.sitemap.Menu -import net.liftweb.util.Helpers +import net.liftweb.util.{CssSel, Helpers} import net.liftweb.common.{Box, Empty} - import Helpers._ import scala.util.matching.Regex import scala.xml.{Elem, NodeSeq} trait MetaLDAPProtoUser[ModelType <: LDAPProtoUser[ModelType]] extends MetaMegaProtoUser[ModelType] { - self: ModelType => + self: ModelType => - override def signupFields: List[FieldPointerType] = uid :: cn :: dn :: Nil + override def signupFields: List[FieldPointerType] = uid :: cn :: dn :: Nil - override def fieldOrder: List[FieldPointerType] = uid :: cn :: dn :: Nil + override def fieldOrder: List[FieldPointerType] = uid :: cn :: dn :: Nil - /** - * The menu item for creating the user/sign up (make this "Empty" to disable) - */ - override def createUserMenuLoc: Box[Menu] = Empty + /** + * The menu item for creating the user/sign up (make this "Empty" to disable) + */ + override def createUserMenuLoc: Box[Menu] = Empty - /** - * The menu item for lost password (make this "Empty" to disable) - */ - override def lostPasswordMenuLoc: Box[Menu] = Empty + /** + * The menu item for lost password (make this "Empty" to disable) + */ + override def lostPasswordMenuLoc: Box[Menu] = Empty - /** - * The menu item for resetting the password (make this "Empty" to disable) - */ - override def resetPasswordMenuLoc: Box[Menu] = Empty + /** + * The menu item for resetting the password (make this "Empty" to disable) + */ + override def resetPasswordMenuLoc: Box[Menu] = Empty - /** - * The menu item for changing password (make this "Empty" to disable) - */ - override def changePasswordMenuLoc: Box[Menu] = Empty + /** + * The menu item for changing password (make this "Empty" to disable) + */ + override def changePasswordMenuLoc: Box[Menu] = Empty - /** - * The menu item for validating a user (make this "Empty" to disable) - */ - override def validateUserMenuLoc: Box[Menu] = Empty + /** + * The menu item for validating a user (make this "Empty" to disable) + */ + override def validateUserMenuLoc: Box[Menu] = Empty - override def editUserMenuLoc: Box[Menu] = Empty + override def editUserMenuLoc: Box[Menu] = Empty - /** - * User search sentence - */ - def ldapUserSearch: String = "(uid=%s)" + /** + * User search sentence + */ + def ldapUserSearch: String = "(uid=%s)" - /** - * Error messages - */ - def loginErrorMessage: String = "Unable to login with : %s" + /** + * Error messages + */ + def loginErrorMessage: String = "Unable to login with : %s" def commonNameAttributeName = "cn" def uidAttributeName = "uid" - override def loginXhtml : Elem = { -
- - - - - - - - - - - - - -
{S.?("log.in")}
Username
Password
 
-
+ override def loginXhtml : Elem = { + val loginStr = S.?("log.in") + +
+ + + + + + + + + + + + + +
{loginStr}
Username
Password
 
+
+ } + + def ldapVendor: LDAPVendor = SimpleLDAPVendor + + override def login : NodeSeq = { + if (S.post_?) { + if (!ldapLogin(S.param("username").openOr(""), + S.param("password").openOr(""))) + S.error(loginErrorMessage.format(S.param("username").openOr(""))) } - def ldapVendor: LDAPVendor = SimpleLDAPVendor + def bind: CssSel = { + val passwordElemId = nextFuncName + val usernameElemId = nextFuncName - override def login : NodeSeq = { - if (S.post_?) { - if (!ldapLogin(S.param("username").openOr(""), - S.param("password").openOr(""))) - S.error(loginErrorMessage.format(S.param("username").openOr(""))) - } + S.appendJs(JsCmds.Focus(passwordElemId) & JsCmds.Focus(usernameElemId)) - Helpers.bind("user", loginXhtml, - "name" -> JsCmds.FocusOnLoad(), - "password" -> JsCmds.FocusOnLoad(), - "submit" -> ) + "type=text [id]" #> usernameElemId & + "type=password [id]" #> passwordElemId } - def ldapLogin(username: String, password: String): Boolean = { - def _getUserAttributes(dn: String) = ldapVendor.attributesFromDn(dn) + bind(loginXhtml) + } - val users = ldapVendor.search(ldapUserSearch.format(username)) + def ldapLogin(username: String, password: String): Boolean = { + def _getUserAttributes(dn: String) = ldapVendor.attributesFromDn(dn) - if (users.nonEmpty) { - val userDn = users.head - if (ldapVendor.bindUser(userDn, password)) { - val completeDn = userDn + "," + ldapVendor.parameters().getOrElse("ldap.base", "") - logUserIn(this) + val users = ldapVendor.search(ldapUserSearch.format(username)) - bindAttributes(_getUserAttributes(completeDn)) + if (users.nonEmpty) { + val userDn = users.head + if (ldapVendor.bindUser(userDn, password)) { + val completeDn = userDn + "," + ldapVendor.parameters().getOrElse("ldap.base", "") + logUserIn(this) - setRoles(completeDn, ldapVendor) - S.redirectTo(homePage) - } - else return false - } - else return false + bindAttributes(_getUserAttributes(completeDn)) - return true + setRoles(completeDn, ldapVendor) + S.redirectTo(homePage) + true + } + else false } + else false + } - def bindAttributes(attrs: Attributes) { - for { - theCn <- Box !! attrs.get(commonNameAttributeName).get - theUid <- Box !! attrs.get(uidAttributeName).get - } - { - cn(theCn.toString) - uid(theUid.toString) - } + def bindAttributes(attrs: Attributes) { + for { + theCn <- Box !! attrs.get(commonNameAttributeName).get + theUid <- Box !! attrs.get(uidAttributeName).get + } + { + cn(theCn.toString) + uid(theUid.toString) } + } } trait LDAPProtoUser[T <: LDAPProtoUser[T]] extends MegaProtoUser[T] { - self: T => - /** - * User Roles LDAP search filter - */ - def rolesSearchFilter: String = "(&(objectclass=groupofnames)(member=%s))" + self: T => + /** + * User Roles LDAP search filter + */ + def rolesSearchFilter: String = "(&(objectclass=groupofnames)(member=%s))" - /** - * Regular expression to get user roles names - */ - def rolesNameRegex = ".*cn=(.[^,]*),ou=.*" + /** + * Regular expression to get user roles names + */ + def rolesNameRegex = ".*cn=(.[^,]*),ou=.*" - object ldapRoles extends SessionVar[List[String]](List()) - - override def getSingleton: MetaLDAPProtoUser[T] - - object uid extends MappedString(this, 64) { - override def dbIndexed_? = true - } + object ldapRoles extends SessionVar[List[String]](List()) - object dn extends MappedString(this, 64) { - override def dbIndexed_? = true - } + override def getSingleton: MetaLDAPProtoUser[T] - object cn extends MappedString(this, 64) { - override def dbIndexed_? = true - } + object uid extends MappedString(this, 64) { + override def dbIndexed_? = true + } - def getRoles: List[String] = ldapRoles.get + object dn extends MappedString(this, 64) { + override def dbIndexed_? = true + } - def setRoles(userDn: String, ldapVendor: LDAPVendor) { - def getGroupNameFromDn(dn: String): String = { - val regex = new Regex(rolesNameRegex) + object cn extends MappedString(this, 64) { + override def dbIndexed_? = true + } - val regex(groupName) = dn - return groupName - } + def getRoles: List[String] = ldapRoles.get - // Search for user roles - val filter = rolesSearchFilter.format(userDn) + def setRoles(userDn: String, ldapVendor: LDAPVendor) { + def getGroupNameFromDn(dn: String): String = { + val regex = new Regex(rolesNameRegex) - val groups = ldapVendor.search(filter) - groups foreach { g => ldapRoles.set(ldapRoles.get :+ getGroupNameFromDn(g)) } + val regex(groupName) = dn + groupName } -} -} -} + // Search for user roles + val filter = rolesSearchFilter.format(userDn) + + val groups = ldapVendor.search(filter) + groups foreach { g => ldapRoles.set(ldapRoles.get :+ getGroupNameFromDn(g)) } + } +} \ No newline at end of file diff --git a/src/test/scala/net/liftweb/ldap/EmbeddedADS.java b/src/test/scala/net/liftweb/ldap/EmbeddedADS.java index 2ffa837..0b5d78b 100644 --- a/src/test/scala/net/liftweb/ldap/EmbeddedADS.java +++ b/src/test/scala/net/liftweb/ldap/EmbeddedADS.java @@ -17,7 +17,6 @@ import org.apache.directory.api.util.exception.Exceptions; import org.apache.directory.server.constants.ServerDNConstants; import org.apache.directory.server.core.DefaultDirectoryService; -import org.apache.directory.server.core.api.CacheService; import org.apache.directory.server.core.api.DirectoryService; import org.apache.directory.server.core.api.DnFactory; import org.apache.directory.server.core.api.InstanceLayout; @@ -149,11 +148,6 @@ private void initDirectoryService( File workDir ) throws Exception service = new DefaultDirectoryService(); service.setInstanceLayout( new InstanceLayout( workDir ) ); - CacheService cacheService = new CacheService(); - cacheService.initialize( service.getInstanceLayout() ); - - service.setCacheService( cacheService ); - // first load the schema initSchemaPartition(); @@ -243,4 +237,4 @@ public void initServer(int serverPort) throws Exception startServer(serverPort); } -} \ No newline at end of file +}