-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bdd0961
commit 1ccaf15
Showing
7 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
= LDAP Utils | ||
|
||
Utilities for working with LDAP from VEuPathDB containerized services. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package org.veupathdb.lib.ldap | ||
|
||
import com.unboundid.ldap.sdk.* | ||
import org.slf4j.LoggerFactory | ||
|
||
class LDAP(private val config: LDAPConfig) { | ||
private val log = LoggerFactory.getLogger(javaClass) | ||
|
||
private var ldapConnection: LDAPConnection? = null | ||
|
||
init { | ||
if (config.hosts.isEmpty()) | ||
throw IllegalArgumentException("Passed the $javaClass constructor a config with 0 hosts entries") | ||
} | ||
|
||
fun requireSingularOracleNetDesc(commonName: String): OracleNetDesc { | ||
log.trace("requireSingularOracleNetDesc(commonName={})", commonName) | ||
|
||
val tmp = lookupOracleNetDesc(commonName) | ||
|
||
if (tmp.isEmpty()) | ||
throw IllegalStateException("no OracleNetDescs found for common name $commonName") | ||
if (tmp.size > 1) | ||
throw IllegalStateException("multiple OracleNetDescs found for common name $commonName") | ||
|
||
return tmp[0] | ||
} | ||
|
||
fun lookupOracleNetDesc(commonName: String): List<OracleNetDesc> { | ||
log.trace("lookupOracleNetDesc(commonName={})", commonName) | ||
|
||
return getConnection() | ||
.search(SearchRequest( | ||
config.oracleBaseDN, | ||
SearchScope.SUB, | ||
Filter.createANDFilter( | ||
Filter.create("cn=$commonName"), | ||
Filter.create("objectClass=orclNetService") | ||
), | ||
"orclNetDescString" | ||
)) | ||
.searchEntries | ||
.map { OracleNetDesc(it.getAttribute("orclNetDescString").value!!) } | ||
} | ||
|
||
private fun getConnection(): LDAPConnection { | ||
log.trace("getConnection()") | ||
|
||
// Synchronized because this thing is gonna be called from who knows where. | ||
synchronized(this) { | ||
|
||
// If we've already got an LDAP connection | ||
if (ldapConnection != null) { | ||
|
||
// If the LDAP connection we've already got is still connected | ||
if (ldapConnection!!.isConnected) | ||
// then return it | ||
return ldapConnection!! | ||
// else, the LDAP connection we've already got is _not_ still connected | ||
else | ||
// then disregard it | ||
ldapConnection = null | ||
} | ||
|
||
log.debug("Attempting to establish a connection to a configured LDAP server") | ||
for (host in config.hosts) { | ||
log.trace("Trying to connect to {}:{}", host.host, host.port) | ||
|
||
try { | ||
ldapConnection =LDAPConnection(host.host, host.port.toInt()) | ||
.also { log.debug("Connected to {}:{}", host.host, host.port) } | ||
break | ||
} catch (e: Throwable) { | ||
log.debug("Failed to connect to {}:{}", host.host, host.port) | ||
} | ||
} | ||
|
||
if (ldapConnection == null) { | ||
log.error("Failed to establish a connection to any configured LDAP server.") | ||
throw RuntimeException("Failed to establish a connection to any configured LDAP server.") | ||
} | ||
|
||
return ldapConnection!! | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package org.veupathdb.lib.ldap | ||
|
||
data class LDAPConfig(val hosts: Collection<LDAPHost>, val oracleBaseDN: String) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package org.veupathdb.lib.ldap | ||
|
||
data class LDAPHost(val host: String, val port: UShort) { | ||
companion object { | ||
@JvmStatic | ||
fun ofString(str: String): LDAPHost { | ||
val colonIndex = str.indexOf(':') | ||
|
||
if (colonIndex < 1) | ||
throw IllegalArgumentException("input string $str did not resemble a valid \"host:port\" string") | ||
|
||
return LDAPHost(str.substring(0, colonIndex), str.substring(colonIndex + 1).toUShort()) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package org.veupathdb.lib.ldap | ||
|
||
import java.math.BigInteger | ||
|
||
private const val HOST_PREFIX = "(HOST=" | ||
private const val PORT_PREFIX = "(PORT=" | ||
private const val SERVICE_NAME_PREFIX = "(SERVICE_NAME=" | ||
private const val VALUE_SUFFIX = ')' | ||
|
||
data class OracleNetDesc( | ||
val host: String, | ||
val port: UShort, | ||
val serviceName: String, | ||
) { | ||
constructor(string: String) : this( | ||
string.requireHostValue(), | ||
string.requirePortValue(), | ||
string.requireServiceNameValue(), | ||
) | ||
} | ||
|
||
private fun String.requireHostValue() = requireValue(HOST_PREFIX, "HOST") | ||
|
||
private fun String.requirePortValue(): UShort { | ||
val bi = try { | ||
BigInteger(requireValue(PORT_PREFIX, "PORT")) | ||
} catch (e: Throwable) { | ||
throw IllegalArgumentException("given orclNetDescString contained an invalid PORT value") | ||
} | ||
|
||
if (bi > BigInteger.valueOf(65535)) | ||
throw IllegalArgumentException("given orclNetDescString contained a PORT value that was too large to be a valid port") | ||
if (bi < BigInteger.ZERO) | ||
throw IllegalArgumentException("given orclNetDescString contained a PORT value that was less than zero") | ||
|
||
return bi.toInt().toUShort() | ||
} | ||
|
||
private fun String.requireServiceNameValue(): String = requireValue(SERVICE_NAME_PREFIX, "SERVICE_NAME") | ||
|
||
private fun String.requireValue(prefix: String, name: String): String { | ||
val start = indexOf(prefix) | ||
|
||
if (start < 0) | ||
throw IllegalArgumentException("given orclNetDescString did not contain a $name value") | ||
|
||
val end = indexOf(VALUE_SUFFIX, start) | ||
|
||
if (end < 0) | ||
throw IllegalArgumentException("malformed orclNetDescString value") | ||
|
||
val out = substring(start + prefix.length, end) | ||
|
||
if (out.isEmpty()) | ||
throw IllegalArgumentException("given orclNetDescString contained an empty $name value") | ||
|
||
return out | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package org.veupathdb.lib.ldap | ||
|
||
import org.junit.jupiter.api.Assertions.* | ||
import org.junit.jupiter.api.DisplayName | ||
import org.junit.jupiter.api.Test | ||
|
||
@DisplayName("LDAPHost") | ||
class LDAPHostTest { | ||
|
||
@Test | ||
@DisplayName("ofString(String)") | ||
fun t1() { | ||
val tgt = LDAPHost.ofString("something:1234") | ||
|
||
assertEquals("something", tgt.host) | ||
assertEquals(1234.toUShort(), tgt.port) | ||
} | ||
} |