Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: net/tools/testserver/testserver.py

Issue 6525035: Invalidate credentials if the server rejects them. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Extra whitespace Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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))
OLDNEW
« net/http/http_auth_handler_digest.cc ('K') | « net/http/http_auth_handler_digest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698