Не подтверждена Коммит 07dd782c создал по автору Osip Fatkullin's avatar Osip Fatkullin Зафиксировано автором GitHub
Просмотр файлов

KTOR-7775 Auth: Add clearToken method (#4645)

* Add clearToken to BasicAuthProvider
* Add clearToken to DigestAuthProvider
* Add KDoc comments to clearToken
владелец 203c29c9
...@@ -55,6 +55,7 @@ public final class io/ktor/client/plugins/auth/providers/BasicAuthProvider : io/ ...@@ -55,6 +55,7 @@ public final class io/ktor/client/plugins/auth/providers/BasicAuthProvider : io/
public fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V public fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun addRequestHeaders (Lio/ktor/client/request/HttpRequestBuilder;Lio/ktor/http/auth/HttpAuthHeader;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun addRequestHeaders (Lio/ktor/client/request/HttpRequestBuilder;Lio/ktor/http/auth/HttpAuthHeader;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun clearToken ()V
public fun getSendWithoutRequest ()Z public fun getSendWithoutRequest ()Z
public fun isApplicable (Lio/ktor/http/auth/HttpAuthHeader;)Z public fun isApplicable (Lio/ktor/http/auth/HttpAuthHeader;)Z
public fun refreshToken (Lio/ktor/client/statement/HttpResponse;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun refreshToken (Lio/ktor/client/statement/HttpResponse;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
...@@ -120,6 +121,7 @@ public final class io/ktor/client/plugins/auth/providers/DigestAuthProvider : io ...@@ -120,6 +121,7 @@ public final class io/ktor/client/plugins/auth/providers/DigestAuthProvider : io
public fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Ljava/lang/String;)V public fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Ljava/lang/String;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun addRequestHeaders (Lio/ktor/client/request/HttpRequestBuilder;Lio/ktor/http/auth/HttpAuthHeader;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun addRequestHeaders (Lio/ktor/client/request/HttpRequestBuilder;Lio/ktor/http/auth/HttpAuthHeader;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun clearToken ()V
public final fun getAlgorithmName ()Ljava/lang/String; public final fun getAlgorithmName ()Ljava/lang/String;
public final fun getRealm ()Ljava/lang/String; public final fun getRealm ()Ljava/lang/String;
public fun getSendWithoutRequest ()Z public fun getSendWithoutRequest ()Z
......
...@@ -52,6 +52,7 @@ final class io.ktor.client.plugins.auth.providers/BasicAuthProvider : io.ktor.cl ...@@ -52,6 +52,7 @@ final class io.ktor.client.plugins.auth.providers/BasicAuthProvider : io.ktor.cl
final val sendWithoutRequest // io.ktor.client.plugins.auth.providers/BasicAuthProvider.sendWithoutRequest|{}sendWithoutRequest[0] final val sendWithoutRequest // io.ktor.client.plugins.auth.providers/BasicAuthProvider.sendWithoutRequest|{}sendWithoutRequest[0]
final fun <get-sendWithoutRequest>(): kotlin/Boolean // io.ktor.client.plugins.auth.providers/BasicAuthProvider.sendWithoutRequest.<get-sendWithoutRequest>|<get-sendWithoutRequest>(){}[0] final fun <get-sendWithoutRequest>(): kotlin/Boolean // io.ktor.client.plugins.auth.providers/BasicAuthProvider.sendWithoutRequest.<get-sendWithoutRequest>|<get-sendWithoutRequest>(){}[0]
final fun clearToken() // io.ktor.client.plugins.auth.providers/BasicAuthProvider.clearToken|clearToken(){}[0]
final fun isApplicable(io.ktor.http.auth/HttpAuthHeader): kotlin/Boolean // io.ktor.client.plugins.auth.providers/BasicAuthProvider.isApplicable|isApplicable(io.ktor.http.auth.HttpAuthHeader){}[0] final fun isApplicable(io.ktor.http.auth/HttpAuthHeader): kotlin/Boolean // io.ktor.client.plugins.auth.providers/BasicAuthProvider.isApplicable|isApplicable(io.ktor.http.auth.HttpAuthHeader){}[0]
final fun sendWithoutRequest(io.ktor.client.request/HttpRequestBuilder): kotlin/Boolean // io.ktor.client.plugins.auth.providers/BasicAuthProvider.sendWithoutRequest|sendWithoutRequest(io.ktor.client.request.HttpRequestBuilder){}[0] final fun sendWithoutRequest(io.ktor.client.request/HttpRequestBuilder): kotlin/Boolean // io.ktor.client.plugins.auth.providers/BasicAuthProvider.sendWithoutRequest|sendWithoutRequest(io.ktor.client.request.HttpRequestBuilder){}[0]
final suspend fun addRequestHeaders(io.ktor.client.request/HttpRequestBuilder, io.ktor.http.auth/HttpAuthHeader?) // io.ktor.client.plugins.auth.providers/BasicAuthProvider.addRequestHeaders|addRequestHeaders(io.ktor.client.request.HttpRequestBuilder;io.ktor.http.auth.HttpAuthHeader?){}[0] final suspend fun addRequestHeaders(io.ktor.client.request/HttpRequestBuilder, io.ktor.http.auth/HttpAuthHeader?) // io.ktor.client.plugins.auth.providers/BasicAuthProvider.addRequestHeaders|addRequestHeaders(io.ktor.client.request.HttpRequestBuilder;io.ktor.http.auth.HttpAuthHeader?){}[0]
...@@ -131,6 +132,7 @@ final class io.ktor.client.plugins.auth.providers/DigestAuthProvider : io.ktor.c ...@@ -131,6 +132,7 @@ final class io.ktor.client.plugins.auth.providers/DigestAuthProvider : io.ktor.c
final val sendWithoutRequest // io.ktor.client.plugins.auth.providers/DigestAuthProvider.sendWithoutRequest|{}sendWithoutRequest[0] final val sendWithoutRequest // io.ktor.client.plugins.auth.providers/DigestAuthProvider.sendWithoutRequest|{}sendWithoutRequest[0]
final fun <get-sendWithoutRequest>(): kotlin/Boolean // io.ktor.client.plugins.auth.providers/DigestAuthProvider.sendWithoutRequest.<get-sendWithoutRequest>|<get-sendWithoutRequest>(){}[0] final fun <get-sendWithoutRequest>(): kotlin/Boolean // io.ktor.client.plugins.auth.providers/DigestAuthProvider.sendWithoutRequest.<get-sendWithoutRequest>|<get-sendWithoutRequest>(){}[0]
final fun clearToken() // io.ktor.client.plugins.auth.providers/DigestAuthProvider.clearToken|clearToken(){}[0]
final fun isApplicable(io.ktor.http.auth/HttpAuthHeader): kotlin/Boolean // io.ktor.client.plugins.auth.providers/DigestAuthProvider.isApplicable|isApplicable(io.ktor.http.auth.HttpAuthHeader){}[0] final fun isApplicable(io.ktor.http.auth/HttpAuthHeader): kotlin/Boolean // io.ktor.client.plugins.auth.providers/DigestAuthProvider.isApplicable|isApplicable(io.ktor.http.auth.HttpAuthHeader){}[0]
final fun sendWithoutRequest(io.ktor.client.request/HttpRequestBuilder): kotlin/Boolean // io.ktor.client.plugins.auth.providers/DigestAuthProvider.sendWithoutRequest|sendWithoutRequest(io.ktor.client.request.HttpRequestBuilder){}[0] final fun sendWithoutRequest(io.ktor.client.request/HttpRequestBuilder): kotlin/Boolean // io.ktor.client.plugins.auth.providers/DigestAuthProvider.sendWithoutRequest|sendWithoutRequest(io.ktor.client.request.HttpRequestBuilder){}[0]
final suspend fun addRequestHeaders(io.ktor.client.request/HttpRequestBuilder, io.ktor.http.auth/HttpAuthHeader?) // io.ktor.client.plugins.auth.providers/DigestAuthProvider.addRequestHeaders|addRequestHeaders(io.ktor.client.request.HttpRequestBuilder;io.ktor.http.auth.HttpAuthHeader?){}[0] final suspend fun addRequestHeaders(io.ktor.client.request/HttpRequestBuilder, io.ktor.http.auth/HttpAuthHeader?) // io.ktor.client.plugins.auth.providers/DigestAuthProvider.addRequestHeaders|addRequestHeaders(io.ktor.client.request.HttpRequestBuilder;io.ktor.http.auth.HttpAuthHeader?){}[0]
......
/* /*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. * Copyright 2014-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/ */
package io.ktor.client.plugins.auth.providers package io.ktor.client.plugins.auth.providers
...@@ -162,6 +162,24 @@ public class BasicAuthProvider( ...@@ -162,6 +162,24 @@ public class BasicAuthProvider(
tokensHolder.setToken(credentials) tokensHolder.setToken(credentials)
return true return true
} }
/**
* Clears the currently stored authentication tokens from the cache.
*
* This method should be called in the following cases:
* - When the credentials have been updated and need to take effect
* - When you want to force re-authentication
* - When you want to clear sensitive authentication data
*
* Note: The result of [credentials] invocation is cached internally.
* Calling this method will force the next authentication attempt to fetch fresh credentials.
*
* [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.plugins.auth.providers.BasicAuthProvider.clearToken)
*/
@InternalAPI // TODO KTOR-8180: Provide control over tokens to user code
public fun clearToken() {
tokensHolder.clearToken()
}
} }
internal fun constructBasicAuthValue(credentials: BasicAuthCredentials): String { internal fun constructBasicAuthValue(credentials: BasicAuthCredentials): String {
......
/* /*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. * Copyright 2014-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/ */
package io.ktor.client.plugins.auth.providers package io.ktor.client.plugins.auth.providers
...@@ -162,6 +162,19 @@ public class BearerAuthProvider( ...@@ -162,6 +162,19 @@ public class BearerAuthProvider(
return newToken != null return newToken != null
} }
/**
* Clears the currently stored authentication tokens from the cache.
*
* This method should be called in the following cases:
* - When access or refresh tokens have been updated externally
* - When you want to clear sensitive token data (for example, during logout)
*
* Note: The result of `loadTokens` invocation is cached internally.
* Calling this method will force the next authentication attempt to fetch fresh tokens
* through the configured `loadTokens` function.
*
* [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.plugins.auth.providers.BearerAuthProvider.clearToken)
*/
public fun clearToken() { public fun clearToken() {
tokensHolder.clearToken() tokensHolder.clearToken()
} }
......
/* /*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. * Copyright 2014-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/ */
package io.ktor.client.plugins.auth.providers package io.ktor.client.plugins.auth.providers
...@@ -13,7 +13,7 @@ import io.ktor.util.* ...@@ -13,7 +13,7 @@ import io.ktor.util.*
import io.ktor.utils.io.* import io.ktor.utils.io.*
import io.ktor.utils.io.charsets.* import io.ktor.utils.io.charsets.*
import io.ktor.utils.io.core.* import io.ktor.utils.io.core.*
import kotlinx.atomicfu.* import kotlinx.atomicfu.atomic
/** /**
* Installs the client's [DigestAuthProvider]. * Installs the client's [DigestAuthProvider].
...@@ -218,4 +218,21 @@ public class DigestAuthProvider( ...@@ -218,4 +218,21 @@ public class DigestAuthProvider(
val digest = Digest(algorithmName) val digest = Digest(algorithmName)
return digest.build(data.toByteArray(Charsets.UTF_8)) return digest.build(data.toByteArray(Charsets.UTF_8))
} }
/**
* Clears the currently stored authentication tokens from the cache.
*
* This method should be called in the following cases:
* - When the credentials have been updated and need to take effect
* - When you want to clear sensitive authentication data
*
* Note: The result of [credentials] invocation is cached internally.
* Calling this method will force the next authentication attempt to fetch fresh credentials.
*
* [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.plugins.auth.providers.DigestAuthProvider.clearToken)
*/
@InternalAPI // TODO KTOR-8180: Provide control over tokens to user code
public fun clearToken() {
tokenHolder.clearToken()
}
} }
/* /*
* Copyright 2014-2019 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. * Copyright 2014-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/ */
package io.ktor.client.plugins.auth package io.ktor.client.plugins.auth
import io.ktor.client.plugins.auth.providers.* import io.ktor.client.plugins.auth.providers.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.http.auth.* import io.ktor.http.auth.*
import kotlin.test.* import io.ktor.utils.io.*
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
class BasicProviderTest { class BasicProviderTest {
@Test @Test
...@@ -44,6 +51,25 @@ class BasicProviderTest { ...@@ -44,6 +51,25 @@ class BasicProviderTest {
assertTrue(provider.isApplicable(header), "Provider with capitalized scheme should be applicable") assertTrue(provider.isApplicable(header), "Provider with capitalized scheme should be applicable")
} }
@OptIn(InternalAPI::class)
@Test
fun `update credentials after clearToken`() = runTest {
var credentials = BasicAuthCredentials("admin", "admin")
val provider = BasicAuthProvider(credentials = { credentials })
val requestBuilder = HttpRequestBuilder()
suspend fun assertAuthorizationHeader(expected: String) {
provider.addRequestHeaders(requestBuilder, authHeader = null)
assertEquals(expected, requestBuilder.headers[HttpHeaders.Authorization])
}
assertAuthorizationHeader("Basic YWRtaW46YWRtaW4=")
credentials = BasicAuthCredentials("user", "qwerty")
assertAuthorizationHeader("Basic YWRtaW46YWRtaW4=")
provider.clearToken()
assertAuthorizationHeader("Basic dXNlcjpxd2VydHk=")
}
private fun buildAuthString(username: String, password: String): String = private fun buildAuthString(username: String, password: String): String =
constructBasicAuthValue(BasicAuthCredentials(username, password)) constructBasicAuthValue(BasicAuthCredentials(username, password))
} }
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать