@@ -1444,40 +1444,64 @@ def test_osx_proxy_bypass(self):
14441444bypass = {'exclude_simple': True, 'exceptions': []}
14451445self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
144614461447-def test_basic_auth(self, quote_char='"'):
1448-opener = OpenerDirector()
1449-password_manager = MockPasswordManager()
1450-auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
1451-realm = "ACME Widget Store"
1452-http_handler = MockHTTPHandler(
1453-401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1454- (quote_char, realm, quote_char))
1455-opener.add_handler(auth_handler)
1456-opener.add_handler(http_handler)
1457-self._test_basic_auth(opener, auth_handler, "Authorization",
1458-realm, http_handler, password_manager,
1459-"http://acme.example.com/protected",
1460-"http://acme.example.com/protected",
1461- )
1462-1463-def test_basic_auth_with_single_quoted_realm(self):
1464-self.test_basic_auth(quote_char="'")
1465-1466-def test_basic_auth_with_unquoted_realm(self):
1467-opener = OpenerDirector()
1468-password_manager = MockPasswordManager()
1469-auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
1470-realm = "ACME Widget Store"
1471-http_handler = MockHTTPHandler(
1472-401, 'WWW-Authenticate: Basic realm=%s\r\n\r\n' % realm)
1473-opener.add_handler(auth_handler)
1474-opener.add_handler(http_handler)
1475-with self.assertWarns(UserWarning):
1447+def check_basic_auth(self, headers, realm):
1448+with self.subTest(realm=realm, headers=headers):
1449+opener = OpenerDirector()
1450+password_manager = MockPasswordManager()
1451+auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
1452+body = '\r\n'.join(headers) + '\r\n\r\n'
1453+http_handler = MockHTTPHandler(401, body)
1454+opener.add_handler(auth_handler)
1455+opener.add_handler(http_handler)
14761456self._test_basic_auth(opener, auth_handler, "Authorization",
1477-realm, http_handler, password_manager,
1478-"http://acme.example.com/protected",
1479-"http://acme.example.com/protected",
1480- )
1457+realm, http_handler, password_manager,
1458+"http://acme.example.com/protected",
1459+"http://acme.example.com/protected")
1460+1461+def test_basic_auth(self):
1462+realm = "realm2@example.com"
1463+realm2 = "realm2@example.com"
1464+basic = f'Basic realm="{realm}"'
1465+basic2 = f'Basic realm="{realm2}"'
1466+other_no_realm = 'Otherscheme xxx'
1467+digest = (f'Digest realm="{realm2}", '
1468+f'qop="auth, auth-int", '
1469+f'nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", '
1470+f'opaque="5ccc069c403ebaf9f0171e9517f40e41"')
1471+for realm_str in (
1472+# test "quote" and 'quote'
1473+f'Basic realm="{realm}"',
1474+f"Basic realm='{realm}'",
1475+1476+# charset is ignored
1477+f'Basic realm="{realm}", charset="UTF-8"',
1478+1479+# Multiple challenges per header
1480+f'{basic}, {basic2}',
1481+f'{basic}, {other_no_realm}',
1482+f'{other_no_realm}, {basic}',
1483+f'{basic}, {digest}',
1484+f'{digest}, {basic}',
1485+ ):
1486+headers = [f'WWW-Authenticate: {realm_str}']
1487+self.check_basic_auth(headers, realm)
1488+1489+# no quote: expect a warning
1490+with support.check_warnings(("Basic Auth Realm was unquoted",
1491+UserWarning)):
1492+headers = [f'WWW-Authenticate: Basic realm={realm}']
1493+self.check_basic_auth(headers, realm)
1494+1495+# Multiple headers: one challenge per header.
1496+# Use the first Basic realm.
1497+for challenges in (
1498+ [basic, basic2],
1499+ [basic, digest],
1500+ [digest, basic],
1501+ ):
1502+headers = [f'WWW-Authenticate: {challenge}'
1503+for challenge in challenges]
1504+self.check_basic_auth(headers, realm)
1481150514821506def test_proxy_basic_auth(self):
14831507opener = OpenerDirector()