Skip to content

Commit

Permalink
gPlazma-ldap: fix non-serializable Set problem
Browse files Browse the repository at this point in the history
reverseMap returned a automatically Scala to Java converted Set class
that did not implement Serializable.  This caused an
NotSerializableException when the object should be send in a cell
message.  This patch adds a couple of manual conversions instead of
automatic ones, ensuring the returned Set is Serializable.

Ticket:
Acked-by:
Target: trunk
Require-book: no
Require-notes: no
  • Loading branch information
Karsten Schwank committed Nov 21, 2013
1 parent f6afcf7 commit 110be4f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 37 deletions.
Expand Up @@ -3,7 +3,7 @@ package org.dcache.gplazma.plugins
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import scala.collection.JavaConversions._
import scala.collection.convert.Wrappers._

import javax.naming.{Context, CommunicationException, NamingEnumeration, NamingException}
import javax.naming.directory.BasicAttributes
Expand All @@ -23,6 +23,7 @@ import org.dcache.auth.attributes.ReadOnly
import org.dcache.auth.attributes.RootDirectory
import org.dcache.gplazma.AuthenticationException
import org.dcache.gplazma.NoSuchPrincipalException
import scala.collection.convert.WrapAsJava

/**
* gPlazma plug-in which uses LDAP server to provide requested information.
Expand Down Expand Up @@ -114,22 +115,24 @@ class Ldap(properties : Properties) extends GPlazmaIdentityPlugin with GPlazmaSe
}
}

private implicit def attrToString(attr: javax.naming.directory.Attribute) : String = attr.get.asInstanceOf[String]

def map(principals: java.util.Set[Principal]) {
principals.find( p => p.isInstanceOf[UserNamePrincipal] ) match {
JSetWrapper(principals).find( p => p.isInstanceOf[UserNamePrincipal] ) match {
case Some(p) => try {
val peopleMaps = mapSearchPeopleByName(p).foldLeft(List[Principal]())( (pset, peopleResult) => {
val userAttr = peopleResult.getAttributes
new UidPrincipal(userAttr.get(Ldap.UID_NUMBER_ATTRIBUTE).get.asInstanceOf[String]) ::
new GidPrincipal(userAttr.get(Ldap.GID_NUMBER_ATTRIBUTE).get.asInstanceOf[String], true) ::
new UidPrincipal(userAttr.get(Ldap.UID_NUMBER_ATTRIBUTE)) ::
new GidPrincipal(userAttr.get(Ldap.GID_NUMBER_ATTRIBUTE), true) ::
pset
})
principals.addAll(peopleMaps)
principals.addAll(SeqWrapper(peopleMaps))

val groupMaps = mapSearchGroupByName(p).foldLeft(List[Principal]())( (pset, groupResult) => {
new GidPrincipal(groupResult.getAttributes.get(Ldap.GID_NUMBER_ATTRIBUTE).get.asInstanceOf[String], false) ::
new GidPrincipal(groupResult.getAttributes.get(Ldap.GID_NUMBER_ATTRIBUTE), false) ::
pset
})
principals.addAll(groupMaps)
principals.addAll(SeqWrapper(groupMaps))
} catch {
case e: NamingException => {
log.debug("Failed to get mapping: {}", e.toString)
Expand All @@ -140,14 +143,14 @@ class Ldap(properties : Properties) extends GPlazmaIdentityPlugin with GPlazmaSe
}
}

private def mapSearchGroupByName(principal: Principal): NamingEnumeration[SearchResult] = {
private def mapSearchGroupByName(principal: Principal) = JEnumerationWrapper {
retryWithNewContextOnException[NamingEnumeration[SearchResult]]( () => {
ctx.search(groupOU,
new BasicAttributes(Ldap.MEMBER_UID_ATTRIBUTE, principal.getName))
})
}

private def mapSearchPeopleByName(principal: Principal): NamingEnumeration[SearchResult] = {
private def mapSearchPeopleByName(principal: Principal) = JEnumerationWrapper {
retryWithNewContextOnException[NamingEnumeration[SearchResult]]( () => {
ctx.search(peopleOU,
String.format(userFilter, principal.getName),
Expand All @@ -161,11 +164,11 @@ class Ldap(properties : Properties) extends GPlazmaIdentityPlugin with GPlazmaSe
principal match {
case _: UserNamePrincipal =>
mapSearchPeopleById(name).collectFirst[Principal]( { case searchResult =>
new UidPrincipal(searchResult.getAttributes.get(Ldap.UID_NUMBER_ATTRIBUTE).get.asInstanceOf[String])
new UidPrincipal(searchResult.getAttributes.get(Ldap.UID_NUMBER_ATTRIBUTE))
})
case _: GroupNamePrincipal =>
mapSearchGroupById(name).collectFirst[Principal]( { case searchResult =>
new GidPrincipal(searchResult.getAttributes.get(Ldap.GID_NUMBER_ATTRIBUTE).get.asInstanceOf[String], false)
new GidPrincipal(searchResult.getAttributes.get(Ldap.GID_NUMBER_ATTRIBUTE), false)
})
case _ => None
}
Expand All @@ -181,36 +184,37 @@ class Ldap(properties : Properties) extends GPlazmaIdentityPlugin with GPlazmaSe
}


private def mapSearchGroupById(name: String): NamingEnumeration[SearchResult] = {
private def mapSearchGroupById(name: String) = JEnumerationWrapper {
retryWithNewContextOnException( () => {
ctx.search(groupOU,
String.format("(%s=%s)", Ldap.COMMON_NAME_ATTRIBUTE, name),
getSimpleSearchControls(Array(Ldap.GID_NUMBER_ATTRIBUTE)))
})
}

private def mapSearchPeopleById(name: String): NamingEnumeration[SearchResult] = {
private def mapSearchPeopleById(name: String) = JEnumerationWrapper {
retryWithNewContextOnException( () => {
ctx.search(peopleOU,
String.format("(%s=%s)", Ldap.USER_ID_ATTRIBUTE, name),
getSimpleSearchControls(Array(Ldap.UID_NUMBER_ATTRIBUTE)))
})
}

def reverseMap(principal: Principal) : java.util.Set[Principal] = (
def reverseMap(principal: Principal) = new java.util.HashSet[Principal](
WrapAsJava.asJavaCollection((
try {
val id: String = principal.getName
principal match {
case _: GidPrincipal =>
reverseMapSearchGroup(id).map((searchResult) => {
new GroupNamePrincipal(
searchResult.getAttributes.get(Ldap.COMMON_NAME_ATTRIBUTE).get.asInstanceOf[String]
searchResult.getAttributes.get(Ldap.COMMON_NAME_ATTRIBUTE)
)
})
case _: UidPrincipal =>
reverseMapSearchUser(id).map((searchResult) => {
new UserNamePrincipal(
searchResult.getAttributes.get(Ldap.USER_ID_ATTRIBUTE).get.asInstanceOf[String]
searchResult.getAttributes.get(Ldap.USER_ID_ATTRIBUTE)
)
})
case _ => Nil
Expand All @@ -222,30 +226,30 @@ class Ldap(properties : Properties) extends GPlazmaIdentityPlugin with GPlazmaSe
Nil
}
}
).toSet[Principal]
).toSet[Principal]))

private def reverseMapSearchUser(id: String): NamingEnumeration[SearchResult] = {
private def reverseMapSearchUser(id: String) = JEnumerationWrapper {
retryWithNewContextOnException( () => {
ctx.search(peopleOU,
new BasicAttributes(Ldap.UID_NUMBER_ATTRIBUTE, id))
})
}

private def reverseMapSearchGroup(id: String): NamingEnumeration[SearchResult] = {
private def reverseMapSearchGroup(id: String) = JEnumerationWrapper {
retryWithNewContextOnException( () => {
ctx.search(groupOU,
new BasicAttributes(Ldap.GID_NUMBER_ATTRIBUTE, id))
})
}

def session(authorizedPrincipals: java.util.Set[Principal], attrib: java.util.Set[AnyRef]) {
val principal = authorizedPrincipals.find(p => p.isInstanceOf[UserNamePrincipal])
val principal = JSetWrapper(authorizedPrincipals).find(p => p.isInstanceOf[UserNamePrincipal])
principal match {
case Some(p) =>
try {
val sResult = sessionSearchHome(p)
sResult.foreach( searchResult => {
attrib.add(new HomeDirectory(searchResult.getAttributes.get(Ldap.HOME_DIR_ATTRIBUTE).get.asInstanceOf[String]))
attrib.add(new HomeDirectory(searchResult.getAttributes.get(Ldap.HOME_DIR_ATTRIBUTE)))
attrib.add(new RootDirectory("/"))
attrib.add(new ReadOnly(false))
})
Expand All @@ -256,7 +260,7 @@ class Ldap(properties : Properties) extends GPlazmaIdentityPlugin with GPlazmaSe
}
}

private def sessionSearchHome(principal: Principal): NamingEnumeration[SearchResult] = {
private def sessionSearchHome(principal: Principal) = JEnumerationWrapper {
retryWithNewContextOnException( () => {
ctx.search(peopleOU,
String.format(userFilter, principal.getName),
Expand Down
Expand Up @@ -4,15 +4,16 @@ import org.scalatest._
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith

import scala.collection.JavaConversions._

import java.util
import java.util.Properties
import java.security.Principal

import scala.collection.convert.WrapAsJava.setAsJavaSet

import org.dcache.auth.{GroupNamePrincipal, GidPrincipal, UidPrincipal, UserNamePrincipal}
import org.dcache.gplazma.NoSuchPrincipalException
import java.security.Principal
import org.dcache.auth.attributes.{ReadOnly, HomeDirectory, RootDirectory}
import java.util


/**
* Tests for the gPlazma LDAP plugin.
Expand All @@ -38,14 +39,13 @@ class LdapPluginTest extends FlatSpec with Matchers {

"map(Set[Principal])" should "return matching Uid and Gid Principals for an existent user name" in {
val principals = new util.HashSet[Principal]()
principals add new UserNamePrincipal("karsten")
principals add new UserNamePrincipal("testuser")

ldapPlugin.map(principals)
principals.size should be (4)
principals should contain (new UserNamePrincipal("karsten"))
principals should contain (new UidPrincipal("121"))
principals.size should be (3)
principals should contain (new UserNamePrincipal("testuser"))
principals should contain (new UidPrincipal("50999"))
principals should contain (new GidPrincipal("3752", true))
principals should contain (new GidPrincipal("1000", false))
}

it should "leave the principals set unchanged for a non existent user name" in {
Expand All @@ -58,7 +58,7 @@ class LdapPluginTest extends FlatSpec with Matchers {
}

"map(UserNamePrincipal)" should "return a UidPrincipal for an existing user name" in {
ldapPlugin.map(new UserNamePrincipal("karsten")) should be (new UidPrincipal("121"))
ldapPlugin.map(new UserNamePrincipal("testuser")) should be (new UidPrincipal("50999"))
}

it should "throw a NoSuchPrincipalException if a user does not exist" in {
Expand All @@ -69,7 +69,12 @@ class LdapPluginTest extends FlatSpec with Matchers {
}

"reverseMap" should "return a Set containing a UserNamePrincipal for an existing Uid" in {
ldapPlugin.reverseMap(new UidPrincipal("121")) should contain (new UserNamePrincipal("karsten"))
ldapPlugin.reverseMap(new UidPrincipal("50999")) should contain (new UserNamePrincipal("testuser"))
}

it should "return a serializable Set" in {
val set = ldapPlugin.reverseMap(new UidPrincipal("50999"))
set.isInstanceOf[java.io.Serializable] should be (true)
}

it should "return an empty Set for an non existent Uid" in {
Expand All @@ -81,16 +86,16 @@ class LdapPluginTest extends FlatSpec with Matchers {
}

it should "return an empty Set for a non existent Gid" in {
ldapPlugin.reverseMap(new GidPrincipal("666", true)) should be ('empty)
ldapPlugin.reverseMap(new GidPrincipal("51000", true)) should be ('empty)
}

"session" should "return the user's home and root directory, and the access rights" in {
var attr = new java.util.HashSet[AnyRef]()
ldapPlugin.session(Set[Principal](new UserNamePrincipal("karsten")), attr)
val attr = new java.util.HashSet[AnyRef]()
ldapPlugin.session(setAsJavaSet(Set[Principal](new UserNamePrincipal("testuser"))), attr)

attr should have size 3
attr should contain (new RootDirectory("/"))
attr should contain (new HomeDirectory("/dcache-cloud/karsten"))
attr should contain (new HomeDirectory("/dcache-cloud/testuser"))
attr should contain (new ReadOnly(false))
}

Expand Down

0 comments on commit 110be4f

Please sign in to comment.