Skip to content

Commit

Permalink
Handle TLS client certificates in NextCloudWebViewClient
Browse files Browse the repository at this point in the history
All interaction with the nextcloud server is handled by the `NextCloudWebViewClient`, so TLS client certificate handling should be done by that class. Since `AuthenticatorActivity` only extends `NextCloudWebViewClient` with some additional methods, it is enough to have the certificate handling in one place.

Signed-off-by: Elv1zz <[email protected]>
  • Loading branch information
Elv1zz committed Jan 31, 2023
1 parent 5033281 commit c785913
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.webkit.ClientCertRequest;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebResourceRequest;
Expand Down Expand Up @@ -99,7 +98,6 @@
import com.owncloud.android.lib.common.UserInfo;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
import com.owncloud.android.lib.common.network.AdvancedX509KeyManager;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
Expand Down Expand Up @@ -128,8 +126,6 @@
import com.owncloud.android.utils.theme.ViewThemeUtils;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Locale;
Expand Down Expand Up @@ -469,24 +465,7 @@ public void onReceivedError(WebView view, int errorCode, String description, Str
if (!customError.isEmpty()) {
accountSetupWebviewBinding.loginWebview.loadData(customError, "text/html; charset=UTF-8", null);
}

if (errorCode >= 400 && errorCode < 500) {
Log_OC.w(TAG, "WebView failed with error code " + errorCode + "; remove key chain aliases");
// chosen client certificate alias does not seem to work -> discard it
try {
URL url = new URL(failingUrl);
new AdvancedX509KeyManager(getApplicationContext()).removeKeys(url.getHost(), url.getPort());
} catch (MalformedURLException e) {
Log_OC.e(TAG, "Malformed URL: " + failingUrl);
}
}
}

@Override
public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
new AdvancedX509KeyManager(getApplicationContext()).handleWebViewClientCertRequest(request);
}

});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ package com.owncloud.android.ui
import android.annotation.SuppressLint
import android.net.http.SslCertificate
import android.net.http.SslError
import android.webkit.ClientCertRequest
import android.webkit.SslErrorHandler
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.fragment.app.FragmentManager
import com.owncloud.android.authentication.AuthenticatorActivity
import com.owncloud.android.lib.common.network.AdvancedX509KeyManager
import com.owncloud.android.lib.common.network.NetworkUtils
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog
import java.io.ByteArrayInputStream
import java.net.MalformedURLException
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
Expand Down Expand Up @@ -78,4 +83,36 @@ open class NextcloudWebViewClient(val supportFragmentManager: FragmentManager) :
ft.addToBackStack(null)
dialog.show(ft, AuthenticatorActivity.UNTRUSTED_CERT_DIALOG_TAG)
}

/**
* Handle request for a TLS client certificate.
*/
override fun onReceivedClientCertRequest(view: WebView?, request: ClientCertRequest?) {
if (view == null || request == null) {
return
}
AdvancedX509KeyManager(view.context).handleWebViewClientCertRequest(request)
}

/**
* Handle HTTP errors.
*
* We might receive an HTTP status code 400 (bad request), which probably tells us that our certificate
* is not valid (anymore), e.g. because it expired. In that case we forget the selected client certificate,
* so it can be re-selected.
*/
override fun onReceivedHttpError(
view: WebView?,
request: WebResourceRequest?,
errorResponse: WebResourceResponse?
) {
val errorCode = errorResponse?.statusCode ?: return
if (errorCode == 400) {
Log_OC.w(tag, "WebView failed with error code $errorCode; remove key chain aliases")
// chosen client certificate alias does not seem to work -> discard it
val failingUrl = request?.url ?: return
val context = view?.context ?: return
AdvancedX509KeyManager(context).removeKeys(failingUrl.host, failingUrl.port)
}
}
}

0 comments on commit c785913

Please sign in to comment.