KtorサーバーでのDigest認証
必要な依存関係: io.ktor:ktor-server-auth
コード例: auth-digest
Digest認証スキームは、アクセス制御と認証に使用されるHTTPフレームワークの一部です。このスキームでは、ユーザー名とパスワードをネットワーク経由で送信する前に、ハッシュ関数が適用されます。
Ktorでは、ユーザーのログインと特定のルートの保護にDigest認証を使用できます。Ktorでの認証に関する一般情報は、Ktorサーバーでの認証と認可セクションで確認できます。
依存関係の追加
digest
認証を有効にするには、ビルドスクリプトにktor-server-auth
アーティファクトを含める必要があります。
Digest認証フロー
Digest認証フローは次のようになります。
クライアントは、
Authorization
ヘッダーなしで、サーバーアプリケーション内の特定のルートにリクエストを行います。サーバーは、クライアントに
401
(Unauthorized)応答ステータスで応答し、WWW-Authenticate
応答ヘッダーを使用して、そのルートを保護するためにDigest認証スキームが使用されているという情報を提供します。一般的なWWW-Authenticate
ヘッダーは次のようになります。WWW-Authenticate: Digest realm="Access to the '/' path", nonce="e4549c0548886bc2", algorithm="MD5"
Ktorでは、
digest
認証プロバイダーを設定する際に、レルムとノンス値の生成方法を指定できます。通常、クライアントはユーザーが資格情報を入力できるログインダイアログを表示します。その後、クライアントは次の
Authorization
ヘッダーを含むリクエストを行います。Authorization: Digest username="jetbrains", realm="Access to the '/' path", nonce="e4549c0548886bc2", uri="/", algorithm=MD5, response="6299988bb4f05c0d8ad44295873858cf"
response
値は次のように生成されます。a.
HA1 = MD5(username:realm:password)
この部分はサーバーに保存され、Ktorがユーザーの資格情報を検証するために使用できます。
b.
HA2 = MD5(method:digestURI)
c.
response = MD5(HA1:nonce:HA2)
サーバーはクライアントから送信された資格情報を検証し、要求されたコンテンツで応答します。
Digest認証のインストール
digest
認証プロバイダーをインストールするには、install
ブロック内でdigest関数を呼び出します。
import io.ktor.server.application.*
import io.ktor.server.auth.*
// ...
install(Authentication) {
digest {
// Digest認証を設定します
}
}
オプションで、指定されたルートを認証するために使用できるプロバイダー名を指定できます。
Digest認証の設定
Ktorで異なる認証プロバイダーを設定する方法の概要については、認証の設定を参照してください。このセクションでは、digest
認証プロバイダーの設定の詳細について説明します。
ステップ1: ダイジェストを含むユーザーテーブルの提供
digest
認証プロバイダーは、ダイジェストメッセージのHA1
部分を使用してユーザーの資格情報を検証します。したがって、ユーザー名とそれに対応するHA1
ハッシュを含むユーザーテーブルを提供できます。以下の例では、getMd5Digest
関数を使用してHA1
ハッシュを生成しています。
fun getMd5Digest(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray(UTF_8))
val myRealm = "Access to the '/' path"
val userTable: Map<String, ByteArray> = mapOf(
"jetbrains" to getMd5Digest("jetbrains:$myRealm:foobar"),
"admin" to getMd5Digest("admin:$myRealm:password")
)
ステップ2: Digestプロバイダーの設定
digest
認証プロバイダーは、DigestAuthenticationProvider.Configクラスを介して設定を公開します。以下の例では、次の設定が指定されています。
realm
プロパティは、WWW-Authenticate
ヘッダーで渡されるレルムを設定します。digestProvider
関数は、指定されたユーザー名のダイジェストのHA1
部分を取得します。- (オプション)
validate
関数を使用すると、資格情報をカスタムプリンシパルにマッピングできます。
fun Application.main() {
install(Authentication) {
digest("auth-digest") {
realm = myRealm
digestProvider { userName, realm ->
userTable[userName]
}
validate { credentials ->
if (credentials.userName.isNotEmpty()) {
CustomPrincipal(credentials.userName, credentials.realm)
} else {
null
}
}
}
}
}
data class CustomPrincipal(val userName: String, val realm: String)
nonceManagerプロパティを使用して、ノンス値の生成方法を指定することもできます。
ステップ3: 特定のリソースを保護する
digest
プロバイダーを設定した後、**authenticate**関数を使用してアプリケーション内の特定のリソースを保護できます。認証が成功した場合、call.principal
関数を使用してルートハンドラー内で認証されたPrincipalを取得し、認証されたユーザーの名前を取得できます。
routing {
authenticate("auth-digest") {
get("/") {
call.respondText("Hello, ${call.principal<CustomPrincipal>()?.userName}!")
}
}
}