GetRemoteStatusOperation and DetectAuthenticationMethodOperations are joint in GetSer...
authorDavid A. Velasco <dvelasco@solidgear.es>
Tue, 1 Apr 2014 09:41:11 +0000 (11:41 +0200)
committerDavid A. Velasco <dvelasco@solidgear.es>
Tue, 1 Apr 2014 09:41:11 +0000 (11:41 +0200)
owncloud-android-library
src/com/owncloud/android/authentication/AuthenticatorActivity.java
src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java
src/com/owncloud/android/operations/GetServerInfoOperation.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/SamlWebViewDialog.java

index 25c53f3..a368311 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 25c53f3bf978f53cceed125edfb9a37eecfa15a8
+Subproject commit a3683116ae04f639ff39484b1c54788bbce9fd30
index 129da6c..dd20d48 100644 (file)
@@ -71,11 +71,11 @@ import com.owncloud.android.lib.common.OwnCloudClientFactory;
 import com.owncloud.android.lib.common.OwnCloudClient;\r
 import com.owncloud.android.operations.DetectAuthenticationMethodOperation;\r
 import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;\r
+import com.owncloud.android.operations.GetServerInfoOperation;\r
 import com.owncloud.android.operations.OAuth2GetAccessToken;\r
 
 import com.owncloud.android.lib.common.network.CertificateCombinedException;\r
 import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;\r
-import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation;\r
 import com.owncloud.android.lib.common.operations.RemoteOperation;\r
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;\r
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;\r
@@ -142,8 +142,8 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
 \r
     private static final String TAG_SAML_DIALOG = "samlWebViewDialog";\r
 \r
-    private String mHostBaseUrl;\r
-    private OwnCloudVersion mDiscoveredVersion;\r
+    private String mHostBaseUrl;                // TODO remove\r
+    private OwnCloudVersion mDiscoveredVersion; // TODO remove\r
 \r
     private String mAuthMessageText;\r
     private int mAuthMessageVisibility, mServerStatusText, mServerStatusIcon;\r
@@ -156,7 +156,8 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
 \r
     private final Handler mHandler = new Handler();\r
     private Thread mOperationThread;\r
-    private GetRemoteStatusOperation mOcServerChkOperation;\r
+    //private GetRemoteStatusOperation mOcServerChkOperation;\r
+    private GetServerInfoOperation mServerInfoOperation;\r
     private ExistenceCheckRemoteOperation mAuthCheckOperation;\r
 \r
     private Uri mNewCapturedUriFromOAuth2Redirection;\r
@@ -196,6 +197,8 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     \r
     private OperationsServiceBinder mOperationsServiceBinder = null;\r
 \r
+    private GetServerInfoOperation.ServerInfo mServerInfo;\r
+\r
     /**\r
      * {@inheritDoc}\r
      * \r
@@ -361,8 +364,8 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             mOAuth2Check.setVisibility(View.GONE);\r
         }\r
 \r
-        //if (mServerIsChecked && !mServerIsValid && mRefreshButtonEnabled) showRefreshButton();\r
-        if (mServerIsChecked && !mServerIsValid && refreshButtonEnabled) showRefreshButton();\r
+        //showRefreshButton(mServerIsChecked && !mServerIsValid && mRefreshButtonEnabled);\r
+        showRefreshButton(mServerIsChecked && !mServerIsValid && refreshButtonEnabled);\r
         mOkButton.setEnabled(mServerIsValid); // state not automatically recovered in configuration changes\r
 \r
         if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType) || \r
@@ -488,7 +491,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
         outState.putInt(KEY_SERVER_STATUS_ICON, mServerStatusIcon);\r
         outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);\r
         outState.putBoolean(KEY_SERVER_CHECKED, mServerIsChecked);\r
-        outState.putBoolean(KEY_SERVER_CHECK_IN_PROGRESS, (!mServerIsValid && mOcServerChkOperation != null));\r
+        outState.putBoolean(KEY_SERVER_CHECK_IN_PROGRESS, (!mServerIsValid && mServerInfoOperation != null));\r
         outState.putBoolean(KEY_IS_SSL_CONN, mIsSslConn);\r
         outState.putBoolean(KEY_PASSWORD_VISIBLE, isPasswordVisible());\r
         outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);\r
@@ -623,7 +626,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
                 onUrlInputFocusLost((TextView) view);\r
             }\r
             else {\r
-                hideRefreshButton();\r
+                showRefreshButton(false);\r
             }\r
 \r
         } else if (view.getId() == R.id.account_password) {\r
@@ -648,32 +651,45 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             checkOcServer();\r
         } else {\r
             mOkButton.setEnabled(mServerIsValid);\r
-            if (!mServerIsValid) {\r
-                showRefreshButton();\r
-            }\r
+            showRefreshButton(!mServerIsValid);\r
         }\r
     }\r
 \r
 \r
     private void checkOcServer() {\r
-        String uri = trimUrlWebdav(mHostUrlInput.getText().toString().trim());\r
+        String uri = mHostUrlInput.getText().toString().trim();\r
 \r
         if (!mHostUrlInputEnabled){\r
-            uri = getString(R.string.server_url);\r
+            uri = getString(R.string.server_url).trim();\r
         }\r
 \r
         mServerIsValid = false;\r
         mServerIsChecked = false;\r
         mOkButton.setEnabled(false);\r
         mDiscoveredVersion = null;\r
-        hideRefreshButton();\r
+        mServerAuthMethod = AuthenticationMethod.UNKNOWN;\r
+        showRefreshButton(false);\r
+        \r
         if (uri.length() != 0) {\r
             mServerStatusText = R.string.auth_testing_connection;\r
             mServerStatusIcon = R.drawable.progress_small;\r
             showServerStatus();\r
-            mOcServerChkOperation = new  GetRemoteStatusOperation(uri, this);\r
+            mServerInfoOperation = new GetServerInfoOperation(uri, mAuthTokenType, this);\r
             OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(uri), this, true);\r
-            mOperationThread = mOcServerChkOperation.execute(client, this, mHandler);\r
+            mServerInfoOperation.execute(client, this, mHandler);\r
+            \r
+            /*\r
+             * TODO start joint operation in OperationsService\r
+            Intent detectAuthIntent = new Intent();\r
+            detectAuthIntent.setAction(OperationsService.ACTION_DETECT_AUTHENTICATION_METHOD);\r
+            detectAuthIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mBaseUrl);\r
+            detectAuthIntent.putExtra(OperationsService.EXTRA_WEBDAV_PATH, webdav_path);\r
+            if (mOperationsServiceBinder != null) {\r
+                //Log.wtf(TAG, "starting detection..." );\r
+                mDetectAuthOpId = mOperationsServiceBinder.newOperation(detectAuthIntent);\r
+            }\r
+            */\r
+            \r
         } else {\r
             mServerStatusText = 0;\r
             mServerStatusIcon = 0;\r
@@ -861,8 +877,12 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     @Override\r
     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
 \r
-        if (operation instanceof GetRemoteStatusOperation) {\r
-            onOcServerCheckFinish((GetRemoteStatusOperation) operation, result);\r
+        if (operation instanceof GetServerInfoOperation) {\r
+            if (operation.equals(mServerInfoOperation)) {\r
+                onGetServerInfoFinish(result);\r
+            }   // else nothing ; only the last check operation is considered; \r
+                // multiple can be triggered if the user amends a URL before a previous check \r
+                // can be triggered\r
 \r
         } else if (operation instanceof OAuth2GetAccessToken) {\r
             onGetOAuthAccessTokenFinish((OAuth2GetAccessToken)operation, result);\r
@@ -983,42 +1003,63 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
      * @param operation     Server check performed.\r
      * @param result        Result of the check.\r
      */\r
-    private void onOcServerCheckFinish(GetRemoteStatusOperation operation, RemoteOperationResult result) {\r
-        if (operation.equals(mOcServerChkOperation)) {\r
-            /// save result state\r
-            mServerIsChecked = true;\r
-            mServerIsValid = result.isSuccess();\r
-            mIsSslConn = (result.getCode() == ResultCode.OK_SSL);\r
-            mOcServerChkOperation = null;\r
-\r
-\r
-            /// retrieve discovered version and normalize server URL\r
-            mDiscoveredVersion = operation.getDiscoveredVersion();\r
-            mHostBaseUrl = normalizeUrl(mHostUrlInput.getText().toString());\r
+    private void onGetServerInfoFinish(RemoteOperationResult result) {\r
+        /// update activity state\r
+        mServerIsChecked = true;\r
+        mIsSslConn = (result.getCode() == ResultCode.OK_SSL);\r
+        mServerInfoOperation = null;\r
+        mDetectAuthOpId = -1;\r
+        \r
+        // update server status, but don't show it yet\r
+        updateServerStatusIconAndText(result);\r
 \r
-            // Refresh server status, but don't show it\r
-            updateServerStatusIconAndText(result);\r
+        if (result.isSuccess()) {\r
+            /// SUCCESS means:\r
+            //      1. connection succeeded, and we know if it's SSL or not\r
+            //      2. server is installed\r
+            //      3. we got the server version\r
+            //      4. we got the authentication method required by the server \r
+            mServerInfo = (GetServerInfoOperation.ServerInfo) (result.getData().get(0));\r
+            mDiscoveredVersion = mServerInfo.mVersion;\r
+            mHostBaseUrl = mServerInfo.mBaseUrl;\r
+            \r
+            if (!authSupported(mServerInfo.mAuthMethod)) {\r
+                \r
+                updateServerStatusIconNoRegularAuth();  // overrides updateServerStatusIconAndText()  \r
+                mServerIsValid = false;\r
 \r
-            /// update status icon and text\r
-            if (mServerIsValid) {\r
-                hideRefreshButton();\r
-                // Try to create an account with user and pass "", to know if it is a regular server\r
-                // Update connect button in the answer of this method\r
-                detectAuthorizationMethod();\r
             } else {\r
-                showRefreshButton();\r
-                // Show server status\r
-                showServerStatus();\r
+                mServerIsValid = true;\r
             }\r
+            \r
+        } else {\r
+            mServerIsValid = false;\r
+        }\r
 \r
-            /// very special case (TODO: move to a common place for all the remote operations)\r
-            if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {\r
-                showUntrustedCertDialog(result);\r
-            }\r
+        // refresh UI\r
+        showRefreshButton(!mServerIsValid);\r
+        showServerStatus();\r
+        mOkButton.setEnabled(mServerIsValid);\r
+        \r
+        /// very special case (TODO: move to a common place for all the remote operations)\r
+        if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {\r
+            showUntrustedCertDialog(result);\r
+        }\r
+    }\r
 \r
 \r
-        }   // else nothing ; only the last check operation is considered; \r
-        // multiple can be triggered if the user amends a URL before a previous check can be triggered\r
+    private boolean authSupported(AuthenticationMethod authMethod) {\r
+        String basic = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
+        String oAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
+        String saml =  AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
+        \r
+        return (( mAuthTokenType.equals(basic) && \r
+                    authMethod.equals(AuthenticationMethod.BASIC_HTTP_AUTH) ) ||\r
+                ( mAuthTokenType.equals(oAuth) && \r
+                    authMethod.equals(AuthenticationMethod.BEARER_TOKEN)) ||\r
+                ( mAuthTokenType.equals(saml)  && \r
+                    authMethod.equals(AuthenticationMethod.SAML_WEB_SSO))\r
+        );\r
     }\r
 \r
 \r
@@ -1048,6 +1089,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     }\r
 \r
 \r
+    // TODO remove, if possible\r
     private String normalizeUrl(String url) {\r
         if (url != null && url.length() > 0) {\r
             url = url.trim();\r
@@ -1072,6 +1114,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     }\r
 \r
 \r
+    // TODO remove, if possible\r
     private String trimUrlWebdav(String url){       \r
         if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0)){\r
             url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0.length());             \r
@@ -1325,7 +1368,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             mServerIsChecked = true;\r
             mServerIsValid = false;\r
             mIsSslConn = false;\r
-            mOcServerChkOperation = null;\r
+            mServerInfoOperation = null;\r
             mDiscoveredVersion = null;\r
             mHostBaseUrl = normalizeUrl(mHostUrlInput.getText().toString());\r
 \r
@@ -1337,7 +1380,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             showAuthStatus();\r
 \r
             // update input controls state\r
-            showRefreshButton();\r
+            showRefreshButton(true);\r
             mOkButton.setEnabled(false);\r
 \r
             // very special case (TODO: move to a common place for all the remote operations) (dangerous here?)\r
@@ -1592,12 +1635,12 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     }     \r
 \r
 \r
-    private void showRefreshButton() {\r
-        mRefreshButton.setVisibility(View.VISIBLE);\r
-    }\r
-\r
-    private void hideRefreshButton() {\r
-        mRefreshButton.setVisibility(View.GONE);\r
+    private void showRefreshButton (boolean show) {\r
+        if (show)  {\r
+            mRefreshButton.setVisibility(View.VISIBLE);\r
+        } else {\r
+            mRefreshButton.setVisibility(View.GONE);\r
+        }\r
     }\r
 \r
     /**\r
index 6bc8750..b817e72 100644 (file)
@@ -126,6 +126,9 @@ public class DetectAuthenticationMethodOperation extends RemoteOperation {
         // else - fall back to UNKNOWN
         Log.d(TAG, "Authentication method found: " + authenticationMethodToString(authMethod));
         
+        if (!authMethod.equals(AuthenticationMethod.UNKNOWN)) {
+            result = new RemoteOperationResult(true, result.getHttpCode(), null);
+        }
         ArrayList<Object> data = new ArrayList<Object>();
         data.add(authMethod);
         result.setData(data);
diff --git a/src/com/owncloud/android/operations/GetServerInfoOperation.java b/src/com/owncloud/android/operations/GetServerInfoOperation.java
new file mode 100644 (file)
index 0000000..c210153
--- /dev/null
@@ -0,0 +1,163 @@
+/* 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.operations;
+
+import java.util.ArrayList;
+
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;
+import com.owncloud.android.utils.Log_OC;
+
+import android.content.Context;
+
+/**
+ * Get basic information from an ownCloud server given its URL.
+ * 
+ * Checks the existence of a configured ownCloud server in the URL, gets its version 
+ * and finds out what authentication method is needed to access files in it.
+ * 
+ * @author David A. Velasco
+ * @author masensio
+ */
+
+public class GetServerInfoOperation extends RemoteOperation {
+    
+    private static final String TAG = GetServerInfoOperation.class.getSimpleName();
+    
+    private String mUrl;
+    private String mAuthTokenType;
+    private Context mContext;
+    
+    private ServerInfo mResultData;
+
+    /** 
+     * Constructor.
+     * 
+     * @param url               URL to an ownCloud server.
+     * @param authTokenType     Identifies the authorization token supported by the caller;
+     *                          TODO ugly dependency, get rid of it. 
+     * @param context           Android context; needed to check network state
+     *                          TODO ugly dependency, get rid of it. 
+     */
+    public GetServerInfoOperation(String url, String authTokenType, Context context) {
+        mUrl = trimWebdavSuffix(url);
+        mAuthTokenType = authTokenType;
+        mContext = context;
+        
+        mResultData = new ServerInfo();
+    }
+    
+    
+    /**
+     * Performs the operation
+     * 
+     * @return      Result of the operation. If successful, includes an instance of 
+     *              {@link ServerInfo} with the information retrieved from the server. 
+     *              Call {@link RemoteOperationResult#getData()}.get(0) to get it.
+     */
+       @Override
+       protected RemoteOperationResult run(OwnCloudClient client) {
+           
+           // first: check the status of the server (including its version)
+           GetRemoteStatusOperation getStatus = new GetRemoteStatusOperation(mUrl, mContext);
+           RemoteOperationResult result = getStatus.execute(client);
+
+        if (result.isSuccess()) {
+            // second: get authentication method required by the server
+            mResultData.mVersion = (OwnCloudVersion)(result.getData().get(0));
+            boolean isSslConn = (result.getCode() == ResultCode.OK_SSL);
+            mResultData.mBaseUrl = normalizeProtocolPrefix(mUrl, isSslConn);
+            RemoteOperationResult detectAuthResult = detectAuthorizationMethod(client);
+            
+            // third: merge results
+            if (detectAuthResult.isSuccess()) {
+                mResultData.mAuthMethod = 
+                        (AuthenticationMethod)detectAuthResult.getData().get(0);
+                ArrayList<Object> data = new ArrayList<Object>();
+                data.add(mResultData);
+                result.setData(data);
+            } else {
+                result = detectAuthResult;
+            }
+        }
+        return result;
+       }
+
+       
+    private RemoteOperationResult detectAuthorizationMethod(OwnCloudClient client) {
+        Log_OC.d(TAG, "Trying empty authorization to detect authentication method");
+        String webdav_path = AccountUtils.getWebdavPath(mResultData.mVersion, mAuthTokenType);
+        String webdav_url = mResultData.mBaseUrl + webdav_path;
+        DetectAuthenticationMethodOperation operation = 
+                new DetectAuthenticationMethodOperation(mContext, webdav_url);
+        return operation.execute(client);
+    }
+    
+
+    private String trimWebdavSuffix(String url) {
+        if (url == null) {
+            url = "";
+        } else {
+            if (url.endsWith("/")) {
+                url = url.substring(0, url.length() - 1);
+            }
+            if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0)){
+                url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0.length());
+            } else if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_2_0)){
+                url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_2_0.length());
+            } else if (url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_1_2)){
+                url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_1_2.length());
+            }
+        }
+        return url;
+    }
+
+    
+    private String normalizeProtocolPrefix(String url, boolean isSslConn) {
+        if (!url.toLowerCase().startsWith("http://") &&
+                !url.toLowerCase().startsWith("https://")) {
+            if (isSslConn) {
+                return "https://" + url;
+            } else {
+                return "http://" + url;
+            }
+        }
+        return url;
+    }
+    
+    
+    public static class ServerInfo {
+        public OwnCloudVersion mVersion;
+        public String mBaseUrl;
+        public AuthenticationMethod mAuthMethod;
+    }
+       
+}
index cbf1acb..0c17a6f 100644 (file)
@@ -72,7 +72,7 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
      * 
      * @param handler
      * @param Url           Url to open at WebView
-     * @param targetURL     mHostBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType)
+     * @param targetURL     mBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType)
      * @return              New dialog instance, ready to show.
      */
     public static SamlWebViewDialog newInstance(String url, String targetUrl) {