mirror of
				https://github.com/owncloud/android-library.git
				synced 2025-10-31 02:17:41 +00:00 
			
		
		
		
	Invalidate the client token when access token expires and try the last operation [WIP]
This commit is contained in:
		
							parent
							
								
									fe947194c5
								
							
						
					
					
						commit
						a1b1c2f9ed
					
				| @ -1,5 +1,5 @@ | ||||
| /* ownCloud Android Library is available under MIT license | ||||
|  *   Copyright (C) 2016 ownCloud GmbH. | ||||
|  *   Copyright (C) 2017 ownCloud GmbH. | ||||
|  *    | ||||
|  *   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  *   of this software and associated documentation files (the "Software"), to deal | ||||
| @ -45,58 +45,75 @@ import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * Operation which execution involves one or several interactions with an ownCloud server. | ||||
|  *  | ||||
|  * | ||||
|  * Provides methods to execute the operation both synchronously or asynchronously. | ||||
|  *  | ||||
|  * @author David A. Velasco  | ||||
|  * | ||||
|  * @author David A. Velasco | ||||
|  * @author David González Verdugo | ||||
|  */ | ||||
| public abstract class RemoteOperation implements Runnable { | ||||
| 	 | ||||
| 
 | ||||
|     private static final String TAG = RemoteOperation.class.getSimpleName(); | ||||
| 
 | ||||
|     /** OCS API header name */ | ||||
|     /** | ||||
|      * OCS API header name | ||||
|      */ | ||||
|     public static final String OCS_API_HEADER = "OCS-APIREQUEST"; | ||||
| 
 | ||||
|     /** OCS API header value */ | ||||
|     /** | ||||
|      * OCS API header value | ||||
|      */ | ||||
|     public static final String OCS_API_HEADER_VALUE = "true"; | ||||
| 
 | ||||
|     /** ownCloud account in the remote ownCloud server to operate */ | ||||
|     /** | ||||
|      * ownCloud account in the remote ownCloud server to operate | ||||
|      */ | ||||
|     private Account mAccount = null; | ||||
|      | ||||
|     /** Android Application context */ | ||||
|     private Context mContext = null; | ||||
|      | ||||
| 	/** Object to interact with the remote server */ | ||||
| 	private OwnCloudClient mClient = null; | ||||
| 	 | ||||
| 	/** Callback object to notify about the execution of the remote operation */ | ||||
| 	private OnRemoteOperationListener mListener = null; | ||||
| 	 | ||||
| 	/** Handler to the thread where mListener methods will be called */ | ||||
| 	private Handler mListenerHandler = null; | ||||
| 
 | ||||
| 	/** Activity */ | ||||
|     /** | ||||
|      * Android Application context | ||||
|      */ | ||||
|     private Context mContext = null; | ||||
| 
 | ||||
|     /** | ||||
|      * Object to interact with the remote server | ||||
|      */ | ||||
|     private OwnCloudClient mClient = null; | ||||
| 
 | ||||
|     /** | ||||
|      * Callback object to notify about the execution of the remote operation | ||||
|      */ | ||||
|     private OnRemoteOperationListener mListener = null; | ||||
| 
 | ||||
|     /** | ||||
|      * 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. | ||||
| 	 */ | ||||
| 	protected abstract RemoteOperationResult run(OwnCloudClient client); | ||||
| 	 | ||||
| 
 | ||||
|     /** | ||||
|      * Abstract method to implement the operation in derived classes. | ||||
|      */ | ||||
|     protected abstract RemoteOperationResult run(OwnCloudClient client); | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Synchronously executes the remote operation on the received ownCloud account. | ||||
|      *  | ||||
|      * | ||||
|      * Do not call this method from the main thread. | ||||
|      *  | ||||
|      * | ||||
|      * This method should be used whenever an ownCloud account is available, instead of | ||||
|      * {@link #execute(OwnCloudClient)}. | ||||
|      *  | ||||
|      * @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. | ||||
|      * @return          Result of the operation. | ||||
|      * | ||||
|      * @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. | ||||
|      * @return Result of the operation. | ||||
|      */ | ||||
|     public RemoteOperationResult execute(Account account, Context context) { | ||||
|         if (account == null) | ||||
| @ -108,54 +125,53 @@ public abstract class RemoteOperation implements Runnable { | ||||
|         mAccount = account; | ||||
|         mContext = context.getApplicationContext(); | ||||
|         try { | ||||
|         	OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); | ||||
|             OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); | ||||
|             mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). | ||||
|             		getClientFor(ocAccount, mContext); | ||||
|                     getClientFor(ocAccount, mContext); | ||||
|         } catch (Exception e) { | ||||
|             Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); | ||||
|             return new RemoteOperationResult(e); | ||||
|         } | ||||
|         return run(mClient); | ||||
|     } | ||||
|      | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Synchronously executes the remote operation | ||||
| 	 *  | ||||
|      * Do not call this method from the main thread. | ||||
|      *  | ||||
| 	 * @param client	Client object to reach an ownCloud server during the execution of | ||||
|      *                  the operation. | ||||
| 	 * @return			Result of the operation. | ||||
| 	 */ | ||||
| 	public RemoteOperationResult execute(OwnCloudClient client) { | ||||
| 		if (client == null) | ||||
| 			throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " + | ||||
|                     "OwnCloudClient"); | ||||
| 		mClient = client; | ||||
| 		return run(client); | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
|     /** | ||||
|      * Synchronously executes the remote operation | ||||
|      * | ||||
|      * Do not call this method from the main thread. | ||||
|      * | ||||
|      * @param client Client object to reach an ownCloud server during the execution of | ||||
|      *               the operation. | ||||
|      * @return Result of the operation. | ||||
|      */ | ||||
|     public RemoteOperationResult execute(OwnCloudClient client) { | ||||
|         if (client == null) | ||||
|             throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " + | ||||
|                     "OwnCloudClient"); | ||||
|         mClient = client; | ||||
|         return run(client); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Asynchronously executes the remote operation | ||||
|      *  | ||||
|      * | ||||
|      * 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. | ||||
|      * | ||||
|      * @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 This method will be removed in version 1.0. | ||||
|      * Use {@link #execute(Account, Context, OnRemoteOperationListener, | ||||
|      * Handler)} instead. | ||||
|      */ | ||||
| 	@Deprecated | ||||
|     @Deprecated | ||||
|     public Thread execute(Account account, Context context, OnRemoteOperationListener listener, | ||||
|                           Handler listenerHandler, Activity callerActivity) { | ||||
|         if (account == null) | ||||
| @ -168,34 +184,34 @@ public abstract class RemoteOperation implements Runnable { | ||||
|         mContext = context.getApplicationContext(); | ||||
|         mCallerActivity = callerActivity; | ||||
|         mClient = null;     // the client instance will be created from mAccount | ||||
|                             // and mContext in the runnerThread to create below | ||||
|         // 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 | ||||
|      *  | ||||
|      * This method should be used whenever an ownCloud account is available,  | ||||
|      * | ||||
|      * 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. | ||||
|      * | ||||
|      * @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"); | ||||
| @ -206,147 +222,185 @@ public abstract class RemoteOperation implements Runnable { | ||||
|         mContext = context.getApplicationContext(); | ||||
|         mCallerActivity = null; | ||||
|         mClient = null;     // the client instance will be created from | ||||
|                             // mAccount and mContext in the runnerThread to create below | ||||
|          | ||||
|         // 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 | ||||
| 	 *  | ||||
| 	 * @param client			Client object to reach an ownCloud server | ||||
|      *                          during the execution of the operation. | ||||
| 	 * @param listener			Listener to be notified about the execution of the operation. | ||||
| 	 * @param listenerHandler	Handler, if passed in, 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(OwnCloudClient client, | ||||
| 
 | ||||
|     /** | ||||
|      * Asynchronously executes the remote operation | ||||
|      * | ||||
|      * @param client          Client object to reach an ownCloud server | ||||
|      *                        during the execution of the operation. | ||||
|      * @param listener        Listener to be notified about the execution of the operation. | ||||
|      * @param listenerHandler Handler, if passed in, 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(OwnCloudClient client, | ||||
|                           OnRemoteOperationListener listener, Handler listenerHandler) { | ||||
| 		if (client == null) { | ||||
| 			throw new IllegalArgumentException | ||||
|         if (client == null) { | ||||
|             throw new IllegalArgumentException | ||||
|                     ("Trying to execute a remote operation with a NULL OwnCloudClient"); | ||||
| 		} | ||||
| 		mClient = client; | ||||
| 		 | ||||
| 		if (listener == null) { | ||||
| 			throw new IllegalArgumentException | ||||
|         } | ||||
|         mClient = client; | ||||
| 
 | ||||
|         if (listener == null) { | ||||
|             throw new IllegalArgumentException | ||||
|                     ("Trying to execute a remote operation asynchronously " + | ||||
|                             "without a listener to notiy the result"); | ||||
| 		} | ||||
| 		mListener = listener; | ||||
| 		 | ||||
| 		if (listenerHandler != null) { | ||||
|         } | ||||
|         mListener = listener; | ||||
| 
 | ||||
|         if (listenerHandler != null) { | ||||
|             mListenerHandler = listenerHandler; | ||||
| 		} | ||||
| 
 | ||||
| 		 | ||||
| 		Thread runnerThread = new Thread(this); | ||||
| 		runnerThread.start(); | ||||
| 		return runnerThread; | ||||
| 	} | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Asynchronous execution of the operation  | ||||
| 	 * started by {@link RemoteOperation#execute(OwnCloudClient, | ||||
|      *              OnRemoteOperationListener, Handler)}, | ||||
| 	 * and result posting. | ||||
| 	 *  | ||||
| 	 * TODO refactor && clean the code; now it's a mess | ||||
| 	 */ | ||||
|         Thread runnerThread = new Thread(this); | ||||
|         runnerThread.start(); | ||||
|         return runnerThread; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Asynchronous execution of the operation | ||||
|      * started by {@link RemoteOperation#execute(OwnCloudClient, | ||||
|      * OnRemoteOperationListener, Handler)}, | ||||
|      * and result posting. | ||||
|      * | ||||
|      * TODO refactor && clean the code; now it's a mess | ||||
|      */ | ||||
|     @Override | ||||
|     public final void run() { | ||||
|         RemoteOperationResult result = null; | ||||
|         boolean repeat = false; | ||||
|         do { | ||||
|             try{ | ||||
|             try { | ||||
|                 if (mClient == null) { | ||||
|                     if (mAccount != null && mContext != null) { | ||||
|                     	/** DEPRECATED BLOCK - will be removed at version 1.0 */ | ||||
|                         /** DEPRECATED BLOCK - will be removed at version 1.0 */ | ||||
|                         if (mCallerActivity != null) { | ||||
|                             mClient = OwnCloudClientFactory.createOwnCloudClient( | ||||
|                             		mAccount, mContext, mCallerActivity); | ||||
|                                     mAccount, mContext, mCallerActivity); | ||||
|                         } else { | ||||
|                         /** EOF DEPRECATED */ | ||||
|                         	OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); | ||||
|                             /** EOF DEPRECATED */ | ||||
|                             OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); | ||||
|                             mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). | ||||
|                             		getClientFor(ocAccount, mContext); | ||||
|                                     getClientFor(ocAccount, mContext); | ||||
|                         } | ||||
|                          | ||||
| 
 | ||||
|                     } else { | ||||
|                         throw new IllegalStateException("Trying to run a remote operation " + | ||||
|                                 "asynchronously with no client instance or account"); | ||||
|                     } | ||||
|                 } | ||||
|              | ||||
| 
 | ||||
|             } catch (IOException e) { | ||||
|                 Log_OC.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) { | ||||
|                 Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); | ||||
|                 result = new RemoteOperationResult(e); | ||||
|             } | ||||
|     	 | ||||
| 
 | ||||
|             if (result == null) | ||||
|                 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 && | ||||
| 
 | ||||
| 
 | ||||
|             AccountManager mAccountManager = AccountManager.get(mContext); | ||||
| 
 | ||||
|             String isOAuthStr = mAccountManager.getUserData(mAccount, | ||||
|                     AccountUtils.Constants.KEY_SUPPORTS_OAUTH2); | ||||
| 
 | ||||
|             Boolean isOAuth = Boolean.valueOf(isOAuthStr); | ||||
| 
 | ||||
|             /** DEPRECATED BLOCK - will be removed at version 1.0 ; don't trust in this code | ||||
|              * 						to trigger authentication update */ | ||||
|             if (mAccount != null && mContext != null && | ||||
|                     !result.isSuccess() && | ||||
|                     ResultCode.UNAUTHORIZED.equals(result.getCode()) | ||||
|                 ) { | ||||
|                     ) { | ||||
|                 /// possible fail due to lack of authorization | ||||
|                 // in an operation performed in foreground | ||||
|                 OwnCloudCredentials cred = mClient.getCredentials(); | ||||
|                 if (cred != null) { | ||||
|                     /// confirmed : unauthorized operation | ||||
|                     AccountManager am = AccountManager.get(mContext); | ||||
|                     if (cred.authTokenExpires()) { | ||||
|                         am.invalidateAuthToken( | ||||
|                                 mAccount.type,  | ||||
|                                 cred.getAuthToken() | ||||
|                         ); | ||||
|                     } else { | ||||
|                         am.clearPassword(mAccount); | ||||
| 
 | ||||
|                     OwnCloudClient client; | ||||
|                     OwnCloudAccount ocAccount; | ||||
| 
 | ||||
|                     try { | ||||
|                         /// Step 1: Invalidate credentials of current account | ||||
|                         ocAccount = new OwnCloudAccount(mAccount, mContext); | ||||
|                         client = (OwnCloudClientManagerFactory.getDefaultSingleton(). | ||||
|                                 removeClientFor(ocAccount)); | ||||
|                         if (client != null) { | ||||
|                             AccountManager am = AccountManager.get(mContext); | ||||
|                             if (cred.authTokenExpires()) { | ||||
|                                 am.invalidateAuthToken( // SAML & OAuth | ||||
|                                         mAccount.type, | ||||
|                                         cred.getAuthToken() | ||||
|                                 ); | ||||
|                             } else { //Basic | ||||
|                                 am.clearPassword(mAccount); | ||||
|                             } | ||||
|                         } | ||||
| 
 | ||||
|                         /// Step 2: Get new access token using refresh token | ||||
|                         //  Params needed: clientId, clientSecret (switch credentials), grantype and | ||||
|                         //  refresh token | ||||
|                         String refreshToken = mAccountManager.getUserData(mAccount, | ||||
|                                 AccountUtils.Constants.KEY_OAUTH2_REFRESH_TOKEN); | ||||
| 
 | ||||
| //                        mClient.executeMethod(postMethod); | ||||
| 
 | ||||
|                         /// Step 3: Save access token in account manager | ||||
| 
 | ||||
|                     } catch (AccountUtils.AccountNotFoundException e) { | ||||
|                         e.printStackTrace(); | ||||
|                     } | ||||
| 
 | ||||
|                     mClient = null; | ||||
| 
 | ||||
|                     // when repeated, the creation of a new OwnCloudClient after erasing the saved | ||||
|                     // credentials will trigger the login activity | ||||
|                     repeat = true; | ||||
|                     if (isOAuth) { | ||||
|                         repeat = true; | ||||
|                     } | ||||
| 
 | ||||
|                     result = null; | ||||
|                 } | ||||
|             } | ||||
|             /** EOF DEPRECATED BLOCK **/ | ||||
|         } while (repeat); | ||||
|          | ||||
| 
 | ||||
|         if (mAccount != null && mContext != null) { | ||||
|         	// Save Client Cookies | ||||
|             // Save Client Cookies | ||||
|             AccountUtils.saveClient(mClient, mAccount, mContext); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         final RemoteOperationResult resultToSend = result; | ||||
|         if (mListenerHandler != null && mListener != null) { | ||||
|         	mListenerHandler.post(new Runnable() { | ||||
|             mListenerHandler.post(new Runnable() { | ||||
|                 @Override | ||||
|                 public void run() { | ||||
|                     mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|         else if(mListener != null) { | ||||
|         } else if (mListener != null) { | ||||
|             mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend); | ||||
|         } | ||||
|     } | ||||
| @ -354,11 +408,10 @@ 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. | ||||
|      * | ||||
|      * @return Current client instance to access the remote server. | ||||
|      */ | ||||
|     public final OwnCloudClient getClient() { | ||||
|         return mClient; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user