1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-07 16:06:08 +00:00

add update authToken code to connectionValidator

This commit is contained in:
Christian Schabesberger 2021-09-14 14:36:49 +02:00
parent cfd69987e9
commit e27a968ddb
3 changed files with 112 additions and 19 deletions

View File

@ -1,31 +1,37 @@
package com.owncloud.android.lib.common
import android.accounts.AccountManager
import android.accounts.AccountsException
import android.content.Context
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials
import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.files.CheckPathExistenceRemoteOperation
import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation
import com.owncloud.android.lib.resources.status.RemoteServerInfo
import org.apache.commons.lang3.exception.ExceptionUtils
import timber.log.Timber
import java.io.IOException
import java.lang.Exception
class ConnectionValidator (
val context: Context,
val clearCookiesOnValidation: Boolean
){
fun validate(baseClient: OwnCloudClient): Boolean {
fun validate(baseClient: OwnCloudClient, singleSessionManager: SingleSessionManager): Boolean {
try {
var validationRetryCount = 0
val client = OwnCloudClient(baseClient.baseUri, null, false)
val client = OwnCloudClient(baseClient.baseUri, null, false, singleSessionManager)
if (clearCookiesOnValidation) {
client.clearCookies();
} else {
client.cookiesForBaseUri = baseClient.cookiesForBaseUri
}
client.account = baseClient.account
client.credentials = baseClient.credentials
while (validationRetryCount < 5) {
Timber.d("+++++++++++++++++++++++++++++++++++++ validationRetryCout %d", validationRetryCount)
@ -40,7 +46,7 @@ class ConnectionValidator (
}
// Skip the part where we try to check if we can access the parts where we have to be logged in... if we are not logged in
if(baseClient.credentials !is OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials) {
if(baseClient.credentials !is OwnCloudAnonymousCredentials) {
client.setFollowRedirects(false)
val contentReply = canAccessRootFolder(client)
if (contentReply.httpCode == HttpConstants.HTTP_OK) {
@ -51,8 +57,8 @@ class ConnectionValidator (
}
} else {
failCounter++
if (contentReply.hashCode() == HttpConstants.HTTP_UNAUTHORIZED) {
triggerAuthRefresh()
if (contentReply.httpCode == HttpConstants.HTTP_UNAUTHORIZED) {
checkUnauthorizedAccess(client, singleSessionManager, contentReply.httpCode)
}
}
}
@ -92,4 +98,89 @@ class ConnectionValidator (
val checkPathExistenceRemoteOperation = CheckPathExistenceRemoteOperation("/", true)
return checkPathExistenceRemoteOperation.execute(client)
}
/**
* Determines if credentials should be invalidated according the to the HTTPS status
* of a network request just performed.
*
* @param httpStatusCode Result of the last request ran with the 'credentials' belows.
* @return 'True' if credentials should and might be invalidated, 'false' if shouldn't or
* cannot be invalidated with the given arguments.
*/
private fun shouldInvalidateAccountCredentials(credentials: OwnCloudCredentials, account: OwnCloudAccount, httpStatusCode: Int): Boolean {
var shouldInvalidateAccountCredentials = httpStatusCode == HttpConstants.HTTP_UNAUTHORIZED
shouldInvalidateAccountCredentials = shouldInvalidateAccountCredentials and // real credentials
(credentials !is OwnCloudAnonymousCredentials)
// test if have all the needed to effectively invalidate ...
shouldInvalidateAccountCredentials =
shouldInvalidateAccountCredentials and (account.savedAccount != null)
return shouldInvalidateAccountCredentials
}
/**
* Invalidates credentials stored for the given account in the system [AccountManager] and in
* current [SingleSessionManager.getDefaultSingleton] instance.
*
*
* [.shouldInvalidateAccountCredentials] should be called first.
*
*/
private fun invalidateAccountCredentials(account: OwnCloudAccount, credentials: OwnCloudCredentials) {
val am = AccountManager.get(context)
am.invalidateAuthToken(
account.savedAccount.type,
credentials.authToken
)
am.clearPassword(account.savedAccount) // being strict, only needed for Basic Auth credentials
}
/**
* Checks the status code of an execution and decides if should be repeated with fresh credentials.
*
*
* Invalidates current credentials if the request failed as anauthorized.
*
*
* Refresh current credentials if possible, and marks a retry.
*
* @param status
* @param repeatCounter
* @return
*/
private fun checkUnauthorizedAccess(client: OwnCloudClient, singleSessionManager: SingleSessionManager, status: Int): Boolean {
var credentialsWereRefreshed = false
val account = client.account
val credentials = account.credentials
if (shouldInvalidateAccountCredentials(credentials, account, status)) {
invalidateAccountCredentials(account, credentials)
if (credentials.authTokenCanBeRefreshed()) {
try {
account.loadCredentials(context)
// if mAccount.getCredentials().length() == 0 --> refresh failed
client.credentials = account.credentials
credentialsWereRefreshed = true
} catch (e: AccountsException) {
Timber.e(
e, "Error while trying to refresh auth token for %s\ntrace: %s",
account.savedAccount.name,
ExceptionUtils.getStackTrace(e)
)
} catch (e: IOException) {
Timber.e(
e, "Error while trying to refresh auth token for %s\ntrace: %s",
account.savedAccount.name,
ExceptionUtils.getStackTrace(e)
)
}
if (!credentialsWereRefreshed) {
// if credentials are not refreshed, client must be removed
// from the OwnCloudClientManager to prevent it is reused once and again
singleSessionManager.removeClientFor(account)
}
}
// else: onExecute will finish with status 401
}
return credentialsWereRefreshed
}
}

View File

@ -59,7 +59,6 @@ public class OwnCloudClient extends HttpClient {
public static final String STATUS_PATH = "/status.php";
private static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
private static final int MAX_REDIRECTIONS_COUNT = 5;
private static final int MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS = 1;
private static int sIntanceCounter = 0;
private OwnCloudCredentials mCredentials = null;
@ -80,12 +79,13 @@ public class OwnCloudClient extends HttpClient {
private boolean mFollowRedirects = false;
public OwnCloudClient(Uri baseUri, ConnectionValidator connectionValidator, boolean synchronizeRequests) {
public OwnCloudClient(Uri baseUri, ConnectionValidator connectionValidator, boolean synchronizeRequests, SingleSessionManager singleSessionManager) {
if (baseUri == null) {
throw new IllegalArgumentException("Parameter 'baseUri' cannot be NULL");
}
mBaseUri = baseUri;
mSynchronizeRequests = synchronizeRequests;
mSingleSessionManager = singleSessionManager;
mInstanceNumber = sIntanceCounter++;
Timber.d("#" + mInstanceNumber + "Creating OwnCloudClient");
@ -134,8 +134,10 @@ public class OwnCloudClient extends HttpClient {
stacklog(status, method);
if (mConnectionValidator != null &&
status == HttpConstants.HTTP_MOVED_TEMPORARILY) {
retry = mConnectionValidator.validate(this); // retry on success fail on no success
(status == HttpConstants.HTTP_MOVED_TEMPORARILY ||
(!(mCredentials instanceof OwnCloudAnonymousCredentials) &&
status == HttpConstants.HTTP_UNAUTHORIZED))) {
retry = mConnectionValidator.validate(this, mSingleSessionManager); // retry on success fail on no success
} else if (mFollowRedirects) {
status = followRedirection(method).getLastStatus();
}
@ -145,8 +147,8 @@ public class OwnCloudClient extends HttpClient {
if (repeatWithFreshCredentials) {
repeatCounter++;
}
*/
} while (retry);
return status;
@ -163,6 +165,7 @@ public class OwnCloudClient extends HttpClient {
"\nMethod: " + method.toString() +
"\nUrl: " + method.getHttpUrl() +
"\nCookeis: " + getCookiesForBaseUri().toString() +
"\nCredentials type: " + mCredentials.getClass().toString() +
"\ntrace: " + ExceptionUtils.getStackTrace(e) +
"---------------------------");
}
@ -374,7 +377,7 @@ public class OwnCloudClient extends HttpClient {
invalidateAccountCredentials();
if (getCredentials().authTokenCanBeRefreshed() &&
repeatCounter < MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS) {
repeatCounter < 1) {
try {
mAccount.loadCredentials(getContext());
// if mAccount.getCredentials().length() == 0 --> refresh failed

View File

@ -77,9 +77,8 @@ public class SingleSessionManager {
sUserAgent = userAgent;
}
private static OwnCloudClient createOwnCloudClient(Uri uri, Context context, boolean followRedirects, ConnectionValidator connectionValidator) {
OwnCloudClient client = new OwnCloudClient(uri, connectionValidator, true);
client.setFollowRedirects(followRedirects);
private static OwnCloudClient createOwnCloudClient(Uri uri, Context context, ConnectionValidator connectionValidator, SingleSessionManager singleSessionManager) {
OwnCloudClient client = new OwnCloudClient(uri, connectionValidator, true, singleSessionManager);
HttpClient.setContext(context);
return client;
@ -132,8 +131,8 @@ public class SingleSessionManager {
client = createOwnCloudClient(
account.getBaseUri(),
context.getApplicationContext(),
true,
connectionValidator); // TODO remove dependency on OwnCloudClientFactory
connectionValidator,
this);
//the next two lines are a hack because okHttpclient is used as a singleton instead of being an
//injected instance that can be deleted when required