浏览代码

Merge pull request #347 from owncloud/refactor_remote_saml_authentication

Refactored remote saml authentication
David A. Velasco 11 年之前
父节点
当前提交
8cf7a1c3db

+ 2 - 3
oc_framework/src/com/owncloud/android/oc_framework/accounts/AccountUtils.java

@@ -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;
         }
     }
-
 }

+ 6 - 2
oc_framework/src/com/owncloud/android/oc_framework/operations/RemoteOperationResult.java

@@ -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";
             }

+ 127 - 0
oc_framework/src/com/owncloud/android/oc_framework/operations/remote/GetUserNameRemoteOperation.java

@@ -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);
+    }
+    
+}

+ 44 - 45
src/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -64,6 +64,7 @@ import com.owncloud.android.oc_framework.operations.RemoteOperation;
 import com.owncloud.android.oc_framework.operations.RemoteOperationResult;
 import com.owncloud.android.oc_framework.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.oc_framework.operations.remote.ExistenceCheckRemoteOperation;
+import com.owncloud.android.oc_framework.operations.remote.GetUserNameRemoteOperation;
 import com.owncloud.android.ui.dialog.SamlWebViewDialog;
 import com.owncloud.android.ui.dialog.SslValidatorDialog;
 import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
@@ -102,8 +103,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     private static final String KEY_AUTH_STATUS_TEXT = "AUTH_STATUS_TEXT";
     private static final String KEY_AUTH_STATUS_ICON = "AUTH_STATUS_ICON";
     private static final String KEY_REFRESH_BUTTON_ENABLED = "KEY_REFRESH_BUTTON_ENABLED";
-    
-    private static final String KEY_OC_USERNAME_EQUALS = "oc_username=";
 
     private static final String AUTH_ON = "on";
     private static final String AUTH_OFF = "off";
@@ -792,10 +791,41 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             } else {
                 onAuthorizationCheckFinish((ExistenceCheckRemoteOperation)operation, result);
             }
+        } else if (operation instanceof GetUserNameRemoteOperation) {
+            onGetUserNameFinish((GetUserNameRemoteOperation) operation, result);
+             
         }
+        
     }
-    
-    
+
+    private void onGetUserNameFinish(GetUserNameRemoteOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            boolean success = false;
+            String username = operation.getUserName();
+            
+            if ( mAction == ACTION_CREATE) {
+                mUsernameInput.setText(username);
+                success = createAccount();
+            } else {
+                
+                if (!mUsernameInput.getText().toString().equals(username)) {
+                    // fail - not a new account, but an existing one; disallow
+                    result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME); 
+                    updateAuthStatusIconAndText(result);
+                    showAuthStatus();
+                    Log_OC.d(TAG, result.getLogMessage());
+                } else {
+                  updateToken();
+                  success = true;
+                }
+            }
+            
+            if (success)
+                finish();
+        }
+        
+    }
+
     private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperation operation, RemoteOperationResult result) {
         try {
             dismissDialog(DIALOG_LOGIN_PROGRESS);
@@ -1120,7 +1150,8 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
                 success = createAccount();
 
             } else {
-                success = updateToken();
+                updateToken();
+                success = true;
             }
 
             if (success) {
@@ -1166,7 +1197,7 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      * Sets the proper response to get that the Account Authenticator that started this activity saves 
      * a new authorization token for mAccount.
      */
-    private boolean updateToken() {
+    private void updateToken() {
         Bundle response = new Bundle();
         response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);
         response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);
@@ -1177,16 +1208,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);
             
         } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) {
-            String username = getUserNameForSamlSso();
-            if (!mUsernameInput.getText().toString().equals(username)) {
-                // fail - not a new account, but an existing one; disallow
-                RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME); 
-                updateAuthStatusIconAndText(result);
-                showAuthStatus();
-                Log_OC.d(TAG, result.getLogMessage());
-                
-                return false;
-            }
             
             response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);
             // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention
@@ -1198,7 +1219,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         }
         setAccountAuthenticatorResult(response);
         
-        return true;
     }
 
 
@@ -1216,10 +1236,7 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
 
         Uri uri = Uri.parse(mHostBaseUrl);
         String username = mUsernameInput.getText().toString().trim();
-        if (isSaml) {
-            username = getUserNameForSamlSso();
-            
-        } else if (isOAuth) {
+        if (isOAuth) {
             username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();
         }            
         String accountName = username + "@" + uri.getHost();
@@ -1279,20 +1296,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         }
     }
 
-    
-    private String getUserNameForSamlSso() {
-        if (mAuthToken != null) {
-            String [] cookies = mAuthToken.split(";");
-            for (int i=0; i<cookies.length; i++) {
-                if (cookies[i].startsWith(KEY_OC_USERNAME_EQUALS )) {
-                    String value = Uri.decode(cookies[i].substring(KEY_OC_USERNAME_EQUALS.length()));
-                    return value;
-                }
-            }
-        }
-        return "";
-    }
-
 
     /**
      * {@inheritDoc}
@@ -1593,16 +1596,11 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         
         if (sessionCookie != null && sessionCookie.length() > 0) {
             mAuthToken = sessionCookie;
-            boolean success = false;
-            if (mAction == ACTION_CREATE) {
-                success = createAccount();
-        
-            } else {
-                success = updateToken();
-            }
-            if (success) {
-                finish();
-            }
+
+            GetUserNameRemoteOperation getUserOperation = new GetUserNameRemoteOperation();            
+            WebdavClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl), getApplicationContext(), true);
+            client.setSsoSessionCookie(mAuthToken);
+            getUserOperation.execute(client, this, mHandler);
         }
 
             
@@ -1652,4 +1650,5 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         }
         return super.onTouchEvent(event);
     }
+    
 }

+ 11 - 6
src/com/owncloud/android/authentication/SsoWebViewClient.java

@@ -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;
     }
-    */
+
 }