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)) } }
I hope this blog helped.