Home > Blockchain >  ktor digest Authentication
ktor digest Authentication

Time:09-25

I would like to use this method to authenticate client/server communication in my app, but can't figure out why getting error. Code in super simple and come from original ktor example.

Server:

val myRealm = "Access to the '/' path"
val userTable: Map<String, ByteArray> = mapOf(
    "jetbrains" to getMd5Digest("jetbrains:$myRealm:foobar"),
    "admin" to getMd5Digest("admin:$myRealm:password")


fun Application.configureSecurity() {

    install(Authentication) {

        digest("myDigestAuth") {
            digestProvider { userName, realm ->
                userTable[userName]
            }
        }
    }

    routing {
        authenticate("myDigestAuth") {
            get("/protected/route/digest") {
                val principal = call.principal<UserIdPrincipal>()!!
                call.respondText("Hello ${principal.name}")
            }
        }
    }
}

Client:

val client = HttpClient(CIO) {
    install(Logging) {
        logger = Logger.DEFAULT
        level = LogLevel.HEADERS
    }
    install(Auth) {
        digest {
            credentials {
                DigestAuthCredentials(username = "jetbrains", password = "foobar")
            }
            realm = myRealm
        }
    }
}
val response: HttpResponse =   client.get("http://0.0.0.0:8080/protected/route/digest")

Here the log of the communication:

[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - REQUEST: http://0.0.0.0:8080/protected/route/digest
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - COMMON HEADERS
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - -> Accept: */*
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - CONTENT HEADERS
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - -> Content-Length: 0
[ktor-jetty-8080-1] INFO  ktor.application - 401 Unauthorized: GET - /protected/route/digest
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - RESPONSE: 401 Unauthorized
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - FROM: http://0.0.0.0:8080/protected/route/digest
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - COMMON HEADERS
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - -> Content-Length: 0
[DefaultDispatcher-worker-1] INFO  io.ktor.client.HttpClient - -> WWW-Authenticate: Digest realm="Ktor Server", nonce="ce825e23d3275f40", algorithm="MD5"

And this is why client client immediately fail with:

Exception in thread "main" io.ktor.client.features.ClientRequestException: Client request(http://0.0.0.0:8080/protected/route/digest) invalid: 401 Unauthorized. Text: ""
        at io.ktor.client.features.DefaultResponseValidationKt$addDefaultResponseValidation$1$1.invokeSuspend(DefaultResponseValidation.kt:47)
        at io.ktor.client.features.DefaultResponseValidationKt$addDefaultResponseValidation$1$1.invoke(DefaultResponseValidation.kt)
        at io.ktor.client.features.DefaultResponseValidationKt$addDefaultResponseValidation$1$1.invoke(DefaultResponseValidation.kt)
        at io.ktor.client.features.HttpCallValidator.validateResponse(HttpCallValidator.kt:54)
        at io.ktor.client.features.HttpCallValidator.access$validateResponse(HttpCallValidator.kt:33)
        at io.ktor.client.features.HttpCallValidator$Companion$install$3.invokeSuspend(HttpCallValidator.kt:133)
        at io.ktor.client.features.HttpCallValidator$Companion$install$3.invoke(HttpCallValidator.kt)
        at io.ktor.client.features.HttpCallValidator$Companion$install$3.invoke(HttpCallValidator.kt)
        at io.ktor.client.features.HttpSend$Feature$install$1.invokeSuspend(HttpSend.kt:96)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:191)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:147)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(SuspendFunctionGun.kt:15)
        at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:93)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:191)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:147)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(SuspendFunctionGun.kt:15)
        at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:93)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

Don't know if it right and/or related with the error.... but I was expecting in the header from the server to get the "realm" as per set in the code "Access to the '/' path" and not "Ktor server"

CodePudding user response:

When setting up the server, you're missing the realm:

install(Authentication) {

    digest("myDigestAuth") {
        realm = myRealm // This part is missing from your code
        digestProvider { userName, realm ->
            userTable[userName]
        }
    }
}

Reference: https://ktor.io/docs/digest.html#configure-provider

Without this, the server uses the default realm ("Ktor server"), and the client doesn't have credentials for that realm.

  • Related