From 1cb224cba183f63f11aaeb28957a0405474ea340 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Fri, 23 May 2014 13:03:59 +0200 Subject: [PATCH 01/35] Grant that requests done through the same OwnCloudClient using Basic HTTP Authentication keep cookies --- src/com/owncloud/android/lib/common/OwnCloudClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index 14405326..a78f2a1e 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -102,6 +102,7 @@ public class OwnCloudClient extends HttpClient { mCredentials = new UsernamePasswordCredentials(username, password); getState().setCredentials(AuthScope.ANY, mCredentials); mSsoSessionCookie = null; + getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); } public void setSsoSessionCookie(String accessToken) { From 3eedb860910445d3da557faed64b2f821f789c2c Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 29 May 2014 17:49:45 +0200 Subject: [PATCH 02/35] Grant that requests send through the same OwnCloudClient using SAML SSO Authentication keep cookies --- .../android/lib/common/OwnCloudClient.java | 202 ++++++++++++++---- 1 file changed, 163 insertions(+), 39 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index a78f2a1e..e47de84b 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -30,6 +30,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import org.apache.commons.httpclient.Cookie; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; @@ -57,28 +58,43 @@ import android.net.Uri; import android.util.Log; public class OwnCloudClient extends HttpClient { + + private static final String TAG = OwnCloudClient.class.getSimpleName(); + public static final String USER_AGENT = "Android-ownCloud"; private static final int MAX_REDIRECTIONS_COUNT = 3; + private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header"; + private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true; + + private static byte[] sExhaustBuffer = new byte[1024]; + private static int sIntanceCounter = 0; + + private boolean mFollowRedirects = true; + private Credentials mCredentials = null; + private String mSsoSessionCookie = null; + private int mInstanceNumber = 0; private Uri mUri; private Uri mWebdavUri; - private Credentials mCredentials; - private boolean mFollowRedirects; - private String mSsoSessionCookie; - final private static String TAG = OwnCloudClient.class.getSimpleName(); - public static final String USER_AGENT = "Android-ownCloud"; - - static private byte[] sExhaustBuffer = new byte[1024]; /** * Constructor */ public OwnCloudClient(HttpConnectionManager connectionMgr) { super(connectionMgr); - Log.d(TAG, "Creating OwnCloudClient"); + + mInstanceNumber = sIntanceCounter++; + Log.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient"); + getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT); - getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); - mFollowRedirects = true; - mSsoSessionCookie = null; + getParams().setParameter( + CoreProtocolPNames.PROTOCOL_VERSION, + HttpVersion.HTTP_1_1); + + getParams().setCookiePolicy( + CookiePolicy.BROWSER_COMPATIBILITY); // to keep sessions + getParams().setParameter( + PARAM_SINGLE_COOKIE_HEADER, // to avoid problems with some web servers + PARAM_SINGLE_COOKIE_HEADER_VALUE); } public void setBearerCredentials(String accessToken) { @@ -88,6 +104,7 @@ public class OwnCloudClient extends HttpClient { authPrefs.add(BearerAuthScheme.AUTH_POLICY); getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); + getParams().setAuthenticationPreemptive(true); mCredentials = new BearerCredentials(accessToken); getState().setCredentials(AuthScope.ANY, mCredentials); mSsoSessionCookie = null; @@ -102,14 +119,38 @@ public class OwnCloudClient extends HttpClient { mCredentials = new UsernamePasswordCredentials(username, password); getState().setCredentials(AuthScope.ANY, mCredentials); mSsoSessionCookie = null; - getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); } public void setSsoSessionCookie(String accessToken) { + Log.d(TAG + " #" + mInstanceNumber, "Setting session cookie: " + accessToken); + Log.e(TAG + " #" + mInstanceNumber, "BASE URL: " + mUri); + Log.e(TAG + " #" + mInstanceNumber, "WebDAV URL: " + mWebdavUri); + getParams().setAuthenticationPreemptive(false); - getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES); + mSsoSessionCookie = accessToken; mCredentials = null; + + Uri serverUri = (mUri != null)? mUri : mWebdavUri; + // TODO refactoring the mess of URIs + + String[] cookies = mSsoSessionCookie.split(";"); + if (cookies.length > 0) { + //Cookie[] cookies = new Cookie[cookiesStr.length]; + for (int i=0; i= 0) { method.getParams().setSoTimeout(readTimeout); // this should be enough... - getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS + getParams().setSoTimeout(readTimeout); // ... but HTTPS needs this } if (connectionTimeout >= 0) { getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout); @@ -168,43 +212,71 @@ public class OwnCloudClient extends HttpClient { @Override public int executeMethod(HttpMethod method) throws IOException, HttpException { - boolean customRedirectionNeeded = false; - try { - method.setFollowRedirects(mFollowRedirects); - } catch (Exception e) { - //if (mFollowRedirects) Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + " method, custom redirection will be used if needed"); - customRedirectionNeeded = mFollowRedirects; + try { // just to log + boolean customRedirectionNeeded = false; + try { + method.setFollowRedirects(mFollowRedirects); + } catch (Exception e) { + /* + if (mFollowRedirects) + Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + + " method, custom redirection will be used if needed"); + */ + customRedirectionNeeded = mFollowRedirects; + } + + Log.d(TAG + " #" + mInstanceNumber, "REQUEST " + + method.getName() + " " + method.getPath()); + + logCookiesAtRequest(method.getRequestHeaders(), "before"); + logCookiesAtState("before"); + + int status = super.executeMethod(method); + + if (customRedirectionNeeded) { + status = patchRedirection(status, method); + } + + logCookiesAtRequest(method.getRequestHeaders(), "after"); + logCookiesAtState("after"); + logSetCookiesAtResponse(method.getResponseHeaders()); + + return status; + + } catch (IOException e) { + Log.d(TAG + " #" + mInstanceNumber, "Exception occured", e); + throw e; } - if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) { - method.addRequestHeader("Cookie", mSsoSessionCookie); - } - int status = super.executeMethod(method); + } + + private int patchRedirection(int status, HttpMethod method) throws HttpException, IOException { int redirectionsCount = 0; - while (customRedirectionNeeded && - redirectionsCount < MAX_REDIRECTIONS_COUNT && + while (redirectionsCount < MAX_REDIRECTIONS_COUNT && ( status == HttpStatus.SC_MOVED_PERMANENTLY || status == HttpStatus.SC_MOVED_TEMPORARILY || status == HttpStatus.SC_TEMPORARY_REDIRECT) ) { Header location = method.getResponseHeader("Location"); + if (location == null) { + location = method.getResponseHeader("location"); + } if (location != null) { - Log.d(TAG, "Location to redirect: " + location.getValue()); + Log.d(TAG + " #" + mInstanceNumber, + "Location to redirect: " + location.getValue()); method.setURI(new URI(location.getValue(), true)); status = super.executeMethod(method); redirectionsCount++; } else { - Log.d(TAG, "No location to redirect!"); + Log.d(TAG + " #" + mInstanceNumber, "No location to redirect!"); status = HttpStatus.SC_NOT_FOUND; } } - return status; - } + } - - /** + /** * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation. * * @param responseBodyAsStream InputStream with the HTTP response to exhaust. @@ -216,13 +288,15 @@ public class OwnCloudClient extends HttpClient { responseBodyAsStream.close(); } catch (IOException io) { - Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io); + Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response;" + + " will be IGNORED", io); } } } /** - * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client. + * Sets the connection and wait-for-data timeouts to be applied by default to the methods + * performed by this client. */ public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) { getParams().setSoTimeout(defaultDataTimeout); @@ -230,7 +304,8 @@ public class OwnCloudClient extends HttpClient { } /** - * Sets the Webdav URI for the helper methods that receive paths as parameters, instead of full URLs + * Sets the Webdav URI for the helper methods that receive paths as parameters, + * instead of full URLs * @param uri */ public void setWebdavUri(Uri uri) { @@ -242,7 +317,9 @@ public class OwnCloudClient extends HttpClient { } /** - * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs + * Sets the base URI for the helper methods that receive paths as parameters, + * instead of full URLs + * * @param uri */ public void setBaseUri(Uri uri) { @@ -265,4 +342,51 @@ public class OwnCloudClient extends HttpClient { mFollowRedirects = followRedirects; } + + private void logCookiesAtRequest(Header[] headers, String when) { + int counter = 0; + for (int i=0; i Date: Thu, 5 Jun 2014 17:48:53 +0200 Subject: [PATCH 03/35] Added map/pool component (in progress) for OwnCloudClient instances and removed internal dependencies on OwnCloudClientFactory#createOwnCloudClient(ACCOUNT, ...) methods --- .../android/lib/common/OwnCloudClient.java | 52 +++++++------ .../android/lib/common/OwnCloudClientMap.java | 76 +++++++++++++++++++ .../common/operations/RemoteOperation.java | 54 ++++++++++++- 3 files changed, 156 insertions(+), 26 deletions(-) create mode 100644 src/com/owncloud/android/lib/common/OwnCloudClientMap.java diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index e47de84b..86a259f3 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -126,30 +126,36 @@ public class OwnCloudClient extends HttpClient { Log.e(TAG + " #" + mInstanceNumber, "BASE URL: " + mUri); Log.e(TAG + " #" + mInstanceNumber, "WebDAV URL: " + mWebdavUri); - getParams().setAuthenticationPreemptive(false); + if (accessToken != null && accessToken.length() > 0) { - mSsoSessionCookie = accessToken; - mCredentials = null; - - Uri serverUri = (mUri != null)? mUri : mWebdavUri; - // TODO refactoring the mess of URIs - - String[] cookies = mSsoSessionCookie.split(";"); - if (cookies.length > 0) { - //Cookie[] cookies = new Cookie[cookiesStr.length]; - for (int i=0; i 0) { + //Cookie[] cookies = new Cookie[cookiesStr.length]; + for (int i=0; i mClients = + new java.util.concurrent.ConcurrentHashMap(); + + public static synchronized OwnCloudClient getClientFor(Account account, Context context) + throws OperationCanceledException, AuthenticatorException, + AccountNotFoundException, IOException { + + OwnCloudClient client = mClients.get(account); + if (client == null) { + client = OwnCloudClientFactory.createOwnCloudClient( + account, + context.getApplicationContext()); + mClients.putIfAbsent(account.name, client); + } + return client; + } + + + public static synchronized OwnCloudClient removeClientFor(Account account) { + return mClients.remove(account.name); + } + + + public static synchronized void clearPool() { + mClients.clear(); + } + +} diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index 9d453090..859dac0e 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -30,6 +30,7 @@ import org.apache.commons.httpclient.Credentials; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; +import com.owncloud.android.lib.common.OwnCloudClientMap; import com.owncloud.android.lib.common.network.BearerCredentials; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; @@ -105,7 +106,7 @@ public abstract class RemoteOperation implements Runnable { mAccount = account; mContext = context.getApplicationContext(); try { - mClient = OwnCloudClientFactory.createOwnCloudClient(mAccount, mContext); + mClient = OwnCloudClientMap.getClientFor(mAccount, mContext); } catch (Exception e) { Log.e(TAG, "Error while trying to access to " + mAccount.name, e); return new RemoteOperationResult(e); @@ -135,12 +136,17 @@ public abstract class RemoteOperation implements Runnable { * * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}. * + * @deprecated This method will be removed in version 1.0. + * Use {@link #execute(Account, Context, OnRemoteOperationListener, Handler)} + * instead. + * * @param account ownCloud account in remote ownCloud server to reach during the execution of the operation. * @param context Android context for the component calling the method. * @param listener Listener to be notified about the execution of the operation. * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called. * @return Thread were the remote operation is executed. */ + @Deprecated public Thread execute(Account account, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) { if (account == null) throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account"); @@ -161,6 +167,42 @@ public abstract class RemoteOperation implements Runnable { } + /** + * Asynchronously executes the remote operation + * + * This method should be used whenever an ownCloud account is available, + * instead of {@link #execute(OwnCloudClient, OnRemoteOperationListener, Handler))}. + * + * @param account ownCloud account in remote ownCloud server to reach during the + * execution of the operation. + * @param context Android context for the component calling the method. + * @param listener Listener to be notified about the execution of the operation. + * @param listenerHandler Handler associated to the thread where the methods of the listener + * objects must be called. + * @return Thread were the remote operation is executed. + */ + public Thread execute(Account account, Context context, OnRemoteOperationListener listener, + Handler listenerHandler) { + + if (account == null) + throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account"); + if (context == null) + throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context"); + mAccount = account; + mContext = context.getApplicationContext(); + mCallerActivity = null; + mClient = null; // the client instance will be created from mAccount and mContext in the runnerThread to create below + + mListener = listener; + + mListenerHandler = listenerHandler; + + Thread runnerThread = new Thread(this); + runnerThread.start(); + return runnerThread; + } + + /** * Asynchronously executes the remote operation * @@ -205,10 +247,13 @@ public abstract class RemoteOperation implements Runnable { try{ if (mClient == null) { if (mAccount != null && mContext != null) { + /** DEPRECATED BLOCK - will be removed at version 1.0 */ if (mCallerActivity != null) { - mClient = OwnCloudClientFactory.createOwnCloudClient(mAccount, mContext, mCallerActivity); + mClient = OwnCloudClientFactory.createOwnCloudClient( + mAccount, mContext, mCallerActivity); } else { - mClient = OwnCloudClientFactory.createOwnCloudClient(mAccount, mContext); + /** EOF DEPRECATED */ + mClient = OwnCloudClientMap.getClientFor(mAccount, mContext); } } else { throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account"); @@ -228,6 +273,8 @@ public abstract class RemoteOperation implements Runnable { result = run(mClient); repeat = false; + /** DEPRECATED BLOCK - will be removed at version 1.0 ; don't trust in this code + * to trigger authentication update */ if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() && // (result.getCode() == ResultCode.UNAUTHORIZED || (result.isTemporalRedirection() && result.isIdPRedirection()))) { (result.getCode() == ResultCode.UNAUTHORIZED || result.isIdPRedirection())) { @@ -251,6 +298,7 @@ public abstract class RemoteOperation implements Runnable { result = null; } } + /** EOF DEPRECATED BLOCK **/ } while (repeat); final RemoteOperationResult resultToSend = result; From 0cf283526820c0f056f8f5e6c1c1fcc09bb55262 Mon Sep 17 00:00:00 2001 From: masensio Date: Fri, 6 Jun 2014 12:37:03 +0200 Subject: [PATCH 04/35] Add a method clearCredentials() to OwnCloudClient --- src/com/owncloud/android/lib/common/OwnCloudClient.java | 6 ++++++ .../owncloud/android/lib/common/network/WebdavUtils.java | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index 86a259f3..caa2d707 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -159,6 +159,12 @@ public class OwnCloudClient extends HttpClient { } } + public void clearCredentials() { + mCredentials = new UsernamePasswordCredentials("", ""); + getState().clearCredentials(); + getState().clearCookies(); + mSsoSessionCookie = null; + } /** * Check if a file exists in the OC server diff --git a/src/com/owncloud/android/lib/common/network/WebdavUtils.java b/src/com/owncloud/android/lib/common/network/WebdavUtils.java index 16e70bdf..c797725a 100644 --- a/src/com/owncloud/android/lib/common/network/WebdavUtils.java +++ b/src/com/owncloud/android/lib/common/network/WebdavUtils.java @@ -28,7 +28,6 @@ package com.owncloud.android.lib.common.network; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.Locale; import android.net.Uri; From 37f4383b075dabd04a04e24ac810fa3fe8e4c670 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Mon, 9 Jun 2014 11:02:02 +0200 Subject: [PATCH 05/35] Fixed bug enforcing the creation of new OwnCloudClients unintendedly --- src/com/owncloud/android/lib/common/OwnCloudClientMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index 4edd5ff2..9c0bf19b 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -53,7 +53,7 @@ public class OwnCloudClientMap { throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, IOException { - OwnCloudClient client = mClients.get(account); + OwnCloudClient client = mClients.get(account.name); if (client == null) { client = OwnCloudClientFactory.createOwnCloudClient( account, From 811190065d31ee58c3da917d8a856c47717e478a Mon Sep 17 00:00:00 2001 From: masensio Date: Mon, 9 Jun 2014 12:24:19 +0200 Subject: [PATCH 06/35] Persistent cookies: Create saveClient in OwnCloudClientMap --- .../android/lib/common/OwnCloudClientMap.java | 15 +++++++++++++++ .../android/lib/common/accounts/AccountUtils.java | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index 9c0bf19b..cbe5cb0d 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.util.concurrent.ConcurrentMap; import android.accounts.Account; +import android.accounts.AccountManager; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; @@ -35,6 +36,7 @@ import android.content.Context; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; +import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; /** * Map for {@link OwnCloudClient} instances associated to ownCloud {@link Account}s @@ -43,9 +45,12 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundExce * * TODO consider converting into a non static object saved in the application context * @author David A. Velasco + * @author masensio */ + public class OwnCloudClientMap { + private static ConcurrentMap mClients = new java.util.concurrent.ConcurrentHashMap(); @@ -73,4 +78,14 @@ public class OwnCloudClientMap { mClients.clear(); } + public static synchronized void saveClient(Account account, Context context) { + + // Account Manager + AccountManager ac = AccountManager.get(context); + + OwnCloudClient client = mClients.get(account); + + String cookies = client.getState().getCookies().toString(); + ac.setUserData(account, Constants.KEY_COOKIES, cookies); + } } diff --git a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java index 7f0cd351..84c9a6a9 100644 --- a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -160,5 +160,9 @@ public class AccountUtils { * Flag signaling if the ownCloud server supports Share API" */ public static final String KEY_SUPPORTS_SHARE_API = "oc_supports_share_api"; + /** + * OC accout cookies + */ + public static final String KEY_COOKIES = "oc_account_cookies"; } } From b18dffe100942a4e7df8ce1615ba5a254cac8dbc Mon Sep 17 00:00:00 2001 From: masensio Date: Mon, 9 Jun 2014 15:05:44 +0200 Subject: [PATCH 07/35] Cookie to string in OwnCloudClientMap#saveClient --- .../android/lib/common/OwnCloudClientMap.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index cbe5cb0d..bb0c5bac 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -27,6 +27,8 @@ package com.owncloud.android.lib.common; import java.io.IOException; import java.util.concurrent.ConcurrentMap; +import org.apache.commons.httpclient.Cookie; + import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; @@ -83,9 +85,14 @@ public class OwnCloudClientMap { // Account Manager AccountManager ac = AccountManager.get(context); - OwnCloudClient client = mClients.get(account); + OwnCloudClient client = mClients.get(account.name); - String cookies = client.getState().getCookies().toString(); - ac.setUserData(account, Constants.KEY_COOKIES, cookies); + Cookie[] cookies =client.getState().getCookies(); + String cookiesString =""; + for (Cookie cookie: cookies) { + cookiesString = cookiesString + cookie.toString(); + } + ac.setUserData(account, Constants.KEY_COOKIES, cookiesString); + //Log.d("OwnCloudClientMap", "Saving Cookies: "+ cookiesString ); } } From 9a5b41e8030ccb9f168681c518c4fe85c885b5a8 Mon Sep 17 00:00:00 2001 From: masensio Date: Tue, 10 Jun 2014 11:03:57 +0200 Subject: [PATCH 08/35] Create saveAllClients in OwnCloudClientMap. Changes from notes in commits: 8111900 and b18dffe --- .../android/lib/common/OwnCloudClientMap.java | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index bb0c5bac..7fcfbd80 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -34,6 +34,7 @@ import android.accounts.AccountManager; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; +import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; @@ -83,16 +84,30 @@ public class OwnCloudClientMap { public static synchronized void saveClient(Account account, Context context) { // Account Manager - AccountManager ac = AccountManager.get(context); + AccountManager ac = AccountManager.get(context.getApplicationContext()); - OwnCloudClient client = mClients.get(account.name); - - Cookie[] cookies =client.getState().getCookies(); - String cookiesString =""; - for (Cookie cookie: cookies) { - cookiesString = cookiesString + cookie.toString(); + if (account!= null) { + OwnCloudClient client = mClients.get(account.name); + + Cookie[] cookies =client.getState().getCookies(); + String cookiesString =""; + for (Cookie cookie: cookies) { + cookiesString = cookiesString + cookie.toString() + ";"; + } + ac.setUserData(account, Constants.KEY_COOKIES, cookiesString); + Log.d("OwnCloudClientMap", "Saving Cookies: "+ cookiesString ); } - ac.setUserData(account, Constants.KEY_COOKIES, cookiesString); - //Log.d("OwnCloudClientMap", "Saving Cookies: "+ cookiesString ); + } + + public static synchronized void saveAllClients(Context context, String accountType) { + + // Get all accounts + Account [] accounts = AccountManager.get(context.getApplicationContext()).getAccountsByType(accountType); + + // Save cookies for all accounts + for(Account account: accounts){ + saveClient(account, context.getApplicationContext()); + } + } } From 057758671f4d3ae30bf99aed2e3c293bbc8c1943 Mon Sep 17 00:00:00 2001 From: masensio Date: Tue, 10 Jun 2014 12:00:36 +0200 Subject: [PATCH 09/35] Show cookies information in log, when saving a cookie --- .../android/lib/common/OwnCloudClientMap.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index 7fcfbd80..17a28249 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -53,6 +53,7 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; public class OwnCloudClientMap { + private static final String TAG = OwnCloudClientMap.class.getSimpleName(); private static ConcurrentMap mClients = new java.util.concurrent.ConcurrentHashMap(); @@ -81,7 +82,7 @@ public class OwnCloudClientMap { mClients.clear(); } - public static synchronized void saveClient(Account account, Context context) { + private static synchronized void saveClient(Account account, Context context) { // Account Manager AccountManager ac = AccountManager.get(context.getApplicationContext()); @@ -93,21 +94,34 @@ public class OwnCloudClientMap { String cookiesString =""; for (Cookie cookie: cookies) { cookiesString = cookiesString + cookie.toString() + ";"; + + logCookie(cookie); } ac.setUserData(account, Constants.KEY_COOKIES, cookiesString); - Log.d("OwnCloudClientMap", "Saving Cookies: "+ cookiesString ); + Log.d(TAG, "Saving Cookies: "+ cookiesString ); } } public static synchronized void saveAllClients(Context context, String accountType) { - // Get all accounts - Account [] accounts = AccountManager.get(context.getApplicationContext()).getAccountsByType(accountType); - + Account [] accounts = AccountManager.get(context.getApplicationContext()) + .getAccountsByType(accountType); // Save cookies for all accounts for(Account account: accounts){ saveClient(account, context.getApplicationContext()); } } + + private static void logCookie(Cookie cookie) { + Log.d(TAG, "Cookie name: "+ cookie.getName() ); + Log.d(TAG, " value: "+ cookie.getValue() ); + Log.d(TAG, " domain: "+ cookie.getDomain()); + Log.d(TAG, " path: "+ cookie.getPath() ); + Log.d(TAG, " version: "+ cookie.getVersion() ); + Log.d(TAG, " expiryDate: " + + (cookie.getExpiryDate() != null ? cookie.getExpiryDate().toString() : "--")); + Log.d(TAG, " comment: "+ cookie.getComment() ); + Log.d(TAG, " secure: "+ cookie.getSecure() ); + } } From b5ff057e95858f1b8a0559a4598053702adcbf0e Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Tue, 10 Jun 2014 12:48:45 +0200 Subject: [PATCH 10/35] Added method to OwnCloudClientMap to get/create new OwnCloudClients without credentials --- .../android/lib/common/OwnCloudClientMap.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index 17a28249..8ffb260e 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -35,6 +35,7 @@ import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; import android.util.Log; +import android.net.Uri; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; @@ -58,6 +59,9 @@ public class OwnCloudClientMap { private static ConcurrentMap mClients = new java.util.concurrent.ConcurrentHashMap(); + private static ConcurrentMap mAnonymousClient = + new java.util.concurrent.ConcurrentHashMap(); + public static synchronized OwnCloudClient getClientFor(Account account, Context context) throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, IOException { @@ -73,6 +77,20 @@ public class OwnCloudClientMap { } + public static synchronized OwnCloudClient getAnonymousClientFor( + Uri baseUri, Context context, boolean followRedirects) { + OwnCloudClient client = mAnonymousClient.get(baseUri.toString()); + if (client == null) { + client = OwnCloudClientFactory.createOwnCloudClient( + baseUri, + context.getApplicationContext(), + followRedirects); + mAnonymousClient.putIfAbsent(baseUri.toString(), client); + } + return client; + } + + public static synchronized OwnCloudClient removeClientFor(Account account) { return mClients.remove(account.name); } From dd0831b9fd9f1aaf2d92bb5136a0ecbd09be0436 Mon Sep 17 00:00:00 2001 From: masensio Date: Tue, 10 Jun 2014 13:05:52 +0200 Subject: [PATCH 11/35] saveClient --> public method --- src/com/owncloud/android/lib/common/OwnCloudClientMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index 8ffb260e..efb894db 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -100,7 +100,7 @@ public class OwnCloudClientMap { mClients.clear(); } - private static synchronized void saveClient(Account account, Context context) { + public static synchronized void saveClient(Account account, Context context) { // Account Manager AccountManager ac = AccountManager.get(context.getApplicationContext()); From 1b3af22b89feeaf0c09431a9afdf38dcf71f9219 Mon Sep 17 00:00:00 2001 From: masensio Date: Tue, 10 Jun 2014 13:58:14 +0200 Subject: [PATCH 12/35] Check if account.name is null in OwnCloudClientMap#saveClient --- src/com/owncloud/android/lib/common/OwnCloudClientMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index efb894db..343ce2a7 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -105,7 +105,7 @@ public class OwnCloudClientMap { // Account Manager AccountManager ac = AccountManager.get(context.getApplicationContext()); - if (account!= null) { + if (account.name != null) { OwnCloudClient client = mClients.get(account.name); Cookie[] cookies =client.getState().getCookies(); From becf4f3c13f6ec5aee9e2c4ee435ceca4cca11d3 Mon Sep 17 00:00:00 2001 From: masensio Date: Tue, 10 Jun 2014 15:22:16 +0200 Subject: [PATCH 13/35] Add cookie restore to methods OwnCloudClientFactory#createOwnCloudClient(Account ...) --- .../lib/common/OwnCloudClientFactory.java | 42 ++++++++++++++++++- .../android/lib/common/OwnCloudClientMap.java | 2 + 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java index 47c8f455..28e9ce3f 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java @@ -27,9 +27,12 @@ package com.owncloud.android.lib.common; import java.io.IOException; import java.security.GeneralSecurityException; +import org.apache.commons.httpclient.Cookie; + import com.owncloud.android.lib.common.accounts.AccountTypeUtils; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; +import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; import com.owncloud.android.lib.common.network.NetworkUtils; import android.accounts.Account; @@ -85,7 +88,7 @@ public class OwnCloudClientFactory { } else if (isSamlSso) { // TODO avoid a call to getUserData here String accessToken = am.blockingGetAuthToken(account, AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), false); client.setSsoSessionCookie(accessToken); - + } else { String username = account.name.substring(0, account.name.lastIndexOf('@')); //String password = am.getPassword(account); @@ -93,6 +96,9 @@ public class OwnCloudClientFactory { client.setBasicCredentials(username, password); } + // Restore cookies + restoreCookies(am, account, client); + return client; } @@ -130,6 +136,9 @@ public class OwnCloudClientFactory { client.setBasicCredentials(username, password); } + // Restore cookies + restoreCookies(am, account, client); + return client; } @@ -159,5 +168,34 @@ public class OwnCloudClientFactory { return client; } - + /** + * Restore the client cookies + * @param am + * @param account + * @param client + */ + private static void restoreCookies(AccountManager am, Account account, OwnCloudClient client) { + + Log.d(TAG, "Restoring cookies for " + account.name); + + Uri serverUri = (client.getBaseUri() != null)? client.getBaseUri() : client.getWebdavUri(); + + String cookiesString = am.getUserData(account, Constants.KEY_COOKIES); + if (cookiesString !=null) { + String[] cookies = cookiesString.split(";"); + if (cookies.length > 0) { + for (int i=0; i< cookies.length; i++) { + Cookie cookie = new Cookie(); + int equalPos = cookies[i].indexOf('='); + cookie.setName(cookies[i].substring(0, equalPos)); + cookie.setValue(cookies[i].substring(equalPos + 1)); + cookie.setDomain(serverUri.getHost()); // VERY IMPORTANT + cookie.setPath(serverUri.getPath()); // VERY IMPORTANT + + client.getState().addCookie(cookie); + } + } + } + + } } diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java index 343ce2a7..03d6abf7 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java @@ -124,6 +124,7 @@ public class OwnCloudClientMap { // Get all accounts Account [] accounts = AccountManager.get(context.getApplicationContext()) .getAccountsByType(accountType); + // Save cookies for all accounts for(Account account: accounts){ saveClient(account, context.getApplicationContext()); @@ -142,4 +143,5 @@ public class OwnCloudClientMap { Log.d(TAG, " comment: "+ cookie.getComment() ); Log.d(TAG, " secure: "+ cookie.getSecure() ); } + } From a42f6b5d6d7ffab813330870979e4a118ff9b1ad Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 12 Jun 2014 08:58:34 +0200 Subject: [PATCH 14/35] OwnCloudClientMap abstracted to interface OwnCloudClientManager, and provided two alternative implementations; added also OwnCloudCredentials interface to abstract all the credential types handled --- .../lib/sampleclient/MainActivity.java | 8 +- .../lib/common/OwnCloudBasicCredentials.java | 43 ++++ .../lib/common/OwnCloudBearerCredentials.java | 45 ++++ .../android/lib/common/OwnCloudClient.java | 42 ++-- .../lib/common/OwnCloudClientFactory.java | 75 ++++-- .../lib/common/OwnCloudClientManager.java | 66 ++++++ .../common/OwnCloudClientManagerFactory.java | 30 +++ .../android/lib/common/OwnCloudClientMap.java | 147 ------------ .../lib/common/OwnCloudCredentials.java | 28 +++ .../common/OwnCloudCredentialsFactory.java | 47 ++++ .../common/OwnCloudSamlSsoCredentials.java | 52 +++++ .../lib/common/SimpleFactoryManager.java | 56 +++++ .../lib/common/SingleSessionManager.java | 214 ++++++++++++++++++ .../lib/common/accounts/AccountUtils.java | 82 ++++++- .../common/operations/RemoteOperation.java | 27 +-- .../lib/test_project/TestActivity.java | 8 +- 16 files changed, 777 insertions(+), 193 deletions(-) create mode 100644 src/com/owncloud/android/lib/common/OwnCloudBasicCredentials.java create mode 100644 src/com/owncloud/android/lib/common/OwnCloudBearerCredentials.java create mode 100644 src/com/owncloud/android/lib/common/OwnCloudClientManager.java create mode 100644 src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java delete mode 100644 src/com/owncloud/android/lib/common/OwnCloudClientMap.java create mode 100644 src/com/owncloud/android/lib/common/OwnCloudCredentials.java create mode 100644 src/com/owncloud/android/lib/common/OwnCloudCredentialsFactory.java create mode 100644 src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java create mode 100644 src/com/owncloud/android/lib/common/SimpleFactoryManager.java create mode 100644 src/com/owncloud/android/lib/common/SingleSessionManager.java diff --git a/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java b/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java index 7383dc0a..8e24c15e 100644 --- a/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java +++ b/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java @@ -36,6 +36,7 @@ import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.lib.common.operations.RemoteOperation; @@ -80,7 +81,12 @@ public class MainActivity extends Activity implements OnRemoteOperationListener, Uri serverUri = Uri.parse(getString(R.string.server_base_url) + AccountUtils.WEBDAV_PATH_4_0); mClient = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true); - mClient.setBasicCredentials(getString(R.string.username), getString(R.string.password)); + mClient.setCredentials( + OwnCloudCredentialsFactory.newBasicCredentials( + getString(R.string.username), + getString(R.string.password) + ) + ); mFilesAdapter = new FilesArrayAdapter(this, R.layout.file_in_list); ((ListView)findViewById(R.id.list_view)).setAdapter(mFilesAdapter); diff --git a/src/com/owncloud/android/lib/common/OwnCloudBasicCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudBasicCredentials.java new file mode 100644 index 00000000..cb30f093 --- /dev/null +++ b/src/com/owncloud/android/lib/common/OwnCloudBasicCredentials.java @@ -0,0 +1,43 @@ +package com.owncloud.android.lib.common; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.auth.AuthPolicy; +import org.apache.commons.httpclient.auth.AuthScope; + +public class OwnCloudBasicCredentials implements OwnCloudCredentials { + + private String mUsername; + private String mPassword; + + public OwnCloudBasicCredentials(String username, String password) { + mUsername = username != null ? username : ""; + mPassword = password != null ? password : ""; + } + + @Override + public void applyTo(OwnCloudClient client) { + List authPrefs = new ArrayList(1); + authPrefs.add(AuthPolicy.BASIC); + client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); + + client.getParams().setAuthenticationPreemptive(true); + client.getState().setCredentials( + AuthScope.ANY, + new UsernamePasswordCredentials(mUsername, mPassword) + ); + } + + @Override + public String getAuthToken() { + return mPassword; + } + + @Override + public boolean authTokenExpires() { + return false; + } + +} diff --git a/src/com/owncloud/android/lib/common/OwnCloudBearerCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudBearerCredentials.java new file mode 100644 index 00000000..2a9f4515 --- /dev/null +++ b/src/com/owncloud/android/lib/common/OwnCloudBearerCredentials.java @@ -0,0 +1,45 @@ +package com.owncloud.android.lib.common; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.httpclient.auth.AuthPolicy; +import org.apache.commons.httpclient.auth.AuthScope; + +import com.owncloud.android.lib.common.network.BearerAuthScheme; +import com.owncloud.android.lib.common.network.BearerCredentials; + +public class OwnCloudBearerCredentials implements OwnCloudCredentials { + + private String mAccessToken; + + public OwnCloudBearerCredentials(String accessToken) { + mAccessToken = accessToken != null ? accessToken : ""; + } + + @Override + public void applyTo(OwnCloudClient client) { + AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class); + + List authPrefs = new ArrayList(1); + authPrefs.add(BearerAuthScheme.AUTH_POLICY); + client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); + + client.getParams().setAuthenticationPreemptive(true); + client.getState().setCredentials( + AuthScope.ANY, + new BearerCredentials(mAccessToken) + ); + } + + @Override + public String getAuthToken() { + return mAccessToken; + } + + @Override + public boolean authTokenExpires() { + return true; + } + +} diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index caa2d707..615f1b20 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -27,11 +27,8 @@ package com.owncloud.android.lib.common; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; import org.apache.commons.httpclient.Cookie; -import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpConnectionManager; @@ -40,17 +37,12 @@ import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.HttpVersion; import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthPolicy; -import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.http.HttpStatus; import org.apache.http.params.CoreProtocolPNames; -import com.owncloud.android.lib.common.network.BearerAuthScheme; -import com.owncloud.android.lib.common.network.BearerCredentials; import com.owncloud.android.lib.common.network.WebdavUtils; @@ -66,11 +58,12 @@ public class OwnCloudClient extends HttpClient { private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true; private static byte[] sExhaustBuffer = new byte[1024]; - private static int sIntanceCounter = 0; + private static int sIntanceCounter = 0; private boolean mFollowRedirects = true; - private Credentials mCredentials = null; - private String mSsoSessionCookie = null; + //private Credentials mCredentials = null; + private OwnCloudCredentials mCredentials = null; + //private String mSsoSessionCookie = null; private int mInstanceNumber = 0; private Uri mUri; @@ -97,6 +90,17 @@ public class OwnCloudClient extends HttpClient { PARAM_SINGLE_COOKIE_HEADER_VALUE); } + + public void setCredentials(OwnCloudCredentials credentials) { + if (credentials != null) { + mCredentials = credentials; + mCredentials.applyTo(this); + } else { + clearCredentials(); + } + } + + /* public void setBearerCredentials(String accessToken) { AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class); @@ -109,7 +113,9 @@ public class OwnCloudClient extends HttpClient { getState().setCredentials(AuthScope.ANY, mCredentials); mSsoSessionCookie = null; } + */ + /* public void setBasicCredentials(String username, String password) { List authPrefs = new ArrayList(1); authPrefs.add(AuthPolicy.BASIC); @@ -120,7 +126,9 @@ public class OwnCloudClient extends HttpClient { getState().setCredentials(AuthScope.ANY, mCredentials); mSsoSessionCookie = null; } + */ + /* public void setSsoSessionCookie(String accessToken) { Log.d(TAG + " #" + mInstanceNumber, "Setting session cookie: " + accessToken); Log.e(TAG + " #" + mInstanceNumber, "BASE URL: " + mUri); @@ -158,12 +166,12 @@ public class OwnCloudClient extends HttpClient { Log.e(TAG, "Setting access token " + accessToken); } } + */ public void clearCredentials() { - mCredentials = new UsernamePasswordCredentials("", ""); + mCredentials = null; getState().clearCredentials(); getState().clearCookies(); - mSsoSessionCookie = null; } /** @@ -342,13 +350,21 @@ public class OwnCloudClient extends HttpClient { return mUri; } + /* public final Credentials getCredentials() { return mCredentials; } + */ + public final OwnCloudCredentials getCredentials() { + return mCredentials; + } + + /* public final String getSsoSessionCookie() { return mSsoSessionCookie; } + */ public void setFollowRedirects(boolean followRedirects) { mFollowRedirects = followRedirects; diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java index 28e9ce3f..61ab218c 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java @@ -74,7 +74,7 @@ public class OwnCloudClientFactory { //Log_OC.d(TAG, "Creating OwnCloudClient associated to " + account.name); Uri webdavUri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account)); - Uri uri = Uri.parse(AccountUtils.constructBasicURLForAccount(appContext, account)); + Uri uri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account)); AccountManager am = AccountManager.get(appContext); boolean isOauth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2) != null; // TODO avoid calling to getUserData here boolean isSamlSso = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null; @@ -82,18 +82,37 @@ public class OwnCloudClientFactory { client.setBaseUri(uri); if (isOauth2) { - String accessToken = am.blockingGetAuthToken(account, AccountTypeUtils.getAuthTokenTypeAccessToken(account.type), false); - client.setBearerCredentials(accessToken); // TODO not assume that the access token is a bearer token + String accessToken = am.blockingGetAuthToken( + account, + AccountTypeUtils.getAuthTokenTypeAccessToken(account.type), + false); + + client.setCredentials( + OwnCloudCredentialsFactory.newBearerCredentials(accessToken) + ); } else if (isSamlSso) { // TODO avoid a call to getUserData here - String accessToken = am.blockingGetAuthToken(account, AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), false); - client.setSsoSessionCookie(accessToken); + String accessToken = am.blockingGetAuthToken( + account, + AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), + false); + + client.setCredentials( + OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken) + ); } else { String username = account.name.substring(0, account.name.lastIndexOf('@')); //String password = am.getPassword(account); - String password = am.blockingGetAuthToken(account, AccountTypeUtils.getAuthTokenTypePass(account.type), false); - client.setBasicCredentials(username, password); + String password = am.blockingGetAuthToken( + account, + AccountTypeUtils.getAuthTokenTypePass(account.type), + false); + + client.setCredentials( + OwnCloudCredentialsFactory.newBasicCredentials(username, password) + ); + } // Restore cookies @@ -105,7 +124,7 @@ public class OwnCloudClientFactory { public static OwnCloudClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException { Uri webdavUri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account)); - Uri uri = Uri.parse(AccountUtils.constructBasicURLForAccount(appContext, account)); + Uri uri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account)); AccountManager am = AccountManager.get(appContext); boolean isOauth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2) != null; // TODO avoid calling to getUserData here boolean isSamlSso = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null; @@ -113,27 +132,55 @@ public class OwnCloudClientFactory { client.setBaseUri(uri); if (isOauth2) { // TODO avoid a call to getUserData here - AccountManagerFuture future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypeAccessToken(account.type), null, currentActivity, null, null); + AccountManagerFuture future = am.getAuthToken( + account, + AccountTypeUtils.getAuthTokenTypeAccessToken(account.type), + null, + currentActivity, + null, + null); + Bundle result = future.getResult(); String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN); if (accessToken == null) throw new AuthenticatorException("WTF!"); - client.setBearerCredentials(accessToken); // TODO not assume that the access token is a bearer token + client.setCredentials( + OwnCloudCredentialsFactory.newBearerCredentials(accessToken) + ); } else if (isSamlSso) { // TODO avoid a call to getUserData here - AccountManagerFuture future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), null, currentActivity, null, null); + AccountManagerFuture future = am.getAuthToken( + account, + AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), + null, + currentActivity, + null, + null); + Bundle result = future.getResult(); String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN); if (accessToken == null) throw new AuthenticatorException("WTF!"); - client.setSsoSessionCookie(accessToken); + client.setCredentials( + OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken) + ); + } else { String username = account.name.substring(0, account.name.lastIndexOf('@')); //String password = am.getPassword(account); //String password = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypePass(), false); - AccountManagerFuture future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypePass(account.type), null, currentActivity, null, null); + AccountManagerFuture future = am.getAuthToken( + account, + AccountTypeUtils.getAuthTokenTypePass(account.type), + null, + currentActivity, + null, + null); + Bundle result = future.getResult(); String password = result.getString(AccountManager.KEY_AUTHTOKEN); - client.setBasicCredentials(username, password); + client.setCredentials( + OwnCloudCredentialsFactory.newBasicCredentials(username, password) + ); } // Restore cookies diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java new file mode 100644 index 00000000..5372a272 --- /dev/null +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java @@ -0,0 +1,66 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common; + +import java.io.IOException; + +import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.Context; +import android.net.Uri; + +import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; + + +/** + * Manager to create and reuse OwnCloudClient instances to access remote OC servers. + * + * @author David A. Velasco + * @author masensio + */ + +public interface OwnCloudClientManager { + + public OwnCloudClient getClientFor(Account savedAccount, Context context) + throws AccountNotFoundException, AuthenticatorException, + IOException, OperationCanceledException; + + public OwnCloudClient getClientFor( + Uri serverBaseUri, OwnCloudCredentials credentials, Context context); + + public void saveClient(Account savedAccount, Context context) + throws AccountNotFoundException, AuthenticatorException, + IOException, OperationCanceledException; + + public void saveAllClients(Context context, String accountType) + throws AccountNotFoundException, AuthenticatorException, + IOException, OperationCanceledException; + + public OwnCloudClient removeClientFor(Account account, Context context) + throws AccountNotFoundException, AuthenticatorException, + IOException, OperationCanceledException; + +} diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java new file mode 100644 index 00000000..78b6858e --- /dev/null +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -0,0 +1,30 @@ +package com.owncloud.android.lib.common; + +public class OwnCloudClientManagerFactory { + + public static enum Policy { + ALWAYS_NEW_CLIENT, + SINGLE_SESSION_PER_ACCOUNT + } + + public final static Policy DEFAULT_POLICY = Policy.ALWAYS_NEW_CLIENT; + + public static OwnCloudClientManager newDefaultOwnCloudClientManager() { + return newOwnCloudClientManager(DEFAULT_POLICY); + } + + public static OwnCloudClientManager newOwnCloudClientManager(Policy policy) { + switch (policy) { + case ALWAYS_NEW_CLIENT: + return new SingleSessionManager(); + + case SINGLE_SESSION_PER_ACCOUNT: + return new SimpleFactoryManager(); + + default: + throw new IllegalArgumentException("Unknown policy"); + } + } + + +} diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java b/src/com/owncloud/android/lib/common/OwnCloudClientMap.java deleted file mode 100644 index 03d6abf7..00000000 --- a/src/com/owncloud/android/lib/common/OwnCloudClientMap.java +++ /dev/null @@ -1,147 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2014 ownCloud Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package com.owncloud.android.lib.common; - -import java.io.IOException; -import java.util.concurrent.ConcurrentMap; - -import org.apache.commons.httpclient.Cookie; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.Context; -import android.util.Log; -import android.net.Uri; - -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.OwnCloudClientFactory; -import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; -import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; - -/** - * Map for {@link OwnCloudClient} instances associated to ownCloud {@link Account}s - * - * TODO check synchronization - * - * TODO consider converting into a non static object saved in the application context - * @author David A. Velasco - * @author masensio - */ - -public class OwnCloudClientMap { - - private static final String TAG = OwnCloudClientMap.class.getSimpleName(); - - private static ConcurrentMap mClients = - new java.util.concurrent.ConcurrentHashMap(); - - private static ConcurrentMap mAnonymousClient = - new java.util.concurrent.ConcurrentHashMap(); - - public static synchronized OwnCloudClient getClientFor(Account account, Context context) - throws OperationCanceledException, AuthenticatorException, - AccountNotFoundException, IOException { - - OwnCloudClient client = mClients.get(account.name); - if (client == null) { - client = OwnCloudClientFactory.createOwnCloudClient( - account, - context.getApplicationContext()); - mClients.putIfAbsent(account.name, client); - } - return client; - } - - - public static synchronized OwnCloudClient getAnonymousClientFor( - Uri baseUri, Context context, boolean followRedirects) { - OwnCloudClient client = mAnonymousClient.get(baseUri.toString()); - if (client == null) { - client = OwnCloudClientFactory.createOwnCloudClient( - baseUri, - context.getApplicationContext(), - followRedirects); - mAnonymousClient.putIfAbsent(baseUri.toString(), client); - } - return client; - } - - - public static synchronized OwnCloudClient removeClientFor(Account account) { - return mClients.remove(account.name); - } - - - public static synchronized void clearPool() { - mClients.clear(); - } - - public static synchronized void saveClient(Account account, Context context) { - - // Account Manager - AccountManager ac = AccountManager.get(context.getApplicationContext()); - - if (account.name != null) { - OwnCloudClient client = mClients.get(account.name); - - Cookie[] cookies =client.getState().getCookies(); - String cookiesString =""; - for (Cookie cookie: cookies) { - cookiesString = cookiesString + cookie.toString() + ";"; - - logCookie(cookie); - } - ac.setUserData(account, Constants.KEY_COOKIES, cookiesString); - Log.d(TAG, "Saving Cookies: "+ cookiesString ); - } - } - - public static synchronized void saveAllClients(Context context, String accountType) { - // Get all accounts - Account [] accounts = AccountManager.get(context.getApplicationContext()) - .getAccountsByType(accountType); - - // Save cookies for all accounts - for(Account account: accounts){ - saveClient(account, context.getApplicationContext()); - } - - } - - private static void logCookie(Cookie cookie) { - Log.d(TAG, "Cookie name: "+ cookie.getName() ); - Log.d(TAG, " value: "+ cookie.getValue() ); - Log.d(TAG, " domain: "+ cookie.getDomain()); - Log.d(TAG, " path: "+ cookie.getPath() ); - Log.d(TAG, " version: "+ cookie.getVersion() ); - Log.d(TAG, " expiryDate: " + - (cookie.getExpiryDate() != null ? cookie.getExpiryDate().toString() : "--")); - Log.d(TAG, " comment: "+ cookie.getComment() ); - Log.d(TAG, " secure: "+ cookie.getSecure() ); - } - -} diff --git a/src/com/owncloud/android/lib/common/OwnCloudCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudCredentials.java new file mode 100644 index 00000000..deba8177 --- /dev/null +++ b/src/com/owncloud/android/lib/common/OwnCloudCredentials.java @@ -0,0 +1,28 @@ +/* ownCloud Android client application + * Copyright (C) 2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.lib.common; + +public interface OwnCloudCredentials { + + public void applyTo(OwnCloudClient ownCloudClient); + + public String getAuthToken(); + + public boolean authTokenExpires(); + +} diff --git a/src/com/owncloud/android/lib/common/OwnCloudCredentialsFactory.java b/src/com/owncloud/android/lib/common/OwnCloudCredentialsFactory.java new file mode 100644 index 00000000..45ee53de --- /dev/null +++ b/src/com/owncloud/android/lib/common/OwnCloudCredentialsFactory.java @@ -0,0 +1,47 @@ +package com.owncloud.android.lib.common; + +public class OwnCloudCredentialsFactory { + + private static OwnCloudAnonymousCredentials sAnonymousCredentials; + + public static OwnCloudCredentials newBasicCredentials(String username, String password) { + return new OwnCloudBasicCredentials(username, password); + } + + public static OwnCloudCredentials newBearerCredentials(String authToken) { + return new OwnCloudBearerCredentials(authToken); + } + + public static OwnCloudCredentials newSamlSsoCredentials(String sessionCookie) { + return new OwnCloudSamlSsoCredentials(sessionCookie); + } + + public static final OwnCloudCredentials getAnonymousCredentials() { + if (sAnonymousCredentials == null) { + sAnonymousCredentials = new OwnCloudAnonymousCredentials(); + } + return sAnonymousCredentials; + } + + public static final class OwnCloudAnonymousCredentials implements OwnCloudCredentials { + + protected OwnCloudAnonymousCredentials() { + } + + @Override + public void applyTo(OwnCloudClient client) { + client.clearCredentials(); + } + + @Override + public String getAuthToken() { + return ""; + } + + @Override + public boolean authTokenExpires() { + return false; + } + } + +} diff --git a/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java new file mode 100644 index 00000000..a50d3177 --- /dev/null +++ b/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java @@ -0,0 +1,52 @@ +package com.owncloud.android.lib.common; + +import org.apache.commons.httpclient.Cookie; +import org.apache.commons.httpclient.cookie.CookiePolicy; + +import android.net.Uri; + +public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials { + + private String mSessionCookie; + + public OwnCloudSamlSsoCredentials(String sessionCookie) { + mSessionCookie = sessionCookie != null ? mSessionCookie : ""; + } + + @Override + public void applyTo(OwnCloudClient client) { + client.getParams().setAuthenticationPreemptive(false); + client.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES); + client.setFollowRedirects(false); + + Uri serverUri = client.getBaseUri(); + if (serverUri == null) { + // TODO fix the mess of Uris in OwnCloudClient + serverUri = client.getWebdavUri(); + } + + String[] cookies = mSessionCookie.split(";"); + if (cookies.length > 0) { + for (int i=0; i> mClientsPerServer = + new HashMap>(); + + + public static OwnCloudClientManager getInstance() { + if (mInstance == null) { + mInstance = new SingleSessionManager(); + } + return mInstance ; + } + + + @Override + public synchronized OwnCloudClient getClientFor(Account savedAccount, Context context) + throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, + IOException { + + Uri serverBaseUri = + Uri.parse(AccountUtils.getBaseUrlForAccount(context, savedAccount)); + + OwnCloudCredentials credentials = + AccountUtils.getCredentialsForAccount(context, savedAccount); + + return getClientFor(serverBaseUri, credentials, context); + + } + + + @Override + public synchronized OwnCloudClient getClientFor( + Uri serverBaseUri, OwnCloudCredentials credentials, Context context) { + + Map clientsPerAccount = + mClientsPerServer.get(serverBaseUri.toString()); + + if (clientsPerAccount == null) { + clientsPerAccount = new HashMap(); + mClientsPerServer.put( + serverBaseUri.toString(), + clientsPerAccount); + } + + if (credentials == null) { + credentials = OwnCloudCredentialsFactory.getAnonymousCredentials(); + } + + /// TODO - CRITERIA FOR MATCH OF KEYS!!! + OwnCloudClient client = clientsPerAccount.get(credentials); + if (client == null) { + client = OwnCloudClientFactory.createOwnCloudClient( + serverBaseUri, + context.getApplicationContext(), + true); + + client.setCredentials(credentials); + clientsPerAccount.put(credentials, client); + } + + return client; + } + + + @Override + public synchronized OwnCloudClient removeClientFor(Account savedAccount, Context context) + throws AccountNotFoundException, OperationCanceledException, AuthenticatorException, IOException { + + Uri serverBaseUri = + Uri.parse(AccountUtils.getBaseUrlForAccount(context, savedAccount)); + + Map clientsPerAccount = + mClientsPerServer.get(serverBaseUri.toString()); + + if (clientsPerAccount != null) { + OwnCloudCredentials credentials = + AccountUtils.getCredentialsForAccount(context, savedAccount); + + return clientsPerAccount.remove(credentials); + } + return null; + } + + + @Override + public synchronized void saveClient(Account savedAccount, Context context) + throws AccountNotFoundException, AuthenticatorException, IOException, + OperationCanceledException { + + // Account Manager + AccountManager ac = AccountManager.get(context.getApplicationContext()); + + if (savedAccount != null) { + Uri serverBaseUri = + Uri.parse(AccountUtils.getBaseUrlForAccount(context, savedAccount)); + + Map clientsPerAccount = + mClientsPerServer.get(serverBaseUri.toString()); + + if (clientsPerAccount != null) { + OwnCloudCredentials credentials = + AccountUtils.getCredentialsForAccount(context, savedAccount); + + /// TODO - CRITERIA FOR MATCH OF KEYS!!! + OwnCloudClient client = clientsPerAccount.get(credentials); + + if (client != null) { + + Cookie[] cookies = client.getState().getCookies(); + String cookiesString =""; + for (Cookie cookie: cookies) { + cookiesString = cookiesString + cookie.toString() + ";"; + + logCookie(cookie); + } + ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString); + Log.d(TAG, "Saving Cookies: "+ cookiesString ); + } + } + } + + } + + @Override + public synchronized void saveAllClients(Context context, String accountType) + throws AccountNotFoundException, AuthenticatorException, IOException, + OperationCanceledException { + + // Get all accounts + Account [] accounts = AccountManager.get(context.getApplicationContext()) + .getAccountsByType(accountType); + + // Save cookies for all accounts + for(Account account: accounts){ + saveClient(account, context.getApplicationContext()); + } + + } + + private void logCookie(Cookie cookie) { + Log.d(TAG, "Cookie name: "+ cookie.getName() ); + Log.d(TAG, " value: "+ cookie.getValue() ); + Log.d(TAG, " domain: "+ cookie.getDomain()); + Log.d(TAG, " path: "+ cookie.getPath() ); + Log.d(TAG, " version: "+ cookie.getVersion() ); + Log.d(TAG, " expiryDate: " + + (cookie.getExpiryDate() != null ? cookie.getExpiryDate().toString() : "--")); + Log.d(TAG, " comment: "+ cookie.getComment() ); + Log.d(TAG, " secure: "+ cookie.getSecure() ); + } + + +} diff --git a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java index 84c9a6a9..8fddc4e6 100644 --- a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -25,11 +25,17 @@ package com.owncloud.android.lib.common.accounts; +import java.io.IOException; + +import com.owncloud.android.lib.common.OwnCloudCredentials; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; import com.owncloud.android.lib.resources.status.OwnCloudVersion; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountsException; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; import android.content.Context; public class AccountUtils { @@ -94,13 +100,32 @@ public class AccountUtils { /** * Extracts url server from the account + * + * @deprecated This method will be removed in version 1.0. + * Use {@link #getBaseUrlForAccount(Context, Account)} + * instead. + * * @param context * @param account * @return url server or null on failure * @throws AccountNotFoundException When 'account' is unknown for the AccountManager */ - public static String constructBasicURLForAccount(Context context, Account account) throws AccountNotFoundException { - AccountManager ama = AccountManager.get(context); + @Deprecated + public static String constructBasicURLForAccount(Context context, Account account) + throws AccountNotFoundException { + return getBaseUrlForAccount(context, account); + } + + /** + * Extracts url server from the account + * @param context + * @param account + * @return url server or null on failure + * @throws AccountNotFoundException When 'account' is unknown for the AccountManager + */ + public static String getBaseUrlForAccount(Context context, Account account) + throws AccountNotFoundException { + AccountManager ama = AccountManager.get(context.getApplicationContext()); String baseurl = ama.getUserData(account, Constants.KEY_OC_BASE_URL); if (baseurl == null ) @@ -109,6 +134,58 @@ public class AccountUtils { return baseurl; } + + /** + * + * @return + * @throws IOException + * @throws AuthenticatorException + * @throws OperationCanceledException + */ + public static OwnCloudCredentials getCredentialsForAccount(Context context, Account account) + throws OperationCanceledException, AuthenticatorException, IOException { + + OwnCloudCredentials credentials = null; + AccountManager am = AccountManager.get(context); + + boolean isOauth2 = am.getUserData( + account, + AccountUtils.Constants.KEY_SUPPORTS_OAUTH2) != null; + + boolean isSamlSso = am.getUserData( + account, + AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null; + + if (isOauth2) { + String accessToken = am.blockingGetAuthToken( + account, + AccountTypeUtils.getAuthTokenTypeAccessToken(account.type), + false); + + credentials = OwnCloudCredentialsFactory.newBearerCredentials(accessToken); + + } else if (isSamlSso) { + String accessToken = am.blockingGetAuthToken( + account, + AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), + false); + + credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(accessToken); + + } else { + String username = account.name.substring(0, account.name.lastIndexOf('@')); + String password = am.blockingGetAuthToken( + account, + AccountTypeUtils.getAuthTokenTypePass(account.type), + false); + + credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password); + } + + return credentials; + + } + public static class AccountNotFoundException extends AccountsException { @@ -165,4 +242,5 @@ public class AccountUtils { */ public static final String KEY_COOKIES = "oc_account_cookies"; } + } diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index 859dac0e..fa89b24b 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -26,12 +26,10 @@ package com.owncloud.android.lib.common.operations; import java.io.IOException; -import org.apache.commons.httpclient.Credentials; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; -import com.owncloud.android.lib.common.OwnCloudClientMap; -import com.owncloud.android.lib.common.network.BearerCredentials; +import com.owncloud.android.lib.common.OwnCloudCredentials; +import com.owncloud.android.lib.common.SingleSessionManager; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; @@ -106,7 +104,7 @@ public abstract class RemoteOperation implements Runnable { mAccount = account; mContext = context.getApplicationContext(); try { - mClient = OwnCloudClientMap.getClientFor(mAccount, mContext); + mClient = SingleSessionManager.getInstance().getClientFor(mAccount, mContext); } catch (Exception e) { Log.e(TAG, "Error while trying to access to " + mAccount.name, e); return new RemoteOperationResult(e); @@ -253,7 +251,8 @@ public abstract class RemoteOperation implements Runnable { mAccount, mContext, mCallerActivity); } else { /** EOF DEPRECATED */ - mClient = OwnCloudClientMap.getClientFor(mAccount, mContext); + mClient = SingleSessionManager.getInstance(). + getClientFor(mAccount, mContext); } } else { throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account"); @@ -279,17 +278,15 @@ public abstract class RemoteOperation implements Runnable { // (result.getCode() == ResultCode.UNAUTHORIZED || (result.isTemporalRedirection() && result.isIdPRedirection()))) { (result.getCode() == ResultCode.UNAUTHORIZED || result.isIdPRedirection())) { /// possible fail due to lack of authorization in an operation performed in foreground - Credentials cred = mClient.getCredentials(); - String ssoSessionCookie = mClient.getSsoSessionCookie(); - if (cred != null || ssoSessionCookie != null) { + OwnCloudCredentials cred = mClient.getCredentials(); + if (cred != null) { /// confirmed : unauthorized operation AccountManager am = AccountManager.get(mContext); - boolean bearerAuthorization = (cred != null && cred instanceof BearerCredentials); - boolean samlBasedSsoAuthorization = (cred == null && ssoSessionCookie != null); - if (bearerAuthorization) { - am.invalidateAuthToken(mAccount.type, ((BearerCredentials)cred).getAccessToken()); - } else if (samlBasedSsoAuthorization ) { - am.invalidateAuthToken(mAccount.type, ssoSessionCookie); + if (cred.authTokenExpires()) { + am.invalidateAuthToken( + mAccount.type, + cred.getAuthToken() + ); } else { am.clearPassword(mAccount); } diff --git a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java index 65771dab..1b5eefe4 100644 --- a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java +++ b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java @@ -35,6 +35,7 @@ import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.lib.common.network.NetworkUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult; @@ -113,7 +114,12 @@ public class TestActivity extends Activity { OwnCloudClientFactory.DEFAULT_CONNECTION_TIMEOUT); mClient.setWebdavUri(uri); mClient.setFollowRedirects(true); - mClient.setBasicCredentials(mUser, mPass); + mClient.setCredentials( + OwnCloudCredentialsFactory.newBasicCredentials( + mUser, + mPass + ) + ); mClient.setBaseUri(Uri.parse(mServerUri)); Log.v(TAG, "onCreate finished, ownCloud client ready"); From e7a0e30a2773a4de694e37b3f8882db158b137cd Mon Sep 17 00:00:00 2001 From: masensio Date: Thu, 12 Jun 2014 11:07:49 +0200 Subject: [PATCH 15/35] Add getCookiesString method in OwnCloudClient --- .../android/lib/common/OwnCloudClient.java | 25 +++++++++++++++++ .../lib/common/SingleSessionManager.java | 27 ++++--------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index 615f1b20..521e68ba 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -415,6 +415,31 @@ public class OwnCloudClient extends HttpClient { } } + + public String getCookiesString(){ + Cookie[] cookies = getState().getCookies(); + String cookiesString =""; + for (Cookie cookie: cookies) { + cookiesString = cookiesString + cookie.toString() + ";"; + + logCookie(cookie); + } + + return cookiesString; + + } + + private void logCookie(Cookie cookie) { + Log.d(TAG, "Cookie name: "+ cookie.getName() ); + Log.d(TAG, " value: "+ cookie.getValue() ); + Log.d(TAG, " domain: "+ cookie.getDomain()); + Log.d(TAG, " path: "+ cookie.getPath() ); + Log.d(TAG, " version: "+ cookie.getVersion() ); + Log.d(TAG, " expiryDate: " + + (cookie.getExpiryDate() != null ? cookie.getExpiryDate().toString() : "--")); + Log.d(TAG, " comment: "+ cookie.getComment() ); + Log.d(TAG, " secure: "+ cookie.getSecure() ); + } } diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index 4c636513..d1bea6ec 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -166,16 +166,11 @@ public class SingleSessionManager implements OwnCloudClientManager { OwnCloudClient client = clientsPerAccount.get(credentials); if (client != null) { - - Cookie[] cookies = client.getState().getCookies(); - String cookiesString =""; - for (Cookie cookie: cookies) { - cookiesString = cookiesString + cookie.toString() + ";"; - - logCookie(cookie); - } - ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString); - Log.d(TAG, "Saving Cookies: "+ cookiesString ); + String cookiesString = client.getCookiesString(); + if (cookiesString != "") { + ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString); + Log.d(TAG, "Saving Cookies: "+ cookiesString ); + } } } } @@ -197,18 +192,6 @@ public class SingleSessionManager implements OwnCloudClientManager { } } - - private void logCookie(Cookie cookie) { - Log.d(TAG, "Cookie name: "+ cookie.getName() ); - Log.d(TAG, " value: "+ cookie.getValue() ); - Log.d(TAG, " domain: "+ cookie.getDomain()); - Log.d(TAG, " path: "+ cookie.getPath() ); - Log.d(TAG, " version: "+ cookie.getVersion() ); - Log.d(TAG, " expiryDate: " + - (cookie.getExpiryDate() != null ? cookie.getExpiryDate().toString() : "--")); - Log.d(TAG, " comment: "+ cookie.getComment() ); - Log.d(TAG, " secure: "+ cookie.getSecure() ); - } } From 44f5337a5019ff949fd230d471ac814b738e98ce Mon Sep 17 00:00:00 2001 From: masensio Date: Thu, 12 Jun 2014 15:43:53 +0200 Subject: [PATCH 16/35] Move responsibility of saving cookies from OwnCloudClientManager#saveClient(Account, Context) to AccountUtils#saveClient(Account , Context) --- .../lib/common/OwnCloudClientManager.java | 4 -- .../lib/common/SimpleFactoryManager.java | 5 -- .../lib/common/SingleSessionManager.java | 66 +++++++------------ .../lib/common/accounts/AccountUtils.java | 22 ++++++- .../common/operations/RemoteOperation.java | 3 + 5 files changed, 45 insertions(+), 55 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java index 5372a272..c2bd0bf5 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java @@ -51,10 +51,6 @@ public interface OwnCloudClientManager { public OwnCloudClient getClientFor( Uri serverBaseUri, OwnCloudCredentials credentials, Context context); - public void saveClient(Account savedAccount, Context context) - throws AccountNotFoundException, AuthenticatorException, - IOException, OperationCanceledException; - public void saveAllClients(Context context, String accountType) throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException; diff --git a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java index fb7a0849..e37ff4c8 100644 --- a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java +++ b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java @@ -36,11 +36,6 @@ public class SimpleFactoryManager implements OwnCloudClientManager { return client; } - @Override - public void saveClient(Account savedAccount, Context context) { - // TODO Auto-generated method stub - } - @Override public void saveAllClients(Context context, String accountType) { // TODO Auto-generated method stub diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index d1bea6ec..f8fe97cd 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -28,21 +28,17 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; -import org.apache.commons.httpclient.Cookie; - import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; -import android.util.Log; import android.net.Uri; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; -import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; /** * Implementation of {@link OwnCloudClientManager} @@ -57,7 +53,7 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; public class SingleSessionManager implements OwnCloudClientManager { - private static final String TAG = SingleSessionManager.class.getSimpleName(); + //private static final String TAG = SingleSessionManager.class.getSimpleName(); private static OwnCloudClientManager mInstance = null; @@ -144,54 +140,36 @@ public class SingleSessionManager implements OwnCloudClientManager { @Override - public synchronized void saveClient(Account savedAccount, Context context) - throws AccountNotFoundException, AuthenticatorException, IOException, + public synchronized void saveAllClients(Context context, String accountType) + throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException { - - // Account Manager - AccountManager ac = AccountManager.get(context.getApplicationContext()); - - if (savedAccount != null) { - Uri serverBaseUri = - Uri.parse(AccountUtils.getBaseUrlForAccount(context, savedAccount)); - + + // Get all accounts + Account [] accounts = AccountManager.get(context.getApplicationContext()) + .getAccountsByType(accountType); + + // Save cookies for all accounts + for(Account account: accounts){ + + Uri serverBaseUri = + Uri.parse(AccountUtils.getBaseUrlForAccount(context, account)); + Map clientsPerAccount = mClientsPerServer.get(serverBaseUri.toString()); if (clientsPerAccount != null) { - OwnCloudCredentials credentials = - AccountUtils.getCredentialsForAccount(context, savedAccount); - - /// TODO - CRITERIA FOR MATCH OF KEYS!!! - OwnCloudClient client = clientsPerAccount.get(credentials); - - if (client != null) { - String cookiesString = client.getCookiesString(); - if (cookiesString != "") { - ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString); - Log.d(TAG, "Saving Cookies: "+ cookiesString ); - } - } + OwnCloudCredentials credentials = + AccountUtils.getCredentialsForAccount(context, account); + + /// TODO - CRITERIA FOR MATCH OF KEYS!!! + OwnCloudClient client = clientsPerAccount.get(credentials); + if (client != null) { + AccountUtils.saveClient(client, account, context.getApplicationContext()); + } } } } - - @Override - public synchronized void saveAllClients(Context context, String accountType) - throws AccountNotFoundException, AuthenticatorException, IOException, - OperationCanceledException { - - // Get all accounts - Account [] accounts = AccountManager.get(context.getApplicationContext()) - .getAccountsByType(accountType); - - // Save cookies for all accounts - for(Account account: accounts){ - saveClient(account, context.getApplicationContext()); - } - - } } diff --git a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java index 8fddc4e6..58f422cd 100644 --- a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -26,7 +26,7 @@ package com.owncloud.android.lib.common.accounts; import java.io.IOException; - +import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudCredentials; import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; import com.owncloud.android.lib.resources.status.OwnCloudVersion; @@ -37,6 +37,7 @@ import android.accounts.AccountsException; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; +import android.util.Log; public class AccountUtils { public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php"; @@ -186,7 +187,24 @@ public class AccountUtils { } - + + public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) { + + // Account Manager + AccountManager ac = AccountManager.get(context.getApplicationContext()); + + if (client != null) { + String cookiesString = client.getCookiesString(); + if (cookiesString != "") { + ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString); + Log.d("AccountUtils", "Saving Cookies: "+ cookiesString ); + } + } + + } + + + public static class AccountNotFoundException extends AccountsException { /** Generated - should be refreshed every time the class changes!! */ diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index fa89b24b..16d24585 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -30,6 +30,7 @@ import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudCredentials; import com.owncloud.android.lib.common.SingleSessionManager; +import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; @@ -254,6 +255,8 @@ public abstract class RemoteOperation implements Runnable { mClient = SingleSessionManager.getInstance(). getClientFor(mAccount, mContext); } + // Save Client Cookies + AccountUtils.saveClient(mClient, mAccount, mContext); } else { throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account"); } From e069a8cb9f4f874ee91d7c012c083899556378e9 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 12 Jun 2014 16:36:24 +0200 Subject: [PATCH 17/35] Added OwnCloudAccount class and method OwnCloudSessionManager#gertClientFor(OwnCloudAccount, ...) to ease the reuse of OwnCloudClient instances after creating accounts with authentication based in external authentication providers --- .../android/lib/common/OwnCloudAccount.java | 95 +++++++++++++++++++ .../lib/common/OwnCloudBasicCredentials.java | 5 + .../lib/common/OwnCloudBearerCredentials.java | 8 +- .../lib/common/OwnCloudClientManager.java | 2 + .../lib/common/OwnCloudCredentials.java | 2 + .../common/OwnCloudCredentialsFactory.java | 6 ++ .../common/OwnCloudSamlSsoCredentials.java | 6 ++ .../lib/common/SimpleFactoryManager.java | 12 +++ .../lib/common/SingleSessionManager.java | 52 +++++++++- .../lib/common/accounts/AccountUtils.java | 10 ++ 10 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 src/com/owncloud/android/lib/common/OwnCloudAccount.java diff --git a/src/com/owncloud/android/lib/common/OwnCloudAccount.java b/src/com/owncloud/android/lib/common/OwnCloudAccount.java new file mode 100644 index 00000000..ff0cf3dd --- /dev/null +++ b/src/com/owncloud/android/lib/common/OwnCloudAccount.java @@ -0,0 +1,95 @@ +/* ownCloud Android client application + * Copyright (C) 2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.lib.common; + + +import java.io.IOException; + +import com.owncloud.android.lib.common.accounts.AccountUtils; +import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; + +import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.Context; +import android.net.Uri; + +/** + * OwnCloud Account + * + * @author David A. Velasco + */ +public class OwnCloudAccount { + + private Uri mBaseUri; + + private OwnCloudCredentials mCredentials; + + private String mSavedAccountName; + + + public OwnCloudAccount(Account savedAccount, Context context) + throws AccountNotFoundException, AuthenticatorException, + IOException, OperationCanceledException { + + if (savedAccount == null) { + throw new IllegalArgumentException("Parameter 'savedAccount' cannot be null"); + } + if (context == null) { + throw new IllegalArgumentException("Parameter 'context' cannot be null"); + } + + mSavedAccountName = savedAccount.name; + mBaseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(context, savedAccount)); + mCredentials = AccountUtils.getCredentialsForAccount(context, savedAccount); + } + + + public OwnCloudAccount(Uri baseUri, OwnCloudCredentials credentials) { + if (baseUri == null) { + throw new IllegalArgumentException("Parameter 'baseUri' cannot be null"); + } + mSavedAccountName = null; + mBaseUri = baseUri; + mCredentials = credentials != null ? + credentials : OwnCloudCredentialsFactory.getAnonymousCredentials(); + String username = credentials.getUsername(); + if (username != null) { + mSavedAccountName = AccountUtils.buildAccountName(mBaseUri, username); + } + } + + + public boolean isAnonymous() { + return (mCredentials == null); + } + + public Uri getBaseUri() { + return mBaseUri; + } + + public OwnCloudCredentials getCredentials() { + return mCredentials; + } + + public String getName() { + return mSavedAccountName; + } + + +} \ No newline at end of file diff --git a/src/com/owncloud/android/lib/common/OwnCloudBasicCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudBasicCredentials.java index cb30f093..6855cfc4 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudBasicCredentials.java +++ b/src/com/owncloud/android/lib/common/OwnCloudBasicCredentials.java @@ -30,6 +30,11 @@ public class OwnCloudBasicCredentials implements OwnCloudCredentials { ); } + @Override + public String getUsername() { + return mUsername; + } + @Override public String getAuthToken() { return mPassword; diff --git a/src/com/owncloud/android/lib/common/OwnCloudBearerCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudBearerCredentials.java index 2a9f4515..fb6f2018 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudBearerCredentials.java +++ b/src/com/owncloud/android/lib/common/OwnCloudBearerCredentials.java @@ -32,6 +32,12 @@ public class OwnCloudBearerCredentials implements OwnCloudCredentials { ); } + @Override + public String getUsername() { + // its unknown + return null; + } + @Override public String getAuthToken() { return mAccessToken; @@ -41,5 +47,5 @@ public class OwnCloudBearerCredentials implements OwnCloudCredentials { public boolean authTokenExpires() { return true; } - + } diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java index 5372a272..7e8a9024 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java @@ -62,5 +62,7 @@ public interface OwnCloudClientManager { public OwnCloudClient removeClientFor(Account account, Context context) throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException; + + public OwnCloudClient getClientFor(OwnCloudAccount account, Context context); } diff --git a/src/com/owncloud/android/lib/common/OwnCloudCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudCredentials.java index deba8177..a3fff2eb 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudCredentials.java +++ b/src/com/owncloud/android/lib/common/OwnCloudCredentials.java @@ -21,6 +21,8 @@ public interface OwnCloudCredentials { public void applyTo(OwnCloudClient ownCloudClient); + public String getUsername(); + public String getAuthToken(); public boolean authTokenExpires(); diff --git a/src/com/owncloud/android/lib/common/OwnCloudCredentialsFactory.java b/src/com/owncloud/android/lib/common/OwnCloudCredentialsFactory.java index 45ee53de..951b4ae3 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudCredentialsFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudCredentialsFactory.java @@ -42,6 +42,12 @@ public class OwnCloudCredentialsFactory { public boolean authTokenExpires() { return false; } + + @Override + public String getUsername() { + // no user name + return null; + } } } diff --git a/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java index a50d3177..78c96bfa 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java +++ b/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java @@ -39,6 +39,12 @@ public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials { } } + @Override + public String getUsername() { + // its unknown + return null; + } + @Override public String getAuthToken() { return mSessionCookie; diff --git a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java index fb7a0849..03839539 100644 --- a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java +++ b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java @@ -13,6 +13,18 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundExce public class SimpleFactoryManager implements OwnCloudClientManager { + @Override + public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) { + OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient( + account.getBaseUri(), + context.getApplicationContext(), + true); + + client.setCredentials(account.getCredentials()); + return client; + } + + @Override public OwnCloudClient getClientFor(Account savedAccount, Context context) throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index 4c636513..17226e5c 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -64,14 +64,64 @@ public class SingleSessionManager implements OwnCloudClientManager { private Map> mClientsPerServer = new HashMap>(); + private Map mClientsWithKnownUsername = + new HashMap(); + + private Map mClientsWithUnknownUsername = + new HashMap(); + public static OwnCloudClientManager getInstance() { if (mInstance == null) { mInstance = new SingleSessionManager(); } - return mInstance ; + return mInstance; } + + @Override + public synchronized OwnCloudClient getClientFor(OwnCloudAccount account, Context context) { + if (account == null) { + throw new IllegalArgumentException("Cannot get an OwnCloudClient for a null account"); + } + + OwnCloudClient client = null; + String accountName = account.getName(); + String sessionName = AccountUtils.buildAccountName( + account.getBaseUri(), + account.getCredentials().getAuthToken()); + + if (accountName != null) { + client = mClientsWithKnownUsername.get(account.getName()); + } + if (client == null) { + if (accountName != null) { + client = mClientsWithUnknownUsername.remove(sessionName); + if (client != null) { + mClientsWithKnownUsername.put(accountName, client); + } + } else { + client = mClientsWithUnknownUsername.get(sessionName); + } + } + + if (client == null) { + // no client to reuse - create a new one + client = OwnCloudClientFactory.createOwnCloudClient( + account.getBaseUri(), + context.getApplicationContext(), + true); + client.setCredentials(account.getCredentials()); + if (accountName != null) { + mClientsWithKnownUsername.put(accountName, client); + } else { + mClientsWithUnknownUsername.put(sessionName, client); + } + } + + return client; + } + @Override public synchronized OwnCloudClient getClientFor(Account savedAccount, Context context) diff --git a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java index 8fddc4e6..60ee1e1e 100644 --- a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -37,6 +37,7 @@ import android.accounts.AccountsException; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; +import android.net.Uri; public class AccountUtils { public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php"; @@ -185,6 +186,15 @@ public class AccountUtils { return credentials; } + + + public static String buildAccountName(Uri serverBaseUrl, String username) { + String accountName = username + "@" + serverBaseUrl.getHost(); + if (serverBaseUrl.getPort() >= 0) { + accountName += ":" + serverBaseUrl.getPort(); + } + return accountName; + } public static class AccountNotFoundException extends AccountsException { From 17d810fe2b74b7e481245108eb4d9d13d5e15615 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 12 Jun 2014 17:28:10 +0200 Subject: [PATCH 18/35] Fixed creation of OwnCloudClientManager instances --- .../android/lib/common/OwnCloudClientManagerFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index 78b6858e..78ac9979 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -16,10 +16,10 @@ public class OwnCloudClientManagerFactory { public static OwnCloudClientManager newOwnCloudClientManager(Policy policy) { switch (policy) { case ALWAYS_NEW_CLIENT: - return new SingleSessionManager(); + return new SimpleFactoryManager(); case SINGLE_SESSION_PER_ACCOUNT: - return new SimpleFactoryManager(); + return new SingleSessionManager(); default: throw new IllegalArgumentException("Unknown policy"); From e6c23205ebb5cc6cef55c2e53acf99ec889bbe42 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 12 Jun 2014 17:36:59 +0200 Subject: [PATCH 19/35] Fixed issue fully breaking the refresh of current folder (fixed only for SimpleFactoryManager for the moment) --- .../common/OwnCloudClientManagerFactory.java | 10 +++++++++- .../lib/common/SimpleFactoryManager.java | 16 ++++++++++++--- .../lib/common/SingleSessionManager.java | 20 ++++++++++--------- .../common/operations/RemoteOperation.java | 6 ++++-- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index 78ac9979..f8a9a2f3 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -8,6 +8,8 @@ public class OwnCloudClientManagerFactory { } public final static Policy DEFAULT_POLICY = Policy.ALWAYS_NEW_CLIENT; + + private static OwnCloudClientManager mDefaultSingleton; public static OwnCloudClientManager newDefaultOwnCloudClientManager() { return newOwnCloudClientManager(DEFAULT_POLICY); @@ -26,5 +28,11 @@ public class OwnCloudClientManagerFactory { } } - + public static OwnCloudClientManager getDefaultSingleton() { + if (mDefaultSingleton == null) { + mDefaultSingleton = newDefaultOwnCloudClientManager(); + } + return mDefaultSingleton; + } + } diff --git a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java index 03839539..5ced7cc5 100644 --- a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java +++ b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java @@ -7,19 +7,23 @@ import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; import android.net.Uri; +import android.util.Log; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; public class SimpleFactoryManager implements OwnCloudClientManager { - + private static final String TAG = OwnCloudClientManager.class.getSimpleName(); + @Override public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) { + Log.d(TAG, "getClientFor(OwnCloudAccount ... : "); OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient( account.getBaseUri(), context.getApplicationContext(), true); + Log.d(TAG, " new client " + client.hashCode()); client.setCredentials(account.getCredentials()); return client; } @@ -29,15 +33,20 @@ public class SimpleFactoryManager implements OwnCloudClientManager { public OwnCloudClient getClientFor(Account savedAccount, Context context) throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, IOException { - - return OwnCloudClientFactory.createOwnCloudClient( + Log.d(TAG, "getClientFor(Account ... : "); + + OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient( savedAccount, context.getApplicationContext()); + + Log.d(TAG, " new client " + client.hashCode()); + return client; } @Override public OwnCloudClient getClientFor(Uri serverBaseUri, OwnCloudCredentials credentials, Context context) { + Log.d(TAG, "getClientFor(Uri ... : "); OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient( serverBaseUri, @@ -45,6 +54,7 @@ public class SimpleFactoryManager implements OwnCloudClientManager { true); client.setCredentials(credentials); + Log.d(TAG, " new client " + client.hashCode()); return client; } diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index 17226e5c..99eb5daf 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -71,16 +71,9 @@ public class SingleSessionManager implements OwnCloudClientManager { new HashMap(); - public static OwnCloudClientManager getInstance() { - if (mInstance == null) { - mInstance = new SingleSessionManager(); - } - return mInstance; - } - - @Override public synchronized OwnCloudClient getClientFor(OwnCloudAccount account, Context context) { + Log.d(TAG, "getClientFor(OwnCloudAccount ... : "); if (account == null) { throw new IllegalArgumentException("Cannot get an OwnCloudClient for a null account"); } @@ -92,17 +85,21 @@ public class SingleSessionManager implements OwnCloudClientManager { account.getCredentials().getAuthToken()); if (accountName != null) { - client = mClientsWithKnownUsername.get(account.getName()); + client = mClientsWithKnownUsername.get(accountName); } if (client == null) { if (accountName != null) { client = mClientsWithUnknownUsername.remove(sessionName); if (client != null) { + Log.d(TAG, " reusing client {" + sessionName + ", " + client.hashCode() + "}"); mClientsWithKnownUsername.put(accountName, client); + Log.d(TAG, " moved client to {" + accountName + ", " + client.hashCode() + "}"); } } else { client = mClientsWithUnknownUsername.get(sessionName); } + } else { + Log.d(TAG, " reusing client {" + accountName + ", " + client.hashCode() + "}"); } if (client == null) { @@ -114,9 +111,14 @@ public class SingleSessionManager implements OwnCloudClientManager { client.setCredentials(account.getCredentials()); if (accountName != null) { mClientsWithKnownUsername.put(accountName, client); + Log.d(TAG, " new client {" + accountName + ", " + client.hashCode() + "}"); + } else { mClientsWithUnknownUsername.put(sessionName, client); + Log.d(TAG, " new client {" + sessionName + ", " + client.hashCode() + "}"); } + } else { + Log.d(TAG, " reusing client {" + sessionName + ", " + client.hashCode() + "}"); } return client; diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index fa89b24b..942be396 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -28,6 +28,7 @@ import java.io.IOException; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.OwnCloudCredentials; import com.owncloud.android.lib.common.SingleSessionManager; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; @@ -104,7 +105,8 @@ public abstract class RemoteOperation implements Runnable { mAccount = account; mContext = context.getApplicationContext(); try { - mClient = SingleSessionManager.getInstance().getClientFor(mAccount, mContext); + mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(mAccount, mContext); } catch (Exception e) { Log.e(TAG, "Error while trying to access to " + mAccount.name, e); return new RemoteOperationResult(e); @@ -251,7 +253,7 @@ public abstract class RemoteOperation implements Runnable { mAccount, mContext, mCallerActivity); } else { /** EOF DEPRECATED */ - mClient = SingleSessionManager.getInstance(). + mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). getClientFor(mAccount, mContext); } } else { From b28701ca30d9159aec4ba0410ecb86efe578f163 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Fri, 13 Jun 2014 09:29:32 +0200 Subject: [PATCH 20/35] Refactored handle of ownCloud URIs inside OwnCloudClient; rest of library adapted --- .../android/lib/common/OwnCloudClient.java | 42 ++++++++-------- .../lib/common/OwnCloudClientFactory.java | 19 +++----- .../lib/common/accounts/AccountUtils.java | 6 ++- .../status/GetRemoteStatusOperation.java | 48 ++++++++++--------- .../users/GetRemoteUserNameOperation.java | 2 +- .../lib/test_project/TestActivity.java | 5 +- 6 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index 521e68ba..da09ee38 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -43,6 +43,7 @@ import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.http.HttpStatus; import org.apache.http.params.CoreProtocolPNames; +import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.network.WebdavUtils; @@ -66,15 +67,20 @@ public class OwnCloudClient extends HttpClient { //private String mSsoSessionCookie = null; private int mInstanceNumber = 0; - private Uri mUri; - private Uri mWebdavUri; + private Uri mBaseUri; + //private Uri mWebdavUri; /** * Constructor */ - public OwnCloudClient(HttpConnectionManager connectionMgr) { + public OwnCloudClient(Uri baseUri, HttpConnectionManager connectionMgr) { super(connectionMgr); + if (baseUri == null) { + throw new IllegalArgumentException("Parameter 'baseUri' cannot be NULL"); + } + mBaseUri = baseUri; + mInstanceNumber = sIntanceCounter++; Log.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient"); @@ -131,7 +137,7 @@ public class OwnCloudClient extends HttpClient { /* public void setSsoSessionCookie(String accessToken) { Log.d(TAG + " #" + mInstanceNumber, "Setting session cookie: " + accessToken); - Log.e(TAG + " #" + mInstanceNumber, "BASE URL: " + mUri); + Log.e(TAG + " #" + mInstanceNumber, "BASE URL: " + mBaseUri); Log.e(TAG + " #" + mInstanceNumber, "WebDAV URL: " + mWebdavUri); if (accessToken != null && accessToken.length() > 0) { @@ -141,7 +147,7 @@ public class OwnCloudClient extends HttpClient { mSsoSessionCookie = accessToken; mCredentials = null; - Uri serverUri = (mUri != null)? mUri : mWebdavUri; + Uri serverUri = (mBaseUri != null)? mBaseUri : mWebdavUri; // TODO refactoring the mess of URIs String[] cookies = mSsoSessionCookie.split(";"); @@ -183,7 +189,7 @@ public class OwnCloudClient extends HttpClient { * @throws Exception When the existence could not be determined */ public boolean existsFile(String path) throws IOException, HttpException { - HeadMethod head = new HeadMethod(mWebdavUri.toString() + WebdavUtils.encodePath(path)); + HeadMethod head = new HeadMethod(getWebdavUri() + WebdavUtils.encodePath(path)); try { int status = executeMethod(head); Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + @@ -323,31 +329,27 @@ public class OwnCloudClient extends HttpClient { getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout); } - /** - * Sets the Webdav URI for the helper methods that receive paths as parameters, - * instead of full URLs - * @param uri - */ - public void setWebdavUri(Uri uri) { - mWebdavUri = uri; - } - public Uri getWebdavUri() { - return mWebdavUri; + if (mCredentials instanceof OwnCloudBearerCredentials) { + return Uri.parse(mBaseUri + AccountUtils.ODAV_PATH); + } else { + return Uri.parse(mBaseUri + AccountUtils.WEBDAV_PATH_4_0); + } } /** - * Sets the base URI for the helper methods that receive paths as parameters, - * instead of full URLs + * Sets the root URI to the ownCloud server. + * + * Use with care. * * @param uri */ public void setBaseUri(Uri uri) { - mUri = uri; + mBaseUri = uri; } public Uri getBaseUri() { - return mUri; + return mBaseUri; } /* diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java index 61ab218c..6784796c 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java @@ -72,14 +72,11 @@ public class OwnCloudClientFactory { */ public static OwnCloudClient createOwnCloudClient (Account account, Context appContext) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException { //Log_OC.d(TAG, "Creating OwnCloudClient associated to " + account.name); - - Uri webdavUri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account)); - Uri uri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account)); + Uri baseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account)); AccountManager am = AccountManager.get(appContext); boolean isOauth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2) != null; // TODO avoid calling to getUserData here boolean isSamlSso = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null; - OwnCloudClient client = createOwnCloudClient(webdavUri, appContext, !isSamlSso); - client.setBaseUri(uri); + OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso); if (isOauth2) { String accessToken = am.blockingGetAuthToken( @@ -123,13 +120,11 @@ public class OwnCloudClientFactory { public static OwnCloudClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException { - Uri webdavUri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account)); - Uri uri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account)); + Uri baseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account)); AccountManager am = AccountManager.get(appContext); boolean isOauth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2) != null; // TODO avoid calling to getUserData here boolean isSamlSso = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null; - OwnCloudClient client = createOwnCloudClient(webdavUri, appContext, !isSamlSso); - client.setBaseUri(uri); + OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso); if (isOauth2) { // TODO avoid a call to getUserData here AccountManagerFuture future = am.getAuthToken( @@ -192,7 +187,7 @@ public class OwnCloudClientFactory { /** * Creates a OwnCloudClient to access a URL and sets the desired parameters for ownCloud client connections. * - * @param uri URL to the ownCloud server + * @param uri URL to the ownCloud server; BASE ENTRY POINT, not WebDavPATH * @param context Android context where the OwnCloudClient is being created. * @return A OwnCloudClient object ready to be used */ @@ -206,10 +201,8 @@ public class OwnCloudClientFactory { Log.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(NetworkUtils.getMultiThreadedConnManager()); - + OwnCloudClient client = new OwnCloudClient(uri, NetworkUtils.getMultiThreadedConnManager()); client.setDefaultTimeouts(DEFAULT_DATA_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT); - client.setWebdavUri(uri); client.setFollowRedirects(followRedirects); return client; diff --git a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java index 376ec611..f9b86e6c 100644 --- a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -45,7 +45,7 @@ public class AccountUtils { public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php"; public static final String WEBDAV_PATH_2_0 = "/files/webdav.php"; public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav"; - private static final String ODAV_PATH = "/remote.php/odav"; + public static final String ODAV_PATH = "/remote.php/odav"; private static final String SAML_SSO_PATH = "/remote.php/webdav"; public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php"; public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php"; @@ -81,11 +81,15 @@ public class AccountUtils { /** * Constructs full url to host and webdav resource basing on host version + * + * @deprecated To be removed in release 1.0. + * * @param context * @param account * @return url or null on failure * @throws AccountNotFoundException When 'account' is unknown for the AccountManager */ + @Deprecated public static String constructFullURLForAccount(Context context, Account account) throws AccountNotFoundException { AccountManager ama = AccountManager.get(context); String baseurl = ama.getUserData(account, Constants.KEY_OC_BASE_URL); diff --git a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java index 9a675587..458a91d3 100644 --- a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java +++ b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java @@ -59,37 +59,39 @@ public class GetRemoteStatusOperation extends RemoteOperation { private static final String NODE_INSTALLED = "installed"; private static final String NODE_VERSION = "version"; - private String mUrl; private RemoteOperationResult mLatestResult; private Context mContext; - public GetRemoteStatusOperation(String url, Context context) { - mUrl = url; + public GetRemoteStatusOperation(Context context) { mContext = context; } - private boolean tryConnection(OwnCloudClient wc, String urlSt) { + private boolean tryConnection(OwnCloudClient client) { boolean retval = false; GetMethod get = null; + String baseUrlSt = client.getBaseUri().toString(); try { - get = new GetMethod(urlSt); - int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT); + get = new GetMethod(baseUrlSt + AccountUtils.STATUS_PATH); + int status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT); String response = get.getResponseBodyAsString(); if (status == HttpStatus.SC_OK) { JSONObject json = new JSONObject(response); if (!json.getBoolean(NODE_INSTALLED)) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); + mLatestResult = new RemoteOperationResult( + RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); } else { String version = json.getString(NODE_VERSION); OwnCloudVersion ocVersion = new OwnCloudVersion(version); if (!ocVersion.isVersionValid()) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION); + mLatestResult = new RemoteOperationResult( + RemoteOperationResult.ResultCode.BAD_OC_VERSION); } else { - mLatestResult = new RemoteOperationResult(urlSt.startsWith("https://") ? - RemoteOperationResult.ResultCode.OK_SSL : - RemoteOperationResult.ResultCode.OK_NO_SSL - ); + mLatestResult = new RemoteOperationResult( + baseUrlSt.startsWith("https://") ? + RemoteOperationResult.ResultCode.OK_SSL : + RemoteOperationResult.ResultCode.OK_NO_SSL + ); ArrayList data = new ArrayList(); data.add(ocVersion); @@ -103,7 +105,8 @@ public class GetRemoteStatusOperation extends RemoteOperation { } } catch (JSONException e) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); + mLatestResult = new RemoteOperationResult( + RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); } catch (Exception e) { mLatestResult = new RemoteOperationResult(e); @@ -114,13 +117,13 @@ public class GetRemoteStatusOperation extends RemoteOperation { } if (mLatestResult.isSuccess()) { - Log.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage()); + Log.i(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); } else if (mLatestResult.getException() != null) { - Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException()); + Log.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException()); } else { - Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage()); + Log.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); } return retval; @@ -138,16 +141,17 @@ public class GetRemoteStatusOperation extends RemoteOperation { if (!isOnline()) { return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION); } - if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) { - tryConnection(client, mUrl + AccountUtils.STATUS_PATH); + String baseUriStr = client.getBaseUri().toString(); + if (baseUriStr.startsWith("http://") || baseUriStr.startsWith("https://")) { + tryConnection(client); } else { - client.setWebdavUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH)); - boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); + client.setBaseUri(Uri.parse("https://" + baseUriStr)); + boolean httpsSuccess = tryConnection(client); if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) { Log.d(TAG, "establishing secure connection failed, trying non secure connection"); - client.setWebdavUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH)); - tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH); + client.setBaseUri(Uri.parse("http://" + baseUriStr)); + tryConnection(client); } } return mLatestResult; diff --git a/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java b/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java index 050b36d2..f153be44 100644 --- a/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java +++ b/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java @@ -78,7 +78,7 @@ public class GetRemoteUserNameOperation extends RemoteOperation { //Get the user try { - get = new GetMethod(client.getWebdavUri() + OCS_ROUTE); + get = new GetMethod(client.getBaseUri() + OCS_ROUTE); get.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE); status = client.executeMethod(get); if(isSuccess(status)) { diff --git a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java index 1b5eefe4..66ff274e 100644 --- a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java +++ b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java @@ -74,7 +74,6 @@ public class TestActivity extends Activity { private String mPass; private boolean mChunked; - private static final String WEBDAV_PATH = "/remote.php/webdav"; private static final int BUFFER_SIZE = 1024; public static final String ASSETS__TEXT_FILE_NAME = "textFile.txt"; @@ -107,12 +106,10 @@ public class TestActivity extends Activity { } } - Uri uri = Uri.parse(mServerUri + WEBDAV_PATH); - mClient = new OwnCloudClient(NetworkUtils.getMultiThreadedConnManager()); + mClient = new OwnCloudClient(Uri.parse(mServerUri), NetworkUtils.getMultiThreadedConnManager()); mClient.setDefaultTimeouts( OwnCloudClientFactory.DEFAULT_DATA_TIMEOUT, OwnCloudClientFactory.DEFAULT_CONNECTION_TIMEOUT); - mClient.setWebdavUri(uri); mClient.setFollowRedirects(true); mClient.setCredentials( OwnCloudCredentialsFactory.newBasicCredentials( From 0c4954928b038e33adeb73ab1938cac3f70c363d Mon Sep 17 00:00:00 2001 From: masensio Date: Fri, 13 Jun 2014 11:49:11 +0200 Subject: [PATCH 21/35] Add cookie restoring to SingleSessionManager#getClientFor(Uri ... ) after calling OwnCloudClientFactory#create --- .../lib/common/OwnCloudClientFactory.java | 36 +--------- .../lib/common/OwnCloudClientManager.java | 2 +- .../lib/common/SingleSessionManager.java | 16 ++++- .../lib/common/accounts/AccountUtils.java | 71 ++++++++++++++++++- .../common/operations/RemoteOperation.java | 9 ++- 5 files changed, 92 insertions(+), 42 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java index 6784796c..6c1944a5 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientFactory.java @@ -27,12 +27,9 @@ package com.owncloud.android.lib.common; import java.io.IOException; import java.security.GeneralSecurityException; -import org.apache.commons.httpclient.Cookie; - import com.owncloud.android.lib.common.accounts.AccountTypeUtils; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; -import com.owncloud.android.lib.common.accounts.AccountUtils.Constants; import com.owncloud.android.lib.common.network.NetworkUtils; import android.accounts.Account; @@ -113,7 +110,7 @@ public class OwnCloudClientFactory { } // Restore cookies - restoreCookies(am, account, client); + AccountUtils.restoreCookies(account, client, appContext); return client; } @@ -179,7 +176,7 @@ public class OwnCloudClientFactory { } // Restore cookies - restoreCookies(am, account, client); + AccountUtils.restoreCookies(account, client, appContext); return client; } @@ -208,34 +205,5 @@ public class OwnCloudClientFactory { return client; } - /** - * Restore the client cookies - * @param am - * @param account - * @param client - */ - private static void restoreCookies(AccountManager am, Account account, OwnCloudClient client) { - Log.d(TAG, "Restoring cookies for " + account.name); - - Uri serverUri = (client.getBaseUri() != null)? client.getBaseUri() : client.getWebdavUri(); - - String cookiesString = am.getUserData(account, Constants.KEY_COOKIES); - if (cookiesString !=null) { - String[] cookies = cookiesString.split(";"); - if (cookies.length > 0) { - for (int i=0; i< cookies.length; i++) { - Cookie cookie = new Cookie(); - int equalPos = cookies[i].indexOf('='); - cookie.setName(cookies[i].substring(0, equalPos)); - cookie.setValue(cookies[i].substring(equalPos + 1)); - cookie.setDomain(serverUri.getHost()); // VERY IMPORTANT - cookie.setPath(serverUri.getPath()); // VERY IMPORTANT - - client.getState().addCookie(cookie); - } - } - } - - } } diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java index b0b26c96..0dc87e4a 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java @@ -50,7 +50,7 @@ public interface OwnCloudClientManager { public OwnCloudClient getClientFor( Uri serverBaseUri, OwnCloudCredentials credentials, Context context); - + public void saveAllClients(Context context, String accountType) throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException; diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index e7ba5e57..4a9551b0 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -107,6 +107,10 @@ public class SingleSessionManager implements OwnCloudClientManager { account.getBaseUri(), context.getApplicationContext(), true); + + // Restore Cookies ?? + AccountUtils.restoreCookies(accountName, client, context); + client.setCredentials(account.getCredentials()); if (accountName != null) { mClientsWithKnownUsername.put(accountName, client); @@ -135,7 +139,12 @@ public class SingleSessionManager implements OwnCloudClientManager { OwnCloudCredentials credentials = AccountUtils.getCredentialsForAccount(context, savedAccount); - return getClientFor(serverBaseUri, credentials, context); + OwnCloudClient client = getClientFor(serverBaseUri, credentials, context); + + // Restore Cookies ?? + AccountUtils.restoreCookies(savedAccount, client, context); + + return client; } @@ -166,8 +175,13 @@ public class SingleSessionManager implements OwnCloudClientManager { context.getApplicationContext(), true); + // Restore Cookies + String accountName = AccountUtils.buildAccountName(serverBaseUri, credentials.getUsername()); + AccountUtils.restoreCookies(accountName, client, context); + client.setCredentials(credentials); clientsPerAccount.put(credentials, client); + } return client; diff --git a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java index f9b86e6c..b70b24e1 100644 --- a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -26,6 +26,9 @@ package com.owncloud.android.lib.common.accounts; import java.io.IOException; + +import org.apache.commons.httpclient.Cookie; + import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudCredentials; import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; @@ -37,11 +40,13 @@ import android.accounts.AccountsException; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; - -import android.util.Log; import android.net.Uri; +import android.util.Log; public class AccountUtils { + + private static final String TAG = AccountUtils.class.getSimpleName(); + public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php"; public static final String WEBDAV_PATH_2_0 = "/files/webdav.php"; public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav"; @@ -212,13 +217,73 @@ public class AccountUtils { String cookiesString = client.getCookiesString(); if (cookiesString != "") { ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString); - Log.d("AccountUtils", "Saving Cookies: "+ cookiesString ); + Log.d(TAG, "Saving Cookies: "+ cookiesString ); } } } + /** + * Restore the client cookies + * @param account + * @param client + * @param context + */ + public static void restoreCookies(Account account, OwnCloudClient client, Context context) { + + Log.d(TAG, "Restoring cookies for " + account.name); + + // Account Manager + AccountManager am = AccountManager.get(context.getApplicationContext()); + + Uri serverUri = (client.getBaseUri() != null)? client.getBaseUri() : client.getWebdavUri(); + + String cookiesString = am.getUserData(account, Constants.KEY_COOKIES); + if (cookiesString !=null) { + String[] cookies = cookiesString.split(";"); + if (cookies.length > 0) { + for (int i=0; i< cookies.length; i++) { + Cookie cookie = new Cookie(); + int equalPos = cookies[i].indexOf('='); + cookie.setName(cookies[i].substring(0, equalPos)); + cookie.setValue(cookies[i].substring(equalPos + 1)); + cookie.setDomain(serverUri.getHost()); // VERY IMPORTANT + cookie.setPath(serverUri.getPath()); // VERY IMPORTANT + + client.getState().addCookie(cookie); + } + } + } + } + + /** + * Restore the client cookies from accountName + * @param accountName + * @param client + * @param context + */ + public static void restoreCookies(String accountName, OwnCloudClient client, Context context) { + Log.d(TAG, "Restoring cookies for " + accountName); + + // Account Manager + AccountManager am = AccountManager.get(context.getApplicationContext()); + + // Get account + Account account = null; + Account accounts[] = am.getAccounts(); + for (Account a : accounts) { + if (a.name.equals(accountName)) { + account = a; + break; + } + } + + // Restoring cookies + if (account != null) { + restoreCookies(account, client, context); + } + } public static class AccountNotFoundException extends AccountsException { diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index 1045d6fd..5476f166 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -30,7 +30,6 @@ import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.OwnCloudCredentials; -import com.owncloud.android.lib.common.SingleSessionManager; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; @@ -257,8 +256,7 @@ public abstract class RemoteOperation implements Runnable { mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). getClientFor(mAccount, mContext); } - // Save Client Cookies - AccountUtils.saveClient(mClient, mAccount, mContext); + } else { throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account"); } @@ -303,6 +301,11 @@ public abstract class RemoteOperation implements Runnable { /** EOF DEPRECATED BLOCK **/ } while (repeat); + if (mAccount != null && mContext != null) { + // Save Client Cookies + AccountUtils.saveClient(mClient, mAccount, mContext); + } + final RemoteOperationResult resultToSend = result; if (mListenerHandler != null && mListener != null) { mListenerHandler.post(new Runnable() { From 9be1323745d8b6cf519315ce2641ab41e808a04b Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Fri, 13 Jun 2014 12:42:40 +0200 Subject: [PATCH 22/35] Removed duplication of OwnCloudClientManager#getClientFor methods with different parameter types --- .../android/lib/common/OwnCloudAccount.java | 2 +- .../android/lib/common/OwnCloudClientManager.java | 9 +++++---- .../android/lib/common/SimpleFactoryManager.java | 9 ++++----- .../android/lib/common/SingleSessionManager.java | 15 +++++++++------ .../android/lib/common/accounts/AccountUtils.java | 3 +++ .../lib/common/operations/RemoteOperation.java | 7 +++++-- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudAccount.java b/src/com/owncloud/android/lib/common/OwnCloudAccount.java index ff0cf3dd..993cd74a 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudAccount.java +++ b/src/com/owncloud/android/lib/common/OwnCloudAccount.java @@ -68,7 +68,7 @@ public class OwnCloudAccount { mBaseUri = baseUri; mCredentials = credentials != null ? credentials : OwnCloudCredentialsFactory.getAnonymousCredentials(); - String username = credentials.getUsername(); + String username = mCredentials.getUsername(); if (username != null) { mSavedAccountName = AccountUtils.buildAccountName(mBaseUri, username); } diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java index 0dc87e4a..25aa4639 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java @@ -30,7 +30,6 @@ import android.accounts.Account; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; -import android.net.Uri; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; @@ -44,13 +43,17 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundExce public interface OwnCloudClientManager { + public OwnCloudClient getClientFor(OwnCloudAccount account, Context context); + + /* public OwnCloudClient getClientFor(Account savedAccount, Context context) throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException; public OwnCloudClient getClientFor( Uri serverBaseUri, OwnCloudCredentials credentials, Context context); - + */ + public void saveAllClients(Context context, String accountType) throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException; @@ -59,6 +62,4 @@ public interface OwnCloudClientManager { throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException; - public OwnCloudClient getClientFor(OwnCloudAccount account, Context context); - } diff --git a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java index 012b9303..3f63e959 100644 --- a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java +++ b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java @@ -1,6 +1,5 @@ package com.owncloud.android.lib.common; -import java.io.IOException; import android.accounts.Account; import android.accounts.AuthenticatorException; @@ -13,7 +12,7 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundExce public class SimpleFactoryManager implements OwnCloudClientManager { - private static final String TAG = OwnCloudClientManager.class.getSimpleName(); + private static final String TAG = SimpleFactoryManager.class.getSimpleName(); @Override public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) { @@ -28,7 +27,7 @@ public class SimpleFactoryManager implements OwnCloudClientManager { return client; } - + /* @Override public OwnCloudClient getClientFor(Account savedAccount, Context context) throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, @@ -57,7 +56,8 @@ public class SimpleFactoryManager implements OwnCloudClientManager { Log.d(TAG, " new client " + client.hashCode()); return client; } - + */ + @Override public void saveAllClients(Context context, String accountType) { // TODO Auto-generated method stub @@ -66,7 +66,6 @@ public class SimpleFactoryManager implements OwnCloudClientManager { @Override public OwnCloudClient removeClientFor(Account account, Context context) { - // TODO Auto-generated method stub return null; } diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index 4a9551b0..f427c8f4 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -58,8 +58,6 @@ public class SingleSessionManager implements OwnCloudClientManager { private static final String TAG = SingleSessionManager.class.getSimpleName(); - private static OwnCloudClientManager mInstance = null; - private Map> mClientsPerServer = new HashMap>(); @@ -86,6 +84,7 @@ public class SingleSessionManager implements OwnCloudClientManager { if (accountName != null) { client = mClientsWithKnownUsername.get(accountName); } + boolean reusingKnown = false; // just for logs if (client == null) { if (accountName != null) { client = mClientsWithUnknownUsername.remove(sessionName); @@ -99,6 +98,7 @@ public class SingleSessionManager implements OwnCloudClientManager { } } else { Log.d(TAG, " reusing client {" + accountName + ", " + client.hashCode() + "}"); + reusingKnown = true; } if (client == null) { @@ -121,13 +121,15 @@ public class SingleSessionManager implements OwnCloudClientManager { Log.d(TAG, " new client {" + sessionName + ", " + client.hashCode() + "}"); } } else { - Log.d(TAG, " reusing client {" + sessionName + ", " + client.hashCode() + "}"); + if (!reusingKnown) { + Log.d(TAG, " reusing client {" + sessionName + ", " + client.hashCode() + "}"); + } } return client; } - + /* @Override public synchronized OwnCloudClient getClientFor(Account savedAccount, Context context) throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, @@ -147,8 +149,9 @@ public class SingleSessionManager implements OwnCloudClientManager { return client; } + */ - + /* @Override public synchronized OwnCloudClient getClientFor( Uri serverBaseUri, OwnCloudCredentials credentials, Context context) { @@ -186,7 +189,7 @@ public class SingleSessionManager implements OwnCloudClientManager { return client; } - + */ @Override public synchronized OwnCloudClient removeClientFor(Account savedAccount, Context context) diff --git a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java index b70b24e1..b061c2e5 100644 --- a/src/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/src/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -200,6 +200,9 @@ public class AccountUtils { public static String buildAccountName(Uri serverBaseUrl, String username) { + if (serverBaseUrl.getScheme() == null) { + serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString()); + } String accountName = username + "@" + serverBaseUrl.getHost(); if (serverBaseUrl.getPort() >= 0) { accountName += ":" + serverBaseUrl.getPort(); diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index 5476f166..1384bd7a 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -26,6 +26,7 @@ package com.owncloud.android.lib.common.operations; import java.io.IOException; +import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; @@ -105,8 +106,9 @@ public abstract class RemoteOperation implements Runnable { mAccount = account; mContext = context.getApplicationContext(); try { + OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(mAccount, mContext); + getClientFor(ocAccount, mContext); } catch (Exception e) { Log.e(TAG, "Error while trying to access to " + mAccount.name, e); return new RemoteOperationResult(e); @@ -253,8 +255,9 @@ public abstract class RemoteOperation implements Runnable { mAccount, mContext, mCallerActivity); } else { /** EOF DEPRECATED */ + OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(mAccount, mContext); + getClientFor(ocAccount, mContext); } } else { From 7e2ec10442a435b097b7cee48a7529e30b364277 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Fri, 13 Jun 2014 13:42:59 +0200 Subject: [PATCH 23/35] Default policy for singleton available in OwnCloudManagerFactory made configurable --- .../android/lib/common/OwnCloudAccount.java | 3 ++ .../common/OwnCloudClientManagerFactory.java | 34 +++++++++++++++---- .../lib/common/SingleSessionManager.java | 10 ++++++ 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudAccount.java b/src/com/owncloud/android/lib/common/OwnCloudAccount.java index 993cd74a..339eb128 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudAccount.java +++ b/src/com/owncloud/android/lib/common/OwnCloudAccount.java @@ -57,6 +57,9 @@ public class OwnCloudAccount { mSavedAccountName = savedAccount.name; mBaseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(context, savedAccount)); mCredentials = AccountUtils.getCredentialsForAccount(context, savedAccount); + if (mCredentials == null) { + mCredentials = OwnCloudCredentialsFactory.getAnonymousCredentials(); + } } diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index f8a9a2f3..cc7ba6b9 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -7,12 +7,12 @@ public class OwnCloudClientManagerFactory { SINGLE_SESSION_PER_ACCOUNT } - public final static Policy DEFAULT_POLICY = Policy.ALWAYS_NEW_CLIENT; + public static Policy sDefaultPolicy = Policy.ALWAYS_NEW_CLIENT; - private static OwnCloudClientManager mDefaultSingleton; + private static OwnCloudClientManager sDefaultSingleton; public static OwnCloudClientManager newDefaultOwnCloudClientManager() { - return newOwnCloudClientManager(DEFAULT_POLICY); + return newOwnCloudClientManager(sDefaultPolicy); } public static OwnCloudClientManager newOwnCloudClientManager(Policy policy) { @@ -29,10 +29,32 @@ public class OwnCloudClientManagerFactory { } public static OwnCloudClientManager getDefaultSingleton() { - if (mDefaultSingleton == null) { - mDefaultSingleton = newDefaultOwnCloudClientManager(); + if (sDefaultSingleton == null) { + sDefaultSingleton = newDefaultOwnCloudClientManager(); } - return mDefaultSingleton; + return sDefaultSingleton; + } + + public static void setDefaultPolicy(Policy policy) { + if (defaultSingletonMustBeUpdated(policy)) { + sDefaultSingleton = null; + } + sDefaultPolicy = policy; } + private static boolean defaultSingletonMustBeUpdated(Policy policy) { + if (sDefaultSingleton == null) { + return false; + } + if (policy == Policy.ALWAYS_NEW_CLIENT && + !(sDefaultSingleton instanceof SimpleFactoryManager)) { + return true; + } + if (policy == Policy.SINGLE_SESSION_PER_ACCOUNT && + !(sDefaultSingleton instanceof SingleSessionManager)) { + return true; + } + return false; + } + } diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index f427c8f4..221e1609 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -99,6 +99,7 @@ public class SingleSessionManager implements OwnCloudClientManager { } else { Log.d(TAG, " reusing client {" + accountName + ", " + client.hashCode() + "}"); reusingKnown = true; + keepCredentialsUpdated(account, client); } if (client == null) { @@ -191,6 +192,15 @@ public class SingleSessionManager implements OwnCloudClientManager { } */ + private void keepCredentialsUpdated(OwnCloudAccount account, OwnCloudClient reusedClient) { + OwnCloudCredentials recentCredentials = account.getCredentials(); + if (!recentCredentials.getAuthToken().equals( + reusedClient.getCredentials().getAuthToken())) { + reusedClient.setCredentials(recentCredentials); + } + + } + @Override public synchronized OwnCloudClient removeClientFor(Account savedAccount, Context context) throws AccountNotFoundException, OperationCanceledException, AuthenticatorException, IOException { From 5130a93ef576f0c75d852840355672551fea2e9c Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Fri, 13 Jun 2014 15:08:20 +0200 Subject: [PATCH 24/35] Updated OwnCloudClientManager#removeClient for new type OWnCloudAccount --- .../lib/common/OwnCloudClientManager.java | 14 +- .../lib/common/SimpleFactoryManager.java | 88 ++++++------ .../lib/common/SingleSessionManager.java | 130 ++++++------------ 3 files changed, 83 insertions(+), 149 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java index 25aa4639..e54ae191 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManager.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManager.java @@ -26,7 +26,6 @@ package com.owncloud.android.lib.common; import java.io.IOException; -import android.accounts.Account; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; @@ -45,21 +44,10 @@ public interface OwnCloudClientManager { public OwnCloudClient getClientFor(OwnCloudAccount account, Context context); - /* - public OwnCloudClient getClientFor(Account savedAccount, Context context) - throws AccountNotFoundException, AuthenticatorException, - IOException, OperationCanceledException; - - public OwnCloudClient getClientFor( - Uri serverBaseUri, OwnCloudCredentials credentials, Context context); - */ + public OwnCloudClient removeClientFor(OwnCloudAccount account); public void saveAllClients(Context context, String accountType) throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException; - public OwnCloudClient removeClientFor(Account account, Context context) - throws AccountNotFoundException, AuthenticatorException, - IOException, OperationCanceledException; - } diff --git a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java index 3f63e959..94918ec6 100644 --- a/src/com/owncloud/android/lib/common/SimpleFactoryManager.java +++ b/src/com/owncloud/android/lib/common/SimpleFactoryManager.java @@ -1,14 +1,34 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + package com.owncloud.android.lib.common; -import android.accounts.Account; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.Context; -import android.net.Uri; -import android.util.Log; +import com.owncloud.android.lib.common.accounts.AccountUtils; -import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; +import android.content.Context; +import android.util.Log; public class SimpleFactoryManager implements OwnCloudClientManager { @@ -22,51 +42,27 @@ public class SimpleFactoryManager implements OwnCloudClientManager { context.getApplicationContext(), true); - Log.d(TAG, " new client " + client.hashCode()); + Log.d(TAG, " new client {" + + (account.getName() != null ? + account.getName() : + AccountUtils.buildAccountName( + account.getBaseUri(), + account.getCredentials().getAuthToken())) + + ", " + client.hashCode() + "}"); + client.setCredentials(account.getCredentials()); return client; } - /* @Override - public OwnCloudClient getClientFor(Account savedAccount, Context context) - throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, - IOException { - Log.d(TAG, "getClientFor(Account ... : "); - - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient( - savedAccount, - context.getApplicationContext()); - - Log.d(TAG, " new client " + client.hashCode()); - return client; - } - - @Override - public OwnCloudClient getClientFor(Uri serverBaseUri, OwnCloudCredentials credentials, - Context context) { - Log.d(TAG, "getClientFor(Uri ... : "); - - OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient( - serverBaseUri, - context.getApplicationContext(), - true); - - client.setCredentials(credentials); - Log.d(TAG, " new client " + client.hashCode()); - return client; - } - */ - - @Override - public void saveAllClients(Context context, String accountType) { - // TODO Auto-generated method stub - - } - - @Override - public OwnCloudClient removeClientFor(Account account, Context context) { + public OwnCloudClient removeClientFor(OwnCloudAccount account) { + // nothing to do - not taking care of tracking instances! return null; } + @Override + public void saveAllClients(Context context, String accountType) { + // nothing to do - not taking care of tracking instances! + } + } diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index 221e1609..1dec9441 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -46,16 +46,12 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundExce * * TODO check multithreading safety * - * TODO better mapping? - * * @author David A. Velasco * @author masensio */ public class SingleSessionManager implements OwnCloudClientManager { - //private static final String TAG = SingleSessionManager.class.getSimpleName(); - private static final String TAG = SingleSessionManager.class.getSimpleName(); private Map> mClientsPerServer = @@ -130,96 +126,41 @@ public class SingleSessionManager implements OwnCloudClientManager { return client; } - /* - @Override - public synchronized OwnCloudClient getClientFor(Account savedAccount, Context context) - throws OperationCanceledException, AuthenticatorException, AccountNotFoundException, - IOException { - - Uri serverBaseUri = - Uri.parse(AccountUtils.getBaseUrlForAccount(context, savedAccount)); - - OwnCloudCredentials credentials = - AccountUtils.getCredentialsForAccount(context, savedAccount); - - OwnCloudClient client = getClientFor(serverBaseUri, credentials, context); - - // Restore Cookies ?? - AccountUtils.restoreCookies(savedAccount, client, context); - - return client; - - } - */ - - /* - @Override - public synchronized OwnCloudClient getClientFor( - Uri serverBaseUri, OwnCloudCredentials credentials, Context context) { - - Map clientsPerAccount = - mClientsPerServer.get(serverBaseUri.toString()); - - if (clientsPerAccount == null) { - clientsPerAccount = new HashMap(); - mClientsPerServer.put( - serverBaseUri.toString(), - clientsPerAccount); - } - - if (credentials == null) { - credentials = OwnCloudCredentialsFactory.getAnonymousCredentials(); - } - - /// TODO - CRITERIA FOR MATCH OF KEYS!!! - OwnCloudClient client = clientsPerAccount.get(credentials); - if (client == null) { - client = OwnCloudClientFactory.createOwnCloudClient( - serverBaseUri, - context.getApplicationContext(), - true); - - // Restore Cookies - String accountName = AccountUtils.buildAccountName(serverBaseUri, credentials.getUsername()); - AccountUtils.restoreCookies(accountName, client, context); - - client.setCredentials(credentials); - clientsPerAccount.put(credentials, client); - - } - - return client; - } - */ - private void keepCredentialsUpdated(OwnCloudAccount account, OwnCloudClient reusedClient) { - OwnCloudCredentials recentCredentials = account.getCredentials(); - if (!recentCredentials.getAuthToken().equals( - reusedClient.getCredentials().getAuthToken())) { - reusedClient.setCredentials(recentCredentials); - } + @Override + public OwnCloudClient removeClientFor(OwnCloudAccount account) { + + if (account == null) { + return null; + } + + OwnCloudClient client = null; + String accountName = account.getName(); + if (accountName != null) { + client = mClientsWithKnownUsername.remove(accountName); + if (client != null) { + Log.d(TAG, "Removed client {" + accountName + ", " + client.hashCode() + "}"); + return client; + } else { + Log.d(TAG, "No client tracked for {" + accountName + "}"); + } + } + + String sessionName = AccountUtils.buildAccountName( + account.getBaseUri(), + account.getCredentials().getAuthToken()); + client = mClientsWithUnknownUsername.remove(sessionName); + if (client != null) { + Log.d(TAG, "Removed client {" + sessionName + ", " + client.hashCode() + "}"); + return client; + } + Log.d(TAG, "No client tracked for {" + sessionName + "}"); + + Log.d(TAG, "No client removed"); + return null; } - @Override - public synchronized OwnCloudClient removeClientFor(Account savedAccount, Context context) - throws AccountNotFoundException, OperationCanceledException, AuthenticatorException, IOException { - - Uri serverBaseUri = - Uri.parse(AccountUtils.getBaseUrlForAccount(context, savedAccount)); - - Map clientsPerAccount = - mClientsPerServer.get(serverBaseUri.toString()); - - if (clientsPerAccount != null) { - OwnCloudCredentials credentials = - AccountUtils.getCredentialsForAccount(context, savedAccount); - - return clientsPerAccount.remove(credentials); - } - return null; - } - @Override public synchronized void saveAllClients(Context context, String accountType) @@ -253,5 +194,14 @@ public class SingleSessionManager implements OwnCloudClientManager { } + + private void keepCredentialsUpdated(OwnCloudAccount account, OwnCloudClient reusedClient) { + OwnCloudCredentials recentCredentials = account.getCredentials(); + if (!recentCredentials.getAuthToken().equals( + reusedClient.getCredentials().getAuthToken())) { + reusedClient.setCredentials(recentCredentials); + } + + } } From 1d95320277846c082cda2bfcfbbfeb251d03fcc4 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Mon, 16 Jun 2014 09:33:30 +0200 Subject: [PATCH 25/35] Updated implementation of SingleSessionManager#saveAllClients for current HashMap --- .../lib/common/SingleSessionManager.java | 40 +++++-------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index 1dec9441..f000983e 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -26,14 +26,13 @@ package com.owncloud.android.lib.common; import java.io.IOException; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import android.accounts.Account; -import android.accounts.AccountManager; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; -import android.net.Uri; import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; @@ -54,9 +53,6 @@ public class SingleSessionManager implements OwnCloudClientManager { private static final String TAG = SingleSessionManager.class.getSimpleName(); - private Map> mClientsPerServer = - new HashMap>(); - private Map mClientsWithKnownUsername = new HashMap(); @@ -167,31 +163,17 @@ public class SingleSessionManager implements OwnCloudClientManager { throws AccountNotFoundException, AuthenticatorException, IOException, OperationCanceledException { - // Get all accounts - Account [] accounts = AccountManager.get(context.getApplicationContext()) - .getAccountsByType(accountType); - - // Save cookies for all accounts - for(Account account: accounts){ - - Uri serverBaseUri = - Uri.parse(AccountUtils.getBaseUrlForAccount(context, account)); - - Map clientsPerAccount = - mClientsPerServer.get(serverBaseUri.toString()); - - if (clientsPerAccount != null) { - OwnCloudCredentials credentials = - AccountUtils.getCredentialsForAccount(context, account); - - /// TODO - CRITERIA FOR MATCH OF KEYS!!! - OwnCloudClient client = clientsPerAccount.get(credentials); - if (client != null) { - AccountUtils.saveClient(client, account, context.getApplicationContext()); - } - } + Iterator accountNames = mClientsWithKnownUsername.keySet().iterator(); + String accountName = null; + Account account = null; + while (accountNames.hasNext()) { + accountName = accountNames.next(); + account = new Account(accountName, accountType); + AccountUtils.saveClient( + mClientsWithKnownUsername.get(accountName), + account, + context); } - } From 2e4fc047aff99c238784e7d6091d08f4a3d8c0d5 Mon Sep 17 00:00:00 2001 From: masensio Date: Mon, 16 Jun 2014 13:16:41 +0200 Subject: [PATCH 26/35] Fix in OwnCloudSamlSsoCredentials: Cookies.BROWSER_COMPATIBILITY instead IGNORE_COOKIES. Fix in constructor --- .../android/lib/common/OwnCloudSamlSsoCredentials.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java index 78c96bfa..9365a6b8 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java +++ b/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java @@ -10,13 +10,13 @@ public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials { private String mSessionCookie; public OwnCloudSamlSsoCredentials(String sessionCookie) { - mSessionCookie = sessionCookie != null ? mSessionCookie : ""; + mSessionCookie = sessionCookie != null ? sessionCookie : ""; } @Override public void applyTo(OwnCloudClient client) { client.getParams().setAuthenticationPreemptive(false); - client.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES); + client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); client.setFollowRedirects(false); Uri serverUri = client.getBaseUri(); From c01001b5a1b19ab4c6ff789730a6659b8f6bcbb5 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Tue, 17 Jun 2014 14:12:30 +0200 Subject: [PATCH 27/35] Added unit test for OwnCloudClientManagerFactory --- .../common/OwnCloudClientManagerFactory.java | 11 +- .../OwnCloudClientManagerFactoryTest.java | 155 ++++++++++++++++++ 2 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientManagerFactoryTest.java diff --git a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index cc7ba6b9..216e2e30 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -7,7 +7,7 @@ public class OwnCloudClientManagerFactory { SINGLE_SESSION_PER_ACCOUNT } - public static Policy sDefaultPolicy = Policy.ALWAYS_NEW_CLIENT; + private static Policy sDefaultPolicy = Policy.ALWAYS_NEW_CLIENT; private static OwnCloudClientManager sDefaultSingleton; @@ -35,13 +35,20 @@ public class OwnCloudClientManagerFactory { return sDefaultSingleton; } + public static Policy getDefaultPolicy() { + return sDefaultPolicy; + } + public static void setDefaultPolicy(Policy policy) { + if (policy == null) { + throw new IllegalArgumentException("Default policy cannot be NULL"); + } if (defaultSingletonMustBeUpdated(policy)) { sDefaultSingleton = null; } sDefaultPolicy = policy; } - + private static boolean defaultSingletonMustBeUpdated(Policy policy) { if (sDefaultSingleton == null) { return false; diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientManagerFactoryTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientManagerFactoryTest.java new file mode 100644 index 00000000..b612744c --- /dev/null +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientManagerFactoryTest.java @@ -0,0 +1,155 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +package com.owncloud.android.lib.test_project.test; + +import com.owncloud.android.lib.common.OwnCloudClientManager; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; +import com.owncloud.android.lib.common.SingleSessionManager; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy; +import com.owncloud.android.lib.common.SimpleFactoryManager; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +/** + * Unit test for OwnCloudClientManagerFactory + * + * @author David A. Velasco + */ +public class OwnCloudClientManagerFactoryTest extends TestCase { + + @Override + protected void setUp() { + OwnCloudClientManagerFactory.setDefaultPolicy(Policy.ALWAYS_NEW_CLIENT); + } + + public void testGetDefaultPolicy() { + Policy defaultPolicy = OwnCloudClientManagerFactory.getDefaultPolicy(); + assertNotNull("Returned null value", defaultPolicy); + assertTrue("Returned unknown value", + (Policy.ALWAYS_NEW_CLIENT.equals(defaultPolicy) || + (Policy.SINGLE_SESSION_PER_ACCOUNT.equals(defaultPolicy)))); + } + + public void testSetDefaultPolicy() { + OwnCloudClientManagerFactory.setDefaultPolicy(Policy.SINGLE_SESSION_PER_ACCOUNT); + Policy defaultPolicy = OwnCloudClientManagerFactory.getDefaultPolicy(); + assertEquals("SINGLE_SESSION_PER_ACCOUNT not set", + Policy.SINGLE_SESSION_PER_ACCOUNT, defaultPolicy); + + OwnCloudClientManagerFactory.setDefaultPolicy(Policy.ALWAYS_NEW_CLIENT); + defaultPolicy = OwnCloudClientManagerFactory.getDefaultPolicy(); + assertEquals("ALWAYS_NEW_CLIENT not set", Policy.ALWAYS_NEW_CLIENT, defaultPolicy); + + try { + OwnCloudClientManagerFactory.setDefaultPolicy(null); + throw new AssertionFailedError("Accepted NULL parameter"); + + } catch(Exception e) { + assertTrue("Unexpected exception when setting default policy null", + (e instanceof IllegalArgumentException)); + } + defaultPolicy = OwnCloudClientManagerFactory.getDefaultPolicy(); + assertEquals("ALWAYS_NEW_CLIENT changed after setting null", + Policy.ALWAYS_NEW_CLIENT, defaultPolicy); + + } + + + public void testGetDefaultSingleton() { + OwnCloudClientManager mgr = OwnCloudClientManagerFactory.getDefaultSingleton(); + assertNotNull("Returned NULL default singleton", mgr); + assertTrue("Default singleton does not implement default policy", + mgr instanceof SimpleFactoryManager); + + OwnCloudClientManager mgr2 = OwnCloudClientManagerFactory.getDefaultSingleton(); + assertSame("Not singleton", mgr, mgr2); + + OwnCloudClientManagerFactory.setDefaultPolicy(Policy.SINGLE_SESSION_PER_ACCOUNT); + mgr = OwnCloudClientManagerFactory.getDefaultSingleton(); + assertNotNull("Returned NULL default singleton", mgr); + assertTrue("Default singleton does not implement default policy", + mgr instanceof SingleSessionManager); + + mgr2 = OwnCloudClientManagerFactory.getDefaultSingleton(); + assertSame("Not singleton", mgr, mgr2); + } + + + public void testNewDefaultOwnCloudClientManager() { + OwnCloudClientManager mgr = OwnCloudClientManagerFactory.newDefaultOwnCloudClientManager(); + assertNotNull("Returned NULL default manager", mgr); + assertTrue("New manager does not implement default policy", + mgr instanceof SimpleFactoryManager); + assertNotSame("Not new instance", + mgr, OwnCloudClientManagerFactory.getDefaultSingleton()); + assertNotSame("Not new instance", + mgr, OwnCloudClientManagerFactory.newDefaultOwnCloudClientManager()); + + OwnCloudClientManagerFactory.setDefaultPolicy(Policy.SINGLE_SESSION_PER_ACCOUNT); + mgr = OwnCloudClientManagerFactory.newDefaultOwnCloudClientManager(); + assertNotNull("Returned NULL default manager", mgr); + assertTrue("New manager does not implement default policy", + mgr instanceof SingleSessionManager); + assertNotSame("Not new instance", + mgr, OwnCloudClientManagerFactory.getDefaultSingleton()); + assertNotSame("Not new instance", + mgr, OwnCloudClientManagerFactory.newDefaultOwnCloudClientManager()); + + } + + + public void testNewOwnCloudClientManager() { + OwnCloudClientManager mgr = OwnCloudClientManagerFactory. + newOwnCloudClientManager(Policy.ALWAYS_NEW_CLIENT); + + assertNotNull("Returned NULL manager", mgr); + assertTrue("New manager does not implement policy ALWAYS_NEW_CLIENT", + mgr instanceof SimpleFactoryManager); + assertNotSame("Not new instance", + mgr, OwnCloudClientManagerFactory.getDefaultSingleton()); + assertNotSame("Not new instance", + mgr, OwnCloudClientManagerFactory.newDefaultOwnCloudClientManager()); + assertNotSame("Not new instance", + mgr, OwnCloudClientManagerFactory.newOwnCloudClientManager( + Policy.ALWAYS_NEW_CLIENT)); + + + OwnCloudClientManager mgr2 = OwnCloudClientManagerFactory. + newOwnCloudClientManager(Policy.SINGLE_SESSION_PER_ACCOUNT); + + assertNotNull("Returned NULL manager", mgr2); + assertTrue("New manager does not implement policy SINGLE_SESSION_PER_ACCOUNT", + mgr2 instanceof SingleSessionManager); + assertNotSame("Not new instance", + mgr2, OwnCloudClientManagerFactory.getDefaultSingleton()); + assertNotSame("Not new instance", + mgr2, OwnCloudClientManagerFactory.newDefaultOwnCloudClientManager()); + assertNotSame("Not new instance", + mgr2, OwnCloudClientManagerFactory.newOwnCloudClientManager( + Policy.SINGLE_SESSION_PER_ACCOUNT)); + } + + +} From 179ef41f4c43c162a5fde2fe95594e9b70044b41 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 18 Jun 2014 14:55:19 +0200 Subject: [PATCH 28/35] Normalized OwnCloudClient to hold an instance to OwnCloudAnonymousCredentials instance of null --- .../android/lib/common/OwnCloudClient.java | 104 +++--------------- .../common/OwnCloudCredentialsFactory.java | 3 +- .../common/OwnCloudSamlSsoCredentials.java | 4 - 3 files changed, 15 insertions(+), 96 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index da09ee38..0e828c03 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -43,6 +43,7 @@ import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.http.HttpStatus; import org.apache.http.params.CoreProtocolPNames; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.network.WebdavUtils; @@ -62,13 +63,10 @@ public class OwnCloudClient extends HttpClient { private static int sIntanceCounter = 0; private boolean mFollowRedirects = true; - //private Credentials mCredentials = null; private OwnCloudCredentials mCredentials = null; - //private String mSsoSessionCookie = null; private int mInstanceNumber = 0; private Uri mBaseUri; - //private Uri mWebdavUri; /** * Constructor @@ -94,100 +92,36 @@ public class OwnCloudClient extends HttpClient { getParams().setParameter( PARAM_SINGLE_COOKIE_HEADER, // to avoid problems with some web servers PARAM_SINGLE_COOKIE_HEADER_VALUE); + + clearCredentials(); } public void setCredentials(OwnCloudCredentials credentials) { if (credentials != null) { - mCredentials = credentials; + mCredentials = credentials; mCredentials.applyTo(this); } else { clearCredentials(); } } - /* - public void setBearerCredentials(String accessToken) { - AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class); - - List authPrefs = new ArrayList(1); - authPrefs.add(BearerAuthScheme.AUTH_POLICY); - getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); - - getParams().setAuthenticationPreemptive(true); - mCredentials = new BearerCredentials(accessToken); - getState().setCredentials(AuthScope.ANY, mCredentials); - mSsoSessionCookie = null; - } - */ - - /* - public void setBasicCredentials(String username, String password) { - List authPrefs = new ArrayList(1); - authPrefs.add(AuthPolicy.BASIC); - getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); - - getParams().setAuthenticationPreemptive(true); - mCredentials = new UsernamePasswordCredentials(username, password); - getState().setCredentials(AuthScope.ANY, mCredentials); - mSsoSessionCookie = null; - } - */ - - /* - public void setSsoSessionCookie(String accessToken) { - Log.d(TAG + " #" + mInstanceNumber, "Setting session cookie: " + accessToken); - Log.e(TAG + " #" + mInstanceNumber, "BASE URL: " + mBaseUri); - Log.e(TAG + " #" + mInstanceNumber, "WebDAV URL: " + mWebdavUri); - - if (accessToken != null && accessToken.length() > 0) { - - getParams().setAuthenticationPreemptive(false); - - mSsoSessionCookie = accessToken; - mCredentials = null; - - Uri serverUri = (mBaseUri != null)? mBaseUri : mWebdavUri; - // TODO refactoring the mess of URIs - - String[] cookies = mSsoSessionCookie.split(";"); - if (cookies.length > 0) { - //Cookie[] cookies = new Cookie[cookiesStr.length]; - for (int i=0; i 0) { From a57be369259bbfb3741a649a8d585fc8de6ac669 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 25 Jun 2014 09:08:29 +0200 Subject: [PATCH 29/35] Added unit test for OwnCloudClient --- .../android/lib/common/OwnCloudClient.java | 17 +- .../test_project/test/OwnCloudClientTest.java | 376 ++++++++++++++++++ 2 files changed, 391 insertions(+), 2 deletions(-) create mode 100644 test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientTest.java diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index 0e828c03..ace942e4 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -174,6 +174,7 @@ public class OwnCloudClient extends HttpClient { public int executeMethod(HttpMethod method) throws IOException, HttpException { try { // just to log boolean customRedirectionNeeded = false; + try { method.setFollowRedirects(mFollowRedirects); } catch (Exception e) { @@ -259,8 +260,12 @@ public class OwnCloudClient extends HttpClient { * performed by this client. */ public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) { - getParams().setSoTimeout(defaultDataTimeout); - getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout); + if (defaultDataTimeout >= 0) { + getParams().setSoTimeout(defaultDataTimeout); + } + if (defaultConnectionTimeout >= 0) { + getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout); + } } public Uri getWebdavUri() { @@ -352,6 +357,14 @@ public class OwnCloudClient extends HttpClient { return cookiesString; } + + public int getConnectionTimeout() { + return getHttpConnectionManager().getParams().getConnectionTimeout(); + } + + public int getDataTimeout() { + return getParams().getSoTimeout(); + } private void logCookie(Cookie cookie) { Log.d(TAG, "Cookie name: "+ cookie.getName() ); diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientTest.java new file mode 100644 index 00000000..476a8ceb --- /dev/null +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientTest.java @@ -0,0 +1,376 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +package com.owncloud.android.lib.test_project.test; + +import java.io.IOException; +import java.io.InputStream; +import java.net.SocketTimeoutException; +import java.security.GeneralSecurityException; +import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.HeadMethod; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.apache.http.HttpStatus; +import org.apache.jackrabbit.webdav.DavConstants; +import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; + +import junit.framework.AssertionFailedError; + +import android.net.Uri; +import android.test.AndroidTestCase; +import android.util.Log; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudCredentials; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; +import com.owncloud.android.lib.common.accounts.AccountUtils; +import com.owncloud.android.lib.common.network.NetworkUtils; +import com.owncloud.android.lib.test_project.R; +import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; + + +/** + * Unit test for OwnCloudClient + * + * @author David A. Velasco + */ +public class OwnCloudClientTest extends AndroidTestCase { + + private static final String TAG = OwnCloudClientTest.class.getSimpleName(); + + private Uri mServerUri; + private String mUsername; + private String mPassword; + + public OwnCloudClientTest() { + super(); + + Protocol pr = Protocol.getProtocol("https"); + if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { + try { + ProtocolSocketFactory psf = new SelfSignedConfidentSslSocketFactory(); + Protocol.registerProtocol( + "https", + new Protocol("https", psf, 443)); + + } catch (GeneralSecurityException e) { + throw new AssertionFailedError( + "Self-signed confident SSL context could not be loaded"); + } + } + } + + + @Override + protected void setUp() throws Exception { + super.setUp(); + mServerUri = Uri.parse(getContext().getString(R.string.server_base_url)); + mUsername = getContext().getString(R.string.username); + mPassword = getContext().getString(R.string.password); + } + + + public void testConstructor() { + try { + new OwnCloudClient(null, NetworkUtils.getMultiThreadedConnManager()); + throw new AssertionFailedError("Accepted NULL parameter"); + + } catch(Exception e) { + assertTrue("Unexpected exception passing NULL baseUri", + (e instanceof IllegalArgumentException)); + } + + try { + new OwnCloudClient(mServerUri, null); + throw new AssertionFailedError("Accepted NULL parameter"); + + } catch(Exception e) { + assertTrue("Unexpected exception passing NULL connectionMgr", + (e instanceof IllegalArgumentException)); + } + + OwnCloudClient client = + new OwnCloudClient(mServerUri, NetworkUtils.getMultiThreadedConnManager()); + assertNotNull("OwnCloudClient instance not built", client); + assertEquals("Wrong user agent", + client.getParams().getParameter(HttpMethodParams.USER_AGENT), + OwnCloudClient.USER_AGENT); + } + + + public void testGetSetCredentials() { + OwnCloudClient client = + new OwnCloudClient(mServerUri, NetworkUtils.getMultiThreadedConnManager()); + + assertNotNull("Returned NULL credentials", client.getCredentials()); + assertEquals("Not instanced without credentials", + client.getCredentials(), OwnCloudCredentialsFactory.getAnonymousCredentials()); + + OwnCloudCredentials credentials = + OwnCloudCredentialsFactory.newBasicCredentials("user", "pass"); + client.setCredentials(credentials); + assertEquals("Basic credentials not set", credentials, client.getCredentials()); + + credentials = OwnCloudCredentialsFactory.newBearerCredentials("bearerToken"); + client.setCredentials(credentials); + assertEquals("Bearer credentials not set", credentials, client.getCredentials()); + + credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials("samlSessionCookie=124"); + client.setCredentials(credentials); + assertEquals("SAML2 session credentials not set", credentials, client.getCredentials()); + + } + + public void testExecuteMethodWithTimeouts() throws HttpException, IOException { + OwnCloudClient client = + new OwnCloudClient(mServerUri, NetworkUtils.getMultiThreadedConnManager()); + int connectionTimeout = client.getConnectionTimeout(); + int readTimeout = client.getDataTimeout(); + + HeadMethod head = new HeadMethod(client.getWebdavUri() + "/"); + try { + client.executeMethod(head, 1, 1000); + throw new AssertionFailedError("Completed HEAD with impossible read timeout"); + + } catch (Exception e) { + Log.e("OwnCloudClientTest", "EXCEPTION", e); + assertTrue("Unexcepted exception " + e.getLocalizedMessage(), + (e instanceof ConnectTimeoutException) || + (e instanceof SocketTimeoutException)); + + } finally { + head.releaseConnection(); + } + + assertEquals("Connection timeout was changed for future requests", + connectionTimeout, client.getConnectionTimeout()); + assertEquals("Read timeout was changed for future requests", + readTimeout, client.getDataTimeout()); + + try { + client.executeMethod(head, 1000, 1); + throw new AssertionFailedError("Completed HEAD with impossible connection timeout"); + + } catch (Exception e) { + Log.e("OwnCloudClientTest", "EXCEPTION", e); + assertTrue("Unexcepted exception " + e.getLocalizedMessage(), + (e instanceof ConnectTimeoutException) || + (e instanceof SocketTimeoutException)); + + } finally { + head.releaseConnection(); + } + + assertEquals("Connection timeout was changed for future requests", + connectionTimeout, client.getConnectionTimeout()); + assertEquals("Read timeout was changed for future requests", + readTimeout, client.getDataTimeout()); + + } + + + public void testExecuteMethod() { + OwnCloudClient client = + new OwnCloudClient(mServerUri, NetworkUtils.getMultiThreadedConnManager()); + HeadMethod head = new HeadMethod(client.getWebdavUri() + "/"); + int status = -1; + try { + status = client.executeMethod(head); + assertTrue("Wrong status code returned: " + status, + status > 99 && status < 600); + + } catch (IOException e) { + Log.e(TAG, "Exception in HEAD method execution", e); + // TODO - make it fail? ; try several times, and make it fail if none + // is right? + + } finally { + head.releaseConnection(); + } + } + + + public void testExhaustResponse() { + OwnCloudClient client = + new OwnCloudClient(mServerUri, NetworkUtils.getMultiThreadedConnManager()); + + PropFindMethod propfind = null; + try { + propfind = new PropFindMethod(client.getWebdavUri() + "/", + DavConstants.PROPFIND_ALL_PROP, + DavConstants.DEPTH_0); + client.executeMethod(propfind); + InputStream responseBody = propfind.getResponseBodyAsStream(); + if (responseBody != null) { + client.exhaustResponse(responseBody); + + try { + int character = responseBody.read(); + assertEquals("Response body was not fully exhausted", + character, -1); // -1 is acceptable + + } catch (IOException e) { + // this is the preferred result + } + + } else { + Log.e(TAG, "Could not test exhaustResponse due to wrong response"); + // TODO - make it fail? ; try several times, and make it fail if none + // is right? + } + + } catch (IOException e) { + Log.e(TAG, "Exception in PROPFIND method execution", e); + // TODO - make it fail? ; try several times, and make it fail if none + // is right? + + } finally { + propfind.releaseConnection(); + } + + client.exhaustResponse(null); // must run with no exception + } + + + public void testGetSetDefaultTimeouts() { + OwnCloudClient client = + new OwnCloudClient(mServerUri, NetworkUtils.getMultiThreadedConnManager()); + + int oldDataTimeout = client.getDataTimeout(); + int oldConnectionTimeout = client.getConnectionTimeout(); + + client.setDefaultTimeouts(oldDataTimeout + 1000, oldConnectionTimeout + 1000); + assertEquals("Data timeout not set", + oldDataTimeout + 1000, client.getDataTimeout()); + assertEquals("Connection timeout not set", + oldConnectionTimeout + 1000, client.getConnectionTimeout()); + + client.setDefaultTimeouts(0, 0); + assertEquals("Zero data timeout not set", + 0, client.getDataTimeout()); + assertEquals("Zero connection timeout not set", + 0, client.getConnectionTimeout()); + + client.setDefaultTimeouts(-1, -1); + assertEquals("Negative data timeout not ignored", + 0, client.getDataTimeout()); + assertEquals("Negative connection timeout not ignored", + 0, client.getConnectionTimeout()); + + client.setDefaultTimeouts(-1, 1000); + assertEquals("Negative data timeout not ignored", + 0, client.getDataTimeout()); + assertEquals("Connection timeout not set", + 1000, client.getConnectionTimeout()); + + client.setDefaultTimeouts(1000, -1); + assertEquals("Data timeout not set", + 1000, client.getDataTimeout()); + assertEquals("Negative connection timeout not ignored", + 1000, client.getConnectionTimeout()); + + } + + + public void testGetWebdavUri() { + OwnCloudClient client = + new OwnCloudClient(mServerUri, NetworkUtils.getMultiThreadedConnManager()); + client.setCredentials(OwnCloudCredentialsFactory.newBearerCredentials("fakeToken")); + Uri webdavUri = client.getWebdavUri(); + assertTrue("WebDAV URI does not point to the right entry point for OAuth2 " + + "authenticated servers", + webdavUri.getPath().endsWith(AccountUtils.ODAV_PATH)); + + client.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials( + mUsername, mPassword)); + webdavUri = client.getWebdavUri(); + assertTrue("WebDAV URI does not point to the right entry point", + webdavUri.getPath().endsWith(AccountUtils.WEBDAV_PATH_4_0)); + PropFindMethod propfind = null; + try { + propfind = new PropFindMethod(webdavUri + "/", + DavConstants.PROPFIND_ALL_PROP, + DavConstants.DEPTH_0); + int status = client.executeMethod(propfind); + assertEquals("WebDAV request did not work on WebDAV URI", + HttpStatus.SC_MULTI_STATUS, status); + + } catch (IOException e) { + Log.e(TAG, "Exception in PROPFIND method execution", e); + // TODO - make it fail? ; try several times, and make it fail if none + // is right? + + } finally { + propfind.releaseConnection(); + } + + } + + + public void testGetSetBaseUri() { + // TODO implement test body + /** + * Sets the root URI to the ownCloud server. + * + * Use with care. + * + * @param uri + *-/ + public void setBaseUri(Uri uri) { + mBaseUri = uri; + } + public Uri getBaseUri() { + return mBaseUri; + } + */ + } + + + public void testGetCookiesString() { + // TODO implement test body + /*public String getCookiesString(){ + Cookie[] cookies = getState().getCookies(); + String cookiesString =""; + for (Cookie cookie: cookies) { + cookiesString = cookiesString + cookie.toString() + ";"; + + logCookie(cookie); + } + + return cookiesString; + + } + */ + } + + + public void testSetFollowRedirects() { + // TODO implement test body + // to implement this we need a redirected server + } + + +} From 4c8f31df2fb63dbb29be6eacfb8767bc73a34312 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 25 Jun 2014 17:03:16 +0200 Subject: [PATCH 30/35] Added test to unit tests for OwnCloudClient --- .../android/lib/common/OwnCloudClient.java | 3 ++ .../common/operations/RemoteOperation.java | 1 - .../test_project/test/OwnCloudClientTest.java | 39 +++++++++++-------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index ace942e4..e6696ef0 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -284,6 +284,9 @@ public class OwnCloudClient extends HttpClient { * @param uri */ public void setBaseUri(Uri uri) { + if (uri == null) { + throw new IllegalArgumentException("URI cannot be NULL"); + } mBaseUri = uri; } diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index 1384bd7a..bef4b86c 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -281,7 +281,6 @@ public abstract class RemoteOperation implements Runnable { /** DEPRECATED BLOCK - will be removed at version 1.0 ; don't trust in this code * to trigger authentication update */ if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() && -// (result.getCode() == ResultCode.UNAUTHORIZED || (result.isTemporalRedirection() && result.isIdPRedirection()))) { (result.getCode() == ResultCode.UNAUTHORIZED || result.isIdPRedirection())) { /// possible fail due to lack of authorization in an operation performed in foreground OwnCloudCredentials cred = mClient.getCredentials(); diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientTest.java index 476a8ceb..43de601a 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/OwnCloudClientTest.java @@ -303,6 +303,9 @@ public class OwnCloudClientTest extends AndroidTestCase { assertTrue("WebDAV URI does not point to the right entry point for OAuth2 " + "authenticated servers", webdavUri.getPath().endsWith(AccountUtils.ODAV_PATH)); + assertTrue("WebDAV URI is not a subpath of base URI", + webdavUri.getAuthority().equals(mServerUri.getAuthority()) && + webdavUri.getPath().startsWith(mServerUri.getPath())); client.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials( mUsername, mPassword)); @@ -331,21 +334,24 @@ public class OwnCloudClientTest extends AndroidTestCase { public void testGetSetBaseUri() { - // TODO implement test body - /** - * Sets the root URI to the ownCloud server. - * - * Use with care. - * - * @param uri - *-/ - public void setBaseUri(Uri uri) { - mBaseUri = uri; - } - public Uri getBaseUri() { - return mBaseUri; - } - */ + OwnCloudClient client = + new OwnCloudClient(mServerUri, NetworkUtils.getMultiThreadedConnManager()); + assertEquals("Returned base URI different that URI passed to constructor", + mServerUri, client.getBaseUri()); + + Uri otherUri = Uri.parse("https://whatever.com/basePath/here"); + client.setBaseUri(otherUri); + assertEquals("Returned base URI different that URI passed to constructor", + otherUri, client.getBaseUri()); + + try { + client.setBaseUri(null); + throw new AssertionFailedError("Accepted NULL parameter"); + + } catch(Exception e) { + assertTrue("Unexpected exception passing NULL base URI", + (e instanceof IllegalArgumentException)); + } } @@ -368,8 +374,7 @@ public class OwnCloudClientTest extends AndroidTestCase { public void testSetFollowRedirects() { - // TODO implement test body - // to implement this we need a redirected server + // TODO - to implement this test we need a redirected server } From 6cedc03465bee985c95f5b0b3c5433c490d054b4 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 25 Jun 2014 18:13:48 +0200 Subject: [PATCH 31/35] Grant that SingleSessionManager keeps URL updated --- .../lib/common/SingleSessionManager.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index f000983e..68ffbe1d 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -33,6 +33,7 @@ import android.accounts.Account; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; +import android.net.Uri; import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; @@ -81,9 +82,11 @@ public class SingleSessionManager implements OwnCloudClientManager { if (accountName != null) { client = mClientsWithUnknownUsername.remove(sessionName); if (client != null) { - Log.d(TAG, " reusing client {" + sessionName + ", " + client.hashCode() + "}"); + Log.d(TAG, " reusing client {" + sessionName + ", " + + client.hashCode() + "}"); mClientsWithKnownUsername.put(accountName, client); - Log.d(TAG, " moved client to {" + accountName + ", " + client.hashCode() + "}"); + Log.d(TAG, " moved client to {" + accountName + ", " + + client.hashCode() + "}"); } } else { client = mClientsWithUnknownUsername.get(sessionName); @@ -91,7 +94,6 @@ public class SingleSessionManager implements OwnCloudClientManager { } else { Log.d(TAG, " reusing client {" + accountName + ", " + client.hashCode() + "}"); reusingKnown = true; - keepCredentialsUpdated(account, client); } if (client == null) { @@ -117,6 +119,8 @@ public class SingleSessionManager implements OwnCloudClientManager { if (!reusingKnown) { Log.d(TAG, " reusing client {" + sessionName + ", " + client.hashCode() + "}"); } + keepCredentialsUpdated(account, client); + keepUriUpdated(account, client); } return client; @@ -186,4 +190,15 @@ public class SingleSessionManager implements OwnCloudClientManager { } + // this method is just a patch; we need to distinguish accounts in the same host but + // different paths; but that requires updating the accountNames for apps upgrading + private void keepUriUpdated(OwnCloudAccount account, OwnCloudClient reusedClient) { + Uri recentUri = account.getBaseUri(); + if (!recentUri.equals(reusedClient.getBaseUri())) { + reusedClient.setBaseUri(recentUri); + } + + } + + } From 8080e4904de8f042fdff17691674e900607c66a8 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 26 Jun 2014 10:24:45 +0200 Subject: [PATCH 32/35] Fixed OutOfBoundsException --- .../lib/common/OwnCloudSamlSsoCredentials.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java b/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java index 02bbbdc7..d59f5b0c 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java +++ b/src/com/owncloud/android/lib/common/OwnCloudSamlSsoCredentials.java @@ -23,14 +23,17 @@ public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials { String[] cookies = mSessionCookie.split(";"); if (cookies.length > 0) { + Cookie cookie = null; for (int i=0; i= 0) { + cookie = new Cookie(); + cookie.setName(cookies[i].substring(0, equalPos)); + cookie.setValue(cookies[i].substring(equalPos + 1)); + cookie.setDomain(serverUri.getHost()); // VERY IMPORTANT + cookie.setPath(serverUri.getPath()); // VERY IMPORTANT + client.getState().addCookie(cookie); + } } } } From be03f46c7e65dd22a3ce616907c1baa7200e08a3 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Tue, 1 Jul 2014 12:45:10 +0200 Subject: [PATCH 33/35] Added lost import --- src/com/owncloud/android/lib/common/network/WebdavUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/owncloud/android/lib/common/network/WebdavUtils.java b/src/com/owncloud/android/lib/common/network/WebdavUtils.java index 6568290f..b5b3607c 100644 --- a/src/com/owncloud/android/lib/common/network/WebdavUtils.java +++ b/src/com/owncloud/android/lib/common/network/WebdavUtils.java @@ -28,6 +28,7 @@ package com.owncloud.android.lib.common.network; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import android.net.Uri; From 7fe8979846ee16df0132baf9e788452305ccfae5 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Tue, 1 Jul 2014 13:26:29 +0200 Subject: [PATCH 34/35] Added unit test for SingleSessionManager --- .../lib/common/SingleSessionManager.java | 2 +- .../test/SingleSessionManagerTest.java | 123 ++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 test_client/tests/src/com/owncloud/android/lib/test_project/test/SingleSessionManagerTest.java diff --git a/src/com/owncloud/android/lib/common/SingleSessionManager.java b/src/com/owncloud/android/lib/common/SingleSessionManager.java index 68ffbe1d..690056ff 100644 --- a/src/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/src/com/owncloud/android/lib/common/SingleSessionManager.java @@ -101,7 +101,7 @@ public class SingleSessionManager implements OwnCloudClientManager { client = OwnCloudClientFactory.createOwnCloudClient( account.getBaseUri(), context.getApplicationContext(), - true); + true); // TODO remove dependency on OwnCloudClientFactory // Restore Cookies ?? AccountUtils.restoreCookies(accountName, client, context); diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/SingleSessionManagerTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/SingleSessionManagerTest.java new file mode 100644 index 00000000..8e0799ae --- /dev/null +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/SingleSessionManagerTest.java @@ -0,0 +1,123 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +package com.owncloud.android.lib.test_project.test; + +import java.security.GeneralSecurityException; + +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; + +import android.net.Uri; +import android.test.AndroidTestCase; + +import com.owncloud.android.lib.common.OwnCloudAccount; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; +import com.owncloud.android.lib.common.SingleSessionManager; +import com.owncloud.android.lib.test_project.R; +import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; + +import junit.framework.AssertionFailedError; + +/** + * Unit test for SingleSessionManager + * + * @author David A. Velasco + */ +public class SingleSessionManagerTest extends AndroidTestCase { + + private SingleSessionManager mSSMgr; + + private Uri mServerUri; + private String mUsername; + private OwnCloudAccount mValidAccount; + private OwnCloudAccount mAnonymousAccount; + + public SingleSessionManagerTest() { + super(); + + Protocol pr = Protocol.getProtocol("https"); + if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { + try { + ProtocolSocketFactory psf = new SelfSignedConfidentSslSocketFactory(); + Protocol.registerProtocol( + "https", + new Protocol("https", psf, 443)); + + } catch (GeneralSecurityException e) { + throw new AssertionFailedError( + "Self-signed confident SSL context could not be loaded"); + } + } + } + + + @Override + protected void setUp() throws Exception { + super.setUp(); + mSSMgr = new SingleSessionManager(); + mServerUri = Uri.parse(getContext().getString(R.string.server_base_url)); + mUsername = getContext().getString(R.string.username); + + mValidAccount = new OwnCloudAccount( + mServerUri, OwnCloudCredentialsFactory.newBasicCredentials( + mUsername, + getContext().getString(R.string.password) + ) + ); + + mAnonymousAccount = new OwnCloudAccount( + mServerUri, OwnCloudCredentialsFactory.getAnonymousCredentials()); + + } + + public void testGetClientFor() { + OwnCloudClient client1 = mSSMgr.getClientFor(mValidAccount, getContext()); + OwnCloudClient client2 = mSSMgr.getClientFor(mAnonymousAccount, getContext()); + + assertNotSame("Got same client instances for different accounts", + client1, client2); + assertSame("Got different client instances for same account", + client1, mSSMgr.getClientFor(mValidAccount, getContext())); + + // TODO harder tests + } + + public void testRemoveClientFor() { + OwnCloudClient client1 = mSSMgr.getClientFor(mValidAccount, getContext()); + mSSMgr.removeClientFor(mValidAccount); + assertNotSame("Got same client instance after removing it from manager", + client1, mSSMgr.getClientFor(mValidAccount, getContext())); + + // TODO harder tests + } + + + public void testSaveAllClients() { + // TODO implement test; + // or refactor saveAllClients() method out of OwnCloudClientManager to make + // it independent of AccountManager + } + +} From 3c116514fb33992d050f7051e756b6c2244953b0 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Tue, 1 Jul 2014 13:32:43 +0200 Subject: [PATCH 35/35] Added unit test for SimpleFactoryManager --- .../test/SimpleFactoryManagerTest.java | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 test_client/tests/src/com/owncloud/android/lib/test_project/test/SimpleFactoryManagerTest.java diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/SimpleFactoryManagerTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/SimpleFactoryManagerTest.java new file mode 100644 index 00000000..3254c589 --- /dev/null +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/SimpleFactoryManagerTest.java @@ -0,0 +1,124 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +package com.owncloud.android.lib.test_project.test; + +import java.security.GeneralSecurityException; + +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; + +import android.net.Uri; +import android.test.AndroidTestCase; + +import com.owncloud.android.lib.common.OwnCloudAccount; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; +import com.owncloud.android.lib.common.SimpleFactoryManager; +import com.owncloud.android.lib.test_project.R; +import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; + +import junit.framework.AssertionFailedError; + +/** + * Unit test for SimpleFactoryManager + * + * @author David A. Velasco + */ + +public class SimpleFactoryManagerTest extends AndroidTestCase { + + private SimpleFactoryManager mSFMgr; + + private Uri mServerUri; + private String mUsername; + private OwnCloudAccount mValidAccount; + private OwnCloudAccount mAnonymousAccount; + + public SimpleFactoryManagerTest() { + super(); + + Protocol pr = Protocol.getProtocol("https"); + if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { + try { + ProtocolSocketFactory psf = new SelfSignedConfidentSslSocketFactory(); + Protocol.registerProtocol( + "https", + new Protocol("https", psf, 443)); + + } catch (GeneralSecurityException e) { + throw new AssertionFailedError( + "Self-signed confident SSL context could not be loaded"); + } + } + } + + + @Override + protected void setUp() throws Exception { + super.setUp(); + mSFMgr = new SimpleFactoryManager(); + mServerUri = Uri.parse(getContext().getString(R.string.server_base_url)); + mUsername = getContext().getString(R.string.username); + + mValidAccount = new OwnCloudAccount( + mServerUri, OwnCloudCredentialsFactory.newBasicCredentials( + mUsername, + getContext().getString(R.string.password) + ) + ); + + mAnonymousAccount = new OwnCloudAccount( + mServerUri, OwnCloudCredentialsFactory.getAnonymousCredentials()); + + } + + public void testGetClientFor() { + OwnCloudClient client = mSFMgr.getClientFor(mValidAccount, getContext()); + + assertNotSame("Got same client instances for same account", + client, mSFMgr.getClientFor(mValidAccount, getContext())); + + assertNotSame("Got same client instances for different accounts", + client, mSFMgr.getClientFor(mAnonymousAccount, getContext())); + + // TODO harder tests + } + + public void testRemoveClientFor() { + OwnCloudClient client = mSFMgr.getClientFor(mValidAccount, getContext()); + mSFMgr.removeClientFor(mValidAccount); + assertNotSame("Got same client instance after removing it from manager", + client, mSFMgr.getClientFor(mValidAccount, getContext())); + + // TODO harder tests + } + + + public void testSaveAllClients() { + // TODO implement test; + // or refactor saveAllClients() method out of OwnCloudClientManager to make + // it independent of AccountManager + } + +}