Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-25755] Android: WebView should prompt user for client certificate if requested by server

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionDone
Resolution Date2018-07-10T00:31:08.000+0000
Affected Version/sRelease 6.3.0
Fix Version/sRelease 7.3.0
ComponentsAndroid
Labelsandroid, titanium, webview
ReporterMartin Williamson
AssigneeGary Mathews
Created2018-02-06T09:44:11.000+0000
Updated2020-11-13T03:19:32.000+0000

Description

_*Edit:*_ _Original issue turned out to be a WebView hardware acceleration bug on Google's end based on the web page's content, which was worked-around by adding a border to the WebView. However, we're keeping the code change where the WebView will prompt the end-user for a client certificate via a dialog if requested by the web server._ *Original Post:* The following page will not render in an Android Webview, however, it loads correctly the iOS webview and in all Android stock browsers. [https://idp.unilever.com/adfs/ls/?client-request-id=9b52f9a3-756e-4cde-99bd-64515d1e274a&wa=wsignin1.0&wtrealm=urn%%3afederation%%3aMicrosoftOnline&wctx=LoginOptions%%3D3%%26estsredirect%%3d2%%26estsrequest%%3drQIIAa2Qv4vUQACFM7c_PNcVjsNCLOQK5arZJJNkNhkQjKeLJ3d4blhFQWQymbmNJDNxJln1_go7UQtFO-0sBRvLK_TqAy2sxEIs1co9wd7C9sHjve_rWWR1WteVIbbdyLzgM67RgMpZXmxr1VQDpkp7S-maFnq5t_Ti5_iJbD5tPHqbXbl5cvXSS3DhH9t2Em9u2LExXNe5kmtKmqbkOuF6ljP-Dpy-FQxThNjQhwx7PvRxNIQRyjBEYcSiEAcRo3QPgC8A7C90EloW6NdC0GhJFDW5IZKW3JCakYMh4g7cP0meQaF0SWvSSFNxloucZ49b_U2Vzu_GVZUkl1-3TgmMBeUOgkHmYehHQQpTwR04DCkWIhIhx_xz60TFa64Hpqay4PfP_iU-oNxr97-2-w4gi4uHlsBxsGL9aIPnnbmy9-LZtw8fL55_Gh95RR8uW7sdm1Fv_Zx3Z3p7zfUEupbi0Xhyb2LCu42a4OtXp-t6J95yRqPxjjrjEvdB9-hu1_retd4c_j-293vHkOOGcM7rBCtuQPyAIHTjNw2&cbcxt=&username=peter.stanley%%40unilever.com&mkt=&lc=](https://idp.unilever.com/adfs/ls/?client-request-id=9b52f9a3-756e-4cde-99bd-64515d1e274a&wa=wsignin1.0&wtrealm=urn%%3afederation%%3aMicrosoftOnline&wctx=LoginOptions%%3D3%%26estsredirect%%3d2%%26estsrequest%%3drQIIAa2Qv4vUQACFM7c_PNcVjsNCLOQK5arZJJNkNhkQjKeLJ3d4blhFQWQymbmNJDNxJln1_go7UQtFO-0sBRvLK_TqAy2sxEIs1co9wd7C9sHjve_rWWR1WteVIbbdyLzgM67RgMpZXmxr1VQDpkp7S-maFnq5t_Ti5_iJbD5tPHqbXbl5cvXSS3DhH9t2Em9u2LExXNe5kmtKmqbkOuF6ljP-Dpy-FQxThNjQhwx7PvRxNIQRyjBEYcSiEAcRo3QPgC8A7C90EloW6NdC0GhJFDW5IZKW3JCakYMh4g7cP0meQaF0SWvSSFNxloucZ49b_U2Vzu_GVZUkl1-3TgmMBeUOgkHmYehHQQpTwR04DCkWIhIhx_xz60TFa64Hpqay4PfP_iU-oNxr97-2-w4gi4uHlsBxsGL9aIPnnbmy9-LZtw8fL55_Gh95RR8uW7sdm1Fv_Zx3Z3p7zfUEupbi0Xhyb2LCu42a4OtXp-t6J95yRqPxjjrjEvdB9-hu1_retd4c_j-293vHkOOGcM7rBCtuQPyAIHTjNw2&cbcxt=&username=peter.stanley%%40unilever.com&mkt=&lc=)

Attachments

FileDateSize
Android build log.txt2018-02-08T13:22:14.000+0000269284
Android build log 6.3.txt2018-02-08T13:22:14.000+0000301618
AndroidWVTest.zip2018-02-06T12:10:24.000+00005552829
Screenshot.png2018-03-29T22:25:51.000+00001200250
ti.webdialog-android-1.0.0-6XX.zip2018-02-08T05:14:31.000+0000114749

Comments

  1. Mostafizur Rahman 2018-02-06

    Hello [~marchief], Thanks for sharing with us. Please provide a full sample testcode that regenerates the issue. Better to provide a sample app as an attachment here. We will test the issue in our environment. Also, provide the SDK and CLI version you are testing on. Thanks.
  2. Martin Williamson 2018-02-06

    Axway Appcelerator Studio, build: 5.0.0.201712081732 Cli 7.0.1 SDK 6.3.0.G.A Sample Project attached, code below:
       //Master View Component Constructor
       function MasterView() {
       	//create object instance, parasitic subclass of Observable
       	var self = Ti.UI.createView({
       		backgroundColor:'white'
       	});
       	
       var webView = Ti.UI.createWebView({
       		url: 'https://idp.unilever.com/adfs/ls/?client-request-id=9b52f9a3-756e-4cde-99bd-64515d1e274a&wa=wsignin1.0&wtrealm=urn%%3afederation%%3aMicrosoftOnline&wctx=LoginOptions%%3D3%%26estsredirect%%3d2%%26estsrequest%%3drQIIAa2Qv4vUQACFM7c_PNcVjsNCLOQK5arZJJNkNhkQjKeLJ3d4blhFQWQymbmNJDNxJln1_go7UQtFO-0sBRvLK_TqAy2sxEIs1co9wd7C9sHjve_rWWR1WteVIbbdyLzgM67RgMpZXmxr1VQDpkp7S-maFnq5t_Ti5_iJbD5tPHqbXbl5cvXSS3DhH9t2Em9u2LExXNe5kmtKmqbkOuF6ljP-Dpy-FQxThNjQhwx7PvRxNIQRyjBEYcSiEAcRo3QPgC8A7C90EloW6NdC0GhJFDW5IZKW3JCakYMh4g7cP0meQaF0SWvSSFNxloucZ49b_U2Vzu_GVZUkl1-3TgmMBeUOgkHmYehHQQpTwR04DCkWIhIhx_xz60TFa64Hpqay4PfP_iU-oNxr97-2-w4gi4uHlsBxsGL9aIPnnbmy9-LZtw8fL55_Gh95RR8uW7sdm1Fv_Zx3Z3p7zfUEupbi0Xhyb2LCu42a4OtXp-t6J95yRqPxjjrjEvdB9-hu1_retd4c_j-293vHkOOGcM7rBCtuQPyAIHTjNw2&cbcxt=&username=peter.stanley%%40unilever.com&mkt=&lc=',
       	height: '100%',
       	width:'100%'
       	});
       	
       	self.add(webView);
       
       	return self;
       };
       
       module.exports = MasterView; [^AndroidWVTest.zip] 
       
  3. Hans Knöchel 2018-02-06

    Thanks [~marchief]! [~ybanev] Would you mind taking a peak?
  4. Joshua Quick 2018-02-06

    [~ybanev], I have not handled certificate challenges with an Android WebView before. I suppose the only work-around that'll work "today" is to use Ti.Platform.openURL() to display the webpage via the Android device's default web browser. http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Platform-method-openURL The above works well on Android because pressing the Back button from the browser app will return the end-user back to the app.
  5. Hans Knöchel 2018-02-06

    Maybe https://github.com/appcelerator-modules/titanium-web-dialog is a good solution as well?
  6. Martin Williamson 2018-02-06

    We need the solution in the app as it is part of an SSO solution so we need to grab the SAML for authentication that is generated after authentication has been performed and placed in a named div for the app to retrieve.
  7. Joshua Quick 2018-02-06

    {quote}We need the solution in the app{quote} Sounds like a feature request to me. :) [~ybanev], can you see what our options are in making this work on Android 4.x please? There's no point in supporting that WebViewClient.onReceivedClientCertRequest() API since it's not supported on older Android OS versions. And let's avoid the "ignore SSL error" technique that devs use on stackoverflow since that's considered a security risk. Alternatively, we could look into switching our WebView implementation over to Google's "Chrome Custom Tab" implementation, but that's a much bigger change that I don't see us doing in the near future. https://developer.chrome.com/multidevice/android/customtabs
  8. Martin Williamson 2018-02-06

    Accessing data through evaljs is a supported feature ;) and works perfectly well in iOS on the URL given. Ignoressl doesn't make any difference on the URL given in android.
  9. Martin Williamson 2018-02-06

    Probably should reference this account for fixes as have enterprise support.
  10. Joshua Quick 2018-02-06

    [~marchief], you may want to give the following module a try... https://github.com/appcelerator-modules/titanium-web-dialog This module uses a "Chrome Custom Tab" within your app to display web content instead of the Android OS' built-in Java "WebView". I haven't tried it for myself, but since you said that you're able to display this webpage via the device's Chrome browser, it should theoretically work via this module as well. And Google's "Chrome Custom Tabs" is supported on Android 4.x. _Edit: Thanks goes to [~hknoechel] for pointing this out above._
  11. Martin Williamson 2018-02-06

    THe module says it's for 7.1 and we are only able to use 6.3 max due to modules currently.
  12. Yordan Banev 2018-02-07

    [~jquick] After a bit more testing: - the problem does not exist on APIs 16-18. The page with Authentication warning is loaded which I assume is fine provided the expected certificate is not installed on the system. - on API 19 this specific request does not trigger any significant WebViewClient events before onPageFinshed that would help us work around the problem. Trying to get some clue from the native error if we can somehow avoid big changes in order to get it done.
  13. Martin Williamson 2018-02-07

    I tried the custom tab option, whilst this does load the page, the "load" event is not fired, therefore we can't read data returned via evalJS. Also the tab option does not load the URL directly, you have to be redirected through as it has issues with URL parameters.
  14. Gary Mathews 2018-02-08

  15. Martin Williamson 2018-02-08

    [~gmatthews] We have tried that, it loads the URL but no events work and can't access the content for evalJS
  16. Joshua Quick 2018-02-23

    [~marchief], we'll look into experimenting more with a week from now (after our 7.1.0.GA release). Unfortunately, nothing on the native Android side just automatically works. The web dialog module is the only work-around at the moment since it works via the installed Chrome browser app... and whatever works in that app will work in the web dialog. They share the same web cache and certificates and is often used for SSO. But unfortunately, it comes with its own limitations. We can improve it in the future, but it may not be possible to give it the same feature set that a WebView has (such as evalJS). We'll look into what our options are for WebView later. The trick is getting it to use the same certificate that the Chrome app is using to satisfy the server's certificate challenge. This may or may not involve adding a new WebView API for you to use to respond to the certificate challenge. And we may not be able to support this in Android 4.x due to limitations on Google's end. We'll see when we experiment with this later.
  17. Gary Mathews 2018-02-24

    master: https://github.com/appcelerator/titanium_mobile/pull/9882
  18. Gary Mathews 2018-02-26

    Here's an SDK build incorporating the above PR: [mobilesdk-7.2.0.v20180226131340-osx.zip](https://www.dropbox.com/s/lallawg0954fd9x/mobilesdk-7.2.0.v20180226131340-osx.zip?dl=1) You can use this to determine if the changes solve your issue. You may need to install the necessary certificate/s on your device first.
  19. Martin Williamson 2018-02-27

    Using the above SDK (the webView runs so much smoother btw) when it reaches the idp page it asks for certificate storage access and then to choose a certificate, cancelling this gives the blank page as before. we are sourcing the certificate to see if this gets around the issue, but I am still not sure why the certificate is not needed when using the stock browser?
  20. Joshua Quick 2018-02-28

    bq. but I am still not sure why the certificate is not needed when using the stock browser? [~marchief], the certificate must have been selected/installed by the stock browser app at some point. Is this a work phone you're using to test this? Are your sure IT at your workplace hasn't already installed a certificate to it? I'm thinking the answer must be yes. Note that when I copy-and-paste the URL you gave us to my desktop web browser, I too get a dialog asking me for a certificate, which I don't have.
  21. Martin Williamson 2018-03-08

    We got the client to test this on their work phone, they are unable to locate the certificate on the device, even though the browsers on the device are ok. I have tried this from several machines and web browsers and none prompt for a certificate, the page just loads and the SSL (secure) lock shows correctly.
  22. Gary Mathews 2018-03-09

    [~anvil_martin] Are you able to provide us with another URL we could use for testing? I'm not sure what https://idp.unilever.com/adfs/ls is meant to be showing, a login prompt? I receive An error occurred on all browsers I've used navigating to it.
  23. Martin Williamson 2018-03-10

    try this one [SSO link](https://idp.unilever.com/adfs/ls/?client-request-id=32c6a80d-2be5-4ceb-91bd-6414b19fc94b&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx=LoginOptions%3D3%26estsredirect%3d2%26estsrequest%3drQIIAa2QvWsUQRyGd3MfxOMCIgmIjSkUC5nbmf3OiOChEYk5LrIxYBqZ2_2NbtydWWZmz8T_QVBLG0EbsRC0CQQEsRBMlTqlIIg2lmLlRrC3sH3h5X2fp2fRc3eNqTR1nFrkBUxBuQMmpnlxR8m6GqSydNakMqxQJ3rH515-dL-c_776-F02_-bZp-uv7OV_bDvJcLTqDLUGZXIpLkuh6xJUAmqap_DBPns7TiGL_DREADEgf2nio9gPYoQZZoTEvs9wdGDbX237cKaTsLJwf80EtRJUMp1rKlgJmpqUHg1RMiB_kjxDXKqSGVoLXUGa8xyyp63-SE6au8OqSpLx29YZHoacAXZRkHlhsx1M0IQDRlHMQs6XeAwhfG6dqsCAGmjDRAE7l_4SH1EetPvf2n3cobOzjaWTrUXrZ9t-3mmUPZEvhq8vyNHD97unA71g7XecjZV7Y721mdRm-8bNesVb37m2HYzLrfrBRhQanl25Za6uGyzW7i9fjCl51J3b71o_utbesf9j-7A372LSmPUQwYskop5HSbj5Gw2&cbcxt=&username=peter.stanley%40unilever.com&mkt=&lc=)
  24. Brian burns 2018-03-15

    I am having the same issue with this URL https://stripe.com/connect-account/legal.
  25. Gary Mathews 2018-03-15

    [~turbomonkey] Thanks, that makes a nice test case
        var win = Ti.UI.createWindow({ backgroundColor: 'gray' }),
            webView = Ti.UI.createWebView({
            	url: 'https://stripe.com/connect-account/legal'
            });
        
        win.add(webView);
        win.open();
        
  26. Brian burns 2018-03-15

    Are you seeing the same issue? I am building with Ti SDK 7.0.2 and Android SDK API 26.
  27. Martin Williamson 2018-03-23

    Is there any update to this? Been over a week with no update
  28. Joshua Quick 2018-03-27

    [~marchief], I'm not sure what else we can do here. The way [~gmathews] implemented it matches what Google recommends here... https://developer.android.com/reference/android/webkit/WebViewClient.html#onReceivedClientCertRequest(android.webkit.WebView,%20android.webkit.ClientCertRequest) Like I said before, the server is doing a certificate challenge and expects the WebView to respond with a client certificate. You can see this happening in your desktop browser when you click on the 2 offending URLs you gave us. My desktop browser displays a dialog asking for a client certificate. My Android phone's main Chrome browser app prompts me for a certificate too. Gary's change makes it do the same, because I'm pretty sure that's all we can do. So, let's take a step back here. Do you not want a dialog to prompt the end-user for a certificate? If that's the case, then the only solution is to change the web server side to not perform a certificate challenge.
  29. Martin Williamson 2018-03-29

    We have had feedback from the clients IT team, seems that the Webview request is not SNI compliant, therefore they are rejecting the connection. {quote} I found that ADFS server is configured to reject any client connection where the client is not SNI Compliant. Can application team confirm if the application is sending server name in the client hello? {quote}
  30. Martin Williamson 2018-03-29

    Also, just to test out if there is a difference in the HttpClient request i tried this
        
        var webView = Ti.UI.createWebView({
        	
        	 });
        	
        	
        	var url = "https://idp.unilever.com/adfs/ls/idpinitiatedsignon.aspx";
         var client = Ti.Network.createHTTPClient({
         	validatesSecureCertificate:true,
             // function called when the response data is available
             onload : function(e) {
                 Ti.API.info("Received text: " + this.responseText);
               webView.html = this.responseText;
             },
             // function called when an error occurs, including a timeout
             onerror : function(e) {
                 Ti.API.debug(e.error);
                 alert('error');
             },
             timeout : 5000  // in milliseconds
         });
         // Prepare the connection.
         client.open("GET", url);
         // Send the request.
         client.send();
        
    which does render the page (i.e. passes the client certificate checks) and presents the basic page.
  31. Joshua Quick 2018-03-29

    [~marchief], something is still amiss here. Forget about the mobile and Titanium side. Why can't anyone on my end display the web page via their desktop web browsers? We can't display the web page in Chrome or Safari. If we can't do this, then there's nothing we can do on the mobile side. This is the root problem. What do we need to do to get a successful response from the server?
  32. Martin Williamson 2018-03-29

    Use the link i put in the http request. When it asks you to install a certificate just click allow or cancel and the page should still load.
  33. Gary Mathews 2018-03-29

    [~anvil_martin] What should the page look like after it loads? Because I see an Authentication Error
  34. Joshua Quick 2018-03-29

    Okay. I see. So, the client certificate request is the expected behavior then. If I hit "continue" in my desktop browser, then I see the attached login page here: !Screenshot.png|thumbnail! This is what we should be seeing on the mobile web view, right?
  35. Martin Williamson 2018-03-29

    [~jquick] yes that is correct, when going to [This link](https://idp.unilever.com/adfs/ls/idpinitiatedsignon.aspx) you are asked for a certificate if your browser doesn't find one automatically or you are from an untrusted connection, but continuing doesn't stop you getting to the site, however from the webview it doesn't give you the option to accept / continue and only shows a blank page. Our client has done some digging and found that the webview on android is not presenting the server name (not SNI compliant) not sure if that makes a difference or not. However if you use the Ti.Network.createHTTPClient this returns the page without an issue, it just doesn't render properly.
  36. Joshua Quick 2018-03-29

    Okay. So the issue here is Android's native WebView is not "generating" a client certificate. What [~gmathews] has implemented will display a dialog asking for a client certificate like how desktop browser's do it, but unfortunately that approach won't generate one. Hmm... _(FYI: How Gary is doing it follows Google's examples.)_
  37. Joshua Quick 2018-03-30

    Quick update. The most common solution to this (other than displaying a dialog asking for a certificate) is to bundle a certificate with the app and use that as the client certificate. However, theoretically, we should be able to generate a client certificate and public key based on the digital signature applied to the APK. I'm going to experiment with this and see how it goes.
  38. Joshua Quick 2018-04-02

    [~marchief], do you know if the web server accepts self-signed client certificates?
  39. Joshua Quick 2018-04-03

    [~marchief], this appears to be a hardware acceleration bug on Google's end. It turns out the WebView is receiving the HTML content just fine (even though it's not sending a client certificate), but the content is not getting rendered when hardware acceleration (via OpenGL and the GPU) is enabled, which is the default setting on Android. Something in the HTML is triggering this naughty behavior. There is a work-around. If you add a border to the WebView, then this will trick the code into disabling hardware acceleration and the content of the page will then appear.
        var window = Ti.UI.createWindow();
        var webView = Ti.UI.createWebView(
        {
        	url: "https://idp.unilever.com/adfs/ls/idpinitiatedsignon.aspx",
        	borderWidth: "1dp",
        	borderColor: "black",
        });
        window.add(webView);
        window.open();
        
  40. Martin Williamson 2018-04-03

    [~jquick] Thanks for all of your hard work, I can confirm that workaround fixes the issue. Also, it will work with a self-signed certificate. Thanks Martin
  41. Joshua Quick 2018-04-03

    [~turbomonkey], the HTML content from your URL is triggering the same Google hardware acceleration bug [~marchief] ran into. I've confirmed that adding a border to the WebView will make it shows its content. Have a look at my code example above.
  42. Brian burns 2018-04-04

    [~jquick] the workaround works for me as well. Thanks for figuring it out and sharing!
  43. Samir Mohammed 2018-07-05

    Closing ticket, as suggested above.

JSON Source