Merge pull request #347 from owncloud/refactor_remote_saml_authentication
authorDavid A. Velasco <dvelasco@owncloud.com>
Mon, 20 Jan 2014 08:10:54 +0000 (00:10 -0800)
committerDavid A. Velasco <dvelasco@owncloud.com>
Mon, 20 Jan 2014 08:10:54 +0000 (00:10 -0800)
Refactored remote saml authentication

oc_framework/src/com/owncloud/android/oc_framework/accounts/AccountUtils.java
oc_framework/src/com/owncloud/android/oc_framework/operations/RemoteOperationResult.java
oc_framework/src/com/owncloud/android/oc_framework/operations/remote/GetUserNameRemoteOperation.java [new file with mode: 0644]
src/com/owncloud/android/authentication/AuthenticatorActivity.java
src/com/owncloud/android/authentication/SsoWebViewClient.java

index 810f3eb..72946dc 100644 (file)
@@ -111,8 +111,8 @@ public class AccountUtils {
     
     public static class AccountNotFoundException extends AccountsException {
         
-        /** Generated - should be refreshed every time the class changes!! */
-        private static final long serialVersionUID = -9013287181793186830L;
+               /** Generated - should be refreshed every time the class changes!! */
+               private static final long serialVersionUID = -1684392454798508693L;
         
         private Account mFailedAccount; 
                 
@@ -125,5 +125,4 @@ public class AccountUtils {
             return mFailedAccount;
         }
     }
-
 }
index 58accf9..a5f5a39 100644 (file)
@@ -33,6 +33,7 @@ import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.HttpStatus;
 import org.apache.jackrabbit.webdav.DavException;
+import org.json.JSONException;
 
 import com.owncloud.android.oc_framework.accounts.AccountUtils.AccountNotFoundException;
 import com.owncloud.android.oc_framework.network.CertificateCombinedException;
@@ -51,9 +52,9 @@ import android.util.Log;
  * @author David A. Velasco
  */
 public class RemoteOperationResult implements Serializable {
-
+       
        /** Generated - should be refreshed every time the class changes!! */
-       private static final long serialVersionUID = -2469951225222759283L;
+       private static final long serialVersionUID = -8257349554488668693L;
     
     private static final String TAG = "RemoteOperationResult";
     
@@ -294,6 +295,9 @@ public class RemoteOperationResult implements Serializable {
             } else if (mException instanceof AccountsException) {
                 return "Exception while using account";
                 
+            } else if (mException instanceof JSONException) {
+               return "JSON exception";
+               
             } else {
                 return "Unexpected exception";
             }
diff --git a/oc_framework/src/com/owncloud/android/oc_framework/operations/remote/GetUserNameRemoteOperation.java b/oc_framework/src/com/owncloud/android/oc_framework/operations/remote/GetUserNameRemoteOperation.java
new file mode 100644 (file)
index 0000000..717fae2
--- /dev/null
@@ -0,0 +1,127 @@
+
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013 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.oc_framework.operations.remote;
+
+import java.io.IOException;
+
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.http.HttpStatus;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.util.Log;
+
+import com.owncloud.android.oc_framework.network.webdav.WebdavClient;
+import com.owncloud.android.oc_framework.operations.RemoteOperation;
+import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
+
+
+/**
+ * @author masensio
+ *
+ * Get the UserName for a SAML connection, from a JSON with the format:
+ *             id
+ *             display-name
+ *             email
+ */
+
+public class GetUserNameRemoteOperation extends RemoteOperation {
+       
+       private static final String TAG = GetUserNameRemoteOperation.class.getSimpleName();
+
+       // HEADER
+       private static final String HEADER_OCS_API = "OCS-APIREQUEST";
+       private static final String HEADER_OCS_API_VALUE = "true";
+
+       // OCS Route
+       private static final String OCS_ROUTE ="/index.php/ocs/cloud/user?format=json"; 
+
+       // JSON Node names
+       private static final String NODE_OCS = "ocs";
+       private static final String NODE_DATA = "data";
+       private static final String NODE_ID = "id";
+       private static final String NODE_DISPLAY_NAME= "display-name";
+       private static final String NODE_EMAIL= "email";
+
+       private String mUserName;
+
+       public String getUserName() {
+               return mUserName;
+       }
+
+       
+       public GetUserNameRemoteOperation() {
+       }
+
+       @Override
+       protected RemoteOperationResult run(WebdavClient client) {
+        RemoteOperationResult result = null;
+        int status = -1;
+        
+        // Get Method
+        GetMethod get = new GetMethod(client.getBaseUri() + OCS_ROUTE);
+        Log.d(TAG, "URL ------> " + client.getBaseUri() + OCS_ROUTE);
+        // Add the Header
+        get.addRequestHeader(HEADER_OCS_API, HEADER_OCS_API_VALUE);
+        
+        //Get the user
+        try {
+                       status = client.executeMethod(get);
+                       if(isSuccess(status)) {
+                                Log.d(TAG, "Obtain RESPONSE");
+                                String response = get.getResponseBodyAsString();
+                                
+                                Log.d(TAG, "GET RESPONSE.................... " + response);
+
+                                // Parse the response
+                                JSONObject respJSON = new JSONObject(response);
+                                JSONObject respOCS = respJSON.getJSONObject(NODE_OCS);
+                                JSONObject respData = respOCS.getJSONObject(NODE_DATA);
+                                String id = respData.getString(NODE_ID);
+                                String displayName = respData.getString(NODE_DISPLAY_NAME);
+                                String email = respData.getString(NODE_EMAIL);
+                                
+                                // Result
+                                result = new RemoteOperationResult(isSuccess(status), status, (get != null ? get.getResponseHeaders() : null));
+                                mUserName =  displayName;
+                                
+                                Log.d(TAG, "Response: " + id + " - " + displayName + " - " + email);
+                                
+                       }
+               } catch (HttpException e) {
+                       result = new RemoteOperationResult(e);
+                       e.printStackTrace();
+               } catch (IOException e) {
+                       result = new RemoteOperationResult(e);
+                       e.printStackTrace();
+               } catch (JSONException e) {
+                       result = new RemoteOperationResult(e);
+                       e.printStackTrace();
+               } finally {
+                       get.releaseConnection();
+               }
+        
+               return result;
+       }
+
+    private boolean isSuccess(int status) {
+        return (status == HttpStatus.SC_OK);
+    }
+    
+}
index 456e284..ad40a06 100644 (file)
@@ -64,6 +64,7 @@ import com.owncloud.android.oc_framework.operations.RemoteOperation;
 import com.owncloud.android.oc_framework.operations.RemoteOperationResult;\r
 import com.owncloud.android.oc_framework.operations.RemoteOperationResult.ResultCode;\r
 import com.owncloud.android.oc_framework.operations.remote.ExistenceCheckRemoteOperation;\r
+import com.owncloud.android.oc_framework.operations.remote.GetUserNameRemoteOperation;\r
 import com.owncloud.android.ui.dialog.SamlWebViewDialog;\r
 import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
 import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
@@ -102,8 +103,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     private static final String KEY_AUTH_STATUS_TEXT = "AUTH_STATUS_TEXT";\r
     private static final String KEY_AUTH_STATUS_ICON = "AUTH_STATUS_ICON";\r
     private static final String KEY_REFRESH_BUTTON_ENABLED = "KEY_REFRESH_BUTTON_ENABLED";\r
-    \r
-    private static final String KEY_OC_USERNAME_EQUALS = "oc_username=";\r
 \r
     private static final String AUTH_ON = "on";\r
     private static final String AUTH_OFF = "off";\r
@@ -792,10 +791,41 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             } else {\r
                 onAuthorizationCheckFinish((ExistenceCheckRemoteOperation)operation, result);\r
             }\r
+        } else if (operation instanceof GetUserNameRemoteOperation) {\r
+            onGetUserNameFinish((GetUserNameRemoteOperation) operation, result);\r
+             \r
         }\r
+        \r
     }\r
-    \r
-    \r
+\r
+    private void onGetUserNameFinish(GetUserNameRemoteOperation operation, RemoteOperationResult result) {\r
+        if (result.isSuccess()) {\r
+            boolean success = false;\r
+            String username = operation.getUserName();\r
+            \r
+            if ( mAction == ACTION_CREATE) {\r
+                mUsernameInput.setText(username);\r
+                success = createAccount();\r
+            } else {\r
+                \r
+                if (!mUsernameInput.getText().toString().equals(username)) {\r
+                    // fail - not a new account, but an existing one; disallow\r
+                    result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME); \r
+                    updateAuthStatusIconAndText(result);\r
+                    showAuthStatus();\r
+                    Log_OC.d(TAG, result.getLogMessage());\r
+                } else {\r
+                  updateToken();\r
+                  success = true;\r
+                }\r
+            }\r
+            \r
+            if (success)\r
+                finish();\r
+        }\r
+        \r
+    }\r
+\r
     private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperation operation, RemoteOperationResult result) {\r
         try {\r
             dismissDialog(DIALOG_LOGIN_PROGRESS);\r
@@ -1120,7 +1150,8 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
                 success = createAccount();\r
 \r
             } else {\r
-                success = updateToken();\r
+                updateToken();\r
+                success = true;\r
             }\r
 \r
             if (success) {\r
@@ -1166,7 +1197,7 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      * Sets the proper response to get that the Account Authenticator that started this activity saves \r
      * a new authorization token for mAccount.\r
      */\r
-    private boolean updateToken() {\r
+    private void updateToken() {\r
         Bundle response = new Bundle();\r
         response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);\r
         response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);\r
@@ -1177,16 +1208,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
             \r
         } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
-            String username = getUserNameForSamlSso();\r
-            if (!mUsernameInput.getText().toString().equals(username)) {\r
-                // fail - not a new account, but an existing one; disallow\r
-                RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME); \r
-                updateAuthStatusIconAndText(result);\r
-                showAuthStatus();\r
-                Log_OC.d(TAG, result.getLogMessage());\r
-                \r
-                return false;\r
-            }\r
             \r
             response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);\r
             // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention\r
@@ -1198,7 +1219,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         }\r
         setAccountAuthenticatorResult(response);\r
         \r
-        return true;\r
     }\r
 \r
 \r
@@ -1216,10 +1236,7 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
 \r
         Uri uri = Uri.parse(mHostBaseUrl);\r
         String username = mUsernameInput.getText().toString().trim();\r
-        if (isSaml) {\r
-            username = getUserNameForSamlSso();\r
-            \r
-        } else if (isOAuth) {\r
+        if (isOAuth) {\r
             username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();\r
         }            \r
         String accountName = username + "@" + uri.getHost();\r
@@ -1279,20 +1296,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         }\r
     }\r
 \r
-    \r
-    private String getUserNameForSamlSso() {\r
-        if (mAuthToken != null) {\r
-            String [] cookies = mAuthToken.split(";");\r
-            for (int i=0; i<cookies.length; i++) {\r
-                if (cookies[i].startsWith(KEY_OC_USERNAME_EQUALS )) {\r
-                    String value = Uri.decode(cookies[i].substring(KEY_OC_USERNAME_EQUALS.length()));\r
-                    return value;\r
-                }\r
-            }\r
-        }\r
-        return "";\r
-    }\r
-\r
 \r
     /**\r
      * {@inheritDoc}\r
@@ -1593,16 +1596,11 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         \r
         if (sessionCookie != null && sessionCookie.length() > 0) {\r
             mAuthToken = sessionCookie;\r
-            boolean success = false;\r
-            if (mAction == ACTION_CREATE) {\r
-                success = createAccount();\r
-        \r
-            } else {\r
-                success = updateToken();\r
-            }\r
-            if (success) {\r
-                finish();\r
-            }\r
+\r
+            GetUserNameRemoteOperation getUserOperation = new GetUserNameRemoteOperation();            \r
+            WebdavClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl), getApplicationContext(), true);\r
+            client.setSsoSessionCookie(mAuthToken);\r
+            getUserOperation.execute(client, this, mHandler);\r
         }\r
 \r
             \r
@@ -1652,4 +1650,5 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         }\r
         return super.onTouchEvent(event);\r
     }\r
+    \r
 }\r
index 8d80e9b..442ec73 100644 (file)
@@ -21,12 +21,16 @@ import java.lang.ref.WeakReference;
 
 import com.owncloud.android.utils.Log_OC;
 
-
 import android.graphics.Bitmap;
+import android.net.http.SslError;
 import android.os.Handler;
 import android.os.Message;
+import android.view.KeyEvent;
 import android.view.View;
 import android.webkit.CookieManager;
+import android.webkit.HttpAuthHandler;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 
@@ -107,7 +111,7 @@ public class SsoWebViewClient extends WebViewClient {
             view.setVisibility(View.GONE);
             CookieManager cookieManager = CookieManager.getInstance();
             final String cookies = cookieManager.getCookie(url);
-            //Log_OC.d(TAG, "Cookies: " + cookies);
+            Log_OC.d(TAG, "Cookies: " + cookies);
             if (mListenerHandler != null && mListenerRef != null) {
                 // this is good idea because onPageFinished is not running in the UI thread
                 mListenerHandler.post(new Runnable() {
@@ -115,16 +119,16 @@ public class SsoWebViewClient extends WebViewClient {
                     public void run() {
                         SsoWebViewClientListener listener = mListenerRef.get();
                         if (listener != null) {
+                               // Send Cookies to the listener
                             listener.onSsoFinished(cookies);
                         }
                     }
                 });
             }
-        }
-
+        } 
     }
     
-    /*
+    
     @Override
     public void doUpdateVisitedHistory (WebView view, String url, boolean isReload) {
         Log_OC.d(TAG, "doUpdateVisitedHistory : " + url);
@@ -133,6 +137,7 @@ public class SsoWebViewClient extends WebViewClient {
     @Override
     public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
         Log_OC.d(TAG, "onReceivedSslError : " + error);
+        handler.proceed();
     }
     
     @Override
@@ -172,5 +177,5 @@ public class SsoWebViewClient extends WebViewClient {
         Log_OC.d(TAG, "shouldOverrideKeyEvent : " + event);
         return false;
     }
-    */
+
 }