From 73f8797b7572e431037fd5ee55c24237c544dfcb Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 17 Jan 2013 13:01:51 +0100 Subject: [PATCH] Redirect app to login screen when operations in file details view fail due to bad credentials --- .../android/network/OwnCloudClientUtils.java | 28 +++++++++++++ .../android/operations/RemoteOperation.java | 34 ++++++++++++---- .../ui/activity/AuthenticatorActivity.java | 15 +++++++ .../ui/activity/FileDisplayActivity.java | 3 +- .../ui/fragment/FileDetailFragment.java | 39 +++++++++---------- .../ui/fragment/OCFileListFragment.java | 6 +-- src/eu/alefzero/webdav/WebdavClient.java | 6 +++ 7 files changed, 99 insertions(+), 32 deletions(-) diff --git a/src/com/owncloud/android/network/OwnCloudClientUtils.java b/src/com/owncloud/android/network/OwnCloudClientUtils.java index 5fb765c2e3..b334fdffb7 100644 --- a/src/com/owncloud/android/network/OwnCloudClientUtils.java +++ b/src/com/owncloud/android/network/OwnCloudClientUtils.java @@ -44,10 +44,13 @@ import eu.alefzero.webdav.WebdavClient; import android.accounts.Account; import android.accounts.AccountManager; +import android.accounts.AccountManagerFuture; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; +import android.app.Activity; import android.content.Context; import android.net.Uri; +import android.os.Bundle; import android.util.Log; public class OwnCloudClientUtils { @@ -103,6 +106,31 @@ public class OwnCloudClientUtils { } + public static WebdavClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException { + Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account)); + WebdavClient client = createOwnCloudClient(uri, appContext); + AccountManager am = AccountManager.get(appContext); + if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) { // TODO avoid a call to getUserData here + AccountManagerFuture future = am.getAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, null, currentActivity, null, null); + Bundle result = future.getResult(); + String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN); + //String accessToken = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, false); + if (accessToken == null) throw new AuthenticatorException("WTF!"); + client.setBearerCredentials(accessToken); // TODO not assume that the access token is a bearer token + + } else { + String username = account.name.substring(0, account.name.lastIndexOf('@')); + //String password = am.getPassword(account); + //String password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, false); + AccountManagerFuture future = am.getAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, null, currentActivity, null, null); + Bundle result = future.getResult(); + String password = result.getString(AccountManager.KEY_AUTHTOKEN); + client.setBasicCredentials(username, password); + } + + return client; + } + /** * Creates a WebdavClient to try a new account before saving it * diff --git a/src/com/owncloud/android/operations/RemoteOperation.java b/src/com/owncloud/android/operations/RemoteOperation.java index b4f04be203..6917cb146e 100644 --- a/src/com/owncloud/android/operations/RemoteOperation.java +++ b/src/com/owncloud/android/operations/RemoteOperation.java @@ -23,8 +23,7 @@ import com.owncloud.android.network.OwnCloudClientUtils; import android.accounts.Account; import android.accounts.AccountsException; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; +import android.app.Activity; import android.content.Context; import android.os.Handler; import android.util.Log; @@ -57,6 +56,9 @@ public abstract class RemoteOperation implements Runnable { /** Handler to the thread where mListener methods will be called */ private Handler mListenerHandler = null; + /** Activity */ + private Activity mCallerActivity; + /** * Abstract method to implement the operation in derived classes. @@ -119,13 +121,14 @@ public abstract class RemoteOperation implements Runnable { * @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 final Thread execute(Account account, Context context, OnRemoteOperationListener listener, Handler listenerHandler) { + public final 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"); if (context == null) throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context"); mAccount = account; mContext = context.getApplicationContext(); + mCallerActivity = callerActivity; mClient = null; // the client instance will be created from mAccount and mContext in the runnerThread to create below if (listener == null) { @@ -207,15 +210,18 @@ public abstract class RemoteOperation implements Runnable { try{ if (mClient == null) { if (mAccount != null && mContext != null) { - mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext); + if (mCallerActivity != null) { + mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext, mCallerActivity); + } else { + mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext); + } } else { throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account"); } } - result = run(mClient); } catch (IOException e) { - Log.e(TAG, "Error while trying to access to " + mAccount.name, e); + Log.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e)); result = new RemoteOperationResult(e); } catch (AccountsException e) { @@ -223,6 +229,9 @@ public abstract class RemoteOperation implements Runnable { result = new RemoteOperationResult(e); } + if (result == null) + result = run(mClient); + final RemoteOperationResult resultToSend = result; if (mListenerHandler != null && mListener != null) { mListenerHandler.post(new Runnable() { @@ -233,6 +242,15 @@ public abstract class RemoteOperation implements Runnable { }); } } - - + + + /** + * Returns the current client instance to access the remote server. + * + * @return Current client instance to access the remote server. + */ + public final WebdavClient getClient() { + return mClient; + } + } diff --git a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java index ecf71e045e..fb5c711b2f 100644 --- a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java +++ b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java @@ -112,6 +112,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private boolean mStatusCorrect, mIsSslConn; private RemoteOperationResult mLastSslUntrustedServerResult; + public static final String PARAM_ACCOUNTNAME = "param_Accountname"; + public static final String PARAM_USERNAME = "param_Username"; public static final String PARAM_HOSTNAME = "param_Hostname"; @@ -196,6 +198,19 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity mStatusText = mStatusIcon = 0; mStatusCorrect = false; mIsSslConn = false; + + String accountName = getIntent().getExtras().getString(PARAM_ACCOUNTNAME); + String tokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE); + if (AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(tokenType)) { + CheckBox oAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check); + oAuth2Check.setChecked(true); + changeViewByOAuth2Check(true); + } + + if (accountName != null) { + ((TextView) findViewById(R.id.account_username)).setText(accountName.substring(0, accountName.lastIndexOf('@'))); + tv.setText(accountName.substring(accountName.lastIndexOf('@') + 1)); + } } iv.setOnClickListener(this); iv2.setOnClickListener(this); diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index d72fb4dae2..a717f0c619 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -658,7 +658,8 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements operation.execute( AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), FileDisplayActivity.this, FileDisplayActivity.this, - mHandler); + mHandler, + FileDisplayActivity.this); dialog.dismiss(); diff --git a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java index 64e3ccaece..8740f834cd 100644 --- a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -18,20 +18,9 @@ package com.owncloud.android.ui.fragment; import java.io.File; -import java.util.ArrayList; -import java.util.List; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.commons.httpclient.params.HttpConnectionManagerParams; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.protocol.HTTP; -import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; -import org.json.JSONObject; +import org.apache.commons.httpclient.Credentials; +import org.apache.commons.httpclient.UsernamePasswordCredentials; import android.accounts.Account; import android.accounts.AccountManager; @@ -66,7 +55,6 @@ import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragment; -import com.owncloud.android.AccountUtils; import com.owncloud.android.DisplayUtils; import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -76,6 +64,7 @@ import com.owncloud.android.files.services.FileObserverService; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; +import com.owncloud.android.network.BearerCredentials; import com.owncloud.android.network.OwnCloudClientUtils; import com.owncloud.android.operations.OnRemoteOperationListener; import com.owncloud.android.operations.RemoteOperation; @@ -90,10 +79,8 @@ import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.TransferServiceGetter; import com.owncloud.android.ui.dialog.EditNameDialog; import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener; -import com.owncloud.android.utils.OwnCloudVersion; import com.owncloud.android.R; -import eu.alefzero.webdav.WebdavClient; import eu.alefzero.webdav.WebdavUtils; /** @@ -308,7 +295,7 @@ public class FileDetailFragment extends SherlockFragment implements } else { mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity()); - mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler); + mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity()); // update ui boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; @@ -422,7 +409,7 @@ public class FileDetailFragment extends SherlockFragment implements mLastRemoteOperation = new RemoveFileOperation( mFile, true, mStorageManager); - mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler); + mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity()); boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); @@ -863,7 +850,7 @@ public class FileDetailFragment extends SherlockFragment implements mAccount, newFilename, new FileDataStorageManager(mAccount, getActivity().getContentResolver())); - mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler); + mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity()); boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity; getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT); } @@ -949,7 +936,19 @@ public class FileDetailFragment extends SherlockFragment implements */ @Override public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { - if (operation.equals(mLastRemoteOperation)) { + if (!result.isSuccess() && result.getCode() == ResultCode.UNAUTHORIZED) { + AccountManager am = AccountManager.get(getSherlockActivity()); + //am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, OwnCloudClientUtils.getAuthorizationTokenType(operation.getClient().getCredentials())); + Credentials cred = operation.getClient().getCredentials(); + if (cred instanceof BearerCredentials) { + am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, ((BearerCredentials)cred).getAccessToken()); + } else { + am.clearPassword(mAccount); + } + operation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity()); // need a new client instance, so avoid retry() + // TODO si el usuario no se autoriza de nuevo, esto genera un bucle infinito; o un error en la creación del objecto cliente + + } else { if (operation instanceof RemoveFileOperation) { onRemoveFileOperationFinish((RemoveFileOperation)operation, result); diff --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java index b1328920c1..751de9eeb9 100644 --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -316,7 +316,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial case R.id.download_file_item: { Account account = AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()); RemoteOperation operation = new SynchronizeFileOperation(mTargetFile, null, mContainerActivity.getStorageManager(), account, true, false, getSherlockActivity()); - operation.execute(account, getSherlockActivity(), mContainerActivity, mHandler); + operation.execute(account, getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity()); getSherlockActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT); return true; } @@ -478,7 +478,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial AccountUtils.getCurrentOwnCloudAccount(getActivity()), newFilename, mContainerActivity.getStorageManager()); - operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler); + operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity()); getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT); } } @@ -491,7 +491,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial RemoteOperation operation = new RemoveFileOperation( mTargetFile, true, mContainerActivity.getStorageManager()); - operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler); + operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity()); getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT); } diff --git a/src/eu/alefzero/webdav/WebdavClient.java b/src/eu/alefzero/webdav/WebdavClient.java index d92d0973df..312b8287bb 100644 --- a/src/eu/alefzero/webdav/WebdavClient.java +++ b/src/eu/alefzero/webdav/WebdavClient.java @@ -335,4 +335,10 @@ public class WebdavClient extends HttpClient { } return super.executeMethod(hostconfig, method, state); } + + + public final Credentials getCredentials() { + return mCredentials; + } + }