Skip to content

Commit d3290d9

Browse files
committed
NMC-3250 -> opening login flow in internal webview instead of external browser.
1 parent 116d921 commit d3290d9

File tree

2 files changed

+12
-211
lines changed

2 files changed

+12
-211
lines changed

app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

Lines changed: 7 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -43,28 +43,21 @@
4343
import android.webkit.WebResourceRequest;
4444
import android.webkit.WebResourceResponse;
4545
import android.webkit.WebView;
46-
import android.widget.LinearLayout;
4746
import android.widget.TextView;
4847
import android.widget.TextView.OnEditorActionListener;
4948
import android.widget.Toast;
5049

5150
import com.blikoon.qrcodescanner.QrCodeActivity;
52-
import com.google.android.material.button.MaterialButton;
5351
import com.google.android.material.snackbar.Snackbar;
54-
import com.google.gson.JsonObject;
55-
import com.google.gson.JsonParser;
5652
import com.nextcloud.android.common.ui.color.ColorUtil;
5753
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
5854
import com.nextcloud.client.account.User;
5955
import com.nextcloud.client.account.UserAccountManager;
6056
import com.nextcloud.client.device.DeviceInfo;
6157
import com.nextcloud.client.di.Injectable;
62-
import com.nextcloud.client.network.ClientFactory;
6358
import com.nextcloud.client.onboarding.FirstRunActivity;
6459
import com.nextcloud.client.onboarding.OnboardingService;
6560
import com.nextcloud.client.preferences.AppPreferences;
66-
import com.nextcloud.common.PlainClient;
67-
import com.nextcloud.operations.PostMethod;
6861
import com.nextcloud.utils.extensions.BundleExtensionsKt;
6962
import com.owncloud.android.MainApp;
7063
import com.owncloud.android.R;
@@ -111,17 +104,13 @@
111104
import com.owncloud.android.utils.theme.CapabilityUtils;
112105
import com.owncloud.android.utils.theme.ViewThemeUtils;
113106

114-
import org.json.JSONObject;
115-
116107
import java.io.InputStream;
117108
import java.net.URLDecoder;
118109
import java.util.HashMap;
119110
import java.util.Locale;
120111
import java.util.Map;
121112
import java.util.Optional;
122113
import java.util.concurrent.Executors;
123-
import java.util.concurrent.ScheduledExecutorService;
124-
import java.util.concurrent.TimeUnit;
125114

126115
import javax.inject.Inject;
127116

@@ -137,16 +126,11 @@
137126
import androidx.fragment.app.Fragment;
138127
import androidx.fragment.app.FragmentManager;
139128
import androidx.fragment.app.FragmentTransaction;
140-
import androidx.lifecycle.Lifecycle;
141-
import androidx.lifecycle.LifecycleEventObserver;
142-
import androidx.lifecycle.ProcessLifecycleOwner;
143129
import de.cotech.hw.fido.WebViewFidoBridge;
144130
import de.cotech.hw.fido.ui.FidoDialogOptions;
145131
import de.cotech.hw.fido2.WebViewWebauthnBridge;
146132
import de.cotech.hw.fido2.ui.WebauthnDialogOptions;
147133
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
148-
import okhttp3.FormBody;
149-
import okhttp3.RequestBody;
150134

151135
import static com.owncloud.android.utils.PermissionUtil.PERMISSIONS_CAMERA;
152136

@@ -184,17 +168,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
184168
private static final String KEY_USERNAME = "USERNAME";
185169
private static final String KEY_PASSWORD = "PASSWORD";
186170
private static final String KEY_ASYNC_TASK_IN_PROGRESS = "AUTH_IN_PROGRESS";
187-
188-
/**
189-
* Login Flow v1
190-
*/
191-
// public static final String WEB_LOGIN = "/index.php/login/flow";
192-
193-
/**
194-
* Login Flow v2
195-
*/
196-
public static final String WEB_LOGIN = "/index.php/login/v2";
197-
171+
public static final String WEB_LOGIN = "/index.php/login/flow";
198172
public static final String PROTOCOL_SUFFIX = "://";
199173
public static final String LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":";
200174
public static final String HTTPS_PROTOCOL = "https://";
@@ -248,9 +222,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
248222
@Inject PassCodeManager passCodeManager;
249223
@Inject ViewThemeUtils.Factory viewThemeUtilsFactory;
250224
@Inject ColorUtil colorUtil;
251-
@Inject ClientFactory clientFactory;
252-
253-
private String token;
254225

255226
private boolean onlyAdd = false;
256227
@SuppressLint("ResourceAsColor") @ColorInt
@@ -275,7 +246,7 @@ protected void onCreate(Bundle savedInstanceState) {
275246
viewThemeUtils = viewThemeUtilsFactory.withPrimaryAsBackground();
276247
viewThemeUtils.platform.themeStatusBar(this, ColorRole.PRIMARY);
277248

278-
// WebViewUtil webViewUtil = new WebViewUtil(this);
249+
WebViewUtil webViewUtil = new WebViewUtil(this);
279250

280251
Uri data = getIntent().getData();
281252
boolean directLogin = data != null && data.toString().startsWith(getString(R.string.login_data_own_scheme));
@@ -340,8 +311,7 @@ protected void onCreate(Bundle savedInstanceState) {
340311
if (webViewLoginMethod) {
341312
accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
342313
setContentView(accountSetupWebviewBinding.getRoot());
343-
anonymouslyPostLoginRequest(webloginUrl);
344-
// initWebViewLogin(webloginUrl, false);
314+
initWebViewLogin(webloginUrl, false);
345315
} else {
346316
accountSetupBinding = AccountSetupBinding.inflate(getLayoutInflater());
347317
setContentView(accountSetupBinding.getRoot());
@@ -356,18 +326,10 @@ protected void onCreate(Bundle savedInstanceState) {
356326
}
357327

358328
initServerPreFragment(savedInstanceState);
359-
ProcessLifecycleOwner.get().getLifecycle().addObserver(lifecycleEventObserver);
360329

361-
// webViewUtil.checkWebViewVersion();
330+
webViewUtil.checkWebViewVersion();
362331
}
363332

364-
private final LifecycleEventObserver lifecycleEventObserver = ((lifecycleOwner, event) -> {
365-
if (event == Lifecycle.Event.ON_START && token != null) {
366-
Log_OC.d(TAG, "Start poolLogin");
367-
poolLogin();
368-
}
369-
});
370-
371333
private void deleteCookies() {
372334
try {
373335
CookieSyncManager.createInstance(this);
@@ -377,72 +339,11 @@ private void deleteCookies() {
377339
}
378340
}
379341

380-
private String baseUrl;
381-
382-
/**
383-
* This function facilitates the login process by anonymously posting a login request to a specified URL.
384-
* After posting the request, it retrieves the login URL for completing the login flow.
385-
* The login flow version used is v2.
386-
*
387-
* @param url The URL where the login request is to be anonymously posted.
388-
* This URL should handle the login request and return the login URL.
389-
* It's typically the entry point for the login process.
390-
* Example: "<a href="https://example.com/index.php/login/v2">...</a>"
391-
*/
392-
private void anonymouslyPostLoginRequest(String url) {
393-
baseUrl = url;
394-
395-
Thread thread = new Thread(() -> {
396-
String response = getResponseOfAnonymouslyPostLoginRequest();
397-
398-
try {
399-
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
400-
String loginUrl = getLoginUrl(jsonObject);
401-
runOnUiThread(() -> {
402-
initLoginInfoView();
403-
launchDefaultWebBrowser(loginUrl);
404-
});
405-
token = jsonObject.getAsJsonObject("poll").get("token").getAsString();
406-
} catch (Throwable t) {
407-
Log_OC.d(TAG, "Error caught at anonymouslyPostLoginRequest: " + t);
408-
DisplayUtils.showSnackMessage(this, R.string.authenticator_activity_login_error);
409-
}
410-
});
411-
412-
thread.start();
413-
}
414-
415-
private String getResponseOfAnonymouslyPostLoginRequest() {
416-
PostMethod post = new PostMethod(baseUrl, false, new FormBody.Builder().build());
417-
PlainClient client = clientFactory.createPlainClient();
418-
post.execute(client);
419-
return post.getResponseBodyAsString();
420-
}
421-
422-
private String getLoginUrl(JsonObject response) {
423-
String result = response.get("login").getAsString();
424-
if (result == null) {
425-
result = getResources().getString(R.string.webview_login_url);
426-
}
427-
428-
return result;
429-
}
430-
431-
private void launchDefaultWebBrowser(String url) {
432-
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
433-
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
434-
startActivity(intent);
435-
}
436-
437342
private static String getWebLoginUserAgent() {
438343
return Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) +
439344
Build.MANUFACTURER.substring(1).toLowerCase(Locale.getDefault()) + " " + Build.MODEL + " (Android)";
440345
}
441346

442-
/**
443-
* @Deprecated This function is deprecated. Please use the {@link #anonymouslyPostLoginRequest(String)} method instead, which utilizes the improved login flow v2.
444-
*/
445-
@Deprecated
446347
@SuppressFBWarnings("ANDROID_WEB_VIEW_JAVASCRIPT")
447348
@SuppressLint("SetJavaScriptEnabled")
448349
private void initWebViewLogin(String baseURL, boolean useGenericUserAgent) {
@@ -802,8 +703,7 @@ protected void onNewIntent(Intent intent) {
802703
if (intent.getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) {
803704
accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
804705
setContentView(accountSetupWebviewBinding.getRoot());
805-
anonymouslyPostLoginRequest(getString(R.string.provider_registration_server));
806-
// initWebViewLogin(getString(R.string.provider_registration_server), true);
706+
initWebViewLogin(getString(R.string.provider_registration_server), true);
807707
}
808708
}
809709

@@ -1040,16 +940,7 @@ private void onGetServerInfoFinish(RemoteOperationResult result) {
1040940

1041941
accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
1042942
setContentView(accountSetupWebviewBinding.getRoot());
1043-
1044-
if (!isLoginProcessCompleted) {
1045-
if (!isRedirectedToTheDefaultBrowser) {
1046-
anonymouslyPostLoginRequest(mServerInfo.mBaseUrl + WEB_LOGIN);
1047-
isRedirectedToTheDefaultBrowser = true;
1048-
} else {
1049-
initLoginInfoView();
1050-
}
1051-
// initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
1052-
}
943+
initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
1053944
}
1054945
} else {
1055946
updateServerStatusIconAndText(result);
@@ -1062,20 +953,6 @@ private void onGetServerInfoFinish(RemoteOperationResult result) {
1062953
}
1063954
}
1064955

1065-
// region LoginInfoView
1066-
private void initLoginInfoView() {
1067-
LinearLayout loginFlowLayout = accountSetupWebviewBinding.loginFlowV2.getRoot();
1068-
MaterialButton cancelButton = accountSetupWebviewBinding.loginFlowV2.cancelButton;
1069-
loginFlowLayout.setVisibility(View.VISIBLE);
1070-
1071-
cancelButton.setOnClickListener(v -> {
1072-
loginFlowExecutorService.shutdown();
1073-
ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleEventObserver);
1074-
recreate();
1075-
});
1076-
}
1077-
// endregion
1078-
1079956
/**
1080957
* Chooses the right icon and text to show to the user for the received operation result.
1081958
*
@@ -1317,8 +1194,7 @@ public void onAuthenticatorTaskCallback(RemoteOperationResult<UserInfo> result)
13171194

13181195
} else { // authorization fail due to client side - probably wrong credentials
13191196
if (accountSetupWebviewBinding != null) {
1320-
anonymouslyPostLoginRequest(mServerInfo.mBaseUrl + WEB_LOGIN);
1321-
// initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
1197+
initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
13221198
DisplayUtils.showSnackMessage(this,
13231199
accountSetupWebviewBinding.loginWebview, R.string.auth_access_failed,
13241200
result.getLogMessage());
@@ -1662,71 +1538,6 @@ public void onServiceDisconnected(ComponentName component) {
16621538
}
16631539
}
16641540

1665-
private final ScheduledExecutorService loginFlowExecutorService = Executors.newSingleThreadScheduledExecutor();
1666-
private boolean isLoginProcessCompleted = false;
1667-
private boolean isRedirectedToTheDefaultBrowser = false;
1668-
1669-
private void poolLogin() {
1670-
loginFlowExecutorService.scheduleWithFixedDelay(() -> {
1671-
if (!isLoginProcessCompleted) {
1672-
performLoginFlowV2();
1673-
}
1674-
}, 0, 30, TimeUnit.SECONDS);
1675-
}
1676-
1677-
private void performLoginFlowV2() {
1678-
String postRequestUrl = baseUrl + "/poll";
1679-
1680-
RequestBody requestBody = new FormBody.Builder()
1681-
.add("token", token)
1682-
.build();
1683-
1684-
PlainClient client = clientFactory.createPlainClient();
1685-
PostMethod post = new PostMethod(postRequestUrl, false, requestBody);
1686-
int status = post.execute(client);
1687-
String response = post.getResponseBodyAsString();
1688-
1689-
Log_OC.d(TAG, "performLoginFlowV2 status: " + status);
1690-
Log_OC.d(TAG, "performLoginFlowV2 response: " + response);
1691-
1692-
if (!response.isEmpty()) {
1693-
runOnUiThread(() -> completeLoginFlow(response, status));
1694-
}
1695-
}
1696-
1697-
private void completeLoginFlow(String response, int status) {
1698-
try {
1699-
JSONObject jsonObject = new JSONObject(response);
1700-
1701-
String server = jsonObject.getString("server");
1702-
String loginName = jsonObject.getString("loginName");
1703-
String appPassword = jsonObject.getString("appPassword");
1704-
1705-
LoginUrlInfo loginUrlInfo = new LoginUrlInfo();
1706-
loginUrlInfo.serverAddress = server;
1707-
loginUrlInfo.username = loginName;
1708-
loginUrlInfo.password = appPassword;
1709-
1710-
isLoginProcessCompleted = (status == 200 && !server.isEmpty() && !loginName.isEmpty() && !appPassword.isEmpty());
1711-
1712-
if (accountSetupBinding != null) {
1713-
accountSetupBinding.hostUrlInput.setText("");
1714-
}
1715-
mServerInfo.mBaseUrl = AuthenticatorUrlUtils.INSTANCE.normalizeUrlSuffix(loginUrlInfo.serverAddress);
1716-
webViewUser = loginUrlInfo.username;
1717-
webViewPassword = loginUrlInfo.password;
1718-
} catch (Exception e) {
1719-
Log_OC.d(TAG, "Error caught at completeLoginFlow: " + e);
1720-
mServerStatusIcon = R.drawable.ic_alert;
1721-
mServerStatusText = getString(R.string.qr_could_not_be_read);
1722-
showServerStatus();
1723-
}
1724-
1725-
checkOcServer();
1726-
loginFlowExecutorService.shutdown();
1727-
ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleEventObserver);
1728-
}
1729-
17301541
/**
17311542
* Called from SslValidatorDialog when a new server certificate was correctly saved.
17321543
*/

app/src/main/res/layout/account_setup_webview.xml

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,21 @@
77
~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
88
-->
99
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
10+
android:orientation="vertical"
1011
android:layout_width="match_parent"
11-
android:layout_height="match_parent"
12-
xmlns:tools="http://schemas.android.com/tools"
13-
android:orientation="vertical">
12+
android:layout_height="match_parent">
1413

15-
<!-- Login Flow V1 -->
1614
<WebView
17-
android:visibility="gone"
18-
android:layout_width="0dp"
19-
android:layout_height="0dp"
15+
android:layout_width="match_parent"
16+
android:layout_height="match_parent"
2017
android:id="@+id/login_webview">
2118
</WebView>
2219

23-
<!-- Login Flow V2 -->
24-
<include
25-
tools:visibility="visible"
26-
android:visibility="gone"
27-
android:id="@+id/login_flow_v2"
28-
layout="@layout/login_flow_info_layout_v2" />
29-
3020
<ProgressBar
3121
android:id="@+id/login_webview_progress_bar"
3222
style="?android:attr/progressBarStyle"
3323
android:layout_width="match_parent"
3424
android:layout_height="wrap_content"
3525
android:layout_gravity="center"
36-
android:indeterminate="true" />
26+
android:indeterminate="true"/>
3727
</FrameLayout>

0 commit comments

Comments
 (0)