/* ownCloud Android client application\r
* Copyright (C) 2012 Bartek Przybylski\r
- * Copyright (C) 2012-2013 ownCloud Inc.\r
+ * Copyright (C) 2012-2014 ownCloud Inc.\r
*\r
* This program is free software: you can redistribute it and/or modify\r
* it under the terms of the GNU General Public License version 2,\r
package com.owncloud.android.authentication;\r
\r
import java.security.cert.X509Certificate;\r
+import java.util.Map;\r
\r
import android.accounts.Account;\r
import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
import android.app.Dialog;\r
-import android.app.ProgressDialog;\r
import android.content.ComponentName;\r
import android.content.Context;\r
-import android.content.DialogInterface;\r
import android.content.Intent;\r
import android.content.ServiceConnection;\r
import android.content.SharedPreferences;\r
import android.view.View.OnTouchListener;\r
import android.view.Window;\r
import android.view.inputmethod.EditorInfo;\r
+import android.webkit.HttpAuthHandler;\r
import android.webkit.SslErrorHandler;\r
+import android.webkit.WebView;\r
import android.widget.Button;\r
import android.widget.CheckBox;\r
import android.widget.EditText;\r
import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;\r
import com.owncloud.android.lib.common.accounts.AccountTypeUtils;\r
import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;\r
-import com.owncloud.android.lib.common.OwnCloudClientFactory;\r
-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.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
+import com.owncloud.android.lib.common.utils.Log_OC;\r
import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;\r
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;\r
import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;\r
-\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.services.OperationsService;\r
import com.owncloud.android.services.OperationsService.OperationsServiceBinder;\r
+import com.owncloud.android.ui.dialog.CredentialsDialogFragment;\r
+import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;\r
import com.owncloud.android.ui.dialog.SamlWebViewDialog;\r
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;\r
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;\r
-import com.owncloud.android.utils.Log_OC;\r
-import com.owncloud.android.lib.resources.status.OwnCloudVersion;\r
+import com.owncloud.android.utils.DisplayUtils;\r
\r
/**\r
* This Activity is used to add an ownCloud account to the App\r
* \r
* @author Bartek Przybylski\r
* @author David A. Velasco\r
+ * @author masensio\r
*/\r
public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
implements OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener, \r
\r
private static final String TAG = AuthenticatorActivity.class.getSimpleName();\r
\r
- public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
- public static final String EXTRA_USER_NAME = "USER_NAME";\r
- public static final String EXTRA_HOST_NAME = "HOST_NAME";\r
public static final String EXTRA_ACTION = "ACTION";\r
- public static final String EXTRA_ENFORCED_UPDATE = "ENFORCE_UPDATE";\r
+ public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
+\r
+ private static final String KEY_AUTH_TOKEN_TYPE = "AUTH_TOKEN_TYPE";\r
\r
- private static final String KEY_AUTH_MESSAGE_VISIBILITY = "AUTH_MESSAGE_VISIBILITY";\r
- private static final String KEY_AUTH_MESSAGE_TEXT = "AUTH_MESSAGE_TEXT";\r
private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT";\r
private static final String KEY_OC_VERSION = "OC_VERSION";\r
- private static final String KEY_OC_VERSION_STRING = "OC_VERSION_STRING";\r
- private static final String KEY_ACCOUNT = "ACCOUNT";\r
private static final String KEY_SERVER_VALID = "SERVER_VALID";\r
private static final String KEY_SERVER_CHECKED = "SERVER_CHECKED";\r
- private static final String KEY_SERVER_CHECK_IN_PROGRESS = "SERVER_CHECK_IN_PROGRESS"; \r
private static final String KEY_SERVER_STATUS_TEXT = "SERVER_STATUS_TEXT";\r
private static final String KEY_SERVER_STATUS_ICON = "SERVER_STATUS_ICON";\r
private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN";\r
- private static final String KEY_PASSWORD_VISIBLE = "PASSWORD_VISIBLE";\r
+ private static final String KEY_PASSWORD_EXPOSED = "PASSWORD_VISIBLE";\r
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
- //private static final String KEY_IS_SHARED_SUPPORTED = "KEY_IS_SHARE_SUPPORTED";\r
+ private static final String KEY_SERVER_AUTH_METHOD = "SERVER_AUTH_METHOD";\r
+ private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";\r
+ private static final String KEY_AUTH_TOKEN = "AUTH_TOKEN";\r
\r
private static final String AUTH_ON = "on";\r
- private static final String AUTH_OFF = "off";\r
private static final String AUTH_OPTIONAL = "optional";\r
\r
- private static final int DIALOG_LOGIN_PROGRESS = 0;\r
- private static final int DIALOG_CERT_NOT_SAVED = 1;\r
- private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 2;\r
-\r
public static final byte ACTION_CREATE = 0;\r
- public static final byte ACTION_UPDATE_TOKEN = 1;\r
+ public static final byte ACTION_UPDATE_TOKEN = 1; // requested by the user\r
+ public static final byte ACTION_UPDATE_EXPIRED_TOKEN = 2; // detected by the app\r
\r
- private static final String TAG_SAML_DIALOG = "samlWebViewDialog";\r
+ private static final String UNTRUSTED_CERT_DIALOG_TAG = "UNTRUSTED_CERT_DIALOG";\r
+ private static final String SAML_DIALOG_TAG = "SAML_DIALOG";\r
+ private static final String WAIT_DIALOG_TAG = "WAIT_DIALOG";\r
+ private static final String CREDENTIALS_DIALOG_TAG = "CREDENTIALS_DIALOG";\r
+ private static final String KEY_AUTH_IS_FIRST_ATTEMPT_TAG = "KEY_AUTH_IS_FIRST_ATTEMPT";\r
\r
- private String mHostBaseUrl;\r
- private OwnCloudVersion mDiscoveredVersion;\r
-\r
- private String mAuthMessageText;\r
- private int mAuthMessageVisibility, mServerStatusText, mServerStatusIcon;\r
- private boolean mServerIsChecked, mServerIsValid, mIsSslConn;\r
- private int mAuthStatusText, mAuthStatusIcon; \r
- private TextView mAuthStatusLayout;\r
-\r
- private ServiceConnection mOperationsConnection = null;\r
- private OperationsServiceBinder mOperationsBinder = null;\r
\r
- private final Handler mHandler = new Handler();\r
- private Thread mOperationThread;\r
- private GetRemoteStatusOperation mOcServerChkOperation;\r
- private ExistenceCheckRemoteOperation mAuthCheckOperation;\r
+ /// parameters from EXTRAs in starter Intent\r
+ private byte mAction;\r
+ private Account mAccount;\r
+ private String mAuthTokenType;\r
\r
- private Uri mNewCapturedUriFromOAuth2Redirection;\r
\r
+ /// activity-level references / state\r
+ private final Handler mHandler = new Handler();\r
+ private ServiceConnection mOperationsServiceConnection = null;\r
+ private OperationsServiceBinder mOperationsServiceBinder = null;\r
private AccountManager mAccountMgr;\r
- private boolean mJustCreated;\r
- private byte mAction;\r
- private Account mAccount;\r
+ private Uri mNewCapturedUriFromOAuth2Redirection;\r
\r
- private TextView mAuthMessage;\r
\r
+ /// Server PRE-Fragment elements \r
private EditText mHostUrlInput;\r
- private boolean mHostUrlInputEnabled;\r
private View mRefreshButton;\r
+ private TextView mServerStatusView;\r
+ \r
+ private TextWatcher mHostUrlInputWatcher;\r
+ private int mServerStatusText = 0, mServerStatusIcon = 0;\r
+ \r
+ private boolean mServerIsChecked = false;\r
+ private boolean mServerIsValid = false;\r
+ private boolean mPendingAutoCheck = false;\r
\r
- private String mAuthTokenType;\r
-\r
- private EditText mUsernameInput;\r
- private EditText mPasswordInput;\r
-\r
+ private GetServerInfoOperation.ServerInfo mServerInfo = \r
+ new GetServerInfoOperation.ServerInfo();\r
+ \r
+ \r
+ /// Authentication PRE-Fragment elements \r
private CheckBox mOAuth2Check;\r
-\r
private TextView mOAuthAuthEndpointText;\r
private TextView mOAuthTokenEndpointText;\r
-\r
- private SamlWebViewDialog mSamlDialog;\r
-\r
+ private EditText mUsernameInput;\r
+ private EditText mPasswordInput;\r
private View mOkButton;\r
+ private TextView mAuthStatusView;\r
\r
- private String mAuthToken;\r
+ private int mAuthStatusText = 0, mAuthStatusIcon = 0;\r
+ \r
+ private String mAuthToken = "";\r
\r
- private boolean mResumed; // Control if activity is resumed\r
+ private boolean mIsFirstAuthAttempt;\r
\r
- public static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT";\r
\r
- private ServiceConnection mOperationsServiceConnection = null;\r
- \r
- private OperationsServiceBinder mOperationsServiceBinder = null;\r
-\r
+ /// Identifier of operation in progress which result shouldn't be lost \r
+ private long mWaitingForOpId = Long.MAX_VALUE;\r
\r
+ \r
/**\r
* {@inheritDoc}\r
* \r
*/\r
@Override\r
protected void onCreate(Bundle savedInstanceState) {\r
+ //Log_OC.wtf(TAG, "onCreate init");\r
super.onCreate(savedInstanceState);\r
getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
\r
- // bind to Operations Service\r
- mOperationsConnection = new ServiceConnection() {\r
+ mIsFirstAuthAttempt = true;\r
\r
- @Override\r
- public void onServiceConnected(ComponentName name, IBinder service) {\r
- Log_OC.d(TAG, "Operations service connected");\r
- mOperationsBinder = (OperationsServiceBinder) service;\r
- }\r
-\r
- @Override\r
- public void onServiceDisconnected(ComponentName name) {\r
- Log_OC.d(TAG, "Operations service crashed");\r
- mOperationsBinder = null;\r
- }\r
- \r
- };\r
+ // bind to Operations Service\r
+ mOperationsServiceConnection = new OperationsServiceConnection();\r
if (!bindService(new Intent(this, OperationsService.class), \r
- mOperationsConnection, \r
- Context.BIND_AUTO_CREATE)) {\r
+ mOperationsServiceConnection, \r
+ Context.BIND_AUTO_CREATE)) {\r
Toast.makeText(this, \r
R.string.error_cant_bind_to_operations_service, \r
Toast.LENGTH_LONG)\r
finish();\r
}\r
\r
- /// set view and get references to view elements\r
+ /// init activity state\r
+ mAccountMgr = AccountManager.get(this);\r
+ mNewCapturedUriFromOAuth2Redirection = null;\r
+ \r
+ /// get input values\r
+ mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); \r
+ mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
+ if (savedInstanceState == null) {\r
+ initAuthTokenType();\r
+ } else {\r
+ mAuthTokenType = savedInstanceState.getString(KEY_AUTH_TOKEN_TYPE);\r
+ mWaitingForOpId = savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID);\r
+ mIsFirstAuthAttempt = savedInstanceState.getBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG);\r
+ }\r
+ \r
+ /// load user interface\r
setContentView(R.layout.account_setup);\r
- mAuthMessage = (TextView) findViewById(R.id.auth_message);\r
- mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);\r
- mHostUrlInput.setText(getString(R.string.server_url)); // valid although R.string.server_url is an empty string\r
- mUsernameInput = (EditText) findViewById(R.id.account_username);\r
- mPasswordInput = (EditText) findViewById(R.id.account_password);\r
- mOAuthAuthEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_1);\r
- mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);\r
- mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);\r
+ \r
+ /// initialize general UI elements\r
+ initOverallUi(savedInstanceState);\r
+ \r
mOkButton = findViewById(R.id.buttonOK);\r
- mAuthStatusLayout = (TextView) findViewById(R.id.auth_status_text); \r
\r
- /// set Host Url Input Enabled\r
- mHostUrlInputEnabled = getResources().getBoolean(R.bool.show_server_url_input);\r
+ /// initialize block to be moved to single Fragment to check server and get info about it \r
+ initServerPreFragment(savedInstanceState);\r
+ \r
+ /// initialize block to be moved to single Fragment to retrieve and validate credentials \r
+ initAuthorizationPreFragment(savedInstanceState);\r
\r
- /// set visibility of link for new users\r
- boolean accountRegisterVisibility = getResources().getBoolean(R.bool.show_welcome_link);\r
- Button welcomeLink = (Button) findViewById(R.id.welcome_link);\r
- if (welcomeLink != null) {\r
- if (accountRegisterVisibility) {\r
- welcomeLink.setVisibility(View.VISIBLE);\r
- welcomeLink.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name))); \r
+ //Log_OC.wtf(TAG, "onCreate end");\r
+ }\r
+\r
+ private void initAuthTokenType() {\r
+ mAuthTokenType = \r
+ getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
+ if (mAuthTokenType == null) {\r
+ if (mAccount != null) {\r
+ boolean oAuthRequired = \r
+ (mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2) != null);\r
+ boolean samlWebSsoRequired = \r
+ (mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null);\r
+ mAuthTokenType = chooseAuthTokenType(oAuthRequired, samlWebSsoRequired);\r
+ \r
} else {\r
- findViewById(R.id.welcome_link).setVisibility(View.GONE);\r
+ boolean oAuthSupported = AUTH_ON.equals(getString(R.string.auth_method_oauth2));\r
+ boolean samlWebSsoSupported = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));\r
+ mAuthTokenType = chooseAuthTokenType(oAuthSupported, samlWebSsoSupported);\r
}\r
}\r
+ }\r
\r
- /// initialization\r
- mAccountMgr = AccountManager.get(this);\r
- mNewCapturedUriFromOAuth2Redirection = null;\r
- mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); \r
- mAccount = null;\r
- mHostBaseUrl = "";\r
- boolean refreshButtonEnabled = false;\r
-\r
- // URL input configuration applied\r
- if (!mHostUrlInputEnabled)\r
- {\r
- findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);\r
- mRefreshButton = findViewById(R.id.centeredRefreshButton);\r
+ private String chooseAuthTokenType(boolean oauth, boolean saml) {\r
+ if (saml) {\r
+ return AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
+ } else if (oauth) {\r
+ return AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
+ } else {\r
+ return AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
+ }\r
+ }\r
\r
+ \r
+ /**\r
+ * Configures elements in the user interface under direct control of the Activity.\r
+ * \r
+ * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}\r
+ */\r
+ private void initOverallUi(Bundle savedInstanceState) {\r
+ \r
+ /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)\r
+ boolean isWelcomeLinkVisible = getResources().getBoolean(R.bool.show_welcome_link);\r
+ \r
+ String instructionsMessageText = null; \r
+ if (mAction == ACTION_UPDATE_EXPIRED_TOKEN) {\r
+ if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())\r
+ .equals(mAuthTokenType)) {\r
+ instructionsMessageText = getString(R.string.auth_expired_oauth_token_toast);\r
+ \r
+ } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType())\r
+ .equals(mAuthTokenType)) {\r
+ instructionsMessageText = getString(R.string.auth_expired_saml_sso_token_toast);\r
+ \r
+ } else {\r
+ instructionsMessageText = getString(R.string.auth_expired_basic_auth_toast);\r
+ }\r
+ }\r
+ \r
+ /// step 2 - set properties of UI elements (text, visibility, enabled...)\r
+ Button welcomeLink = (Button) findViewById(R.id.welcome_link);\r
+ welcomeLink.setVisibility(isWelcomeLinkVisible ? View.VISIBLE : View.GONE);\r
+ welcomeLink.setText(\r
+ String.format(getString(R.string.auth_register), getString(R.string.app_name)));\r
+ \r
+ TextView instructionsView = (TextView) findViewById(R.id.instructions_message);\r
+ if (instructionsMessageText != null) {\r
+ instructionsView.setVisibility(View.VISIBLE);\r
+ instructionsView.setText(instructionsMessageText);\r
} else {\r
- mRefreshButton = findViewById(R.id.embeddedRefreshButton);\r
+ instructionsView.setVisibility(View.GONE);\r
}\r
+ }\r
\r
- if (savedInstanceState == null) {\r
- mResumed = false;\r
- /// connection state and info\r
- mAuthMessageVisibility = View.GONE;\r
- mServerStatusText = mServerStatusIcon = 0;\r
- mServerIsValid = false;\r
- mServerIsChecked = false;\r
- mIsSslConn = false;\r
- mAuthStatusText = mAuthStatusIcon = 0;\r
\r
- /// retrieve extras from intent\r
- mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
- if (mAccount != null) {
+ /**\r
+ * \r
+ * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}\r
+ */\r
+ private void initServerPreFragment(Bundle savedInstanceState) {\r
+\r
+ /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)\r
+ boolean isUrlInputAllowed = getResources().getBoolean(R.bool.show_server_url_input); \r
+ if (savedInstanceState == null) {\r
+ if (mAccount != null) {\r
+ mServerInfo.mBaseUrl = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_BASE_URL);\r
+ mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://"); // TODO do this in a setter for mBaseUrl\r
String ocVersion = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_VERSION);\r
- String ocVersionString = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_VERSION_STRING);
if (ocVersion != null) {\r
- mDiscoveredVersion = new OwnCloudVersion(ocVersion, ocVersionString);\r
+ mServerInfo.mVersion = new OwnCloudVersion(ocVersion);\r
}\r
- mHostBaseUrl = normalizeUrl(mAccountMgr.getUserData(mAccount, Constants.KEY_OC_BASE_URL));\r
- mHostUrlInput.setText(mHostBaseUrl);\r
- String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
- mUsernameInput.setText(userName);
-\r
- }\r
- initAuthorizationMethod(); // checks intent and setup.xml to determine mCurrentAuthorizationMethod\r
- mJustCreated = true;\r
-\r
- if (mAction == ACTION_UPDATE_TOKEN || !mHostUrlInputEnabled) {\r
- checkOcServer(); \r
+ } else {\r
+ mServerInfo.mBaseUrl = getString(R.string.server_url).trim();\r
+ mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://");\r
}\r
-\r
} else {\r
- mResumed = true;\r
- /// connection state and info\r
- mAuthMessageVisibility = savedInstanceState.getInt(KEY_AUTH_MESSAGE_VISIBILITY);\r
- mAuthMessageText = savedInstanceState.getString(KEY_AUTH_MESSAGE_TEXT);\r
- mServerIsValid = savedInstanceState.getBoolean(KEY_SERVER_VALID);\r
- mServerIsChecked = savedInstanceState.getBoolean(KEY_SERVER_CHECKED);\r
mServerStatusText = savedInstanceState.getInt(KEY_SERVER_STATUS_TEXT);\r
mServerStatusIcon = savedInstanceState.getInt(KEY_SERVER_STATUS_ICON);\r
- mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);\r
- mAuthStatusText = savedInstanceState.getInt(KEY_AUTH_STATUS_TEXT);\r
- mAuthStatusIcon = savedInstanceState.getInt(KEY_AUTH_STATUS_ICON);\r
- if (savedInstanceState.getBoolean(KEY_PASSWORD_VISIBLE, false)) {\r
- showPassword();\r
- }\r
-\r
- /// server data\r
+ \r
+ mServerIsValid = savedInstanceState.getBoolean(KEY_SERVER_VALID);\r
+ mServerIsChecked = savedInstanceState.getBoolean(KEY_SERVER_CHECKED);\r
+ \r
+ // TODO parcelable\r
+ mServerInfo.mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);\r
+ mServerInfo.mBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);\r
String ocVersion = savedInstanceState.getString(KEY_OC_VERSION);\r
- String ocVersionString = savedInstanceState.getString(KEY_OC_VERSION_STRING);\r
if (ocVersion != null) {\r
- mDiscoveredVersion = new OwnCloudVersion(ocVersion, ocVersionString);\r
- }\r
- mHostBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);\r
-\r
- // account data, if updating\r
- mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT);\r
- mAuthTokenType = savedInstanceState.getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
- if (mAuthTokenType == null) {\r
- mAuthTokenType = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
-\r
+ mServerInfo.mVersion = new OwnCloudVersion(ocVersion);\r
}\r
-\r
- // check if server check was interrupted by a configuration change\r
- if (savedInstanceState.getBoolean(KEY_SERVER_CHECK_IN_PROGRESS, false)) {\r
- checkOcServer();\r
- } \r
-\r
- // refresh button enabled\r
- refreshButtonEnabled = savedInstanceState.getBoolean(KEY_REFRESH_BUTTON_ENABLED);\r
-\r
-\r
- }\r
-\r
- if (mAuthMessageVisibility== View.VISIBLE) {\r
- showAuthMessage(mAuthMessageText);\r
- }\r
- else {\r
- hideAuthMessage();\r
+ mServerInfo.mAuthMethod = AuthenticationMethod.valueOf(\r
+ savedInstanceState.getString(KEY_SERVER_AUTH_METHOD));\r
+ \r
}\r
- adaptViewAccordingToAuthenticationMethod();\r
- showServerStatus();\r
- showAuthStatus();\r
-\r
- if (mAction == ACTION_UPDATE_TOKEN) {\r
+ \r
+ /// step 2 - set properties of UI elements (text, visibility, enabled...)\r
+ mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);\r
+ // Convert IDN to Unicode\r
+ mHostUrlInput.setText(DisplayUtils.convertIdn(mServerInfo.mBaseUrl, false));\r
+ if (mAction != ACTION_CREATE) {\r
/// lock things that should not change\r
mHostUrlInput.setEnabled(false);\r
mHostUrlInput.setFocusable(false);\r
- mUsernameInput.setEnabled(false);\r
- mUsernameInput.setFocusable(false);\r
- mOAuth2Check.setVisibility(View.GONE);\r
}\r
-\r
- //if (mServerIsChecked && !mServerIsValid && mRefreshButtonEnabled) showRefreshButton();\r
- if (mServerIsChecked && !mServerIsValid && refreshButtonEnabled) showRefreshButton();\r
- mOkButton.setEnabled(mServerIsValid); // state not automatically recovered in configuration changes\r
-\r
- if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType) || \r
- !AUTH_OPTIONAL.equals(getString(R.string.auth_method_oauth2))) {\r
- mOAuth2Check.setVisibility(View.GONE);\r
+ if (isUrlInputAllowed) {\r
+ mRefreshButton = findViewById(R.id.embeddedRefreshButton);\r
+ } else {\r
+ findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);\r
+ mRefreshButton = findViewById(R.id.centeredRefreshButton);\r
}\r
-\r
- mPasswordInput.setText(""); // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside)\r
-\r
- /// bind view elements to listeners and other friends\r
- mHostUrlInput.setOnFocusChangeListener(this);\r
+ showRefreshButton(mServerIsChecked && !mServerIsValid && \r
+ mWaitingForOpId > Integer.MAX_VALUE);\r
+ mServerStatusView = (TextView) findViewById(R.id.server_status_text);\r
+ showServerStatus();\r
+ \r
+ /// step 3 - bind some listeners and options\r
mHostUrlInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);\r
mHostUrlInput.setOnEditorActionListener(this);\r
- mHostUrlInput.addTextChangedListener(new TextWatcher() {\r
-\r
+ \r
+ /// step 4 - create listeners that will be bound at onResume\r
+ mHostUrlInputWatcher = new TextWatcher() {\r
+ \r
@Override\r
public void afterTextChanged(Editable s) {\r
- if (!mHostBaseUrl.equals(normalizeUrl(mHostUrlInput.getText().toString()))) {\r
+ if (mOkButton.isEnabled() &&\r
+ !mServerInfo.mBaseUrl.equals(\r
+ normalizeUrl(s.toString(), mServerInfo.mIsSslConn))) {\r
mOkButton.setEnabled(false);\r
}\r
}\r
\r
@Override\r
public void onTextChanged(CharSequence s, int start, int before, int count) {\r
- if (!mResumed) {\r
+ if (mAuthStatusIcon != 0) {\r
+ Log_OC.d(TAG, "onTextChanged: hiding authentication status");\r
mAuthStatusIcon = 0;\r
mAuthStatusText = 0;\r
- showAuthStatus(); \r
+ showAuthStatus();\r
}\r
- mResumed = false;\r
}\r
- });\r
+ };\r
\r
- mPasswordInput.setOnFocusChangeListener(this);\r
- mPasswordInput.setImeOptions(EditorInfo.IME_ACTION_DONE);\r
- mPasswordInput.setOnEditorActionListener(this);
- mPasswordInput.setOnTouchListener(new RightDrawableOnTouchListener() {\r
- @Override\r
- public boolean onDrawableTouch(final MotionEvent event) {\r
- if (event.getAction() == MotionEvent.ACTION_UP) {\r
- AuthenticatorActivity.this.onViewPasswordClick();\r
- }\r
- return true;\r
- }\r
- });\r
\r
+ // TODO find out if this is really necessary, or if it can done in a different way\r
findViewById(R.id.scroll).setOnTouchListener(new OnTouchListener() {\r
@Override\r
public boolean onTouch(View view, MotionEvent event) {\r
return false;\r
}\r
});\r
+ \r
\r
- mOperationsServiceConnection = new OperationsServiceConnection();\r
- bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE);\r
+ /// step 4 - mark automatic check to be started when OperationsService is ready\r
+ mPendingAutoCheck = (savedInstanceState == null && \r
+ (mAction != ACTION_CREATE || !isUrlInputAllowed));\r
}\r
+ \r
+ \r
+ /**\r
+ * \r
+ * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}\r
+ */\r
+ private void initAuthorizationPreFragment(Bundle savedInstanceState) {\r
+ \r
+ /// step 0 - get UI elements in layout\r
+ mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);\r
+ mOAuthAuthEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_1);\r
+ mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);\r
+ mUsernameInput = (EditText) findViewById(R.id.account_username);\r
+ mPasswordInput = (EditText) findViewById(R.id.account_password);\r
+ mAuthStatusView = (TextView) findViewById(R.id.auth_status_text); \r
+ \r
+ /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)\r
+ String presetUserName = null;\r
+ boolean isPasswordExposed = false;\r
+ if (savedInstanceState == null) {\r
+ if (mAccount != null) {\r
+ presetUserName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
+ }\r
+ \r
+ } else {\r
+ isPasswordExposed = savedInstanceState.getBoolean(KEY_PASSWORD_EXPOSED, false);\r
+ mAuthStatusText = savedInstanceState.getInt(KEY_AUTH_STATUS_TEXT);\r
+ mAuthStatusIcon = savedInstanceState.getInt(KEY_AUTH_STATUS_ICON);\r
+ mAuthToken = savedInstanceState.getString(KEY_AUTH_TOKEN);\r
+ }\r
+ \r
+ /// step 2 - set properties of UI elements (text, visibility, enabled...)\r
+ mOAuth2Check.setChecked(\r
+ AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())\r
+ .equals(mAuthTokenType));\r
+ if (presetUserName != null) {\r
+ mUsernameInput.setText(presetUserName);\r
+ }\r
+ if (mAction != ACTION_CREATE) {\r
+ mUsernameInput.setEnabled(false);\r
+ mUsernameInput.setFocusable(false);\r
+ }\r
+ mPasswordInput.setText(""); // clean password to avoid social hacking\r
+ if (isPasswordExposed) {\r
+ showPassword();\r
+ }\r
+ updateAuthenticationPreFragmentVisibility();\r
+ showAuthStatus();\r
+ mOkButton.setEnabled(mServerIsValid);\r
\r
+ \r
+ /// step 3 - bind listeners\r
+ // bindings for password input field\r
+ mPasswordInput.setOnFocusChangeListener(this);\r
+ mPasswordInput.setImeOptions(EditorInfo.IME_ACTION_DONE);\r
+ mPasswordInput.setOnEditorActionListener(this);\r
+ mPasswordInput.setOnTouchListener(new RightDrawableOnTouchListener() {\r
+ @Override\r
+ public boolean onDrawableTouch(final MotionEvent event) {\r
+ if (event.getAction() == MotionEvent.ACTION_UP) {\r
+ AuthenticatorActivity.this.onViewPasswordClick();\r
+ }\r
+ return true;\r
+ }\r
+ });\r
+ \r
+ }\r
\r
\r
- private void initAuthorizationMethod() {\r
- boolean oAuthRequired = false;\r
- boolean samlWebSsoRequired = false;\r
-\r
- mAuthTokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
- mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
-\r
- // TODO could be a good moment to validate the received token type, if not null\r
-\r
- if (mAuthTokenType == null) { \r
- if (mAccount != null) {\r
- /// same authentication method than the one used to create the account to update\r
- oAuthRequired = (mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2) != null);\r
- samlWebSsoRequired = (mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null);\r
-\r
+ /**\r
+ * Changes the visibility of input elements depending on\r
+ * the current authorization method.\r
+ */\r
+ private void updateAuthenticationPreFragmentVisibility () {\r
+ if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+ equals(mAuthTokenType)) {\r
+ // SAML-based web Single Sign On\r
+ mOAuth2Check.setVisibility(View.GONE);\r
+ mOAuthAuthEndpointText.setVisibility(View.GONE);\r
+ mOAuthTokenEndpointText.setVisibility(View.GONE);\r
+ mUsernameInput.setVisibility(View.GONE);\r
+ mPasswordInput.setVisibility(View.GONE);\r
+ \r
+ } else {\r
+ if (mAction == ACTION_CREATE && \r
+ AUTH_OPTIONAL.equals(getString(R.string.auth_method_oauth2))) {\r
+ mOAuth2Check.setVisibility(View.VISIBLE);\r
} else {\r
- /// use the one set in setup.xml\r
- oAuthRequired = AUTH_ON.equals(getString(R.string.auth_method_oauth2));\r
- samlWebSsoRequired = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso)); \r
+ mOAuth2Check.setVisibility(View.GONE);\r
}\r
- if (oAuthRequired) {\r
- mAuthTokenType = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
- } else if (samlWebSsoRequired) {\r
- mAuthTokenType = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
+ \r
+ if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).\r
+ equals(mAuthTokenType)) {\r
+ // OAuth 2 authorization\r
+ \r
+ mOAuthAuthEndpointText.setVisibility(View.VISIBLE);\r
+ mOAuthTokenEndpointText.setVisibility(View.VISIBLE);\r
+ mUsernameInput.setVisibility(View.GONE);\r
+ mPasswordInput.setVisibility(View.GONE);\r
+ \r
} else {\r
- mAuthTokenType = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
+ // basic HTTP authorization\r
+ mOAuthAuthEndpointText.setVisibility(View.GONE);\r
+ mOAuthTokenEndpointText.setVisibility(View.GONE);\r
+ mUsernameInput.setVisibility(View.VISIBLE);\r
+ mPasswordInput.setVisibility(View.VISIBLE);\r
}\r
}\r
+ }\r
\r
- if (mAccount != null) {\r
- String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
- mUsernameInput.setText(userName);\r
- }\r
-\r
- mOAuth2Check.setChecked(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType));\r
\r
- }\r
\r
/**\r
* Saves relevant state before {@link #onPause()}\r
*/\r
@Override\r
protected void onSaveInstanceState(Bundle outState) {\r
+ //Log_OC.wtf(TAG, "onSaveInstanceState init" );\r
super.onSaveInstanceState(outState);\r
\r
- /// connection state and info\r
- outState.putInt(KEY_AUTH_MESSAGE_VISIBILITY, mAuthMessage.getVisibility());\r
- outState.putString(KEY_AUTH_MESSAGE_TEXT, mAuthMessage.getText().toString());\r
+ /// global state\r
+ outState.putString(KEY_AUTH_TOKEN_TYPE, mAuthTokenType);\r
+ outState.putLong(KEY_WAITING_FOR_OP_ID, mWaitingForOpId);\r
+\r
+ /// Server PRE-fragment state\r
outState.putInt(KEY_SERVER_STATUS_TEXT, mServerStatusText);\r
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_IS_SSL_CONN, mIsSslConn);\r
- outState.putBoolean(KEY_PASSWORD_VISIBLE, isPasswordVisible());\r
- outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);\r
- outState.putInt(KEY_AUTH_STATUS_TEXT, mAuthStatusText);\r
-\r
- /// server data\r
- if (mDiscoveredVersion != null) {\r
- outState.putString(KEY_OC_VERSION, mDiscoveredVersion.getVersion());\r
- outState.putString(KEY_OC_VERSION_STRING, mDiscoveredVersion.getVersionString());\r
- }\r
- outState.putString(KEY_HOST_URL_TEXT, mHostBaseUrl);\r
-\r
- /// account data, if updating\r
- if (mAccount != null) {\r
- outState.putParcelable(KEY_ACCOUNT, mAccount);\r
+ outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);\r
+ outState.putBoolean(KEY_IS_SSL_CONN, mServerInfo.mIsSslConn);\r
+ outState.putString(KEY_HOST_URL_TEXT, mServerInfo.mBaseUrl);\r
+ if (mServerInfo.mVersion != null) {\r
+ outState.putString(KEY_OC_VERSION, mServerInfo.mVersion.getVersion());\r
}\r
- outState.putString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE, mAuthTokenType);\r
+ outState.putString(KEY_SERVER_AUTH_METHOD, mServerInfo.mAuthMethod.name());\r
\r
- // refresh button enabled\r
- outState.putBoolean(KEY_REFRESH_BUTTON_ENABLED, (mRefreshButton.getVisibility() == View.VISIBLE));\r
+ /// Authentication PRE-fragment state\r
+ outState.putBoolean(KEY_PASSWORD_EXPOSED, isPasswordVisible());\r
+ outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);\r
+ outState.putInt(KEY_AUTH_STATUS_TEXT, mAuthStatusText);\r
+ outState.putString(KEY_AUTH_TOKEN, mAuthToken);\r
\r
+ /// authentication\r
+ outState.putBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG, mIsFirstAuthAttempt);\r
\r
+ //Log_OC.wtf(TAG, "onSaveInstanceState end" );\r
}\r
\r
\r
*/\r
@Override\r
protected void onResume() {\r
+ //Log_OC.wtf(TAG, "onResume init" );\r
super.onResume();\r
- if (mAction == ACTION_UPDATE_TOKEN && mJustCreated && getIntent().getBooleanExtra(EXTRA_ENFORCED_UPDATE, false)) {\r
- if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
- //Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show();\r
- showAuthMessage(getString(R.string.auth_expired_oauth_token_toast));\r
- } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
- //Toast.makeText(this, R.string.auth_expired_saml_sso_token_toast, Toast.LENGTH_LONG).show();\r
- showAuthMessage(getString(R.string.auth_expired_saml_sso_token_toast));\r
- } else {\r
- //Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show();\r
- showAuthMessage(getString(R.string.auth_expired_basic_auth_toast));\r
- }\r
- }\r
-\r
+ \r
+ // bound here to avoid spurious changes triggered by Android on device rotations\r
+ mHostUrlInput.setOnFocusChangeListener(this);\r
+ mHostUrlInput.addTextChangedListener(mHostUrlInputWatcher);\r
+ \r
if (mNewCapturedUriFromOAuth2Redirection != null) {\r
getOAuth2AccessTokenFromCapturedRedirection(); \r
}\r
-\r
- mJustCreated = false;\r
-\r
+ \r
+ if (mOperationsServiceBinder != null) {\r
+ doOnResumeAndBound();\r
+ }\r
+ \r
+ //Log_OC.wtf(TAG, "onResume end" );\r
}\r
+\r
\r
+ @Override\r
+ protected void onPause() {\r
+ //Log_OC.wtf(TAG, "onPause init" );\r
+ if (mOperationsServiceBinder != null) {\r
+ //Log_OC.wtf(TAG, "unregistering to listen for operation callbacks" );\r
+ mOperationsServiceBinder.removeOperationListener(this);\r
+ }\r
+ \r
+ mHostUrlInput.removeTextChangedListener(mHostUrlInputWatcher);\r
+ mHostUrlInput.setOnFocusChangeListener(null);\r
+ \r
+ super.onPause();\r
+ //Log_OC.wtf(TAG, "onPause end" );\r
+ }\r
\r
@Override\r
protected void onDestroy() {\r
- if (mOperationsConnection != null) {\r
- unbindService(mOperationsConnection);\r
- mOperationsBinder = null;\r
+\r
+ mHostUrlInputWatcher = null;\r
+ \r
+ if (mOperationsServiceConnection != null) {\r
+ unbindService(mOperationsServiceConnection);\r
+ mOperationsServiceBinder = null;\r
}\r
super.onDestroy();\r
}\r
mNewCapturedUriFromOAuth2Redirection = null;\r
\r
/// Showing the dialog with instructions for the user.\r
- showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
+ IndeterminateProgressDialog dialog = \r
+ IndeterminateProgressDialog.newInstance(R.string.auth_getting_authorization, true);\r
+ dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
\r
- /// GET ACCESS TOKEN to the oAuth server \r
- RemoteOperation operation = new OAuth2GetAccessToken( getString(R.string.oauth2_client_id), \r
- getString(R.string.oauth2_redirect_uri), \r
- getString(R.string.oauth2_grant_type),\r
+ /// GET ACCESS TOKEN to the oAuth server\r
+ Intent getServerInfoIntent = new Intent();\r
+ getServerInfoIntent.setAction(OperationsService.ACTION_OAUTH2_GET_ACCESS_TOKEN);\r
+ \r
+ getServerInfoIntent.putExtra(\r
+ OperationsService.EXTRA_SERVER_URL, \r
+ mOAuthTokenEndpointText.getText().toString().trim());\r
+ \r
+ getServerInfoIntent.putExtra(\r
+ OperationsService.EXTRA_OAUTH2_QUERY_PARAMETERS, \r
queryParameters);\r
- //OwnCloudClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth2_url_endpoint_access)), getApplicationContext());\r
- OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mOAuthTokenEndpointText.getText().toString().trim()), getApplicationContext(), true);\r
- operation.execute(client, this, mHandler);\r
+ \r
+ if (mOperationsServiceBinder != null) {\r
+ //Log_OC.wtf(TAG, "getting access token..." );\r
+ mWaitingForOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent);\r
+ }\r
}\r
\r
\r
onUrlInputFocusLost((TextView) view);\r
}\r
else {\r
- hideRefreshButton();\r
+ showRefreshButton(false);\r
}\r
\r
} else if (view.getId() == R.id.account_password) {\r
* @param hostInput TextView with the URL input field receiving the change of focus.\r
*/\r
private void onUrlInputFocusLost(TextView hostInput) {\r
- if (!mHostBaseUrl.equals(normalizeUrl(mHostUrlInput.getText().toString()))) {\r
+ if (!mServerInfo.mBaseUrl.equals(\r
+ normalizeUrl(mHostUrlInput.getText().toString(), mServerInfo.mIsSslConn))) {\r
+ // check server again only if the user changed something in the field\r
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
-\r
- if (!mHostUrlInputEnabled){\r
- uri = getString(R.string.server_url);\r
- }\r
-\r
+ String uri = mHostUrlInput.getText().toString().trim();\r
mServerIsValid = false;\r
mServerIsChecked = false;\r
mOkButton.setEnabled(false);\r
- mDiscoveredVersion = null;\r
- hideRefreshButton();\r
+ mServerInfo = new GetServerInfoOperation.ServerInfo();\r
+ showRefreshButton(false);\r
+ \r
if (uri.length() != 0) {\r
+ // Handle internationalized domain names\r
+ uri = DisplayUtils.convertIdn(uri, true);\r
mServerStatusText = R.string.auth_testing_connection;\r
mServerStatusIcon = R.drawable.progress_small;\r
showServerStatus();\r
- mOcServerChkOperation = new GetRemoteStatusOperation(uri, this);\r
- OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(uri), this, true);\r
- mOperationThread = mOcServerChkOperation.execute(client, this, mHandler);\r
+ \r
+ Intent getServerInfoIntent = new Intent();\r
+ getServerInfoIntent.setAction(OperationsService.ACTION_GET_SERVER_INFO);\r
+ getServerInfoIntent.putExtra(OperationsService.EXTRA_SERVER_URL, uri);\r
+ if (mOperationsServiceBinder != null) {\r
+ mWaitingForOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent);\r
+ } else {\r
+ Log_OC.wtf(TAG, "Server check tried with OperationService unbound!" );\r
+ }\r
+ \r
} else {\r
mServerStatusText = 0;\r
mServerStatusIcon = 0;\r
\r
\r
private void showViewPasswordButton() {\r
- //int drawable = android.R.drawable.ic_menu_view;\r
int drawable = R.drawable.ic_view;\r
if (isPasswordVisible()) {\r
- //drawable = android.R.drawable.ic_secure;\r
drawable = R.drawable.ic_hide;\r
}\r
mPasswordInput.setCompoundDrawablesWithIntrinsicBounds(0, 0, drawable, 0);\r
showViewPasswordButton();\r
}\r
\r
-\r
- /**\r
- * Cancels the authenticator activity\r
- * \r
- * IMPORTANT ENTRY POINT 3: Never underestimate the importance of cancellation\r
- * \r
- * This method is bound in the layout/acceoun_setup.xml resource file.\r
- * \r
- * @param view Cancel button\r
- */\r
- public void onCancelClick(View view) {\r
- setResult(RESULT_CANCELED); // TODO review how is this related to AccountAuthenticator (debugging)\r
- finish();\r
- }\r
-\r
-\r
-\r
/**\r
* Checks the credentials of the user in the root of the ownCloud server\r
* before creating a new local account.\r
*/\r
public void onOkClick(View view) {\r
// this check should be unnecessary\r
- if (mDiscoveredVersion == null || !mDiscoveredVersion.isVersionValid() || mHostBaseUrl == null || mHostBaseUrl.length() == 0) {\r
+ if (mServerInfo.mVersion == null || \r
+ !mServerInfo.mVersion.isVersionValid() || \r
+ mServerInfo.mBaseUrl == null || \r
+ mServerInfo.mBaseUrl.length() == 0) {\r
mServerStatusIcon = R.drawable.common_error;\r
mServerStatusText = R.string.auth_wtf_reenter_URL;\r
showServerStatus();\r
mOkButton.setEnabled(false);\r
- Log_OC.wtf(TAG, "The user was allowed to click 'connect' to an unchecked server!!");\r
+ //Log_OC.wtf(TAG, "The user was allowed to click 'connect' to an unchecked server!!");\r
return;\r
}\r
\r
* the root folder of the ownCloud server.\r
*/\r
private void checkBasicAuthorization() {\r
- /// get the path to the root folder through WebDAV from the version server\r
- String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
-\r
/// get basic credentials entered by user\r
String username = mUsernameInput.getText().toString();\r
String password = mPasswordInput.getText().toString();\r
\r
/// be gentle with the user\r
- showDialog(DIALOG_LOGIN_PROGRESS);\r
+ IndeterminateProgressDialog dialog = \r
+ IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);\r
+ dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
\r
- /// test credentials accessing the root folder\r
- mAuthCheckOperation = new ExistenceCheckRemoteOperation("", this, false);\r
- OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true);\r
- client.setBasicCredentials(username, password);\r
- mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
+ /// validate credentials accessing the root folder\r
+ accessRootFolderRemoteOperation(username, password);\r
+ \r
}\r
\r
+ private void accessRootFolderRemoteOperation(String username, String password) {\r
+ Intent existenceCheckIntent = new Intent();\r
+ existenceCheckIntent.setAction(OperationsService.ACTION_EXISTENCE_CHECK);\r
+ existenceCheckIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mServerInfo.mBaseUrl);\r
+ existenceCheckIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, "/");\r
+ existenceCheckIntent.putExtra(OperationsService.EXTRA_USERNAME, username);\r
+ existenceCheckIntent.putExtra(OperationsService.EXTRA_PASSWORD, password);\r
+ existenceCheckIntent.putExtra(OperationsService.EXTRA_AUTH_TOKEN, mAuthToken);\r
+ \r
+ if (mOperationsServiceBinder != null) {\r
+ //Log_OC.wtf(TAG, "starting existenceCheckRemoteOperation..." );\r
+ mWaitingForOpId = mOperationsServiceBinder.newOperation(existenceCheckIntent);\r
+ }\r
+ }\r
\r
/**\r
* Starts the OAuth 'grant type' flow to get an access token, with \r
mAuthStatusText = R.string.oauth_login_connection;\r
showAuthStatus();\r
\r
-\r
// GET AUTHORIZATION request\r
- //Uri uri = Uri.parse(getString(R.string.oauth2_url_endpoint_auth));\r
Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim());\r
Uri.Builder uriBuilder = uri.buildUpon();\r
uriBuilder.appendQueryParameter(OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type));\r
uriBuilder.appendQueryParameter(OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri)); \r
uriBuilder.appendQueryParameter(OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id));\r
uriBuilder.appendQueryParameter(OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope));\r
- //uriBuilder.appendQueryParameter(OAuth2Constants.KEY_STATE, whateverwewant);\r
uri = uriBuilder.build();\r
Log_OC.d(TAG, "Starting browser to view " + uri.toString());\r
Intent i = new Intent(Intent.ACTION_VIEW, uri);\r
mAuthStatusIcon = R.drawable.progress_small;\r
mAuthStatusText = R.string.auth_connecting_auth_server;\r
showAuthStatus();\r
- showDialog(DIALOG_LOGIN_PROGRESS);\r
+ IndeterminateProgressDialog dialog = \r
+ IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);\r
+ dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
\r
- /// get the path to the root folder through WebDAV from the version server\r
- String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
-\r
- /// test credentials accessing the root folder\r
- mAuthCheckOperation = new ExistenceCheckRemoteOperation("", this, false);\r
- OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, false);\r
- mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
+ /// validate credentials accessing the root folder\r
+ accessRootFolderRemoteOperation("", "");\r
\r
}\r
\r
@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.hashCode() == mWaitingForOpId) {\r
+ onGetServerInfoFinish(result);\r
+ } // else nothing ; only the last check operation is considered; \r
+ // multiple can be started if the user amends a URL quickly\r
\r
} else if (operation instanceof OAuth2GetAccessToken) {\r
- onGetOAuthAccessTokenFinish((OAuth2GetAccessToken)operation, result);\r
+ onGetOAuthAccessTokenFinish(result);\r
\r
} else if (operation instanceof ExistenceCheckRemoteOperation) {\r
+ //Log_OC.wtf(TAG, "received detection response through callback" );\r
if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
- onSamlBasedFederatedSingleSignOnAuthorizationStart(operation, result);\r
+ onSamlBasedFederatedSingleSignOnAuthorizationStart(result);\r
\r
} else {\r
- onAuthorizationCheckFinish((ExistenceCheckRemoteOperation)operation, result);\r
+ onAuthorizationCheckFinish(result);\r
}\r
} else if (operation instanceof GetRemoteUserNameOperation) {\r
- onGetUserNameFinish((GetRemoteUserNameOperation) operation, result);\r
-\r
- } else if (operation instanceof DetectAuthenticationMethodOperation) {\r
- onDetectAutheticationFinish((DetectAuthenticationMethodOperation) operation, result);\r
+ onGetUserNameFinish(result);\r
}\r
\r
}\r
\r
- private void onDetectAutheticationFinish(DetectAuthenticationMethodOperation operation, RemoteOperationResult result) {\r
- // Read authentication method\r
- if (result.getData().size() > 0) {\r
- AuthenticationMethod authMethod = (AuthenticationMethod) result.getData().get(0);\r
- String basic = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
- String oAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
- String saml = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
-\r
- if ( ( mAuthTokenType.equals(basic) && !authMethod.equals(AuthenticationMethod.BASIC_HTTP_AUTH) ) ||\r
- ( mAuthTokenType.equals(oAuth) && !authMethod.equals(AuthenticationMethod.BEARER_TOKEN) ) || \r
- ( mAuthTokenType.equals(saml) && !authMethod.equals(AuthenticationMethod.SAML_WEB_SSO) ) ) {\r
-\r
- mOkButton.setEnabled(false);\r
- mServerIsValid = false;\r
- //show an alert message ( Server Status )\r
- updateServerStatusIconNoRegularAuth();\r
- showServerStatus();\r
-\r
- } else {\r
- mOkButton.setEnabled(true);\r
-\r
- // Show server status\r
- showServerStatus();\r
- }\r
-\r
- }\r
- }\r
-\r
-\r
-\r
- private void onGetUserNameFinish(GetRemoteUserNameOperation operation, RemoteOperationResult result) {\r
-\r
+ private void onGetUserNameFinish(RemoteOperationResult result) {\r
+ mWaitingForOpId = Long.MAX_VALUE;\r
if (result.isSuccess()) {\r
boolean success = false;\r
- String username = operation.getUserName();\r
+ String username = (String) result.getData().get(0);\r
\r
if ( mAction == ACTION_CREATE) {\r
mUsernameInput.setText(username);\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
+ result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME);\r
+ /*\r
+ OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(\r
+ new OwnCloudAccount(\r
+ Uri.parse(mServerInfo.mBaseUrl),\r
+ OwnCloudCredentialsFactory.newSamlSsoCredentials(mAuthToken))\r
+ );\r
+ */\r
+ mAuthToken = "";\r
updateAuthStatusIconAndText(result);\r
showAuthStatus();\r
Log_OC.d(TAG, result.getLogMessage());\r
\r
}\r
\r
- private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperation operation, RemoteOperationResult result) {\r
- try {\r
- dismissDialog(DIALOG_LOGIN_PROGRESS);\r
- } catch (IllegalArgumentException e) {\r
- // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
- }\r
+ private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperationResult result) {\r
+ mWaitingForOpId = Long.MAX_VALUE;\r
+ dismissDialog(WAIT_DIALOG_TAG);\r
- //if (result.isTemporalRedirection() && result.isIdPRedirection()) {\r
if (result.isIdPRedirection()) {
String url = result.getRedirectedLocation();\r
- String targetUrl = mHostBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
+ String targetUrl = mServerInfo.mBaseUrl \r
+ + AccountUtils.getWebdavPath(mServerInfo.mVersion, mAuthTokenType);\r
\r
// Show dialog\r
- mSamlDialog = SamlWebViewDialog.newInstance(url, targetUrl); \r
- mSamlDialog.show(getSupportFragmentManager(), TAG_SAML_DIALOG);\r
+ SamlWebViewDialog dialog = SamlWebViewDialog.newInstance(url, targetUrl); \r
+ dialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG);\r
\r
mAuthStatusIcon = 0;\r
mAuthStatusText = 0;\r
* @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
+ mWaitingForOpId = Long.MAX_VALUE;\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
+ \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
-\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
+ // 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
- /**\r
- * Try to access with user/pass ""/"", to know if it is a regular server\r
- */\r
- private void detectAuthorizationMethod() {\r
-\r
- Log_OC.d(TAG, "Trying empty authorization to detect authentication method");\r
-\r
- /// test credentials \r
- Intent service = new Intent(this, OperationsService.class);\r
- service.setAction(OperationsService.ACTION_DETECT_AUTHENTICATION_METHOD);\r
- service.putExtra(OperationsService.EXTRA_SERVER_URL, mHostBaseUrl);\r
- startService(service);\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
- private String normalizeUrl(String url) {\r
+ // TODO remove, if possible\r
+ private String normalizeUrl(String url, boolean sslWhenUnprefixed) {\r
if (url != null && url.length() > 0) {\r
url = url.trim();\r
if (!url.toLowerCase().startsWith("http://") &&\r
!url.toLowerCase().startsWith("https://")) {\r
- if (mIsSslConn) {\r
+ if (sslWhenUnprefixed) {\r
url = "https://" + url;\r
} else {\r
url = "http://" + url;\r
}\r
}\r
-\r
- // OC-208: Add suffix remote.php/webdav to normalize (OC-34) \r
+ \r
url = trimUrlWebdav(url);\r
\r
if (url.endsWith("/")) {\r
}\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
case UNKNOWN_ERROR:\r
mServerStatusText = R.string.auth_unknown_error_title;\r
break;\r
+ case OK_REDIRECT_TO_NON_SECURE_CONNECTION:\r
+ mServerStatusIcon = android.R.drawable.ic_partial_secure;\r
+ mServerStatusText = R.string.auth_redirect_non_secure_connection_title;\r
+ break;\r
default:\r
mServerStatusText = 0;\r
mServerStatusIcon = 0;\r
* Processes the result of the request for and access token send \r
* to an OAuth authorization server.\r
* \r
- * @param operation Operation performed requesting the access token.\r
* @param result Result of the operation.\r
*/\r
- private void onGetOAuthAccessTokenFinish(OAuth2GetAccessToken operation, RemoteOperationResult result) {\r
- try {\r
- dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
- } catch (IllegalArgumentException e) {\r
- // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
- }\r
+ private void onGetOAuthAccessTokenFinish(RemoteOperationResult result) {\r
+ mWaitingForOpId = Long.MAX_VALUE;\r
+ dismissDialog(WAIT_DIALOG_TAG);\r
\r
- String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
- if (result.isSuccess() && webdav_path != null) {\r
+ if (result.isSuccess()) {\r
/// be gentle with the user\r
- showDialog(DIALOG_LOGIN_PROGRESS);\r
+ IndeterminateProgressDialog dialog = \r
+ IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);\r
+ dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
\r
/// time to test the retrieved access token on the ownCloud server\r
- mAuthToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
+ @SuppressWarnings("unchecked")\r
+ Map<String, String> tokens = (Map<String, String>)(result.getData().get(0));\r
+ mAuthToken = tokens.get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
+ //mAuthToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
Log_OC.d(TAG, "Got ACCESS TOKEN: " + mAuthToken);\r
- mAuthCheckOperation = new ExistenceCheckRemoteOperation("", this, false);\r
- OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true);\r
- client.setBearerCredentials(mAuthToken);\r
- mAuthCheckOperation.execute(client, this, mHandler);\r
+ \r
+ accessRootFolderRemoteOperation("", "");\r
\r
} else {\r
updateAuthStatusIconAndText(result);\r
* @param operation Access check performed.\r
* @param result Result of the operation.\r
*/\r
- private void onAuthorizationCheckFinish(ExistenceCheckRemoteOperation operation, RemoteOperationResult result) {\r
- try {\r
- dismissDialog(DIALOG_LOGIN_PROGRESS);\r
- } catch (IllegalArgumentException e) {\r
- // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
- }\r
+ private void onAuthorizationCheckFinish(RemoteOperationResult result) {\r
+ mWaitingForOpId = Long.MAX_VALUE;\r
+ dismissDialog(WAIT_DIALOG_TAG);\r
\r
if (result.isSuccess()) {\r
Log_OC.d(TAG, "Successful access - time to save the account");\r
}\r
\r
} else if (result.isServerFail() || result.isException()) {
- /// if server fail or exception in authorization, the UI is updated as when a server check failed\r
+ /// server errors or exceptions in authorization take to requiring a new check of \r
+ /// the server\r
mServerIsChecked = true;\r
mServerIsValid = false;\r
- mIsSslConn = false;\r
- mOcServerChkOperation = null;\r
- mDiscoveredVersion = null;\r
- mHostBaseUrl = normalizeUrl(mHostUrlInput.getText().toString());\r
+ mServerInfo = new GetServerInfoOperation.ServerInfo(); \r
\r
// update status icon and text\r
updateServerStatusIconAndText(result);\r
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
boolean isOAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType);\r
boolean isSaml = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType);\r
\r
- Uri uri = Uri.parse(mHostBaseUrl);\r
+ Uri uri = Uri.parse(mServerInfo.mBaseUrl);\r
String username = mUsernameInput.getText().toString().trim();\r
if (isOAuth) {\r
username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();\r
- } \r
- String accountName = username + "@" + uri.getHost();\r
- if (uri.getPort() >= 0) {\r
- accountName += ":" + uri.getPort();\r
}\r
- mAccount = new Account(accountName, MainApp.getAccountType());\r
- if (AccountUtils.exists(mAccount, getApplicationContext())) {\r
+ String accountName = com.owncloud.android.lib.common.accounts.AccountUtils.\r
+ buildAccountName(uri, username);\r
+ Account newAccount = new Account(accountName, MainApp.getAccountType());\r
+ if (AccountUtils.exists(newAccount, getApplicationContext())) {\r
// fail - not a new account, but an existing one; disallow\r
RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_NEW); \r
updateAuthStatusIconAndText(result);\r
return false;\r
\r
} else {\r
-\r
+ mAccount = newAccount;\r
+ \r
if (isOAuth || isSaml) {\r
mAccountMgr.addAccountExplicitly(mAccount, "", null); // with external authorizations, the password is never input in the app\r
} else {\r
mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
}\r
/// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA
- mAccountMgr.setUserData(mAccount, Constants.KEY_OC_VERSION, mDiscoveredVersion.getVersion());\r
- mAccountMgr.setUserData(mAccount, Constants.KEY_OC_VERSION_STRING, mDiscoveredVersion.getVersionString());\r
- mAccountMgr.setUserData(mAccount, Constants.KEY_OC_BASE_URL, mHostBaseUrl);\r
+ mAccountMgr.setUserData(mAccount, Constants.KEY_OC_VERSION, mServerInfo.mVersion.getVersion());\r
+ mAccountMgr.setUserData(mAccount, Constants.KEY_OC_BASE_URL, mServerInfo.mBaseUrl);\r
if (isSaml) {\r
mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE"); \r
\r
\r
/**\r
- * {@inheritDoc}\r
- * \r
- * Necessary to update the contents of the SSL Dialog\r
- * \r
- * TODO move to some common place for all possible untrusted SSL failures\r
- */\r
- @Override\r
- protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
- switch (id) {\r
- case DIALOG_LOGIN_PROGRESS:\r
- case DIALOG_CERT_NOT_SAVED:\r
- case DIALOG_OAUTH2_LOGIN_PROGRESS:\r
- break;\r
- default:\r
- Log_OC.e(TAG, "Incorrect dialog called with id = " + id);\r
- }\r
- }\r
-\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- @Override\r
- protected Dialog onCreateDialog(int id) {\r
- Dialog dialog = null;\r
- switch (id) {\r
- case DIALOG_LOGIN_PROGRESS: {\r
- /// simple progress dialog\r
- ProgressDialog working_dialog = new ProgressDialog(this);\r
- working_dialog.setMessage(getResources().getString(R.string.auth_trying_to_login));\r
- working_dialog.setIndeterminate(true);\r
- working_dialog.setCancelable(true);\r
- working_dialog\r
- .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
- @Override\r
- public void onCancel(DialogInterface dialog) {\r
- /// TODO study if this is enough\r
- Log_OC.i(TAG, "Login canceled");\r
- if (mOperationThread != null) {\r
- mOperationThread.interrupt();\r
- finish();\r
- }\r
- }\r
- });\r
- dialog = working_dialog;\r
- break;\r
- }\r
- case DIALOG_OAUTH2_LOGIN_PROGRESS: {\r
- ProgressDialog working_dialog = new ProgressDialog(this);\r
- working_dialog.setMessage(String.format("Getting authorization")); \r
- working_dialog.setIndeterminate(true);\r
- working_dialog.setCancelable(true);\r
- working_dialog\r
- .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
- @Override\r
- public void onCancel(DialogInterface dialog) {\r
- Log_OC.i(TAG, "Login canceled");\r
- finish();\r
- }\r
- });\r
- dialog = working_dialog;\r
- break;\r
- }\r
- case DIALOG_CERT_NOT_SAVED: {\r
- AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
- builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
- builder.setCancelable(false);\r
- builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
- @Override\r
- public void onClick(DialogInterface dialog, int which) {\r
- dialog.dismiss();\r
- };\r
- });\r
- dialog = builder.create();\r
- break;\r
- }\r
- default:\r
- Log_OC.e(TAG, "Incorrect dialog called with id = " + id);\r
- }\r
- return dialog;\r
- }\r
-\r
-\r
- /**\r
* Starts and activity to open the 'new account' page in the ownCloud web site\r
* \r
* @param view 'Account register' button\r
/**\r
* Updates the content and visibility state of the icon and text associated\r
* to the last check on the ownCloud server.\r
+ * \r
+ * @param serverStatusText Resource identifier of the text to show.\r
+ * @param serverStatusIcon Resource identifier of the icon to show.\r
*/\r
private void showServerStatus() {\r
- TextView tv = (TextView) findViewById(R.id.server_status_text);\r
-\r
if (mServerStatusIcon == 0 && mServerStatusText == 0) {\r
- tv.setVisibility(View.INVISIBLE);\r
+ mServerStatusView.setVisibility(View.INVISIBLE);\r
\r
} else {\r
- tv.setText(mServerStatusText);\r
- tv.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);\r
- tv.setVisibility(View.VISIBLE);\r
+ mServerStatusView.setText(mServerStatusText);\r
+ mServerStatusView.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);\r
+ mServerStatusView.setVisibility(View.VISIBLE);\r
}\r
\r
}\r
*/\r
private void showAuthStatus() {\r
if (mAuthStatusIcon == 0 && mAuthStatusText == 0) {\r
- mAuthStatusLayout.setVisibility(View.INVISIBLE);\r
+ mAuthStatusView.setVisibility(View.INVISIBLE);\r
\r
} else {\r
- mAuthStatusLayout.setText(mAuthStatusText);\r
- mAuthStatusLayout.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);\r
- mAuthStatusLayout.setVisibility(View.VISIBLE);\r
+ mAuthStatusView.setText(mAuthStatusText);\r
+ mAuthStatusView.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);\r
+ mAuthStatusView.setVisibility(View.VISIBLE);\r
}\r
} \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
} else {\r
mAuthTokenType = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
}\r
- adaptViewAccordingToAuthenticationMethod();\r
+ updateAuthenticationPreFragmentVisibility();\r
}\r
\r
\r
/**\r
- * Changes the visibility of input elements depending on\r
- * the current authorization method.\r
- */\r
- private void adaptViewAccordingToAuthenticationMethod () {\r
- if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
- // OAuth 2 authorization\r
- mOAuthAuthEndpointText.setVisibility(View.VISIBLE);\r
- mOAuthTokenEndpointText.setVisibility(View.VISIBLE);\r
- mUsernameInput.setVisibility(View.GONE);\r
- mPasswordInput.setVisibility(View.GONE);\r
-\r
- } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
- // SAML-based web Single Sign On\r
- mOAuthAuthEndpointText.setVisibility(View.GONE);\r
- mOAuthTokenEndpointText.setVisibility(View.GONE);\r
- mUsernameInput.setVisibility(View.GONE);\r
- mPasswordInput.setVisibility(View.GONE);\r
- } else {\r
- // basic HTTP authorization\r
- mOAuthAuthEndpointText.setVisibility(View.GONE);\r
- mOAuthTokenEndpointText.setVisibility(View.GONE);\r
- mUsernameInput.setVisibility(View.VISIBLE);\r
- mPasswordInput.setVisibility(View.VISIBLE);\r
- }\r
- }\r
-\r
- /**\r
* Called when the 'action' button in an IME is pressed ('enter' in software keyboard).\r
* \r
* Used to trigger the authentication check when the user presses 'enter' after writing the password, \r
}\r
\r
\r
- public void onSamlDialogSuccess(String sessionCookie) {\r
- mAuthToken = sessionCookie;\r
-\r
- if (sessionCookie != null && sessionCookie.length() > 0) {\r
- mAuthToken = sessionCookie;\r
-\r
- GetRemoteUserNameOperation getUserOperation = new GetRemoteUserNameOperation(); \r
- OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(Uri.parse(mHostBaseUrl), getApplicationContext(), true);\r
- client.setSsoSessionCookie(mAuthToken);\r
- getUserOperation.execute(client, this, mHandler);\r
+ private void getRemoteUserNameOperation(String sessionCookie, boolean followRedirects) {\r
+ \r
+ Intent getUserNameIntent = new Intent();\r
+ getUserNameIntent.setAction(OperationsService.ACTION_GET_USER_NAME);\r
+ getUserNameIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mServerInfo.mBaseUrl);\r
+ getUserNameIntent.putExtra(OperationsService.EXTRA_COOKIE, sessionCookie);\r
+ \r
+ if (mOperationsServiceBinder != null) {\r
+ //Log_OC.wtf(TAG, "starting getRemoteUserNameOperation..." );\r
+ mWaitingForOpId = mOperationsServiceBinder.newOperation(getUserNameIntent);\r
}\r
-\r
-\r
}\r
\r
\r
@Override\r
- public void onSsoFinished(String sessionCookies) {\r
- //Toast.makeText(this, "got cookies: " + sessionCookie, Toast.LENGTH_LONG).show();\r
-\r
- if (sessionCookies != null && sessionCookies.length() > 0) {\r
+ public void onSsoFinished(String sessionCookie) {\r
+ if (sessionCookie != null && sessionCookie.length() > 0) {\r
Log_OC.d(TAG, "Successful SSO - time to save the account");\r
- onSamlDialogSuccess(sessionCookies);\r
- Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG);\r
+ mAuthToken = sessionCookie;\r
+ getRemoteUserNameOperation(sessionCookie, true);\r
+ Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);\r
if (fd != null && fd instanceof SherlockDialogFragment) {\r
Dialog d = ((SherlockDialogFragment)fd).getDialog();\r
if (d != null && d.isShowing()) {\r
\r
}\r
\r
- /** Show auth_message \r
- * \r
- * @param message\r
- */\r
- private void showAuthMessage(String message) {\r
- mAuthMessage.setVisibility(View.VISIBLE);\r
- mAuthMessage.setText(message);\r
- }\r
-\r
- private void hideAuthMessage() {\r
- mAuthMessage.setVisibility(View.GONE);\r
- }\r
-\r
@Override\r
public boolean onTouchEvent(MotionEvent event) {\r
if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType) &&\r
FragmentManager fm = getSupportFragmentManager();\r
FragmentTransaction ft = fm.beginTransaction();\r
ft.addToBackStack(null);\r
- dialog.show(ft, DIALOG_UNTRUSTED_CERT);\r
+ dialog.show(ft, UNTRUSTED_CERT_DIALOG_TAG);\r
}\r
\r
+\r
/**\r
* Show untrusted cert dialog \r
*/\r
- public void showUntrustedCertDialog(RemoteOperationResult result) {\r
+ private void showUntrustedCertDialog(RemoteOperationResult result) {\r
// Show a dialog with the certificate info\r
SslUntrustedCertDialog dialog = SslUntrustedCertDialog.newInstanceForFullSslError((CertificateCombinedException)result.getException());\r
FragmentManager fm = getSupportFragmentManager();\r
FragmentTransaction ft = fm.beginTransaction();\r
ft.addToBackStack(null);\r
- dialog.show(ft, DIALOG_UNTRUSTED_CERT);\r
+ dialog.show(ft, UNTRUSTED_CERT_DIALOG_TAG);\r
\r
}\r
\r
/**\r
- * Dismiss untrusted cert dialog\r
- */\r
- public void dismissUntrustedCertDialog(){\r
- /*Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_UNTRUSTED_CERT);\r
- if (frag != null) {\r
- SslErrorViewAdapter dialog = (SslErrorViewAdapter) frag;\r
- dialog.dismiss();\r
- }\r
- */\r
- }\r
-\r
- /**\r
* Called from SslValidatorDialog when a new server certificate was correctly saved.\r
*/\r
public void onSavedCertificate() {\r
- Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG);\r
+ Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);\r
if (fd == null) {\r
// if SAML dialog is not shown, the SslDialog was shown due to an SSL error in the server check\r
checkOcServer();\r
*/\r
@Override\r
public void onFailedSavingCertificate() {\r
- showDialog(DIALOG_CERT_NOT_SAVED);\r
- cancelWebView();\r
+ dismissDialog(SAML_DIALOG_TAG);\r
+ Toast.makeText(this, R.string.ssl_validator_not_saved, Toast.LENGTH_LONG).show();\r
}\r
\r
@Override\r
public void onCancelCertificate() {\r
- cancelWebView();\r
+ dismissDialog(SAML_DIALOG_TAG);\r
}\r
\r
\r
- public void cancelWebView() {\r
- Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG);\r
- if (fd != null && fd instanceof SherlockDialogFragment) {\r
- Dialog d = ((SherlockDialogFragment)fd).getDialog();\r
- if (d != null && d.isShowing()) {\r
- d.dismiss();\r
- }\r
+ private void doOnResumeAndBound() {\r
+ //Log_OC.wtf(TAG, "registering to listen for operation callbacks" );\r
+ mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler);\r
+ if (mWaitingForOpId <= Integer.MAX_VALUE) {\r
+ mOperationsServiceBinder.dispatchResultIfFinished((int)mWaitingForOpId, this);\r
+ }\r
+ \r
+ if (mPendingAutoCheck) {\r
+ checkOcServer();\r
}\r
-\r
}\r
\r
+ \r
+ private void dismissDialog(String dialogTag){\r
+ Fragment frag = getSupportFragmentManager().findFragmentByTag(dialogTag);\r
+ if (frag != null && frag instanceof SherlockDialogFragment) {\r
+ SherlockDialogFragment dialog = (SherlockDialogFragment) frag;\r
+ dialog.dismiss();\r
+ }\r
+ }\r
+ \r
+ \r
/** \r
- * Implements callback methods for service binding. Passed as a parameter to { \r
+ * Implements callback methods for service binding. \r
*/\r
private class OperationsServiceConnection implements ServiceConnection {\r
\r
@Override\r
public void onServiceConnected(ComponentName component, IBinder service) {\r
if (component.equals(new ComponentName(AuthenticatorActivity.this, OperationsService.class))) {\r
- Log_OC.d(TAG, "Operations service connected");\r
+ //Log_OC.wtf(TAG, "Operations service connected");\r
mOperationsServiceBinder = (OperationsServiceBinder) service;\r
- mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler);\r
+ \r
+ doOnResumeAndBound();\r
+ \r
} else {\r
return;\r
}\r
@Override\r
public void onServiceDisconnected(ComponentName component) {\r
if (component.equals(new ComponentName(AuthenticatorActivity.this, OperationsService.class))) {\r
- Log_OC.d(TAG, "Operations service disconnected");\r
+ Log_OC.e(TAG, "Operations service crashed");\r
mOperationsServiceBinder = null;\r
- // TODO whatever could be waiting for the service is unbound\r
}\r
}\r
\r
}\r
+\r
+ /**\r
+ * Create and show dialog for request authentication to the user\r
+ * @param webView\r
+ * @param handler\r
+ */\r
+ public void createAuthenticationDialog(WebView webView, HttpAuthHandler handler) {\r
+\r
+ // Show a dialog with the certificate info\r
+ CredentialsDialogFragment dialog = CredentialsDialogFragment.newInstanceForCredentials(webView, handler);\r
+ FragmentManager fm = getSupportFragmentManager();\r
+ FragmentTransaction ft = fm.beginTransaction();\r
+ ft.addToBackStack(null);\r
+ dialog.setCancelable(false);\r
+ dialog.show(ft, CREDENTIALS_DIALOG_TAG);\r
+\r
+ if (!mIsFirstAuthAttempt) {\r
+ Toast.makeText(getApplicationContext(), getText(R.string.saml_authentication_wrong_pass), Toast.LENGTH_LONG).show();\r
+ } else {\r
+ mIsFirstAuthAttempt = false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * For retrieving the clicking on authentication cancel button\r
+ */\r
+ public void doNegativeAuthenticatioDialogClick(){\r
+ mIsFirstAuthAttempt = true;\r
+ }\r
}\r