1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.webkit.cts; 18 19 import android.cts.util.NullWebViewUtils; 20 import android.test.ActivityInstrumentationTestCase2; 21 import android.webkit.HttpAuthHandler; 22 import android.webkit.WebView; 23 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient; 24 25 26 import org.apache.http.HttpStatus; 27 28 public class HttpAuthHandlerTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> { 29 30 private static final long TIMEOUT = 10000; 31 32 private static final String WRONG_USERNAME = "wrong_user"; 33 private static final String WRONG_PASSWORD = "wrong_password"; 34 private static final String CORRECT_USERNAME = CtsTestServer.AUTH_USER; 35 private static final String CORRECT_PASSWORD = CtsTestServer.AUTH_PASS; 36 37 private CtsTestServer mWebServer; 38 private WebViewOnUiThread mOnUiThread; 39 HttpAuthHandlerTest()40 public HttpAuthHandlerTest() { 41 super("com.android.cts.webkit", WebViewCtsActivity.class); 42 } 43 44 @Override setUp()45 protected void setUp() throws Exception { 46 super.setUp(); 47 WebView webview = getActivity().getWebView(); 48 if (webview != null) { 49 mOnUiThread = new WebViewOnUiThread(this, webview); 50 } 51 } 52 53 @Override tearDown()54 protected void tearDown() throws Exception { 55 if (mOnUiThread != null) { 56 mOnUiThread.cleanUp(); 57 } 58 59 if (mWebServer != null) { 60 mWebServer.shutdown(); 61 } 62 super.tearDown(); 63 } 64 65 private class ProceedHttpAuthClient extends WaitForLoadedClient { 66 String realm; 67 boolean useHttpAuthUsernamePassword; 68 69 private int mMaxAuthAttempts; 70 private String mUser; 71 private String mPassword; 72 private int mAuthCount; 73 ProceedHttpAuthClient(int maxAuthAttempts, String user, String password)74 ProceedHttpAuthClient(int maxAuthAttempts, String user, String password) { 75 super(mOnUiThread); 76 mMaxAuthAttempts = maxAuthAttempts; 77 mUser = user; 78 mPassword = password; 79 } 80 81 @Override onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)82 public void onReceivedHttpAuthRequest(WebView view, 83 HttpAuthHandler handler, String host, String realm) { 84 if (++mAuthCount > mMaxAuthAttempts) { 85 handler.cancel(); 86 return; 87 } 88 89 this.realm = realm; 90 this.useHttpAuthUsernamePassword = handler.useHttpAuthUsernamePassword(); 91 92 handler.proceed(mUser, mPassword); 93 } 94 } 95 96 private class CancelHttpAuthClient extends WaitForLoadedClient { 97 String realm; 98 CancelHttpAuthClient()99 CancelHttpAuthClient() { 100 super(mOnUiThread); 101 } 102 103 @Override onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)104 public void onReceivedHttpAuthRequest(WebView view, 105 HttpAuthHandler handler, String host, String realm) { 106 this.realm = realm; 107 handler.cancel(); 108 } 109 } 110 incorrectCredentialsAccessDenied(String url)111 private void incorrectCredentialsAccessDenied(String url) throws Throwable { 112 ProceedHttpAuthClient client = new ProceedHttpAuthClient(1, WRONG_USERNAME, WRONG_PASSWORD); 113 mOnUiThread.setWebViewClient(client); 114 115 // As we're providing incorrect credentials, the page should complete but at 116 // an access denied page. 117 mOnUiThread.loadUrlAndWaitForCompletion(url); 118 119 assertEquals(CtsTestServer.AUTH_REALM, client.realm); 120 assertEquals(CtsTestServer.getReasonString(HttpStatus.SC_UNAUTHORIZED), mOnUiThread.getTitle()); 121 } 122 missingCredentialsAccessDenied(String url)123 private void missingCredentialsAccessDenied(String url) throws Throwable { 124 ProceedHttpAuthClient client = new ProceedHttpAuthClient(1, null, null); 125 mOnUiThread.setWebViewClient(client); 126 127 // As we're providing no credentials, the page should complete but at 128 // an access denied page. 129 mOnUiThread.loadUrlAndWaitForCompletion(url); 130 131 assertEquals(CtsTestServer.AUTH_REALM, client.realm); 132 assertEquals(CtsTestServer.getReasonString(HttpStatus.SC_UNAUTHORIZED), mOnUiThread.getTitle()); 133 } 134 correctCredentialsAccessGranted(String url)135 private void correctCredentialsAccessGranted(String url) throws Throwable { 136 ProceedHttpAuthClient client = new ProceedHttpAuthClient(1, CORRECT_USERNAME, CORRECT_PASSWORD); 137 mOnUiThread.setWebViewClient(client); 138 139 // As we're providing valid credentials, the page should complete and 140 // at the page we requested. 141 mOnUiThread.loadUrlAndWaitForCompletion(url); 142 143 assertEquals(CtsTestServer.AUTH_REALM, client.realm); 144 assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, mOnUiThread.getTitle()); 145 } 146 testProceed()147 public void testProceed() throws Throwable { 148 if (!NullWebViewUtils.isWebViewAvailable()) { 149 return; 150 } 151 mWebServer = new CtsTestServer(getActivity()); 152 String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); 153 154 incorrectCredentialsAccessDenied(url); 155 missingCredentialsAccessDenied(url); 156 correctCredentialsAccessGranted(url); 157 } 158 testCancel()159 public void testCancel() throws Throwable { 160 if (!NullWebViewUtils.isWebViewAvailable()) { 161 return; 162 } 163 mWebServer = new CtsTestServer(getActivity()); 164 String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); 165 166 CancelHttpAuthClient client = new CancelHttpAuthClient(); 167 mOnUiThread.setWebViewClient(client); 168 169 mOnUiThread.loadUrlAndWaitForCompletion(url); 170 assertEquals(CtsTestServer.AUTH_REALM, client.realm); 171 assertEquals(CtsTestServer.getReasonString(HttpStatus.SC_UNAUTHORIZED), mOnUiThread.getTitle()); 172 } 173 testUseHttpAuthUsernamePassword()174 public void testUseHttpAuthUsernamePassword() throws Throwable { 175 if (!NullWebViewUtils.isWebViewAvailable()) { 176 return; 177 } 178 mWebServer = new CtsTestServer(getActivity()); 179 String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); 180 181 // Try to login once with incorrect credentials. This should cause 182 // useHttpAuthUsernamePassword to be true in the callback, as at that point 183 // we don't yet know that the credentials we will use are invalid. 184 ProceedHttpAuthClient client = new ProceedHttpAuthClient(1, WRONG_USERNAME, WRONG_PASSWORD); 185 mOnUiThread.setWebViewClient(client); 186 mOnUiThread.loadUrlAndWaitForCompletion(url); 187 assertEquals(CtsTestServer.AUTH_REALM, client.realm); 188 assertEquals(CtsTestServer.getReasonString(HttpStatus.SC_UNAUTHORIZED), mOnUiThread.getTitle()); 189 assertTrue(client.useHttpAuthUsernamePassword); 190 191 // Try to login twice with invalid credentials. This should cause 192 // useHttpAuthUsernamePassword to return false, as the credentials 193 // we would have stored on the first auth request 194 // are not suitable for use the second time. 195 client = new ProceedHttpAuthClient(2, WRONG_USERNAME, WRONG_PASSWORD); 196 mOnUiThread.setWebViewClient(client); 197 mOnUiThread.loadUrlAndWaitForCompletion(url); 198 assertEquals(CtsTestServer.AUTH_REALM, client.realm); 199 assertEquals(CtsTestServer.getReasonString(HttpStatus.SC_UNAUTHORIZED), mOnUiThread.getTitle()); 200 assertFalse(client.useHttpAuthUsernamePassword); 201 } 202 } 203