Эх сурвалжийг харах

Foreground operations on files (remove, rename, new folder) failed due to SAML SSO session expired redirect the app to the login view for a new authentication

David A. Velasco 11 жил өмнө
parent
commit
78bcf72188

+ 1 - 0
res/values/strings.xml

@@ -211,6 +211,7 @@
     <string name="auth_wtf_reenter_URL">Unexpected state; please, enter the server URL again</string>
     <string name="auth_expired_oauth_token_toast">Your authorization expired.\nPlease, authorize again</string>
     <string name="auth_expired_basic_auth_toast">Please, enter the current password</string>
+    <string name="auth_expired_saml_sso_token_toast">Your session expired.\nPlease, authenticate again</string>
 	<string name="auth_connecting_auth_server">Connecting to authentication server…</string>
 	<string name="auth_follow_auth_server">Follow instructions above to get authenticated</string>
 	<string name="auth_unsupported_auth_method">The server does not support this authentication method</string>    

+ 12 - 6
src/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -229,6 +229,9 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
                 }
                 mHostBaseUrl = normalizeUrl(mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL));
                 mHostUrlInput.setText(mHostBaseUrl);
+                String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));
+                mUsernameInput.setText(userName);
+                mAccountNameInput.setText(userName);
             }
             initAuthorizationMethod();  // checks intent and setup.xml to determine mCurrentAuthorizationMethod
             mOAuth2Check.setChecked(mCurrentAuthTokenType == AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN);
@@ -287,6 +290,8 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             mUsernameInput.setEnabled(false);
             mUsernameInput.setFocusable(false);
             mOAuth2Check.setVisibility(View.GONE);
+            mAccountNameInput.setEnabled(false);
+            mAccountNameInput.setFocusable(false);
         }
         
         //if (mServerIsChecked && !mServerIsValid && mRefreshButtonEnabled) showRefreshButton();
@@ -378,10 +383,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             }
         }
     
-        if (mAccount != null) {
-            String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));
-            mUsernameInput.setText(userName);
-        }
     }
 
     /**
@@ -450,10 +451,15 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     protected void onResume() {
         super.onResume();
         if (mAction == ACTION_UPDATE_TOKEN && mJustCreated && getIntent().getBooleanExtra(EXTRA_ENFORCED_UPDATE, false)) {
-            if (mOAuth2Check.isChecked())
+            if (AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(mCurrentAuthTokenType)) {
                 Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show();
-            else
+                
+            } else if (AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(mCurrentAuthTokenType)) {
+                Toast.makeText(this, R.string.auth_expired_saml_sso_token_toast, Toast.LENGTH_LONG).show();
+                
+            } else {
                 Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show();
+            }
         }
 
         if (mNewCapturedUriFromOAuth2Redirection != null) {

+ 1 - 1
src/com/owncloud/android/files/services/FileUploader.java

@@ -579,7 +579,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 mUploadClient.exhaustResponse(propfind.getResponseBodyAsStream());
             }
 
-            result = new RemoteOperationResult(isMultiStatus, status);
+            result = new RemoteOperationResult(isMultiStatus, status, propfind.getResponseHeaders());
             Log_OC.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
                     + result.getLogMessage());
 

+ 12 - 6
src/com/owncloud/android/network/OwnCloudClientUtils.java

@@ -32,6 +32,7 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 
 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.protocol.Protocol;
 import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
 import org.apache.http.conn.ssl.X509HostnameVerifier;
@@ -90,13 +91,15 @@ public class OwnCloudClientUtils {
         //Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
        
         Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
-        WebdavClient client = createOwnCloudClient(uri, appContext, true);
         AccountManager am = AccountManager.get(appContext);
-        if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) {    // TODO avoid a call to getUserData here
+        boolean isOauth2 = am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null;   // TODO avoid calling to getUserData here
+        boolean isSamlSso = am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null;
+        WebdavClient client = createOwnCloudClient(uri, appContext, !isSamlSso);
+        if (isOauth2) {    
             String accessToken = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, false);
             client.setBearerCredentials(accessToken);   // TODO not assume that the access token is a bearer token
         
-        } else if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null) {    // TODO avoid a call to getUserData here
+        } else if (isSamlSso) {    // TODO avoid a call to getUserData here
             String accessToken = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE, false);
             client.setSsoSessionCookie(accessToken);
             
@@ -113,16 +116,19 @@ public class OwnCloudClientUtils {
     
     public static WebdavClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {
         Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
-        WebdavClient client = createOwnCloudClient(uri, appContext, true);
         AccountManager am = AccountManager.get(appContext);
-        if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) {    // TODO avoid a call to getUserData here
+        boolean isOauth2 = am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null;   // TODO avoid calling to getUserData here
+        boolean isSamlSso = am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null;
+        WebdavClient client = createOwnCloudClient(uri, appContext, !isSamlSso);
+        
+        if (isOauth2) {    // TODO avoid a call to getUserData here
             AccountManagerFuture<Bundle> 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);
             if (accessToken == null) throw new AuthenticatorException("WTF!");
             client.setBearerCredentials(accessToken);   // TODO not assume that the access token is a bearer token
 
-        } else if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null) {    // TODO avoid a call to getUserData here
+        } else if (isSamlSso) {    // TODO avoid a call to getUserData here
             AccountManagerFuture<Bundle> future =  am.getAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE, null, currentActivity, null, null);
             Bundle result = future.getResult();
             String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);

+ 3 - 0
src/com/owncloud/android/operations/ChunkedUploadFileOperation.java

@@ -68,6 +68,9 @@ public class ChunkedUploadFileOperation extends UploadFileOperation {
             String uriPrefix = client.getBaseUri() + WebdavUtils.encodePath(getRemotePath()) + "-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
             long chunkCount = (long) Math.ceil((double)file.length() / CHUNK_SIZE);
             for (int chunkIndex = 0; chunkIndex < chunkCount ; chunkIndex++, offset += CHUNK_SIZE) {
+                if (mPutMethod != null) {
+                    mPutMethod.releaseConnection();    // let the connection available for other methods
+                }
                 mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
                 mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
                 ((ChunkFromFileChannelRequestEntity)mEntity).setOffset(offset);

+ 1 - 1
src/com/owncloud/android/operations/CreateFolderOperation.java

@@ -77,7 +77,7 @@ public class CreateFolderOperation extends RemoteOperation {
                 mStorageManager.saveFile(newDir);
             }
 
-            result = new RemoteOperationResult(mkcol.succeeded(), status);
+            result = new RemoteOperationResult(mkcol.succeeded(), status, mkcol.getResponseHeaders());
             Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
             client.exhaustResponse(mkcol.getResponseBodyAsStream());
                 

+ 9 - 8
src/com/owncloud/android/operations/DownloadFileOperation.java

@@ -58,6 +58,7 @@ public class DownloadFileOperation extends RemoteOperation {
     private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
     private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
     private long mModificationTimestamp = 0;
+    private GetMethod mGet;
 
     
     public DownloadFileOperation(Account account, OCFile file) {
@@ -154,7 +155,7 @@ public class DownloadFileOperation extends RemoteOperation {
             if (!moved)
                 result = new RemoteOperationResult(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED);
             else
-                result = new RemoteOperationResult(isSuccess(status), status);
+                result = new RemoteOperationResult(isSuccess(status), status, (mGet != null ? mGet.getResponseHeaders() : null));
             Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage());
             
         } catch (Exception e) {
@@ -174,15 +175,15 @@ public class DownloadFileOperation extends RemoteOperation {
     protected int downloadFile(WebdavClient client, File targetFile) throws HttpException, IOException, OperationCancelledException {
         int status = -1;
         boolean savedFile = false;
-        GetMethod get = new GetMethod(client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()));
+        mGet = new GetMethod(client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()));
         Iterator<OnDatatransferProgressListener> it = null;
         
         FileOutputStream fos = null;
         try {
-            status = client.executeMethod(get);
+            status = client.executeMethod(mGet);
             if (isSuccess(status)) {
                 targetFile.createNewFile();
-                BufferedInputStream bis = new BufferedInputStream(get.getResponseBodyAsStream());
+                BufferedInputStream bis = new BufferedInputStream(mGet.getResponseBodyAsStream());
                 fos = new FileOutputStream(targetFile);
                 long transferred = 0;
 
@@ -191,7 +192,7 @@ public class DownloadFileOperation extends RemoteOperation {
                 while ((readResult = bis.read(bytes)) != -1) {
                     synchronized(mCancellationRequested) {
                         if (mCancellationRequested.get()) {
-                            get.abort();
+                            mGet.abort();
                             throw new OperationCancelledException();
                         }
                     }
@@ -205,14 +206,14 @@ public class DownloadFileOperation extends RemoteOperation {
                     }
                 }
                 savedFile = true;
-                Header modificationTime = get.getResponseHeader("Last-Modified");
+                Header modificationTime = mGet.getResponseHeader("Last-Modified");
                 if (modificationTime != null) {
                     Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue());
                     mModificationTimestamp = (d != null) ? d.getTime() : 0;
                 }
                 
             } else {
-                client.exhaustResponse(get.getResponseBodyAsStream());
+                client.exhaustResponse(mGet.getResponseBodyAsStream());
             }
                 
         } finally {
@@ -220,7 +221,7 @@ public class DownloadFileOperation extends RemoteOperation {
             if (!savedFile && targetFile.exists()) {
                 targetFile.delete();
             }
-            get.releaseConnection();    // let the connection available for other methods
+            mGet.releaseConnection();    // let the connection available for other methods
         }
         return status;
     }

+ 2 - 2
src/com/owncloud/android/operations/OAuth2GetAccessToken.java

@@ -80,12 +80,12 @@ public class OAuth2GetAccessToken extends RemoteOperation {
                         result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR);
                     
                     } else {
-                        result = new RemoteOperationResult(true, status);
+                        result = new RemoteOperationResult(true, status, postMethod.getResponseHeaders());
                     }
                     
                 } else {
                     client.exhaustResponse(postMethod.getResponseBodyAsStream());
-                    result = new RemoteOperationResult(false, status);
+                    result = new RemoteOperationResult(false, status, postMethod.getResponseHeaders());
                 }
             }
             

+ 1 - 1
src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java

@@ -80,7 +80,7 @@ public class OwnCloudServerCheckOperation extends RemoteOperation {
                 }
                 
             } else {
-                mLatestResult = new RemoteOperationResult(false, status);
+                mLatestResult = new RemoteOperationResult(false, status, get.getResponseHeaders());
             }
 
         } catch (JSONException e) {

+ 19 - 10
src/com/owncloud/android/operations/RemoteOperation.java

@@ -242,18 +242,27 @@ public abstract class RemoteOperation implements Runnable {
                 result = run(mClient);
         
             repeat = false;
-            if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() && result.getCode() == ResultCode.UNAUTHORIZED) {
-                /// fail due to lack of authorization in an operation performed in foreground
-                AccountManager am = AccountManager.get(mContext);
+            if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() &&
+                    (result.getCode() == ResultCode.UNAUTHORIZED || result.isTemporalRedirection())) {
+                /// possible fail due to lack of authorization in an operation performed in foreground
                 Credentials cred = mClient.getCredentials();
-                if (cred instanceof BearerCredentials) {
-                    am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, ((BearerCredentials)cred).getAccessToken());
-                } else {
-                    am.clearPassword(mAccount);
+                String ssoSessionCookie = mClient.getSsoSessionCookie();
+                if (cred != null || ssoSessionCookie != 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(AccountAuthenticator.ACCOUNT_TYPE, ((BearerCredentials)cred).getAccessToken());
+                    } else if (samlBasedSsoAuthorization ) {
+                        am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, ssoSessionCookie);
+                    } else {
+                        am.clearPassword(mAccount);
+                    }
+                    mClient = null;
+                    repeat = true;  // when repeated, the creation of a new OwnCloudClient after erasing the saved credentials will trigger the login activity
+                    result = null;
                 }
-                mClient = null;
-                repeat = true;  // when repeated, the creation of a new OwnCloudClient after erasing the saved credentials will trigger the login activity
-                result = null;
             }
         } while (repeat);
         

+ 1 - 1
src/com/owncloud/android/operations/RemoteOperationResult.java

@@ -100,7 +100,7 @@ public class RemoteOperationResult implements Serializable {
         mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL);
     }
 
-    public RemoteOperationResult(boolean success, int httpCode) {
+    private RemoteOperationResult(boolean success, int httpCode) {
         mSuccess = success;
         mHttpCode = httpCode;
 

+ 1 - 1
src/com/owncloud/android/operations/RemoveFileOperation.java

@@ -88,7 +88,7 @@ public class RemoveFileOperation extends RemoteOperation {
                 }
             }
             delete.getResponseBodyAsString();   // exhaust the response, although not interesting
-            result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), status);
+            result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), status, delete.getResponseHeaders());
             Log_OC.i(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage());
             
         } catch (Exception e) {

+ 1 - 1
src/com/owncloud/android/operations/RenameFileOperation.java

@@ -136,7 +136,7 @@ public class RenameFileOperation extends RemoteOperation {
             }
             
             move.getResponseBodyAsString(); // exhaust response, although not interesting
-            result = new RemoteOperationResult(move.succeeded(), status);
+            result = new RemoteOperationResult(move.succeeded(), status, move.getResponseHeaders());
             Log_OC.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage());
             
         } catch (Exception e) {

+ 1 - 1
src/com/owncloud/android/operations/SynchronizeFileOperation.java

@@ -101,7 +101,7 @@ public class SynchronizeFileOperation extends RemoteOperation {
                         
                     } else {
                         client.exhaustResponse(propfind.getResponseBodyAsStream());
-                        result = new RemoteOperationResult(false, status);
+                        result = new RemoteOperationResult(false, status, propfind.getResponseHeaders());
                     }
                 }
                 

+ 2 - 2
src/com/owncloud/android/operations/SynchronizeFolderOperation.java

@@ -242,10 +242,10 @@ public class SynchronizeFolderOperation extends RemoteOperation {
                     result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);   // should be different result, but will do the job
                             
                 } else {
-                    result = new RemoteOperationResult(true, status);
+                    result = new RemoteOperationResult(true, status, query.getResponseHeaders());
                 }
             } else {
-                result = new RemoteOperationResult(false, status);
+                result = new RemoteOperationResult(false, status, query.getResponseHeaders());
             }
             
             

+ 1 - 1
src/com/owncloud/android/operations/UpdateOCVersionOperation.java

@@ -65,7 +65,7 @@ public class UpdateOCVersionOperation extends RemoteOperation {
             int status = client.executeMethod(get);
             if (status != HttpStatus.SC_OK) {
                 client.exhaustResponse(get.getResponseBodyAsStream());
-                result = new RemoteOperationResult(false, status);
+                result = new RemoteOperationResult(false, status, get.getResponseHeaders());
                 
             } else {
                 String response = get.getResponseBodyAsString();

+ 1 - 1
src/com/owncloud/android/operations/UploadFileOperation.java

@@ -304,7 +304,7 @@ public class UploadFileOperation extends RemoteOperation {
                 }
             }
 
-            result = new RemoteOperationResult(isSuccess(status), status);
+            result = new RemoteOperationResult(isSuccess(status), status, (mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
 
         } catch (Exception e) {
             // TODO something cleaner with cancellations

+ 4 - 0
src/eu/alefzero/webdav/WebdavClient.java

@@ -206,6 +206,10 @@ public class WebdavClient extends HttpClient {
     public final Credentials getCredentials() {
         return mCredentials;
     }
+    
+    public final String getSsoSessionCookie() {
+        return mSsoSessionCookie;
+    }
 
     public void setFollowRedirects(boolean followRedirects) {
         mFollowRedirects = followRedirects;