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

OwnCloudClientMap abstracted to interface OwnCloudClientManager, and provided two alternative implementations; added also OwnCloudCredentials interface to abstract all the credential types handled

This commit is contained in:
David A. Velasco 2014-06-12 08:58:34 +02:00
parent becf4f3c13
commit a42f6b5d6d
16 changed files with 777 additions and 193 deletions

View File

@ -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);

View File

@ -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<String> authPrefs = new ArrayList<String>(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;
}
}

View File

@ -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<String> authPrefs = new ArrayList<String>(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;
}
}

View File

@ -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<String> authPrefs = new ArrayList<String>(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;

View File

@ -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<Bundle> future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypeAccessToken(account.type), null, currentActivity, null, null);
AccountManagerFuture<Bundle> 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<Bundle> future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type), null, currentActivity, null, null);
AccountManagerFuture<Bundle> 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<Bundle> future = am.getAuthToken(account, AccountTypeUtils.getAuthTokenTypePass(account.type), null, currentActivity, null, null);
AccountManagerFuture<Bundle> 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

View File

@ -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;
}

View File

@ -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");
}
}
}

View File

@ -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<String, OwnCloudClient> mClients =
new java.util.concurrent.ConcurrentHashMap<String, OwnCloudClient>();
private static ConcurrentMap<String, OwnCloudClient> mAnonymousClient =
new java.util.concurrent.ConcurrentHashMap<String, OwnCloudClient>();
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() );
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
package com.owncloud.android.lib.common;
public interface OwnCloudCredentials {
public void applyTo(OwnCloudClient ownCloudClient);
public String getAuthToken();
public boolean authTokenExpires();
}

View File

@ -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;
}
}
}

View File

@ -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<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);
}
}
}
@Override
public String getAuthToken() {
return mSessionCookie;
}
@Override
public boolean authTokenExpires() {
return true;
}
}

View File

@ -0,0 +1,56 @@
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;
public class SimpleFactoryManager implements OwnCloudClientManager {
@Override
public OwnCloudClient getClientFor(Account savedAccount, Context context)
throws OperationCanceledException, AuthenticatorException, AccountNotFoundException,
IOException {
return OwnCloudClientFactory.createOwnCloudClient(
savedAccount,
context.getApplicationContext());
}
@Override
public OwnCloudClient getClientFor(Uri serverBaseUri, OwnCloudCredentials credentials,
Context context) {
OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(
serverBaseUri,
context.getApplicationContext(),
true);
client.setCredentials(credentials);
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
}
@Override
public OwnCloudClient removeClientFor(Account account, Context context) {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,214 @@
/* 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.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}
*
* 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 OwnCloudClientManager mInstance = null;
private Map<String, Map<OwnCloudCredentials, OwnCloudClient>> mClientsPerServer =
new HashMap<String, Map<OwnCloudCredentials, OwnCloudClient>>();
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<OwnCloudCredentials, OwnCloudClient> clientsPerAccount =
mClientsPerServer.get(serverBaseUri.toString());
if (clientsPerAccount == null) {
clientsPerAccount = new HashMap<OwnCloudCredentials, OwnCloudClient>();
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<OwnCloudCredentials, OwnCloudClient> 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<OwnCloudCredentials, OwnCloudClient> 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() );
}
}

View File

@ -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";
}
}

View File

@ -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);
}

View File

@ -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");