LDAP
note
This help topic is in development and will be updated in the future.
Ktor supports LDAP (Lightweight Directory Access Protocol) for credential authentication.
1. authentication {
2. basic("authName") {
3. realm = "realm"
4. validate { credential ->
5. ldapAuthenticate(credential, "ldap://$localhost:${ldapServer.port}", "uid=%s,ou=system")
6. }
7. }
8. }
Optionally you can define an additional validation check:
1. authentication {
2. basic("authName") {
3. realm = "realm"
4. validate { credential ->
5. ldapAuthenticate(credentials, "ldap://localhost:389", "cn=%s ou=users") {
6. if (it.name == it.password) {
7. UserIdPrincipal(it.name)
8. } else {
9. null
10. }
11. }
12. }
13. }
14. }
This signature looks like this:
1. // Simplified signatures
2. fun ldapAuthenticate(credential: UserPasswordCredential, ldapServerURL: String, userDNFormat: String): UserIdPrincipal?
3. 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:
1. 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:
1. application.install(Authentication) {
2. basic {
3. validate { credential ->
4. ldapAuthenticate(
5. credential,
6. "ldap://$localhost:${ldapServer.port}",
7. configure = { env: MutableMap<String, Any?> ->
8. env.put("java.naming.security.principal", "uid=admin,ou=system")
9. env.put("java.naming.security.credentials", "secret")
10. env.put("java.naming.security.authentication", "simple")
11. }
12. ) {
13. val users = (lookup("ou=system") as LdapContext).lookup("ou=users") as LdapContext
14. val controls = SearchControls().apply {
15. searchScope = SearchControls.ONELEVEL_SCOPE
16. returningAttributes = arrayOf("+", "*")
17. }
19. users.search("", "(uid=user-test)", controls).asSequence().firstOrNull {
20. val ldapPassword = (it.attributes.get("userPassword")?.get() as ByteArray?)?.toString(Charsets.ISO_8859_1)
21. ldapPassword == credential.password
22. }?.let { UserIdPrincipal(credential.name) }
23. }
24. }
25. }
26. }
You can see advanced examples for LDAP authentication in the Ktor’s tests.
Bear in mind that current LDAP implementation is synchronous.

