Digest認証

Estimated reading time: 1 minute

KtorはHTTP digest認証をサポートしています。 basic/form認証とは異なる動作をします:

authentication {
    digest {
        val password = "Circle Of Life"
        digester = MessageDigest.getInstance("MD5")
        realm = "testrealm@host.com"
        userNameRealmPasswordDigestProvider = { userName, realm ->
            when (userName) {
                "missing" -> null
                else -> {
                    digester.reset()
                    digester.update("$userName:$realm:$password".toByteArray())
                    digester.digest()
                }
            }
        }
    }
}

verifierを提供する代わりに、userNameRealmPasswordDigestProviderを提供しdigestのHA1部分を返す必要があります。 MD5の場合、MD5("$username:$realm:$password")です。 ここでの考え方はすでにハッシュ化されているパスワードを保存するというものです。 そして期待されるハッシュを特定のユーザに返すか、ユーザが存在しない場合にはnullを返すだけです。 callbackはsuspend可能なので、期待されるハッシュ値の参照・計算を、例えばディスクやデータベースに対し非同期に行うことができます。

authentication {
    val myRealm = "MyRealm"
    val usersInMyRealmToHA1: Map<String, ByteArray> = mapOf(
        // pass="test", HA1=MD5("test:MyRealm:pass")="fb12475e62dedc5c2744d98eb73b8877"
        "test" to hex("fb12475e62dedc5c2744d98eb73b8877")
    )

    digest("auth") {
        userNameRealmPasswordDigestProvider = { userName, realm ->
            usersInMyRealmToHA1[userName]
        }
    }
}

HA1 (H(A1)) はRFC 2069 (An Extension to HTTP: Digest Access Authentication)からきてます。

HA1=MD5(username:realm:password) <-- You usually store this.
HA2=MD5(method:digestURI)
response=MD5(HA1:nonce:HA2) <-- The client and the server sends and checks this.

realmdigestAuthentication関数に渡されたrealmであることが保証されており、便宜的に渡されますが、 userNameには任意の値を指定できます。 そのため、ファイルシステムへのアクセス、データベースへのアクセス、保存、HTMLの生成などにその値を使用する場合は、 これを考慮してエスケープまたは検証することを忘れないでください。