From 5a65ff53c2fa22d0b11df52ab543d045f813c032 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Fri, 26 Jul 2013 13:05:01 +0200 Subject: [PATCH] AuthenticatorActivity updated to test existance through SAML-based-federated-authenticated entry point --- res/values/setup.xml | 2 +- .../android/authentication/AccountUtils.java | 36 ++++- .../authentication/AuthenticatorActivity.java | 153 +++++++++--------- .../ui/activity/AccountSelectActivity.java | 14 +- .../android/ui/activity/FileActivity.java | 2 +- 5 files changed, 129 insertions(+), 78 deletions(-) diff --git a/res/values/setup.xml b/res/values/setup.xml index b3cb69b647..2c46d41540 100644 --- a/res/values/setup.xml +++ b/res/values/setup.xml @@ -5,6 +5,6 @@ off - off + on diff --git a/src/com/owncloud/android/authentication/AccountUtils.java b/src/com/owncloud/android/authentication/AccountUtils.java index 591da010a9..639a3b9d8b 100644 --- a/src/com/owncloud/android/authentication/AccountUtils.java +++ b/src/com/owncloud/android/authentication/AccountUtils.java @@ -32,6 +32,7 @@ public class AccountUtils { public static final String WEBDAV_PATH_2_0 = "/files/webdav.php"; public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav"; private static final String ODAV_PATH = "/remote.php/odav"; + private static final String SAML_SSO_PATH = "/ocShibAuth"; public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php"; public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php"; public static final String STATUS_PATH = "/status.php"; @@ -115,11 +116,41 @@ public class AccountUtils { * @param version version of owncloud * @return webdav path for given OC version, null if OC version unknown */ - public static String getWebdavPath(OwnCloudVersion version, boolean supportsOAuth) { + public static String getWebdavPath(OwnCloudVersion version, boolean supportsOAuth, boolean supportsSamlSso) { if (version != null) { if (supportsOAuth) { return ODAV_PATH; } + if (supportsSamlSso) { + return SAML_SSO_PATH; + } + if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0) + return WEBDAV_PATH_4_0; + if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0 + || version.compareTo(OwnCloudVersion.owncloud_v2) >= 0) + return WEBDAV_PATH_2_0; + if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0) + return WEBDAV_PATH_1_2; + } + return null; + } + + /** + * Returns the proper URL path to access the WebDAV interface of an ownCloud server, + * according to its version and the authorization method used. + * + * @param version Version of ownCloud server. + * @param authTokenType Authorization token type, matching some of the AUTH_TOKEN_TYPE_* constants in {@link AccountAuthenticator}. + * @return WebDAV path for given OC version and authorization method, null if OC version is unknown. + */ + public static String getWebdavPath(OwnCloudVersion version, String authTokenType) { + if (version != null) { + if (AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(authTokenType)) { + return ODAV_PATH; + } + if (AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(authTokenType)) { + return SAML_SSO_PATH; + } if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0) return WEBDAV_PATH_4_0; if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0 @@ -143,8 +174,9 @@ public class AccountUtils { String baseurl = ama.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL); String strver = ama.getUserData(account, AccountAuthenticator.KEY_OC_VERSION); boolean supportsOAuth = (ama.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null); + boolean supportsSamlSso = (ama.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null); OwnCloudVersion ver = new OwnCloudVersion(strver); - String webdavpath = getWebdavPath(ver, supportsOAuth); + String webdavpath = getWebdavPath(ver, supportsOAuth, supportsSamlSso); if (baseurl == null || webdavpath == null) throw new AccountNotFoundException(account, "Account not found", null); diff --git a/src/com/owncloud/android/authentication/AuthenticatorActivity.java b/src/com/owncloud/android/authentication/AuthenticatorActivity.java index d1f79cf12c..35496c3b76 100644 --- a/src/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/src/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -96,7 +96,6 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList private static final String KEY_SERVER_STATUS_ICON = "SERVER_STATUS_ICON"; private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN"; private static final String KEY_PASSWORD_VISIBLE = "PASSWORD_VISIBLE"; - private static final String KEY_AUTH_METHOD = "AUTH_METHOD"; 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"; @@ -105,10 +104,6 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList private static final String AUTH_OFF = "off"; private static final String AUTH_OPTIONAL = "optional"; - private static final int AUTH_METHOD_BASIC_HTTP = 0; - private static final int AUTH_METHOD_OAUTH2 = 1; - private static final int AUTH_METHOD_SAML_WEB_SSO = 2; - private static final int DIALOG_LOGIN_PROGRESS = 0; private static final int DIALOG_SSL_VALIDATOR = 1; private static final int DIALOG_CERT_NOT_SAVED = 2; @@ -142,7 +137,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList private boolean mHostUrlInputEnabled; private View mRefreshButton; - private int mCurrentAuthorizationMethod; + private String mCurrentAuthTokenType; private EditText mUsernameInput; private EditText mPasswordInput; @@ -230,7 +225,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList mHostUrlInput.setText(mHostBaseUrl); } initAuthorizationMethod(); // checks intent and setup.xml to determine mCurrentAuthorizationMethod - mOAuth2Check.setChecked(mCurrentAuthorizationMethod == AUTH_METHOD_OAUTH2); + mOAuth2Check.setChecked(mCurrentAuthTokenType == AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN); mJustCreated = true; if (mAction == ACTION_UPDATE_TOKEN || !mHostUrlInputEnabled) { @@ -259,7 +254,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList // account data, if updating mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT); - mCurrentAuthorizationMethod = savedInstanceState.getInt(KEY_AUTH_METHOD, AUTH_METHOD_BASIC_HTTP); + mCurrentAuthTokenType = savedInstanceState.getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD); // check if server check was interrupted by a configuration change if (savedInstanceState.getBoolean(KEY_SERVER_CHECK_IN_PROGRESS, false)) { @@ -289,7 +284,8 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList if (mServerIsChecked && !mServerIsValid && refreshButtonEnabled) showRefreshButton(); mOkButton.setEnabled(mServerIsValid); // state not automatically recovered in configuration changes - if (mCurrentAuthorizationMethod == AUTH_METHOD_SAML_WEB_SSO || !AUTH_OPTIONAL.equals(getString(R.string.auth_method_oauth2))) { + if (mCurrentAuthTokenType == AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE || + !AUTH_OPTIONAL.equals(getString(R.string.auth_method_oauth2))) { mOAuth2Check.setVisibility(View.GONE); } @@ -331,33 +327,31 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList boolean oAuthRequired = false; boolean samlWebSsoRequired = false; - String tokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE); + mCurrentAuthTokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE); mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT); - if (tokenType != null) { - /// use the authentication method requested by caller - oAuthRequired = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(tokenType); - samlWebSsoRequired = AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(tokenType); - - } else if (mAccount != null) { - /// same authentication method than the one used to create the account to update - oAuthRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null); - samlWebSsoRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null); - - } else { - /// use the one set in setup.xml - oAuthRequired = AUTH_ON.equals(getString(R.string.auth_method_oauth2)); - samlWebSsoRequired = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso)); - } + // TODO could be a good moment to validate the received token type, if not null - if (oAuthRequired) { - mCurrentAuthorizationMethod = AUTH_METHOD_OAUTH2; - } else if (samlWebSsoRequired) { - mCurrentAuthorizationMethod = AUTH_METHOD_SAML_WEB_SSO; - } else { - mCurrentAuthorizationMethod = AUTH_METHOD_BASIC_HTTP; + if (mCurrentAuthTokenType == null) { + if (mAccount != null) { + /// same authentication method than the one used to create the account to update + oAuthRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null); + samlWebSsoRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null); + + } else { + /// use the one set in setup.xml + oAuthRequired = AUTH_ON.equals(getString(R.string.auth_method_oauth2)); + samlWebSsoRequired = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso)); + } + if (oAuthRequired) { + mCurrentAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN; + } else if (samlWebSsoRequired) { + mCurrentAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE; + } else { + mCurrentAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD; + } } - + if (mAccount != null) { String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@')); mUsernameInput.setText(userName); @@ -397,7 +391,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList if (mAccount != null) { outState.putParcelable(KEY_ACCOUNT, mAccount); } - outState.putInt(KEY_AUTH_METHOD, mCurrentAuthorizationMethod); + outState.putString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE, mCurrentAuthTokenType); // refresh button enabled outState.putBoolean(KEY_REFRESH_BUTTON_ENABLED, (mRefreshButton.getVisibility() == View.VISIBLE)); @@ -626,9 +620,10 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList return; } - if (mOAuth2Check.isChecked()) { + if (AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(mCurrentAuthTokenType)) { startOauthorization(); - + } else if (AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(mCurrentAuthTokenType)) { + startSamlBasedFederatedSingleSignOnAuthorization(); } else { checkBasicAuthorization(); } @@ -641,7 +636,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList */ private void checkBasicAuthorization() { /// get the path to the root folder through WebDAV from the version server - String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, false); + String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType); /// get basic credentials entered by user String username = mUsernameInput.getText().toString(); @@ -684,6 +679,20 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList } + /** + * Starts the Web Single Sign On flow to get access to the root folder + * in the server. + */ + private void startSamlBasedFederatedSingleSignOnAuthorization() { + /// get the path to the root folder through WebDAV from the version server + String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType); + + /// test credentials accessing the root folder + mAuthCheckOperation = new ExistenceCheckOperation("", this, false); + WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this); + mOperationThread = mAuthCheckOperation.execute(client, this, mHandler); + } + /** * Callback method invoked when a RemoteOperation executed by this Activity finishes. * @@ -699,8 +708,12 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList onGetOAuthAccessTokenFinish((OAuth2GetAccessToken)operation, result); } else if (operation instanceof ExistenceCheckOperation) { - onAuthorizationCheckFinish((ExistenceCheckOperation)operation, result); - + if (AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(mCurrentAuthTokenType)) { + Toast.makeText(this, result.getLogMessage(), Toast.LENGTH_LONG).show(); + + } else { + onAuthorizationCheckFinish((ExistenceCheckOperation)operation, result); + } } } @@ -952,7 +965,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens } - String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, true); + String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType); if (result.isSuccess() && webdav_path != null) { /// be gentle with the user showDialog(DIALOG_LOGIN_PROGRESS); @@ -1305,9 +1318,9 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList public void onCheckClick(View view) { CheckBox oAuth2Check = (CheckBox)view; if (oAuth2Check.isChecked()) { - mCurrentAuthorizationMethod = AUTH_METHOD_OAUTH2; + mCurrentAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN; } else { - mCurrentAuthorizationMethod = AUTH_METHOD_BASIC_HTTP; + mCurrentAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD; } adaptViewAccordingToAuthenticationMethod(); } @@ -1318,37 +1331,33 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList * the current authorization method. */ private void adaptViewAccordingToAuthenticationMethod () { - switch (mCurrentAuthorizationMethod) { - case AUTH_METHOD_OAUTH2: - // OAuth 2 authorization - mOAuthAuthEndpointText.setVisibility(View.VISIBLE); - mOAuthTokenEndpointText.setVisibility(View.VISIBLE); - mUsernameInput.setVisibility(View.GONE); - mPasswordInput.setVisibility(View.GONE); - mAccountNameInput.setVisibility(View.GONE); - mWebSsoView.setVisibility(View.GONE); - break; - - case AUTH_METHOD_SAML_WEB_SSO: - // SAML-based web Single Sign On - mOAuthAuthEndpointText.setVisibility(View.GONE); - mOAuthTokenEndpointText.setVisibility(View.GONE); - mUsernameInput.setVisibility(View.GONE); - mPasswordInput.setVisibility(View.GONE); - mAccountNameInput.setVisibility(View.VISIBLE); - mWebSsoView.setVisibility(View.VISIBLE); - break; - - case AUTH_METHOD_BASIC_HTTP: - default: - // basic HTTP authorization - mOAuthAuthEndpointText.setVisibility(View.GONE); - mOAuthTokenEndpointText.setVisibility(View.GONE); - mUsernameInput.setVisibility(View.VISIBLE); - mPasswordInput.setVisibility(View.VISIBLE); - mAccountNameInput.setVisibility(View.GONE); - mWebSsoView.setVisibility(View.GONE); - } + if (AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(mCurrentAuthTokenType)) { + // OAuth 2 authorization + mOAuthAuthEndpointText.setVisibility(View.VISIBLE); + mOAuthTokenEndpointText.setVisibility(View.VISIBLE); + mUsernameInput.setVisibility(View.GONE); + mPasswordInput.setVisibility(View.GONE); + mAccountNameInput.setVisibility(View.GONE); + mWebSsoView.setVisibility(View.GONE); + + } else if (AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(mCurrentAuthTokenType)) { + // SAML-based web Single Sign On + mOAuthAuthEndpointText.setVisibility(View.GONE); + mOAuthTokenEndpointText.setVisibility(View.GONE); + mUsernameInput.setVisibility(View.GONE); + mPasswordInput.setVisibility(View.GONE); + mAccountNameInput.setVisibility(View.VISIBLE); + mWebSsoView.setVisibility(View.VISIBLE); + + } else { + // basic HTTP authorization + mOAuthAuthEndpointText.setVisibility(View.GONE); + mOAuthTokenEndpointText.setVisibility(View.GONE); + mUsernameInput.setVisibility(View.VISIBLE); + mPasswordInput.setVisibility(View.VISIBLE); + mAccountNameInput.setVisibility(View.GONE); + mWebSsoView.setVisibility(View.GONE); + } } /** diff --git a/src/com/owncloud/android/ui/activity/AccountSelectActivity.java b/src/com/owncloud/android/ui/activity/AccountSelectActivity.java index 1a1cd51bd4..2c3448d619 100644 --- a/src/com/owncloud/android/ui/activity/AccountSelectActivity.java +++ b/src/com/owncloud/android/ui/activity/AccountSelectActivity.java @@ -50,6 +50,7 @@ import com.actionbarsherlock.view.MenuItem; import com.owncloud.android.authentication.AccountAuthenticator; import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.authentication.AccountUtils; +import com.owncloud.android.ui.activity.FileActivity.AccountCreationCallback; import com.owncloud.android.Log_OC; import com.owncloud.android.R; @@ -133,11 +134,20 @@ public class AccountSelectActivity extends SherlockListActivity implements @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { if (item.getItemId() == R.id.createAccount) { - Intent intent = new Intent( + /*Intent intent = new Intent( android.provider.Settings.ACTION_ADD_ACCOUNT); intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTHORITY }); - startActivity(intent); + startActivity(intent);*/ + AccountManager am = AccountManager.get(getApplicationContext()); + am.addAccount(AccountAuthenticator.ACCOUNT_TYPE, + null, + null, + null, + this, + null, + null); + return true; } return false; diff --git a/src/com/owncloud/android/ui/activity/FileActivity.java b/src/com/owncloud/android/ui/activity/FileActivity.java index a23b3be560..2e47ce0b28 100644 --- a/src/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/com/owncloud/android/ui/activity/FileActivity.java @@ -174,7 +174,7 @@ public abstract class FileActivity extends SherlockFragmentActivity { private void createFirstAccount() { AccountManager am = AccountManager.get(getApplicationContext()); am.addAccount(AccountAuthenticator.ACCOUNT_TYPE, - AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, + null, null, null, this,