ktorio / ktor

Framework for quickly creating connected applications in Kotlin with minimal effort
https://ktor.io
Apache License 2.0
12.99k stars 1.06k forks source link

authentication.formAuthentication give blank page #211

Open hasanOryx opened 7 years ago

hasanOryx commented 7 years ago

I've the below code, route "/" and "/bye" are working fine, but route "login" given blank page once!!

package blog

import kotlinx.html.*
import kotlinx.html.stream.*    // for createHTML
import org.jetbrains.ktor.application.*
import org.jetbrains.ktor.auth.*
import org.jetbrains.ktor.features.*
import org.jetbrains.ktor.http.*
import org.jetbrains.ktor.response.*
import org.jetbrains.ktor.routing.*

import org.jetbrains.ktor.request.*   // for request.uri

import org.jetbrains.ktor.html.*
import org.jetbrains.ktor.pipeline.*

import org.jetbrains.ktor.host.*   // for embededServer
import org.jetbrains.ktor.netty.*  // for Netty

fun main(args: Array<String>) {
    embeddedServer(Netty, 8080, watchPaths = listOf("BlogAppKt"), module = Application::module).start()
}

fun Application.module() {
    install(DefaultHeaders)
    install(CallLogging)

    intercept(ApplicationCallPipeline.Call) { 
        if (call.request.uri == "/hi")
            call.respondText("Test String")
    }

    install(Routing) {
        get("/") {
            call.respondText("""Hello, world!<br><a href="/bye">Say bye?</a>""", ContentType.Text.Html)
        }
        get("/bye") {
            call.respondText("""Good bye! <br><a href="/login">Login?</a> """, ContentType.Text.Html)
        }
        route("/login") {
            authentication {
                formAuthentication { up: UserPasswordCredential ->
                    when {
                        up.password == "ppp" -> UserIdPrincipal(up.name)
                        else -> null
                    }
                }
            }

            handle {
                val principal = call.authentication.principal<UserIdPrincipal>()
                if (principal != null) {
                    call.respondText("Hello, ${principal.name}")
                } else {
                        val html = createHTML().html {
                        body {
                            form(action = "/login", encType = FormEncType.applicationXWwwFormUrlEncoded, method = FormMethod.post) {
                                p {
                                    +"user:"
                                    textInput(name = "user") {
                                        value = principal?.name ?: ""
                                    }
                                }

                                p {
                                    +"password:"
                                    passwordInput(name = "pass")
                                }

                                p {
                                    submitInput() { value = "Login" }
                                }
                            }
                        }
                    }
                    call.respondText(html, ContentType.Text.Html)
                }
            }
        }
    }
}
chrisjenx commented 7 years ago

I noticed the same thing, looks like the formAuth returns a respond(Unauthorised) if the user is not logged in, which does meke sense, but I thought the handle block is meant to handle all responses for this path/location. So I'm not sure if this is a routing bug or a auth bug?

chrisjenx commented 7 years ago

@orangy / @cy6erGn0m you able to clarify? Looks like a bug with the handle pipeline. I don't know enough about the project yet to give a more definitive answer.

hasanOryx commented 7 years ago

It worked with me when I specified the names of the user and password fileds, as below:

        authentication {
            formAuthentication ("user", "pass"){ up: UserPasswordCredential ->
                when {
                    up.password == "ppp" -> UserIdPrincipal(up.name)
                    else -> null
                }
            }
        }
jwmach1 commented 6 years ago

Same blank page upon requesting login. I've a sample with the same route("/login") as above. when I request "/login", the handle block is never invoked. Chrome reports that it received a 401, and the server logs that it returned a 401. Breakpoints show that execution never delegates down to the above route from the interceptor of AuthenticationPipeline.formAuthentication. (ktor 0.9.0)

I believe the FormPostApplication.kt from the ktor-sample-auth sample project needs some love. Note that in the code sample at the top of this thread, the authentication pipeline is projecting both the GET and the POST, so the login form can never be rendered -- resulting in a blank result when ktor returns the 401. The youKube sample shows a functioning use of formAuthentication.

oleg-larshin commented 4 years ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.