From 8f521863a186f5cd975bed280d8a3cd4b9a4cbed Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Wed, 2 Apr 2025 11:20:26 +0200 Subject: [PATCH 1/2] Add possibility to not use cookies to OwnCloudClient --- .../java/com/owncloud/android/AbstractIT.java | 8 +++- .../files/SearchRemoteOperationIT.java | 4 +- .../shares/GetSharesRemoteOperationIT.java | 4 +- .../android/lib/common/OwnCloudClient.java | 30 ++++++++++++-- .../lib/common/OwnCloudClientFactory.java | 41 +++++++++++++------ .../lib/common/OwnCloudClientManager.java | 8 +++- .../lib/common/accounts/AccountUtils.java | 3 +- .../common/operations/RemoteOperation.java | 10 +++-- .../lib/sampleclient/MainActivity.java | 4 +- 9 files changed, 84 insertions(+), 28 deletions(-) diff --git a/library/src/androidTest/java/com/owncloud/android/AbstractIT.java b/library/src/androidTest/java/com/owncloud/android/AbstractIT.java index 83a4869d9..4389fe2a5 100644 --- a/library/src/androidTest/java/com/owncloud/android/AbstractIT.java +++ b/library/src/androidTest/java/com/owncloud/android/AbstractIT.java @@ -111,7 +111,9 @@ public abstract class AbstractIT { String loginName = arguments.getString("TEST_SERVER_USERNAME"); String password = arguments.getString("TEST_SERVER_PASSWORD"); - client = OwnCloudClientFactory.createOwnCloudClient(url, context, true); + client = OwnCloudClientFactory.createOwnCloudClient(url, context, true, + OwnCloudClient.USE_COOKIES); + client.setCredentials(new OwnCloudBasicCredentials(loginName, password)); client.setUserId(loginName); // for test same as userId @@ -119,7 +121,9 @@ public abstract class AbstractIT { String loginName2 = arguments.getString("TEST_SERVER_USERNAME2"); String password2 = arguments.getString("TEST_SERVER_PASSWORD2"); - client2 = OwnCloudClientFactory.createOwnCloudClient(url, context, true); + client2 = OwnCloudClientFactory.createOwnCloudClient(url, context, true, + OwnCloudClient.USE_COOKIES); + client2.setCredentials(new OwnCloudBasicCredentials(loginName2, password2)); client2.setUserId(loginName2); // for test same as userId diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/SearchRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/SearchRemoteOperationIT.java index 480931e20..b0081554b 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/SearchRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/SearchRemoteOperationIT.java @@ -472,7 +472,9 @@ public class SearchRemoteOperationIT extends AbstractIT { Bundle arguments = InstrumentationRegistry.getArguments(); Uri url = Uri.parse(arguments.getString("TEST_SERVER_URL")); - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(url, context, true); + OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(url, context, true, + OwnCloudClient.USE_COOKIES); + client.setCredentials(new OwnCloudBasicCredentials("test@test", "test")); client.setUserId("test@test"); // for test same as userId diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetSharesRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetSharesRemoteOperationIT.java index b2ed3b54f..f0adf6bb3 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetSharesRemoteOperationIT.java +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/shares/GetSharesRemoteOperationIT.java @@ -209,7 +209,9 @@ public class GetSharesRemoteOperationIT extends AbstractIT { String loginName = "user1"; String password = "user1"; - OwnCloudClient clientUser1 = OwnCloudClientFactory.createOwnCloudClient(url, context, true); + OwnCloudClient clientUser1 = OwnCloudClientFactory.createOwnCloudClient(url, context, true, + OwnCloudClient.USE_COOKIES); + clientUser1.setCredentials(new OwnCloudBasicCredentials(loginName, password)); clientUser1.setUserId(loginName); // for test same as userId diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java index 89f0596bd..02572cd58 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java @@ -47,16 +47,16 @@ import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.params.HttpParams; +import androidx.annotation.IntDef; import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.ConnectException; import java.net.SocketTimeoutException; -import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.Locale; import java.util.Map; -import java.util.Set; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -77,11 +77,18 @@ public class OwnCloudClient extends HttpClient { private int mInstanceNumber; private boolean shouldResetCookie = false; + private @CookiesPolicy int cookiesPolicy; + + public static final int USE_COOKIES = 0; + public static final int DONT_USE_COOKIES = 1; + @IntDef({USE_COOKIES, DONT_USE_COOKIES}) + @Retention(RetentionPolicy.SOURCE) + public @interface CookiesPolicy {} /** * Constructor */ - public OwnCloudClient(Uri baseUri, HttpConnectionManager connectionMgr) { + public OwnCloudClient(Uri baseUri, HttpConnectionManager connectionMgr, @CookiesPolicy int cookiesPolicy) { super(connectionMgr); if (baseUri == null) { @@ -89,6 +96,8 @@ public class OwnCloudClient extends HttpClient { } nextcloudUriDelegate = new NextcloudUriDelegate(baseUri); + this.cookiesPolicy = cookiesPolicy; + mInstanceNumber = sInstanceCounter++; Log_OC.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient"); @@ -203,6 +212,15 @@ public class OwnCloudClient extends HttpClient { // logCookiesAtState("before"); method.setFollowRedirects(false); + /* + * We want to clear cookies here specifically for Notes API. + * Indeed, The Notes server APIs have the Cross-Origin Resource Sharing (CORS) flag, + * so are not able to deal with cookie sessions. + */ + if (cookiesPolicy == DONT_USE_COOKIES && method.getURI().getEscapedURI().contains("/apps/notes/")) { + getState().clearCookies(); + } + boolean cookiePassedOnRequest = getState().getCookies().length > 0; int status = super.executeMethod(method); @@ -505,4 +523,8 @@ public class OwnCloudClient extends HttpClient { getState().clearCookies(); shouldResetCookie = false; } + + public @CookiesPolicy int getCookiesPolicy() { + return cookiesPolicy; + } } diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientFactory.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientFactory.java index bb4cecdb0..d31edf244 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientFactory.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientFactory.java @@ -66,6 +66,7 @@ public class OwnCloudClientFactory { * * @param account The ownCloud account * @param appContext Android application context + * @param cookiesPolicy The cookies policy to use * @return A OwnCloudClient object ready to be used * @throws AuthenticatorException If the authenticator failed to get the authorization * token for the account. @@ -75,8 +76,11 @@ public class OwnCloudClientFactory { * authorization token for the account. * @throws AccountNotFoundException If 'account' is unknown for the AccountManager */ - public static OwnCloudClient createOwnCloudClient(Account account, Context appContext) - throws OperationCanceledException, AuthenticatorException, IOException, + public static OwnCloudClient createOwnCloudClient( + Account account, + Context appContext, + @OwnCloudClient.CookiesPolicy int cookiesPolicy + ) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException { //Log_OC.d(TAG, "Creating OwnCloudClient associated to " + account.name); Uri baseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account)); @@ -84,37 +88,45 @@ public class OwnCloudClientFactory { // TODO avoid calling to getUserData here String userId = AccountUtils.getUpdatedUserId(am, account); - OwnCloudClient client = createOwnCloudClient(baseUri, appContext, true); + OwnCloudClient client = createOwnCloudClient(baseUri, appContext, true, cookiesPolicy); client.setUserId(userId); OwnCloudCredentials credentials = AccountUtils.getCredentialsForAccount(appContext, account); client.setCredentials(credentials); // Restore cookies - AccountUtils.restoreCookies(account, client, appContext); + if (cookiesPolicy == OwnCloudClient.USE_COOKIES) { + AccountUtils.restoreCookies(account, client, appContext); + } return client; } - public static OwnCloudClient createOwnCloudClient(Account account, Context appContext, Activity currentActivity) - throws OperationCanceledException, AuthenticatorException, IOException, + public static OwnCloudClient createOwnCloudClient( + Account account, + Context appContext, + Activity currentActivity, + @OwnCloudClient.CookiesPolicy int cookiesPolicy + ) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException { Uri baseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account)); AccountManager am = AccountManager.get(appContext); // TODO avoid calling to getUserData here String userId = AccountUtils.getUpdatedUserId(am, account); - OwnCloudClient client = createOwnCloudClient(baseUri, appContext, true); + OwnCloudClient client = createOwnCloudClient(baseUri, appContext, true, cookiesPolicy); client.setUserId(userId); OwnCloudCredentials credentials = AccountUtils.getCredentialForAccount(appContext, account, currentActivity); client.setCredentials(credentials); - + // Restore cookies - AccountUtils.restoreCookies(account, client, appContext); - + if (cookiesPolicy == OwnCloudClient.USE_COOKIES) { + AccountUtils.restoreCookies(account, client, appContext); + } + return client; } @@ -126,7 +138,12 @@ public class OwnCloudClientFactory { * @param context Android context where the OwnCloudClient is being created. * @return A OwnCloudClient object ready to be used */ - public static OwnCloudClient createOwnCloudClient(Uri uri, Context context, boolean followRedirects) { + public static OwnCloudClient createOwnCloudClient( + Uri uri, + Context context, + boolean followRedirects, + @OwnCloudClient.CookiesPolicy int cookiesPolicy + ) { try { NetworkUtils.registerAdvancedSslContext(true, context); } catch (GeneralSecurityException e) { @@ -137,7 +154,7 @@ public class OwnCloudClientFactory { Log_OC.e(TAG, "The local server truststore could not be read. Default SSL management" + " in the system will be used for HTTPS connections", e); } - OwnCloudClient client = new OwnCloudClient(uri, NetworkUtils.getMultiThreadedConnManager()); + OwnCloudClient client = new OwnCloudClient(uri, NetworkUtils.getMultiThreadedConnManager(), cookiesPolicy); client.setDefaultTimeouts(DEFAULT_DATA_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT); client.setFollowRedirects(followRedirects); diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManager.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManager.java index 3344e14e5..83e211bba 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManager.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManager.java @@ -64,7 +64,11 @@ public class OwnCloudClientManager { private ConcurrentMap clientsNewWithUnknownUsername = new ConcurrentHashMap<>(); @Deprecated - public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws OperationCanceledException, + public OwnCloudClient getClientFor( + OwnCloudAccount account, + Context context, + @OwnCloudClient.CookiesPolicy int cookiesPolicy + ) throws OperationCanceledException, AuthenticatorException, IOException { if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -109,7 +113,7 @@ public class OwnCloudClientManager { // no client to reuse - create a new one // TODO remove dependency on OwnCloudClientFactory client = OwnCloudClientFactory.createOwnCloudClient(account.getBaseUri(), context.getApplicationContext(), - true); + true, cookiesPolicy); client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); // enable cookie tracking diff --git a/library/src/main/java/com/owncloud/android/lib/common/accounts/AccountUtils.java b/library/src/main/java/com/owncloud/android/lib/common/accounts/AccountUtils.java index c502d1b7b..a8ff2c754 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/library/src/main/java/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -261,7 +261,7 @@ public class AccountUtils { } public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) { - if (client == null) { + if (client == null || client.getCookiesPolicy() != OwnCloudClient.USE_COOKIES) { return; } @@ -278,7 +278,6 @@ public class AccountUtils { if (!cookiesString.isBlank()) { ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString); } - } diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperation.java index b2299f421..bb5258c6e 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -138,7 +138,11 @@ public abstract class RemoteOperation implements Runnable { mContext = context.getApplicationContext(); try { OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); - mClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, mContext); + mClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor( + ocAccount, + mContext, + OwnCloudClient.USE_COOKIES + ); } catch (Exception e) { Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); return new RemoteOperationResult(e); @@ -372,12 +376,12 @@ public abstract class RemoteOperation implements Runnable { /** DEPRECATED BLOCK - will be removed at version 1.0 */ if (mCallerActivity != null) { mClient = OwnCloudClientFactory.createOwnCloudClient( - mAccount, mContext, mCallerActivity); + mAccount, mContext, mCallerActivity, OwnCloudClient.USE_COOKIES); } else { /** EOF DEPRECATED */ OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, mContext); + getClientFor(ocAccount, mContext, OwnCloudClient.USE_COOKIES); } } else { diff --git a/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java b/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java index 1c1553734..6b2cb78c2 100644 --- a/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java +++ b/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java @@ -81,7 +81,9 @@ public class MainActivity extends Activity implements OnRemoteOperationListener, mHandler = new Handler(); Uri serverUri = Uri.parse(getString(R.string.server_base_url)); - mClient = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true); + mClient = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true, + OwnCloudClient.USE_COOKIES); + mClient.setCredentials( OwnCloudCredentialsFactory.newBasicCredentials( getString(R.string.username), -- GitLab From c7f5f6cc7036284edb098b9a85f9086d2fa1f78b Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Wed, 2 Apr 2025 11:27:36 +0200 Subject: [PATCH 2/2] Bump version to 2.0.0 --- library/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 6ee710db0..79c688ede 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -45,9 +45,9 @@ configurations { } } -def versionMajor = 1 +def versionMajor = 2 def versionMinor = 0 -def versionPatch = 10 +def versionPatch = 0 def upstreamVersion = "2.17" def releasePatch = "release" def libName = "Nextcloud-Android-Library" -- GitLab