Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@
<groupId>io.ktor</groupId>
<artifactId>ktor-server-metrics-micrometer-jvm</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>dev.hsbrysk</groupId>
<artifactId>caffeine-coroutines</artifactId>
<version>2.0.0</version>
</dependency>


<dependency>
Expand Down
46 changes: 40 additions & 6 deletions src/main/kotlin/no/nav/navansatt/ActiveDirectoryClient.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package no.nav.navansatt

import com.github.benmanes.caffeine.cache.*
import dev.hsbrysk.caffeine.CoroutineLoadingCache
import dev.hsbrysk.caffeine.buildCoroutine
import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.instrumentation.annotations.WithSpan
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.apache.commons.text.StringEscapeUtils
import org.slf4j.LoggerFactory
import java.util.Hashtable
import java.util.Locale
import java.time.Duration
import java.util.*
import java.util.regex.Pattern
import javax.naming.Context
import javax.naming.NamingEnumeration
Expand All @@ -17,6 +20,7 @@ import javax.naming.directory.BasicAttributes
import javax.naming.directory.SearchControls
import javax.naming.ldap.InitialLdapContext


data class User(
val ident: String,
val displayName: String,
Expand All @@ -26,12 +30,17 @@ data class User(
val groups: List<String>,
)

class ActiveDirectoryClient(
interface ActiveDirectoryClient {
suspend fun getUsers(idents: List<String>): List<User>
suspend fun getUser(ident: String): User?
}

class DefaultActiveDirectoryClient(
val url: String,
val base: String,
val username: String,
val password: String?,
) {
): ActiveDirectoryClient {
companion object {
private val LOG = LoggerFactory.getLogger(ActiveDirectoryClient::class.java)
}
Expand All @@ -46,7 +55,7 @@ class ActiveDirectoryClient(
}

@WithSpan(kind = SpanKind.CLIENT)
suspend fun getUsers(idents: List<String>): List<User> = withContext(Dispatchers.IO) {
override suspend fun getUsers(idents: List<String>): List<User> = withContext(Dispatchers.IO) {
val root = InitialLdapContext(env, null)

val filter = (0..(idents.size - 1)).map {
Expand Down Expand Up @@ -95,7 +104,7 @@ class ActiveDirectoryClient(
}

@WithSpan(kind = SpanKind.CLIENT)
suspend fun getUser(ident: String): User? = withContext(Dispatchers.IO) {
override suspend fun getUser(ident: String): User? = withContext(Dispatchers.IO) {
val root = InitialLdapContext(env, null)

val attrs = BasicAttributes().apply {
Expand Down Expand Up @@ -180,3 +189,28 @@ class ActiveDirectoryClient(
return null
}
}

class CachedActiveDirectoryClient(
private val activeDirectoryClient: ActiveDirectoryClient
) : ActiveDirectoryClient {

private val usersByIdents: CoroutineLoadingCache<List<String>, List<User>> = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(Duration.ofMinutes(60))
.refreshAfterWrite(Duration.ofMinutes(60))
.buildCoroutine() { key -> activeDirectoryClient.getUsers(key) }

private val userByIdent: CoroutineLoadingCache<String, User?> = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(Duration.ofMinutes(60))
.refreshAfterWrite(Duration.ofMinutes(60))
.buildCoroutine() { key -> activeDirectoryClient.getUser(key) }

override suspend fun getUsers(idents: List<String>): List<User> {
return usersByIdents.get(idents.sorted())
}

override suspend fun getUser(ident: String): User? {
return userByIdent.get(ident)
}
}
4 changes: 2 additions & 2 deletions src/main/kotlin/no/nav/navansatt/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ data class ApiError(

fun main() {
val config = if (System.getenv("NAIS_APP_NAME") != null) appConfigNais() else appConfigLocal()
val activeDirectoryClient = ActiveDirectoryClient(
val activeDirectoryClient: ActiveDirectoryClient = CachedActiveDirectoryClient(DefaultActiveDirectoryClient(
url = config.adUrl,
base = config.adBase,
username = config.adUsername,
password = config.adPassword
)
))
val httpClient = HttpClient(Apache5) {
engine {
sslContext = SSLContexts.createSystemDefault()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ActiveDirectoryClientTest {
// Wait for the LDAP server to boot
Thread.sleep(1500)

val activeDirectoryClient = ActiveDirectoryClient(
val activeDirectoryClient = DefaultActiveDirectoryClient(
url = "ldap://localhost:$freePort",
base = "DC=test,DC=local",
username = "",
Expand Down