Ktor 1.5.4 Help

LDAP

Add dependencies

To enable LDAP authentication, you need to include the ktor-auth and ktor-auth-ldap artifacts in the build script:

implementation "io.ktor:ktor-auth:$ktor_version" implementation "io.ktor:ktor-auth-ldap:$ktor_version"
implementation("io.ktor:ktor-auth:$ktor_version") implementation("io.ktor:ktor-auth-ldap:$ktor_version")
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-auth</artifactId> <version>${ktor_version}</version> </dependency> <dependency> <groupId>io.ktor</groupId> <artifactId>ktor-auth-ldap</artifactId> <version>${ktor_version}</version> </dependency>

Usage

Ktor supports LDAP (Lightweight Directory Access Protocol) for credential authentication.

install(Authentication) { basic("auth-ldap") { validate { credentials -> ldapAuthenticate(credentials, "ldap://0.0.0.0:389", "cn=%s,dc=ktor,dc=io") } } }

Optionally you can define an additional validation check:

authentication { basic("auth-ldap") { validate { credentials -> ldapAuthenticate(credentials, "ldap://localhost:389", "cn=%s,dc=ktor,dc=io") { if (it.name == it.password) { UserIdPrincipal(it.name) } else { null } } } } }

This signature looks like this:

// Simplified signatures fun ldapAuthenticate(credential: UserPasswordCredential, ldapServerURL: String, userDNFormat: String): UserIdPrincipal? fun ldapAuthenticate(credential: UserPasswordCredential, ldapServerURL: String, userDNFormat: String, validate: InitialDirContext.(UserPasswordCredential) -> UserIdPrincipal?): UserIdPrincipal?

To support more complex scenarios, there is a more complete signature for ldapAuthenticate:

fun <K : Credential, P : Any> ldapAuthenticate(credential: K, ldapServerURL: String, ldapEnvironmentBuilder: (MutableMap<String, Any?>) -> Unit = {}, doVerify: InitialDirContext.(K) -> P?): P?

While the other overloads support only UserPasswordCredential, this overload accept any kind of credential. And instead of receiving a string with the userDNFormat, you can provide a generator to populate a map with the environments for ldap.

A more advanced example using this:

application.install(Authentication) { basic { validate { credential -> ldapAuthenticate( credential, "ldap://$localhost:${ldapServer.port}", configure = { env: MutableMap<String, Any?> -> env.put("java.naming.security.principal", "uid=admin,ou=system") env.put("java.naming.security.credentials", "secret") env.put("java.naming.security.authentication", "simple") } ) { val users = (lookup("ou=system") as LdapContext).lookup("ou=users") as LdapContext val controls = SearchControls().apply { searchScope = SearchControls.ONELEVEL_SCOPE returningAttributes = arrayOf("+", "*") } users.search("", "(uid=user-test)", controls).asSequence().firstOrNull { val ldapPassword = (it.attributes.get("userPassword")?.get() as ByteArray?)?.toString(Charsets.ISO_8859_1) ldapPassword == credential.password }?.let { UserIdPrincipal(credential.name) } } } } }

Bear in mind that current LDAP implementation is synchronous.

Last modified: 28 April 2021