Skip to content
This repository was archived by the owner on Mar 19, 2024. It is now read-only.

Commit e27a968

Browse files
committed
add update authToken code to connectionValidator
1 parent cfd6998 commit e27a968

File tree

3 files changed

+112
-19
lines changed

3 files changed

+112
-19
lines changed

owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/ConnectionValidator.kt

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,37 @@
11
package com.owncloud.android.lib.common
22

3+
import android.accounts.AccountManager
4+
import android.accounts.AccountsException
5+
import android.content.Context
36
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials
47
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory
8+
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials
59
import com.owncloud.android.lib.common.http.HttpConstants
6-
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod
710
import com.owncloud.android.lib.common.operations.RemoteOperationResult
811
import com.owncloud.android.lib.resources.files.CheckPathExistenceRemoteOperation
912
import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation
1013
import com.owncloud.android.lib.resources.status.RemoteServerInfo
1114
import org.apache.commons.lang3.exception.ExceptionUtils
1215
import timber.log.Timber
16+
import java.io.IOException
1317
import java.lang.Exception
1418

1519
class ConnectionValidator (
20+
val context: Context,
1621
val clearCookiesOnValidation: Boolean
1722
){
1823

19-
fun validate(baseClient: OwnCloudClient): Boolean {
24+
fun validate(baseClient: OwnCloudClient, singleSessionManager: SingleSessionManager): Boolean {
2025
try {
2126
var validationRetryCount = 0
22-
val client = OwnCloudClient(baseClient.baseUri, null, false)
27+
val client = OwnCloudClient(baseClient.baseUri, null, false, singleSessionManager)
2328
if (clearCookiesOnValidation) {
2429
client.clearCookies();
2530
} else {
2631
client.cookiesForBaseUri = baseClient.cookiesForBaseUri
2732
}
2833

34+
client.account = baseClient.account
2935
client.credentials = baseClient.credentials
3036
while (validationRetryCount < 5) {
3137
Timber.d("+++++++++++++++++++++++++++++++++++++ validationRetryCout %d", validationRetryCount)
@@ -40,7 +46,7 @@ class ConnectionValidator (
4046
}
4147

4248
// 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
43-
if(baseClient.credentials !is OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials) {
49+
if(baseClient.credentials !is OwnCloudAnonymousCredentials) {
4450
client.setFollowRedirects(false)
4551
val contentReply = canAccessRootFolder(client)
4652
if (contentReply.httpCode == HttpConstants.HTTP_OK) {
@@ -51,8 +57,8 @@ class ConnectionValidator (
5157
}
5258
} else {
5359
failCounter++
54-
if (contentReply.hashCode() == HttpConstants.HTTP_UNAUTHORIZED) {
55-
triggerAuthRefresh()
60+
if (contentReply.httpCode == HttpConstants.HTTP_UNAUTHORIZED) {
61+
checkUnauthorizedAccess(client, singleSessionManager, contentReply.httpCode)
5662
}
5763
}
5864
}
@@ -92,4 +98,89 @@ class ConnectionValidator (
9298
val checkPathExistenceRemoteOperation = CheckPathExistenceRemoteOperation("/", true)
9399
return checkPathExistenceRemoteOperation.execute(client)
94100
}
101+
102+
/**
103+
* Determines if credentials should be invalidated according the to the HTTPS status
104+
* of a network request just performed.
105+
*
106+
* @param httpStatusCode Result of the last request ran with the 'credentials' belows.
107+
* @return 'True' if credentials should and might be invalidated, 'false' if shouldn't or
108+
* cannot be invalidated with the given arguments.
109+
*/
110+
private fun shouldInvalidateAccountCredentials(credentials: OwnCloudCredentials, account: OwnCloudAccount, httpStatusCode: Int): Boolean {
111+
var shouldInvalidateAccountCredentials = httpStatusCode == HttpConstants.HTTP_UNAUTHORIZED
112+
shouldInvalidateAccountCredentials = shouldInvalidateAccountCredentials and // real credentials
113+
(credentials !is OwnCloudAnonymousCredentials)
114+
115+
// test if have all the needed to effectively invalidate ...
116+
shouldInvalidateAccountCredentials =
117+
shouldInvalidateAccountCredentials and (account.savedAccount != null)
118+
return shouldInvalidateAccountCredentials
119+
}
120+
121+
/**
122+
* Invalidates credentials stored for the given account in the system [AccountManager] and in
123+
* current [SingleSessionManager.getDefaultSingleton] instance.
124+
*
125+
*
126+
* [.shouldInvalidateAccountCredentials] should be called first.
127+
*
128+
*/
129+
private fun invalidateAccountCredentials(account: OwnCloudAccount, credentials: OwnCloudCredentials) {
130+
val am = AccountManager.get(context)
131+
am.invalidateAuthToken(
132+
account.savedAccount.type,
133+
credentials.authToken
134+
)
135+
am.clearPassword(account.savedAccount) // being strict, only needed for Basic Auth credentials
136+
}
137+
138+
/**
139+
* Checks the status code of an execution and decides if should be repeated with fresh credentials.
140+
*
141+
*
142+
* Invalidates current credentials if the request failed as anauthorized.
143+
*
144+
*
145+
* Refresh current credentials if possible, and marks a retry.
146+
*
147+
* @param status
148+
* @param repeatCounter
149+
* @return
150+
*/
151+
private fun checkUnauthorizedAccess(client: OwnCloudClient, singleSessionManager: SingleSessionManager, status: Int): Boolean {
152+
var credentialsWereRefreshed = false
153+
val account = client.account
154+
val credentials = account.credentials
155+
if (shouldInvalidateAccountCredentials(credentials, account, status)) {
156+
invalidateAccountCredentials(account, credentials)
157+
if (credentials.authTokenCanBeRefreshed()) {
158+
try {
159+
account.loadCredentials(context)
160+
// if mAccount.getCredentials().length() == 0 --> refresh failed
161+
client.credentials = account.credentials
162+
credentialsWereRefreshed = true
163+
} catch (e: AccountsException) {
164+
Timber.e(
165+
e, "Error while trying to refresh auth token for %s\ntrace: %s",
166+
account.savedAccount.name,
167+
ExceptionUtils.getStackTrace(e)
168+
)
169+
} catch (e: IOException) {
170+
Timber.e(
171+
e, "Error while trying to refresh auth token for %s\ntrace: %s",
172+
account.savedAccount.name,
173+
ExceptionUtils.getStackTrace(e)
174+
)
175+
}
176+
if (!credentialsWereRefreshed) {
177+
// if credentials are not refreshed, client must be removed
178+
// from the OwnCloudClientManager to prevent it is reused once and again
179+
singleSessionManager.removeClientFor(account)
180+
}
181+
}
182+
// else: onExecute will finish with status 401
183+
}
184+
return credentialsWereRefreshed
185+
}
95186
}

owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ public class OwnCloudClient extends HttpClient {
5959
public static final String STATUS_PATH = "/status.php";
6060
private static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
6161
private static final int MAX_REDIRECTIONS_COUNT = 5;
62-
private static final int MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS = 1;
6362

6463
private static int sIntanceCounter = 0;
6564
private OwnCloudCredentials mCredentials = null;
@@ -80,12 +79,13 @@ public class OwnCloudClient extends HttpClient {
8079

8180
private boolean mFollowRedirects = false;
8281

83-
public OwnCloudClient(Uri baseUri, ConnectionValidator connectionValidator, boolean synchronizeRequests) {
82+
public OwnCloudClient(Uri baseUri, ConnectionValidator connectionValidator, boolean synchronizeRequests, SingleSessionManager singleSessionManager) {
8483
if (baseUri == null) {
8584
throw new IllegalArgumentException("Parameter 'baseUri' cannot be NULL");
8685
}
8786
mBaseUri = baseUri;
8887
mSynchronizeRequests = synchronizeRequests;
88+
mSingleSessionManager = singleSessionManager;
8989

9090
mInstanceNumber = sIntanceCounter++;
9191
Timber.d("#" + mInstanceNumber + "Creating OwnCloudClient");
@@ -134,8 +134,10 @@ private int saveExecuteHttpMethod(HttpBaseMethod method) throws Exception {
134134
stacklog(status, method);
135135

136136
if (mConnectionValidator != null &&
137-
status == HttpConstants.HTTP_MOVED_TEMPORARILY) {
138-
retry = mConnectionValidator.validate(this); // retry on success fail on no success
137+
(status == HttpConstants.HTTP_MOVED_TEMPORARILY ||
138+
(!(mCredentials instanceof OwnCloudAnonymousCredentials) &&
139+
status == HttpConstants.HTTP_UNAUTHORIZED))) {
140+
retry = mConnectionValidator.validate(this, mSingleSessionManager); // retry on success fail on no success
139141
} else if (mFollowRedirects) {
140142
status = followRedirection(method).getLastStatus();
141143
}
@@ -145,8 +147,8 @@ private int saveExecuteHttpMethod(HttpBaseMethod method) throws Exception {
145147
if (repeatWithFreshCredentials) {
146148
repeatCounter++;
147149
}
148-
149150
*/
151+
150152
} while (retry);
151153

152154
return status;
@@ -163,6 +165,7 @@ private void stacklog(int status, HttpBaseMethod method) {
163165
"\nMethod: " + method.toString() +
164166
"\nUrl: " + method.getHttpUrl() +
165167
"\nCookeis: " + getCookiesForBaseUri().toString() +
168+
"\nCredentials type: " + mCredentials.getClass().toString() +
166169
"\ntrace: " + ExceptionUtils.getStackTrace(e) +
167170
"---------------------------");
168171
}
@@ -336,8 +339,8 @@ public void setCookiesForBaseUri(List<Cookie> cookies) {
336339
}
337340

338341
public List<Cookie> getCookiesForBaseUri() {
339-
return getOkHttpClient().cookieJar().loadForRequest(
340-
HttpUrl.parse(mBaseUri.toString()));
342+
return getOkHttpClient().cookieJar().loadForRequest(
343+
HttpUrl.parse(mBaseUri.toString()));
341344
}
342345

343346
public OwnCloudVersion getOwnCloudVersion() {
@@ -374,7 +377,7 @@ private boolean checkUnauthorizedAccess(int status, int repeatCounter) {
374377
invalidateAccountCredentials();
375378

376379
if (getCredentials().authTokenCanBeRefreshed() &&
377-
repeatCounter < MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS) {
380+
repeatCounter < 1) {
378381
try {
379382
mAccount.loadCredentials(getContext());
380383
// if mAccount.getCredentials().length() == 0 --> refresh failed

owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/SingleSessionManager.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,8 @@ public static void setUserAgent(String userAgent) {
7777
sUserAgent = userAgent;
7878
}
7979

80-
private static OwnCloudClient createOwnCloudClient(Uri uri, Context context, boolean followRedirects, ConnectionValidator connectionValidator) {
81-
OwnCloudClient client = new OwnCloudClient(uri, connectionValidator, true);
82-
client.setFollowRedirects(followRedirects);
80+
private static OwnCloudClient createOwnCloudClient(Uri uri, Context context, ConnectionValidator connectionValidator, SingleSessionManager singleSessionManager) {
81+
OwnCloudClient client = new OwnCloudClient(uri, connectionValidator, true, singleSessionManager);
8382
HttpClient.setContext(context);
8483

8584
return client;
@@ -132,8 +131,8 @@ public OwnCloudClient getClientFor(OwnCloudAccount account,
132131
client = createOwnCloudClient(
133132
account.getBaseUri(),
134133
context.getApplicationContext(),
135-
true,
136-
connectionValidator); // TODO remove dependency on OwnCloudClientFactory
134+
connectionValidator,
135+
this);
137136

138137
//the next two lines are a hack because okHttpclient is used as a singleton instead of being an
139138
//injected instance that can be deleted when required

0 commit comments

Comments
 (0)