mirror of
https://github.com/nextcloud/android.git
synced 2024-10-23 04:26:01 +03:00
Merge pull request #771 from nextcloud/web-login
Add support for web login
This commit is contained in:
commit
89409ce049
3 changed files with 344 additions and 183 deletions
|
@ -4,8 +4,10 @@
|
|||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -18,6 +20,22 @@
|
|||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* All changes by Mario Danic are distributed under the following terms:
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.authentication;
|
||||
|
@ -30,6 +48,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
|
@ -38,12 +57,14 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -54,6 +75,7 @@ import android.view.inputmethod.EditorInfo;
|
|||
import android.webkit.HttpAuthHandler;
|
||||
import android.webkit.SslErrorHandler;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
|
@ -191,6 +213,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
private View mOkButton;
|
||||
private TextView mAuthStatusView;
|
||||
|
||||
private WebView mLoginWebView;
|
||||
|
||||
private int mAuthStatusText = 0, mAuthStatusIcon = 0;
|
||||
|
||||
private String mAuthToken = "";
|
||||
|
@ -205,6 +229,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
private final String OAUTH_TOKEN_TYPE = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());
|
||||
private final String SAML_TOKEN_TYPE = AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());
|
||||
|
||||
private boolean webViewLoginMethod;
|
||||
private String webViewUser;
|
||||
private String webViewPassword;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -242,42 +270,86 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
mIsFirstAuthAttempt = savedInstanceState.getBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG);
|
||||
}
|
||||
|
||||
webViewLoginMethod = !TextUtils.isEmpty(getResources().getString(R.string.webview_login_url));
|
||||
|
||||
if (webViewLoginMethod) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
|
||||
/// load user interface
|
||||
setContentView(R.layout.account_setup);
|
||||
if (!webViewLoginMethod) {
|
||||
setContentView(R.layout.account_setup);
|
||||
|
||||
/// initialize general UI elements
|
||||
initOverallUi();
|
||||
/// initialize general UI elements
|
||||
initOverallUi();
|
||||
|
||||
mOkButton = findViewById(R.id.buttonOK);
|
||||
mOkButton.setOnClickListener(new View.OnClickListener() {
|
||||
mOkButton = findViewById(R.id.buttonOK);
|
||||
mOkButton.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onOkClick();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onOkClick();
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.centeredRefreshButton).setOnClickListener(new View.OnClickListener() {
|
||||
findViewById(R.id.centeredRefreshButton).setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkOcServer();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkOcServer();
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.embeddedRefreshButton).setOnClickListener(new View.OnClickListener() {
|
||||
findViewById(R.id.embeddedRefreshButton).setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkOcServer();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkOcServer();
|
||||
}
|
||||
});
|
||||
|
||||
/// initialize block to be moved to single Fragment to check server and get info about it
|
||||
|
||||
/// initialize block to be moved to single Fragment to retrieve and validate credentials
|
||||
initAuthorizationPreFragment(savedInstanceState);
|
||||
|
||||
} else {
|
||||
setContentView(R.layout.account_setup_webview);
|
||||
mLoginWebView = (WebView) findViewById(R.id.login_webview);
|
||||
initWebViewLogin();
|
||||
}
|
||||
|
||||
/// initialize block to be moved to single Fragment to check server and get info about it
|
||||
initServerPreFragment(savedInstanceState);
|
||||
}
|
||||
|
||||
private void initWebViewLogin() {
|
||||
mLoginWebView.getSettings().setAllowFileAccess(false);
|
||||
mLoginWebView.getSettings().setJavaScriptEnabled(true);
|
||||
mLoginWebView.getSettings().setUserAgentString(MainApp.getUserAgent());
|
||||
mLoginWebView.loadUrl(getResources().getString(R.string.webview_login_url));
|
||||
mLoginWebView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (url.startsWith(getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/")) {
|
||||
parseAndLoginFromWebView(url);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void parseAndLoginFromWebView(String dataString) {
|
||||
String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
|
||||
LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, dataString);
|
||||
|
||||
if (loginUrlInfo != null) {
|
||||
mServerInfo.mBaseUrl = normalizeUrlSuffix(loginUrlInfo.serverAddress);
|
||||
webViewUser = loginUrlInfo.username;
|
||||
webViewPassword = loginUrlInfo.password;
|
||||
checkOcServer();
|
||||
}
|
||||
|
||||
/// initialize block to be moved to single Fragment to retrieve and validate credentials
|
||||
initAuthorizationPreFragment(savedInstanceState);
|
||||
}
|
||||
|
||||
private void populateLoginFields(String dataString) throws IllegalArgumentException {
|
||||
|
@ -301,7 +373,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
/**
|
||||
* parses a URI string and returns a login data object with the information from the URI string.
|
||||
*
|
||||
* @param prefix URI beginning, e.g. cloud://login/
|
||||
* @param prefix URI beginning, e.g. cloud://login/
|
||||
* @param dataString the complete URI
|
||||
* @return login data
|
||||
* @throws IllegalArgumentException when
|
||||
|
@ -420,7 +492,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith(HTTPS_PROTOCOL);
|
||||
mServerInfo.mVersion = AccountUtils.getServerVersion(mAccount);
|
||||
} else {
|
||||
mServerInfo.mBaseUrl = getString(R.string.server_url).trim();
|
||||
if (!webViewLoginMethod) {
|
||||
mServerInfo.mBaseUrl = getString(R.string.server_url).trim();
|
||||
} else {
|
||||
mServerInfo.mBaseUrl = getString(R.string.webview_login_url).trim();
|
||||
}
|
||||
mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith(HTTPS_PROTOCOL);
|
||||
}
|
||||
} else {
|
||||
|
@ -442,81 +518,74 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
}
|
||||
|
||||
/// step 2 - set properties of UI elements (text, visibility, enabled...)
|
||||
mHostUrlInput = (CustomEditText) findViewById(R.id.hostUrlInput);
|
||||
// Convert IDN to Unicode
|
||||
mHostUrlInput.setText(DisplayUtils.convertIdn(mServerInfo.mBaseUrl, false));
|
||||
if (mAction != ACTION_CREATE) {
|
||||
/// lock things that should not change
|
||||
mHostUrlInput.setEnabled(false);
|
||||
mHostUrlInput.setFocusable(false);
|
||||
if (!webViewLoginMethod) {
|
||||
/// step 2 - set properties of UI elements (text, visibility, enabled...)
|
||||
mHostUrlInput = (CustomEditText) findViewById(R.id.hostUrlInput);
|
||||
// Convert IDN to Unicode
|
||||
mHostUrlInput.setText(DisplayUtils.convertIdn(mServerInfo.mBaseUrl, false));
|
||||
if (mAction != ACTION_CREATE) {
|
||||
/// lock things that should not change
|
||||
mHostUrlInput.setEnabled(false);
|
||||
mHostUrlInput.setFocusable(false);
|
||||
}
|
||||
if (isUrlInputAllowed) {
|
||||
mRefreshButton = findViewById(R.id.embeddedRefreshButton);
|
||||
} else {
|
||||
findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);
|
||||
mRefreshButton = findViewById(R.id.centeredRefreshButton);
|
||||
}
|
||||
showRefreshButton(mServerIsChecked && !mServerIsValid &&
|
||||
mWaitingForOpId > Integer.MAX_VALUE);
|
||||
mServerStatusView = (TextView) findViewById(R.id.server_status_text);
|
||||
showServerStatus();
|
||||
|
||||
/// step 3 - bind some listeners and options
|
||||
mHostUrlInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
|
||||
mHostUrlInput.setOnEditorActionListener(this);
|
||||
|
||||
/// step 4 - create listeners that will be bound at onResume
|
||||
mHostUrlInputWatcher = new TextWatcher() {
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (mOkButton.isEnabled() &&
|
||||
!mServerInfo.mBaseUrl.equals(
|
||||
normalizeUrl(s.toString(), mServerInfo.mIsSslConn))) {
|
||||
mOkButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
if (mAuthStatusIcon != 0) {
|
||||
Log_OC.d(TAG, "onTextChanged: hiding authentication status");
|
||||
mAuthStatusIcon = 0;
|
||||
mAuthStatusText = 0;
|
||||
showAuthStatus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// TODO find out if this is really necessary, or if it can done in a different way
|
||||
findViewById(R.id.scroll).setOnTouchListener(new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN &&
|
||||
AccountTypeUtils
|
||||
.getAuthTokenTypeSamlSessionCookie(MainApp
|
||||
.getAccountType()).equals(mAuthTokenType) &&
|
||||
mHostUrlInput.hasFocus()) {
|
||||
checkOcServer();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String serverInputType = getResources().getString(R.string.server_input_type);
|
||||
|
||||
if (isUrlInputAllowed) {
|
||||
mRefreshButton = findViewById(R.id.embeddedRefreshButton);
|
||||
if (mAction == ACTION_CREATE &&
|
||||
(serverInputType.equals(DIRECTORY_SERVER_INPUT_TYPE) ||
|
||||
serverInputType.equals(SUBDOMAIN_SERVER_INPUT_TYPE))) {
|
||||
mHostUrlInput.setText("");
|
||||
}
|
||||
} else {
|
||||
findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);
|
||||
mRefreshButton = findViewById(R.id.centeredRefreshButton);
|
||||
}
|
||||
|
||||
showRefreshButton(mServerIsChecked && !mServerIsValid &&
|
||||
mWaitingForOpId > Integer.MAX_VALUE);
|
||||
mServerStatusView = (TextView) findViewById(R.id.server_status_text);
|
||||
showServerStatus();
|
||||
|
||||
/// step 3 - bind some listeners and options
|
||||
mHostUrlInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
|
||||
mHostUrlInput.setOnEditorActionListener(this);
|
||||
|
||||
/// step 4 - create listeners that will be bound at onResume
|
||||
mHostUrlInputWatcher = new TextWatcher() {
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (mOkButton.isEnabled() &&
|
||||
!mServerInfo.mBaseUrl.equals(
|
||||
normalizeUrl(mHostUrlInput.getFullServerUrl(), mServerInfo.mIsSslConn))) {
|
||||
mOkButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
if (mAuthStatusIcon != 0) {
|
||||
Log_OC.d(TAG, "onTextChanged: hiding authentication status");
|
||||
mAuthStatusIcon = 0;
|
||||
mAuthStatusText = 0;
|
||||
showAuthStatus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// TODO find out if this is really necessary, or if it can done in a different way
|
||||
findViewById(R.id.scroll).setOnTouchListener(new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN &&
|
||||
AccountTypeUtils
|
||||
.getAuthTokenTypeSamlSessionCookie(MainApp
|
||||
.getAccountType()).equals(mAuthTokenType) &&
|
||||
mHostUrlInput.hasFocus()) {
|
||||
checkOcServer();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -645,11 +714,20 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
outState.putString(KEY_AUTH_TOKEN_TYPE, mAuthTokenType);
|
||||
outState.putLong(KEY_WAITING_FOR_OP_ID, mWaitingForOpId);
|
||||
|
||||
/// Server PRE-fragment state
|
||||
outState.putInt(KEY_SERVER_STATUS_TEXT, mServerStatusText);
|
||||
outState.putInt(KEY_SERVER_STATUS_ICON, mServerStatusIcon);
|
||||
outState.putBoolean(KEY_SERVER_CHECKED, mServerIsChecked);
|
||||
outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);
|
||||
if (!webViewLoginMethod) {
|
||||
/// Server PRE-fragment state
|
||||
outState.putInt(KEY_SERVER_STATUS_TEXT, mServerStatusText);
|
||||
outState.putInt(KEY_SERVER_STATUS_ICON, mServerStatusIcon);
|
||||
outState.putBoolean(KEY_SERVER_CHECKED, mServerIsChecked);
|
||||
outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);
|
||||
|
||||
/// Authentication PRE-fragment state
|
||||
outState.putBoolean(KEY_PASSWORD_EXPOSED, isPasswordVisible());
|
||||
outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);
|
||||
outState.putInt(KEY_AUTH_STATUS_TEXT, mAuthStatusText);
|
||||
outState.putString(KEY_AUTH_TOKEN, mAuthToken);
|
||||
}
|
||||
|
||||
outState.putBoolean(KEY_IS_SSL_CONN, mServerInfo.mIsSslConn);
|
||||
outState.putString(KEY_HOST_URL_TEXT, mServerInfo.mBaseUrl);
|
||||
if (mServerInfo.mVersion != null) {
|
||||
|
@ -657,18 +735,14 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
outState.putString(KEY_SERVER_AUTH_METHOD, mServerInfo.mAuthMethod.name());
|
||||
|
||||
/// Authentication PRE-fragment state
|
||||
outState.putBoolean(KEY_PASSWORD_EXPOSED, isPasswordVisible());
|
||||
outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);
|
||||
outState.putInt(KEY_AUTH_STATUS_TEXT, mAuthStatusText);
|
||||
outState.putString(KEY_AUTH_TOKEN, mAuthToken);
|
||||
|
||||
/// authentication
|
||||
outState.putBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG, mIsFirstAuthAttempt);
|
||||
|
||||
/// AsyncTask (User and password)
|
||||
outState.putString(KEY_USERNAME, mUsernameInput.getText().toString().trim());
|
||||
outState.putString(KEY_PASSWORD, mPasswordInput.getText().toString());
|
||||
if (!webViewLoginMethod) {
|
||||
outState.putString(KEY_USERNAME, mUsernameInput.getText().toString().trim());
|
||||
outState.putString(KEY_PASSWORD, mPasswordInput.getText().toString());
|
||||
}
|
||||
|
||||
if (mAsyncTask != null) {
|
||||
mAsyncTask.cancel(true);
|
||||
|
@ -730,21 +804,23 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// bound here to avoid spurious changes triggered by Android on device rotations
|
||||
mHostUrlInput.setOnFocusChangeListener(this);
|
||||
mHostUrlInput.addTextChangedListener(mHostUrlInputWatcher);
|
||||
if (!webViewLoginMethod) {
|
||||
// bound here to avoid spurious changes triggered by Android on device rotations
|
||||
mHostUrlInput.setOnFocusChangeListener(this);
|
||||
mHostUrlInput.addTextChangedListener(mHostUrlInputWatcher);
|
||||
|
||||
if (mNewCapturedUriFromOAuth2Redirection != null) {
|
||||
getOAuth2AccessTokenFromCapturedRedirection();
|
||||
}
|
||||
if (mNewCapturedUriFromOAuth2Redirection != null) {
|
||||
getOAuth2AccessTokenFromCapturedRedirection();
|
||||
}
|
||||
|
||||
String dataString = getIntent().getDataString();
|
||||
if (dataString != null) {
|
||||
try {
|
||||
populateLoginFields(dataString);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Toast.makeText(this, "Illegal login data URL used", Toast.LENGTH_SHORT).show();
|
||||
Log_OC.e(TAG, "Illegal login data URL used, no Login pre-fill!", e);
|
||||
String dataString = getIntent().getDataString();
|
||||
if (dataString != null) {
|
||||
try {
|
||||
populateLoginFields(dataString);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Toast.makeText(this, "Illegal login data URL used", Toast.LENGTH_SHORT).show();
|
||||
Log_OC.e(TAG, "Illegal login data URL used, no Login pre-fill!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,8 +848,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
mOperationsServiceBinder.removeOperationListener(this);
|
||||
}
|
||||
|
||||
mHostUrlInput.removeTextChangedListener(mHostUrlInputWatcher);
|
||||
mHostUrlInput.setOnFocusChangeListener(null);
|
||||
if (!webViewLoginMethod) {
|
||||
mHostUrlInput.removeTextChangedListener(mHostUrlInputWatcher);
|
||||
mHostUrlInput.setOnFocusChangeListener(null);
|
||||
}
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
@ -787,10 +865,14 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
unbindService(mOperationsServiceConnection);
|
||||
mOperationsServiceBinder = null;
|
||||
}
|
||||
|
||||
if (webViewLoginMethod) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the redirection with the response to the GET AUTHORIZATION request to the
|
||||
* oAuth server and requests for the access token (GET ACCESS TOKEN)
|
||||
|
@ -863,15 +945,23 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
|
||||
private void checkOcServer() {
|
||||
String uri = mHostUrlInput.getFullServerUrl().trim();
|
||||
String uri;
|
||||
if (mHostUrlInput != null) {
|
||||
uri = mHostUrlInput.getText().toString().trim();
|
||||
mOkButton.setEnabled(false);
|
||||
showRefreshButton(false);
|
||||
} else {
|
||||
uri = mServerInfo.mBaseUrl;
|
||||
}
|
||||
|
||||
mServerIsValid = false;
|
||||
mServerIsChecked = false;
|
||||
mOkButton.setEnabled(false);
|
||||
mServerInfo = new GetServerInfoOperation.ServerInfo();
|
||||
showRefreshButton(false);
|
||||
|
||||
if (uri.length() != 0) {
|
||||
uri = stripIndexPhpOrAppsFiles(uri, mHostUrlInput);
|
||||
if (mHostUrlInput != null) {
|
||||
uri = stripIndexPhpOrAppsFiles(uri, mHostUrlInput);
|
||||
}
|
||||
|
||||
// Handle internationalized domain names
|
||||
try {
|
||||
|
@ -880,9 +970,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
// Let Owncloud library check the error of the malformed URI
|
||||
}
|
||||
|
||||
mServerStatusText = R.string.auth_testing_connection;
|
||||
mServerStatusIcon = R.drawable.progress_small;
|
||||
showServerStatus();
|
||||
if (mHostUrlInput != null) {
|
||||
mServerStatusText = R.string.auth_testing_connection;
|
||||
mServerStatusIcon = R.drawable.progress_small;
|
||||
showServerStatus();
|
||||
}
|
||||
|
||||
Intent getServerInfoIntent = new Intent();
|
||||
getServerInfoIntent.setAction(OperationsService.ACTION_GET_SERVER_INFO);
|
||||
|
@ -890,6 +982,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
OperationsService.EXTRA_SERVER_URL,
|
||||
normalizeUrlSuffix(uri)
|
||||
);
|
||||
|
||||
if (mOperationsServiceBinder != null) {
|
||||
mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getServerInfoIntent);
|
||||
} else {
|
||||
|
@ -899,7 +992,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
} else {
|
||||
mServerStatusText = 0;
|
||||
mServerStatusIcon = 0;
|
||||
showServerStatus();
|
||||
if (!webViewLoginMethod) {
|
||||
showServerStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -913,6 +1008,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
*
|
||||
* @param hasFocus 'True' if focus is received, 'false' if is lost
|
||||
*/
|
||||
|
||||
private void onPasswordFocusChanged(boolean hasFocus) {
|
||||
if (hasFocus) {
|
||||
showViewPasswordButton();
|
||||
|
@ -992,7 +1088,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
|
||||
startSamlBasedFederatedSingleSignOnAuthorization();
|
||||
} else {
|
||||
checkBasicAuthorization();
|
||||
checkBasicAuthorization(null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1002,10 +1098,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
* Tests the credentials entered by the user performing a check of existence on
|
||||
* the root folder of the ownCloud server.
|
||||
*/
|
||||
private void checkBasicAuthorization() {
|
||||
private void checkBasicAuthorization(@Nullable String webViewUsername, @Nullable String webViewPassword) {
|
||||
/// get basic credentials entered by user
|
||||
String username = mUsernameInput.getText().toString().trim();
|
||||
String password = mPasswordInput.getText().toString();
|
||||
String username;
|
||||
String password;
|
||||
if (!webViewLoginMethod) {
|
||||
username = mUsernameInput.getText().toString().trim();
|
||||
password = mPasswordInput.getText().toString();
|
||||
} else {
|
||||
username = webViewUsername;
|
||||
password = webViewPassword;
|
||||
}
|
||||
|
||||
/// be gentle with the user
|
||||
IndeterminateProgressDialog dialog =
|
||||
|
@ -1109,11 +1212,13 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
|
||||
if (mAction == ACTION_CREATE) {
|
||||
mUsernameInput.setText(username);
|
||||
if (!webViewLoginMethod) {
|
||||
mUsernameInput.setText(username);
|
||||
}
|
||||
success = createAccount(result);
|
||||
} else {
|
||||
|
||||
if (!mUsernameInput.getText().toString().trim().equals(username)) {
|
||||
if (!webViewLoginMethod && !mUsernameInput.getText().toString().trim().equals(username)) {
|
||||
// fail - not a new account, but an existing one; disallow
|
||||
result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME);
|
||||
mAuthToken = "";
|
||||
|
@ -1138,8 +1243,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
finish();
|
||||
}
|
||||
} else {
|
||||
updateStatusIconFailUserName();
|
||||
showAuthStatus();
|
||||
if (!webViewLoginMethod) {
|
||||
updateStatusIconFailUserName();
|
||||
showAuthStatus();
|
||||
}
|
||||
Log_OC.e(TAG, "Access to user name failed: " + result.getLogMessage());
|
||||
}
|
||||
|
||||
|
@ -1157,7 +1264,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
mWaitingForOpId = Long.MAX_VALUE;
|
||||
|
||||
// update server status, but don't show it yet
|
||||
updateServerStatusIconAndText(result);
|
||||
if (!webViewLoginMethod) {
|
||||
updateServerStatusIconAndText(result);
|
||||
}
|
||||
|
||||
if (result.isSuccess()) {
|
||||
/// SUCCESS means:
|
||||
|
@ -1167,9 +1276,16 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
// 4. we got the authentication method required by the server
|
||||
mServerInfo = (GetServerInfoOperation.ServerInfo) (result.getData().get(0));
|
||||
|
||||
if (webViewLoginMethod) {
|
||||
checkBasicAuthorization(webViewUser, webViewPassword);
|
||||
}
|
||||
|
||||
if (!authSupported(mServerInfo.mAuthMethod)) {
|
||||
|
||||
updateServerStatusIconNoRegularAuth(); // overrides updateServerStatusIconAndText()
|
||||
if (!webViewLoginMethod) {
|
||||
// overrides updateServerStatusIconAndText()
|
||||
updateServerStatusIconNoRegularAuth();
|
||||
}
|
||||
mServerIsValid = false;
|
||||
|
||||
} else {
|
||||
|
@ -1181,9 +1297,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
|
||||
// refresh UI
|
||||
showRefreshButton(!mServerIsValid);
|
||||
showServerStatus();
|
||||
mOkButton.setEnabled(mServerIsValid);
|
||||
if (!webViewLoginMethod) {
|
||||
showRefreshButton(!mServerIsValid);
|
||||
showServerStatus();
|
||||
mOkButton.setEnabled(mServerIsValid);
|
||||
}
|
||||
|
||||
/// very special case (TODO: move to a common place for all the remote operations)
|
||||
if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
|
||||
|
@ -1511,11 +1629,13 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
showServerStatus();
|
||||
mAuthStatusIcon = 0;
|
||||
mAuthStatusText = 0;
|
||||
showAuthStatus();
|
||||
if (!webViewLoginMethod) {
|
||||
showAuthStatus();
|
||||
|
||||
// update input controls state
|
||||
showRefreshButton(true);
|
||||
mOkButton.setEnabled(false);
|
||||
// update input controls state
|
||||
showRefreshButton(true);
|
||||
mOkButton.setEnabled(false);
|
||||
}
|
||||
|
||||
// very special case (TODO: move to a common place for all the remote operations)
|
||||
if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
|
||||
|
@ -1523,8 +1643,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
|
||||
} else { // authorization fail due to client side - probably wrong credentials
|
||||
updateAuthStatusIconAndText(result);
|
||||
showAuthStatus();
|
||||
if (!webViewLoginMethod) {
|
||||
updateAuthStatusIconAndText(result);
|
||||
showAuthStatus();
|
||||
}
|
||||
Log_OC.d(TAG, "Access failed: " + result.getLogMessage());
|
||||
}
|
||||
}
|
||||
|
@ -1562,8 +1684,13 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);
|
||||
|
||||
} else {
|
||||
response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());
|
||||
mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());
|
||||
if (!webViewLoginMethod) {
|
||||
response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());
|
||||
mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());
|
||||
} else {
|
||||
response.putString(AccountManager.KEY_AUTHTOKEN, webViewPassword);
|
||||
mAccountMgr.setPassword(mAccount, webViewPassword);
|
||||
}
|
||||
}
|
||||
|
||||
// remove managed clients for this account to enforce creation with fresh credentials
|
||||
|
@ -1599,7 +1726,12 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
}
|
||||
|
||||
Uri uri = Uri.parse(mServerInfo.mBaseUrl);
|
||||
String username = mUsernameInput.getText().toString().trim();
|
||||
String username;
|
||||
if (!webViewLoginMethod) {
|
||||
username = mUsernameInput.getText().toString().trim();
|
||||
} else {
|
||||
username = webViewUser;
|
||||
}
|
||||
if (isOAuth) {
|
||||
username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();
|
||||
}
|
||||
|
@ -1609,8 +1741,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
if (AccountUtils.exists(newAccount, getApplicationContext())) {
|
||||
// fail - not a new account, but an existing one; disallow
|
||||
RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_NEW);
|
||||
updateAuthStatusIconAndText(result);
|
||||
showAuthStatus();
|
||||
if (!webViewLoginMethod) {
|
||||
updateAuthStatusIconAndText(result);
|
||||
showAuthStatus();
|
||||
}
|
||||
Log_OC.d(TAG, result.getLogMessage());
|
||||
return false;
|
||||
|
||||
|
@ -1621,9 +1755,15 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
// with external authorizations, the password is never input in the app
|
||||
mAccountMgr.addAccountExplicitly(mAccount, "", null);
|
||||
} else {
|
||||
mAccountMgr.addAccountExplicitly(
|
||||
mAccount, mPasswordInput.getText().toString(), null
|
||||
);
|
||||
if (!webViewLoginMethod) {
|
||||
mAccountMgr.addAccountExplicitly(
|
||||
mAccount, mPasswordInput.getText().toString(), null
|
||||
);
|
||||
} else {
|
||||
mAccountMgr.addAccountExplicitly(
|
||||
mAccount, webViewPassword, null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// include account version with the new account
|
||||
|
@ -1706,15 +1846,16 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
* to the last check on the ownCloud server.
|
||||
*/
|
||||
private void showServerStatus() {
|
||||
if (mServerStatusIcon == 0 && mServerStatusText == 0) {
|
||||
mServerStatusView.setVisibility(View.INVISIBLE);
|
||||
if (!webViewLoginMethod) {
|
||||
if (mServerStatusIcon == 0 && mServerStatusText == 0) {
|
||||
mServerStatusView.setVisibility(View.INVISIBLE);
|
||||
|
||||
} else {
|
||||
mServerStatusView.setText(mServerStatusText);
|
||||
mServerStatusView.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);
|
||||
mServerStatusView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mServerStatusView.setText(mServerStatusText);
|
||||
mServerStatusView.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);
|
||||
mServerStatusView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1723,22 +1864,26 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
* to the interactions with the OAuth authorization server.
|
||||
*/
|
||||
private void showAuthStatus() {
|
||||
if (mAuthStatusIcon == 0 && mAuthStatusText == 0) {
|
||||
mAuthStatusView.setVisibility(View.INVISIBLE);
|
||||
if (!webViewLoginMethod) {
|
||||
if (mAuthStatusIcon == 0 && mAuthStatusText == 0) {
|
||||
mAuthStatusView.setVisibility(View.INVISIBLE);
|
||||
|
||||
} else {
|
||||
mAuthStatusView.setText(mAuthStatusText);
|
||||
mAuthStatusView.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);
|
||||
mAuthStatusView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mAuthStatusView.setText(mAuthStatusText);
|
||||
mAuthStatusView.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);
|
||||
mAuthStatusView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void showRefreshButton(boolean show) {
|
||||
if (show) {
|
||||
mRefreshButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mRefreshButton.setVisibility(View.GONE);
|
||||
if (webViewLoginMethod) {
|
||||
if (show) {
|
||||
mRefreshButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mRefreshButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1951,7 +2096,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
mOperationsServiceBinder.dispatchResultIfFinished((int) mWaitingForOpId, this);
|
||||
}
|
||||
|
||||
if (mHostUrlInput.getText() != null && mHostUrlInput.getText().length() > 0 && !mServerIsChecked) {
|
||||
if (!webViewLoginMethod && mHostUrlInput.getText() != null && mHostUrlInput.getText().length() > 0
|
||||
&& !mServerIsChecked) {
|
||||
checkOcServer();
|
||||
}
|
||||
}
|
||||
|
|
12
src/main/res/layout/account_setup_webview.xml
Normal file
12
src/main/res/layout/account_setup_webview.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<WebView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/login_webview">
|
||||
</WebView>
|
||||
</LinearLayout>
|
|
@ -102,6 +102,9 @@
|
|||
|
||||
<!-- login data links -->
|
||||
<string name="login_data_own_scheme" translatable="false">cloud</string>
|
||||
<!-- url for webview login, with the protocol prefix
|
||||
If set, will replace all other login methods available -->
|
||||
<string name="webview_login_url" translatable="false"></string>
|
||||
|
||||
<!-- analytics enabled -->
|
||||
<bool name="analytics_enabled">false</bool>
|
||||
|
|
Loading…
Reference in a new issue