Skip to content

Commit

Permalink
Implement headers support in getCredentials and awaitCredentials (aut…
Browse files Browse the repository at this point in the history
  • Loading branch information
poovamraj authored Nov 29, 2023
1 parent 873989c commit c17b87b
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,37 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
minTtl: Int,
parameters: Map<String, String>,
forceRefresh: Boolean
): Credentials {
return awaitCredentials(scope, minTtl, parameters, mapOf(), forceRefresh)
}

/**
* Retrieves the credentials from the storage and refresh them if they have already expired.
* It will throw [CredentialsManagerException] if the saved access_token or id_token is null,
* or if the tokens have already expired and the refresh_token is null.
* This is a Coroutine that is exposed only for Kotlin.
*
* @param scope the scope to request for the access token. If null is passed, the previous scope will be kept.
* @param minTtl the minimum time in seconds that the access token should last before expiration.
* @param parameters additional parameters to send in the request to refresh expired credentials.
* @param headers additional headers to send in the request to refresh expired credentials.
* @param forceRefresh this will avoid returning the existing credentials and retrieves a new one even if valid credentials exist.
*/
@JvmSynthetic
@Throws(CredentialsManagerException::class)
public suspend fun awaitCredentials(
scope: String?,
minTtl: Int,
parameters: Map<String, String>,
headers: Map<String, String>,
forceRefresh: Boolean
): Credentials {
return suspendCancellableCoroutine { continuation ->
getCredentials(
scope,
minTtl,
parameters,
headers,
forceRefresh,
object : Callback<Credentials, CredentialsManagerException> {
override fun onSuccess(result: Credentials) {
Expand Down Expand Up @@ -201,6 +226,29 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
parameters: Map<String, String>,
forceRefresh: Boolean,
callback: Callback<Credentials, CredentialsManagerException>
) {
getCredentials(scope, minTtl, parameters, mapOf(), forceRefresh, callback)
}

/**
* Retrieves the credentials from the storage and refresh them if they have already expired.
* It will fail with [CredentialsManagerException] if the saved access_token or id_token is null,
* or if the tokens have already expired and the refresh_token is null.
*
* @param scope the scope to request for the access token. If null is passed, the previous scope will be kept.
* @param minTtl the minimum time in seconds that the access token should last before expiration.
* @param parameters additional parameters to send in the request to refresh expired credentials.
* @param headers additional headers to send in the request to refresh expired credentials.
* @param forceRefresh this will avoid returning the existing credentials and retrieves a new one even if valid credentials exist.
* @param callback the callback that will receive a valid [Credentials] or the [CredentialsManagerException].
*/
public fun getCredentials(
scope: String?,
minTtl: Int,
parameters: Map<String, String>,
headers: Map<String, String>,
forceRefresh: Boolean,
callback: Callback<Credentials, CredentialsManagerException>
) {
serialExecutor.execute {
val accessToken = storage.retrieveString(KEY_ACCESS_TOKEN)
Expand Down Expand Up @@ -240,6 +288,10 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
request.addParameter("scope", scope)
}

for (header in headers) {
request.addHeader(header.key, header.value)
}

try {
val fresh = request.execute()
val expiresAt = fresh.expiresAt.time
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
return false
}
if (resultCode == Activity.RESULT_OK) {
continueGetCredentials(scope, minTtl, emptyMap(), forceRefresh, decryptCallback!!)
continueGetCredentials(scope, minTtl, emptyMap(), emptyMap(), forceRefresh, decryptCallback!!)
} else {
decryptCallback!!.onFailure(CredentialsManagerException("The user didn't pass the authentication challenge."))
decryptCallback = null
Expand Down Expand Up @@ -281,12 +281,41 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
minTtl: Int,
parameters: Map<String, String>,
forceRefresh: Boolean,
): Credentials {
return awaitCredentials(scope, minTtl, parameters, mapOf(), forceRefresh)
}

/**
* Tries to obtain the credentials from the Storage. The method will return [Credentials].
* If something unexpected happens, then [CredentialsManagerException] exception will be thrown. Some devices are not compatible
* at all with the cryptographic implementation and will have [CredentialsManagerException.isDeviceIncompatible] return true.
* This is a Coroutine that is exposed only for Kotlin.
*
* If a LockScreen is setup and [SecureCredentialsManager.requireAuthentication] was called, the user will be asked to authenticate before accessing
* the credentials. Your activity must override the [Activity.onActivityResult] method and call
* [SecureCredentialsManager.checkAuthenticationResult] with the received values.
*
* @param scope the scope to request for the access token. If null is passed, the previous scope will be kept.
* @param minTtl the minimum time in seconds that the access token should last before expiration.
* @param parameters additional parameters to send in the request to refresh expired credentials.
* @param headers additional headers to send in the request to refresh expired credentials.
* @param forceRefresh this will avoid returning the existing credentials and retrieves a new one even if valid credentials exist.
*/
@JvmSynthetic
@Throws(CredentialsManagerException::class)
public suspend fun awaitCredentials(
scope: String?,
minTtl: Int,
parameters: Map<String, String>,
headers: Map<String, String>,
forceRefresh: Boolean,
): Credentials {
return suspendCancellableCoroutine { continuation ->
getCredentials(
scope,
minTtl,
parameters,
headers,
forceRefresh,
object : Callback<Credentials, CredentialsManagerException> {
override fun onSuccess(result: Credentials) {
Expand Down Expand Up @@ -384,6 +413,34 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
parameters: Map<String, String>,
forceRefresh: Boolean,
callback: Callback<Credentials, CredentialsManagerException>
) {
getCredentials(scope, minTtl, parameters, mapOf(), forceRefresh, callback)
}

/**
* Tries to obtain the credentials from the Storage. The callback's [Callback.onSuccess] method will be called with the result.
* If something unexpected happens, the [Callback.onFailure] method will be called with the error. Some devices are not compatible
* at all with the cryptographic implementation and will have [CredentialsManagerException.isDeviceIncompatible] return true.
*
*
* If a LockScreen is setup and [SecureCredentialsManager.requireAuthentication] was called, the user will be asked to authenticate before accessing
* the credentials. Your activity must override the [Activity.onActivityResult] method and call
* [SecureCredentialsManager.checkAuthenticationResult] with the received values.
*
* @param scope the scope to request for the access token. If null is passed, the previous scope will be kept.
* @param minTtl the minimum time in seconds that the access token should last before expiration.
* @param parameters additional parameters to send in the request to refresh expired credentials.
* @param headers additional headers to send in the request to refresh expired credentials.
* @param forceRefresh this will avoid returning the existing credentials and retrieves a new one even if valid credentials exist.
* @param callback the callback to receive the result in.
*/
public fun getCredentials(
scope: String?,
minTtl: Int,
parameters: Map<String, String>,
headers: Map<String, String>,
forceRefresh: Boolean,
callback: Callback<Credentials, CredentialsManagerException>
) {
if (!hasValidCredentials(minTtl.toLong())) {
callback.onFailure(CredentialsManagerException("No Credentials were previously set."))
Expand All @@ -402,7 +459,7 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
?: activity?.startActivityForResult(authIntent, authenticationRequestCode)
return
}
continueGetCredentials(scope, minTtl, parameters, forceRefresh, callback)
continueGetCredentials(scope, minTtl, parameters, headers, forceRefresh, callback)
}

/**
Expand Down Expand Up @@ -451,6 +508,7 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
scope: String?,
minTtl: Int,
parameters: Map<String, String>,
headers: Map<String, String>,
forceRefresh: Boolean,
callback: Callback<Credentials, CredentialsManagerException>
) {
Expand Down Expand Up @@ -532,6 +590,10 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
request.addParameter("scope", scope)
}

for (header in headers) {
request.addHeader(header.key, header.value)
}

val freshCredentials: Credentials
try {
val fresh = request.execute()
Expand Down

0 comments on commit c17b87b

Please sign in to comment.