Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Incorporating LDAP with Play 2.x (Scala) application

DZone's Guide to

Incorporating LDAP with Play 2.x (Scala) application

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

For people in hurry here is the code and the steps.

In continuation of Play 2.x (Scala) is it a Spring MVC contender? – Introduction, in this blog, I extend my earlier blog Incorporating Authorization into Play 2.x (Scala) application to integrate with LDAP instead of database.

Again there might be better ways to do this, but right now there is no clear documentation. A quick googling will display this Google group link and this link and this Github code. All of them were of little help to me. So I took the 1st step and put one of these. I have used Unboundid LDAP SDK‘s InMemoryDirectoryServer.

As a first step we need to add the below dependency in Build.scala,

"com.unboundid" % "unboundid-ldapsdk" % "2.3.1",

Next we implement an in memory LDAP helper class LdapUtil.scala as below,

  def start(): InMemoryDirectoryServer = {
    val config = new InMemoryDirectoryServerConfig("dc=org");
    val listenerConfig = new InMemoryListenerConfig("test", null, 12345, null, null, null);
    config.setListenerConfigs(listenerConfig);
    config.setSchema(null); // do not check (attribute) schema
    val server = new InMemoryDirectoryServer(config);
    server.startListening();
...
    server.add("dn: cn=user@test.com,dc=staticsecurity,dc=geomajas,dc=org", "objectClass: person", "locale: nl_BE",
      "sn: NormalUser", "givenName: Joe", "memberOf: cn=testgroup,dc=roles,dc=geomajas,dc=org", "userPassword: password");
    server.add("dn: cn=admin@test.com,dc=staticsecurity,dc=geomajas,dc=org", "objectClass: person", "locale: nl_BE",
      "sn: Administrator", "givenName: Cindy", "memberOf: cn=testgroup,dc=roles,dc=geomajas,dc=org", "userPassword: password");
 
    server
  }
 
  def authenticate(email: String, password: String): Option[Account] = {
    val server = start
 
    val conn = server.getConnection();
    val entry = conn.getEntry("cn=" + email + ",dc=staticsecurity,dc=geomajas,dc=org");
 
    val permission = entry.getAttributeValue("sn").toString
    val retPass = entry.getAttributeValue("userPassword")
    server.shutDown(true)
 
    if (retPass.equals(password)) {
      println("password valid")
      val account = new Account(email, password, permission)
      toOption(account)
    } else {
      None
    }
  }
 
  def findByEmail(email: String): Option[Account] = {
    val server = start
    val conn = server.getConnection();
    val entry = conn.getEntry("cn=" + email + ",dc=staticsecurity,dc=geomajas,dc=org");
 
    val permission = entry.getAttributeValue("sn").toString
    val retPass = entry.getAttributeValue("userPassword")
    server.shutDown(true)
 
    val account = new Account(email, retPass, permission)
    toOption(account)
  }

If you notice the normal user rights are email:= user@test.com, pwd:= password and admin rights are email:= admin@test.com, pwd:= password. As in my earlier blog, we need to customize the AuthConfig as below,

trait AuthConfigImpl extends AuthConfig {
  type Id = String
  type User = Account
  type Authority = String
  val idTag = classTag[Id]
...
  def resolveUser(email: Id) = LdapUtil.findByEmail(email)
...
  def authorize(user: User, authority: Authority) = (user.permission, authority) match {
    case ("Administrator", _) => true
    case ("NormalUser", "NormalUser") => true
    case _ => false
  }
}

Login form looks as below as in Application.scala,

val loginForm = Form {
  mapping("email" -> email, "password" -> text)(LdapUtil.authenticate)(_.map(u => (u.email, "")))
    .verifying("Invalid email or password", result => result.isDefined)
}

Finally the usage looks as below refer CoffeesControler.scala,

def create = StackAction(AuthorityKey -> "Administrator") { implicit request =>
    database withSession {
      Ok(html.coffees.createForm(form, supplierSelect))
    }
  }







 

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:

Published at DZone with permission of Krishna Prasad, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}