Skip to content

Commit

Permalink
LDAP support added: first attempt
Browse files Browse the repository at this point in the history
  • Loading branch information
ignatov committed Aug 12, 2011
1 parent 8c2c8dc commit 12c2f46
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 20 deletions.
1 change: 1 addition & 0 deletions Colladoc.iml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<orderEntry type="library" name="nu.validator.htmlparser_htmlparser_1.2.1" level="project" />
<orderEntry type="library" name="commons-fileupload_commons-fileupload_1.2.2" level="project" />
<orderEntry type="library" name="net.liftweb_lift-mapper_2.8.1_2.2" level="project" />
<orderEntry type="library" name="net.liftweb_lift-ldap_2.8.1_2.2" level="project" />
<orderEntry type="library" name="net.liftweb_lift-proto_2.8.1_2.2" level="project" />
<orderEntry type="library" name="net.liftweb_lift-openid_2.8.1_2.2" level="project" />
<orderEntry type="library" name="org.openid4java_openid4java-consumer_0.9.5" level="project" />
Expand Down
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ libraryDependencies ++= {
"net.liftweb" % "lift-webkit_2.8.1" % liftVersion % "compile->default",
"net.liftweb" % "lift-mapper_2.8.1" % liftVersion % "compile->default",
"net.liftweb" % "lift-openid_2.8.1" % liftVersion % "compile->default",
"net.liftweb" % "lift-widgets_2.8.1" % liftVersion % "compile->default"
"net.liftweb" % "lift-widgets_2.8.1" % liftVersion % "compile->default",
"net.liftweb" % "lift-ldap_2.8.1" % liftVersion % "compile->default"
)
}

Expand Down
7 changes: 7 additions & 0 deletions src/main/scala/bootstrap/liftweb/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import tools.colladoc.boot.ColladocBoot

import xml.{Text, NodeSeq}
import tools.nsc.io.Streamable
import tools.colladoc.lib.ldap.ColladocLdap
import java.io.ByteArrayInputStream

/**
* A class that's instantiated early and run. It allows the application to modify lift's environment
Expand Down Expand Up @@ -90,6 +92,9 @@ class Boot {
// RewriteResponse("search" :: Nil, Map("q" -> query))
// }

// Initialize LDAP properties
ColladocLdap.configureFromDb()

LiftRules.dispatch.append(ColladocOpenIDVendor.dispatchPF)

LiftRules.setSiteMapFunc(sitemap)
Expand Down Expand Up @@ -124,6 +129,8 @@ class Boot {
LiftRules.exceptionHandler.prepend {
case (_, r, e) => Error.render(r, e)
}

LiftRules.ajaxPostTimeout = 5000
}

object Error {
Expand Down
47 changes: 47 additions & 0 deletions src/main/scala/scala/tools/colladoc/lib/ldap/ColladocLdap.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2011, Sergey Ignatov. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COLLABORATIVE SCALADOC PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COLLABORATIVE SCALADOC
* PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package scala.tools.colladoc.lib.ldap

import net.liftweb.ldap.LDAPVendor
import java.io.ByteArrayInputStream
import tools.colladoc.model.mapper.Properties

/**
* LDAP vendor for Colladoc.
* @author ignatov
*/
object ColladocLdap extends LDAPVendor {
def configureFromDb() {
try {
def toStream(text: String) = new ByteArrayInputStream(text.getBytes("UTF-8"))

val stream = toStream(Properties.get("ldap").getOrElse(""))
ColladocLdap.configure(stream)
stream.close()
}
catch {
case e: Exception => e.printStackTrace()
}
}

}
76 changes: 57 additions & 19 deletions src/main/scala/scala/tools/colladoc/model/mapper/User.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ import net.liftweb.http.SHtml.ElemAttr._
import xml.{NodeSeq, Text}
import lib.js.JqUI._
import net.liftweb.widgets.gravatar.Gravatar
import net.liftweb.ldap.{LDAPProtoUser, MetaLDAPProtoUser}
import lib.ldap.ColladocLdap

/**
* Mapper for user table storing registered users.
* @author Petr Hosek
*/
class User extends ProtoUser[User] with OneToMany[Long, User] {
class User extends LDAPProtoUser[User] with OneToMany[Long, User] {
def getSingleton = User

/** Username. */
Expand Down Expand Up @@ -100,45 +102,50 @@ class User extends ProtoUser[User] with OneToMany[Long, User] {
* Mapper for user table storing registered users.
* @author Petr Hosek
*/
object User extends User with KeyedMetaMapper[Long, User] {
object User extends User with MetaLDAPProtoUser[User] with KeyedMetaMapper[Long, User] {
override def dbTableName = "users"

/** Current logged in user identifier */
private object curUserId extends SessionVar[Box[String]](Empty)

/** Get current logged in user identifier */
def currentUserId: Box[String] = curUserId.is
override def currentUserId: Box[String] = curUserId.is

/** Current logged in user */
private object curUser extends RequestVar[Box[User]](currentUserId.flatMap(id => find(id))) with CleanRequestVarOnSessionTransition

/** Get current logged in user */
def currentUser: Box[User] = curUser.is
override def currentUser: Box[User] = curUser.is

/** Whether currently logged in user is superuser */
def superUser_? : Boolean = currentUser.map(_.superUser.is) openOr false
override def superUser_? : Boolean = currentUser.map(_.superUser.is) openOr false

def banned_? = currentUser.map(_.banned.is) openOr true

def validSuperUser_? = superUser_? && !User.banned_?

/** Whether any user is logged in. */
def loggedIn_? = currentUserId.isDefined
override def loggedIn_? = currentUserId.isDefined

/** Log in user with given identifier. */
def logUserIdIn(id: String) {
override def logUserIdIn(id: String) {
curUser.remove()
curUserId(Full(id))
}

/** Log in user. */
def logUserIn(who: User) {
override def logUserIn(who: User) {
curUser.remove()
curUserId(Full(who.id.toString))
}

/** Log out current user. */
def logoutCurrentUser = logUserOut()
override def logoutCurrentUser {
logUserOut()
}

/** Log out user. */
def logUserOut() {
override def logUserOut() {
curUserId.remove()
curUser.remove()
S.request.foreach(_.request.session.terminate)
Expand Down Expand Up @@ -213,7 +220,7 @@ object User extends User with KeyedMetaMapper[Long, User] {
</lift:form>

/** Edit user dialog. */
def edit = {
override def edit = {
val user = currentUser.open_!

def doSave() {
Expand Down Expand Up @@ -253,10 +260,13 @@ object User extends User with KeyedMetaMapper[Long, User] {
private def projectSettings: NodeSeq = {
var title = Properties.get("-doc-title").getOrElse("")
var version = Properties.get("-doc-version").getOrElse("")
var ldap = Properties.get("ldap").getOrElse("")

def doSave(): JsCmd = {
Properties.set("-doc-title", title)
Properties.set("-doc-version", version)
Properties.set("ldap", ldap)
ColladocLdap.configureFromDb()
S.notice("Project settings successfully saved.")
Noop
}
Expand All @@ -265,13 +275,17 @@ object User extends User with KeyedMetaMapper[Long, User] {
<lift:form class="properties">
<fieldset>
<p>
<label for="title">Title:</label>
<label for="title">Title</label>
<settings:title class="text required ui-widget-content ui-corner-all" />
</p>
<p>
<label for="version">Version:</label>
<label for="version">Version</label>
<settings:version class="text required ui-widget-content ui-corner-all" />
</p>
<p>
<label for="ldap">LDAP</label>
<settings:ldap class="text required ui-widget-content ui-corner-all" />
</p>
<settings:submit />
<settings:save />
<settings:reset />
Expand All @@ -281,9 +295,12 @@ object User extends User with KeyedMetaMapper[Long, User] {
bind("settings", form,
"title" -%> SHtml.text(title, title = _, ("id", "title")),
"version" -%> SHtml.text(version, version = _, ("id", "version")),
"ldap" -%> SHtml.textarea(ldap, ldap = _, ("id", "ldap")),
"submit" -> SHtml.hidden(doSave _),
"save" -> SHtml.a(Text("Save"), SubmitForm(".properties"), ("class", "button")),
"reset" -> SHtml.a(Text("Reset"), SetValById("title", Str(title)) & SetValById("version", Str(version)), ("class", "button"))
"reset" -> SHtml.a(Text("Reset"),
SetValById("title", Str(title)) & SetValById("version", Str(version)) & SetValById("ldap", Str(ldap)),
("class", "button"))
)
}

Expand Down Expand Up @@ -417,7 +434,7 @@ object User extends User with KeyedMetaMapper[Long, User] {
</div>

/** Signup user dialog. */
def signup = {
override def signup = {
val user = create

def doSignup() {
Expand Down Expand Up @@ -481,19 +498,39 @@ object User extends User with KeyedMetaMapper[Long, User] {
</div>

/** Login user dialog. */
def login = {
override def login = {
var username: String = ""
var password: String = "*"

def doLogin = {
def doLogin() = {
find(By(userName, username)) match {
case Full(user) if !user.deleted_? && user.password.match_?(password) =>
S.notice("User logged in")
logUserIn(user)
RedirectTo("/")
case _ =>
S.error("Invalid user credentials")
if (ldapAuth_?(username, password)) {
// create or get user from db and logged them in
val user: User = find(By(userName, username)) match {
case Full(u) if !u.deleted_? => u
case _ => create.userName(username).saveMe
}
logUserIn(user)
RedirectTo("/")
} else
S.error("Invalid user credentials")
}
}

def ldapAuth_?(username: String, password: String): Boolean = {
val ldapUserSearch = "(uid=%s)"
val users = ColladocLdap.search(ldapUserSearch.format(username))

if (users.size >= 1) {
if (ColladocLdap.bindUser(users(0), password))
return true
}
false
}

bind("user", loginHtml,
Expand All @@ -503,8 +540,9 @@ object User extends User with KeyedMetaMapper[Long, User] {
}

/** Logout user. */
def logout = {
override def logout: Nothing = {
logoutCurrentUser
S.redirectTo("/")
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/main/webapp/cosettings.css
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@
padding: .4em;
}

.properties textarea.text {
width: 95%;
height: 150px;
padding: .4em;
}

.submit {
padding: 4px 10px;
}
Expand Down

0 comments on commit 12c2f46

Please sign in to comment.