thunderbiscuit
thunderbiscuit

Reputation: 219

Set up Ktor authenticated shutdown route

I'd like to add a shutdown route to my Ktor server but I need it to require authentication.

I'm trying to put the shutdown url in my authenticated routes like so:

// application.conf
ktor {
    deployment {
        port = 8080
        host = 127.0.0.1
        shutdown.url = "/shutdown"
    }
}
// Application.kt
routing {
    root()
    
    authenticate("authenticated-routes") {
        test1()
        test2()
        shutdown()
    }
}

// Routes.kt
fun Route.shutdown() {
    get("/shutdown") {
        // shutting down
    }
}

But somehow the shutdown route does not require authentication for shutting down the server (something to do with the config overriding the route defined in Routes.kt?)

The docs unfortunately do not give any hints as to how to make the shutdown route authenticated. Any ideas on how I could make sure not just anyone can call the shutdown route and shutdown my server?

Upvotes: 3

Views: 847

Answers (1)

Aleksei Tirman
Aleksei Tirman

Reputation: 6999

The ShutDownUrl plugin has nothing with Routing that's why you can't integrate it with the Authentication plugin. To solve your problem you can manually make an instance of ShutDownUrl class and execute the doShutdown method in a route that may require authentication. Here is an example:

import io.ktor.application.*
import io.ktor.auth.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*

fun main() {
    val shutdown = ShutDownUrl("") { 1 }

    embeddedServer(Netty, port = 3333) {
        install(Authentication) {
            basic {
                realm = "Access for shutting the server down"
                validate { credentials ->
                    if (credentials.name == "jetbrains" && credentials.password == "foobar") {
                        UserIdPrincipal(credentials.name)
                    } else {
                        null
                    }
                }
            }
        }

        routing {
            get("/") {
                call.respondText { "hello" }
            }

            authenticate {
                get("/shutdown") {
                    shutdown.doShutdown(call)
                }
            }
        }
    }.start()
}

Upvotes: 4

Related Questions