OLD | NEW |
1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """This is a simple HTTP server used for testing Chrome. | 6 """This is a simple HTTP server used for testing Chrome. |
7 | 7 |
8 It supports several test URLs, as specified by the handlers in TestPageHandler. | 8 It supports several test URLs, as specified by the handlers in TestPageHandler. |
9 By default, it listens on an ephemeral port and sends the port number back to | 9 By default, it listens on an ephemeral port and sends the port number back to |
10 the originating process over a pipe. The originating process can specify an | 10 the originating process over a pipe. The originating process can specify an |
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
925 """This handler tests 'Basic' authentication. It just sends a page with | 925 """This handler tests 'Basic' authentication. It just sends a page with |
926 title 'user/pass' if you succeed.""" | 926 title 'user/pass' if you succeed.""" |
927 | 927 |
928 if not self._ShouldHandleRequest("/auth-basic"): | 928 if not self._ShouldHandleRequest("/auth-basic"): |
929 return False | 929 return False |
930 | 930 |
931 username = userpass = password = b64str = "" | 931 username = userpass = password = b64str = "" |
932 expected_password = 'secret' | 932 expected_password = 'secret' |
933 realm = 'testrealm' | 933 realm = 'testrealm' |
934 set_cookie_if_challenged = False | 934 set_cookie_if_challenged = False |
| 935 force_auth = False |
935 | 936 |
936 _, _, url_path, _, query, _ = urlparse.urlparse(self.path) | 937 _, _, url_path, _, query, _ = urlparse.urlparse(self.path) |
937 query_params = cgi.parse_qs(query, True) | 938 query_params = cgi.parse_qs(query, True) |
| 939 _, cookies = cgi.parse_header('Dummy; ' + |
| 940 self.headers.getheader('cookie', '')) |
938 if 'set-cookie-if-challenged' in query_params: | 941 if 'set-cookie-if-challenged' in query_params: |
939 set_cookie_if_challenged = True | 942 set_cookie_if_challenged = True |
940 if 'password' in query_params: | 943 if 'password' in query_params: |
941 expected_password = query_params['password'][0] | 944 expected_password = query_params['password'][0] |
942 if 'realm' in query_params: | 945 if 'realm' in query_params: |
943 realm = query_params['realm'][0] | 946 realm = query_params['realm'][0] |
| 947 # The 'force' argument forces a single 401 response to a request |
| 948 # even if it includes an 'Authorization' header. It sets the |
| 949 # 'got_forced' cookie which prevents any subsequent requests from |
| 950 # sending a 401. |
| 951 if 'force' in query_params and 'got_forced' not in cookies: |
| 952 force_auth = True |
944 | 953 |
945 auth = self.headers.getheader('authorization') | 954 auth = self.headers.getheader('authorization') |
946 try: | 955 try: |
947 if not auth: | 956 if not auth: |
948 raise Exception('no auth') | 957 raise Exception('no auth') |
949 b64str = re.findall(r'Basic (\S+)', auth)[0] | 958 b64str = re.findall(r'Basic (\S+)', auth)[0] |
950 userpass = base64.b64decode(b64str) | 959 userpass = base64.b64decode(b64str) |
951 username, password = re.findall(r'([^:]+):(\S+)', userpass)[0] | 960 username, password = re.findall(r'([^:]+):(\S+)', userpass)[0] |
952 if password != expected_password: | 961 if password != expected_password: |
953 raise Exception('wrong password') | 962 raise Exception('wrong password') |
| 963 if force_auth: |
| 964 raise Exception('Correct password. Re-requesting auth') |
954 except Exception, e: | 965 except Exception, e: |
955 # Authentication failed. | 966 # Authentication failed. |
956 self.send_response(401) | 967 self.send_response(401) |
957 self.send_header('WWW-Authenticate', 'Basic realm="%s"' % realm) | 968 self.send_header('WWW-Authenticate', 'Basic realm="%s"' % realm) |
958 self.send_header('Content-type', 'text/html') | 969 self.send_header('Content-type', 'text/html') |
959 if set_cookie_if_challenged: | 970 if set_cookie_if_challenged: |
960 self.send_header('Set-Cookie', 'got_challenged=true') | 971 self.send_header('Set-Cookie', 'got_challenged=true') |
| 972 if force_auth: |
| 973 self.send_header('Set-Cookie', 'got_forced=true') |
961 self.end_headers() | 974 self.end_headers() |
962 self.wfile.write('<html><head>') | 975 self.wfile.write('<html><head>') |
963 self.wfile.write('<title>Denied: %s</title>' % e) | 976 self.wfile.write('<title>Denied: %s</title>' % e) |
964 self.wfile.write('</head><body>') | 977 self.wfile.write('</head><body>') |
965 self.wfile.write('auth=%s<p>' % auth) | 978 self.wfile.write('auth=%s<p>' % auth) |
966 self.wfile.write('b64str=%s<p>' % b64str) | 979 self.wfile.write('b64str=%s<p>' % b64str) |
967 self.wfile.write('username: %s<p>' % username) | 980 self.wfile.write('username: %s<p>' % username) |
968 self.wfile.write('userpass: %s<p>' % userpass) | 981 self.wfile.write('userpass: %s<p>' % userpass) |
969 self.wfile.write('password: %s<p>' % password) | 982 self.wfile.write('password: %s<p>' % password) |
970 self.wfile.write('You sent:<br>%s<p>' % self.headers) | 983 self.wfile.write('You sent:<br>%s<p>' % self.headers) |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1029 def AuthDigestHandler(self): | 1042 def AuthDigestHandler(self): |
1030 """This handler tests 'Digest' authentication. | 1043 """This handler tests 'Digest' authentication. |
1031 | 1044 |
1032 It just sends a page with title 'user/pass' if you succeed. | 1045 It just sends a page with title 'user/pass' if you succeed. |
1033 | 1046 |
1034 A stale response is sent iff "stale" is present in the request path. | 1047 A stale response is sent iff "stale" is present in the request path. |
1035 """ | 1048 """ |
1036 if not self._ShouldHandleRequest("/auth-digest"): | 1049 if not self._ShouldHandleRequest("/auth-digest"): |
1037 return False | 1050 return False |
1038 | 1051 |
| 1052 _, cookies = cgi.parse_header('Dummy; ' + |
| 1053 self.headers.getheader('cookie', '')) |
1039 stale = 'stale' in self.path | 1054 stale = 'stale' in self.path |
1040 nonce = self.GetNonce(force_reset=stale) | 1055 force = ('force' in self.path and 'got_forced' not in cookies) |
| 1056 nonce = self.GetNonce(force_reset=(stale or force)) |
1041 opaque = _new_md5('opaque').hexdigest() | 1057 opaque = _new_md5('opaque').hexdigest() |
1042 password = 'secret' | 1058 password = 'secret' |
1043 realm = 'testrealm' | 1059 realm = 'testrealm' |
1044 | 1060 |
1045 auth = self.headers.getheader('authorization') | 1061 auth = self.headers.getheader('authorization') |
1046 pairs = {} | 1062 pairs = {} |
1047 try: | 1063 try: |
1048 if not auth: | 1064 if not auth: |
1049 raise Exception('no auth') | 1065 raise Exception('no auth') |
1050 if not auth.startswith('Digest'): | 1066 if not auth.startswith('Digest'): |
(...skipping 13 matching lines...) Expand all Loading... |
1064 ':'.join([pairs['username'], realm, password])).hexdigest() | 1080 ':'.join([pairs['username'], realm, password])).hexdigest() |
1065 hash_a2 = _new_md5(':'.join([self.command, pairs['uri']])).hexdigest() | 1081 hash_a2 = _new_md5(':'.join([self.command, pairs['uri']])).hexdigest() |
1066 if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: | 1082 if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: |
1067 response = _new_md5(':'.join([hash_a1, nonce, pairs['nc'], | 1083 response = _new_md5(':'.join([hash_a1, nonce, pairs['nc'], |
1068 pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() | 1084 pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() |
1069 else: | 1085 else: |
1070 response = _new_md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest() | 1086 response = _new_md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest() |
1071 | 1087 |
1072 if pairs['response'] != response: | 1088 if pairs['response'] != response: |
1073 raise Exception('wrong password') | 1089 raise Exception('wrong password') |
| 1090 if force: |
| 1091 raise Exception('Forcing') |
1074 except Exception, e: | 1092 except Exception, e: |
1075 # Authentication failed. | 1093 # Authentication failed. |
1076 self.send_response(401) | 1094 self.send_response(401) |
1077 hdr = ('Digest ' | 1095 hdr = ('Digest ' |
1078 'realm="%s", ' | 1096 'realm="%s", ' |
1079 'domain="/", ' | 1097 'domain="/", ' |
1080 'qop="auth", ' | 1098 'qop="auth", ' |
1081 'algorithm=MD5, ' | 1099 'algorithm=MD5, ' |
1082 'nonce="%s", ' | 1100 'nonce="%s", ' |
1083 'opaque="%s"') % (realm, nonce, opaque) | 1101 'opaque="%s"') % (realm, nonce, opaque) |
1084 if stale: | 1102 if stale: |
1085 hdr += ', stale="TRUE"' | 1103 hdr += ', stale="TRUE"' |
1086 self.send_header('WWW-Authenticate', hdr) | 1104 self.send_header('WWW-Authenticate', hdr) |
1087 self.send_header('Content-type', 'text/html') | 1105 self.send_header('Content-type', 'text/html') |
| 1106 if force: |
| 1107 self.send_header('Set-Cookie', 'got_forced=true') |
1088 self.end_headers() | 1108 self.end_headers() |
1089 self.wfile.write('<html><head>') | 1109 self.wfile.write('<html><head>') |
1090 self.wfile.write('<title>Denied: %s</title>' % e) | 1110 self.wfile.write('<title>Denied: %s</title>' % e) |
1091 self.wfile.write('</head><body>') | 1111 self.wfile.write('</head><body>') |
1092 self.wfile.write('auth=%s<p>' % auth) | 1112 self.wfile.write('auth=%s<p>' % auth) |
1093 self.wfile.write('pairs=%s<p>' % pairs) | 1113 self.wfile.write('pairs=%s<p>' % pairs) |
1094 self.wfile.write('You sent:<br>%s<p>' % self.headers) | 1114 self.wfile.write('You sent:<br>%s<p>' % self.headers) |
1095 self.wfile.write('We are replying:<br>%s<p>' % hdr) | 1115 self.wfile.write('We are replying:<br>%s<p>' % hdr) |
1096 self.wfile.write('</body></html>') | 1116 self.wfile.write('</body></html>') |
1097 return True | 1117 return True |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1530 option_parser.add_option('', '--policy-cert-chain', action='append', | 1550 option_parser.add_option('', '--policy-cert-chain', action='append', |
1531 help='Specify a path to a certificate file to sign ' | 1551 help='Specify a path to a certificate file to sign ' |
1532 'policy responses. This option may be used ' | 1552 'policy responses. This option may be used ' |
1533 'multiple times to define a certificate chain. ' | 1553 'multiple times to define a certificate chain. ' |
1534 'The first element will be used for signing, ' | 1554 'The first element will be used for signing, ' |
1535 'the last element should be the root ' | 1555 'the last element should be the root ' |
1536 'certificate.') | 1556 'certificate.') |
1537 options, args = option_parser.parse_args() | 1557 options, args = option_parser.parse_args() |
1538 | 1558 |
1539 sys.exit(main(options, args)) | 1559 sys.exit(main(options, args)) |
OLD | NEW |