This repository has been archived by the owner on Sep 17, 2018. It is now read-only.
/
check-domain.py
executable file
·148 lines (115 loc) · 4.4 KB
/
check-domain.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python
#
# Checks whether or not a domain is a primary authority for BrowserID
#
# Return codes:
#
# 0 - domain is correctly setup as a primary
# 1 - domain doesn't advertise itself as a primary
# 2 - domain configuration problem
# 3 - tool error
from common import stringify_time
import httplib2
import json
import socket
import sys
import time
CACERTS = '/etc/ssl/certs/ca-certificates.crt'
URL_TIMEOUT = 5 # in seconds
WELLKNOWN_FILENAME = '/.well-known/browserid'
def fetch_url(domain, path):
url = 'https://%s%s' % (domain, path)
client = httplib2.Http(timeout=URL_TIMEOUT, ca_certs=CACERTS)
response = content = None
error = False
try:
response, content = client.request(url, 'GET')
except socket.error as e:
print "%s doesn't listen on port 443: %s" % (domain, e)
error = True
except httplib2.HttpLib2Error as e:
print 'Error while trying to retrieve the well-known file: %s' % e
error = True
return (response, content, error)
def parse_wellknown_file(domain, wellknown_content):
try:
details = json.loads(wellknown_content)
except Exception as e:
print "Error parsing well-known file: %s" % e
return 2
# TODO: check for 'authority' handle delegation to that other domain
auth_page = None
if 'authentication' in details:
auth_page = details['authentication']
(response, content, error) = fetch_url(domain, auth_page)
if error or int(response.status) != 200:
print "%s points to an invalid authentication page: https://%s%s" % (domain, domain, auth_page)
return 2
prov_page = None
if 'provisioning' in details:
prov_page = details['provisioning']
(response, content, error) = fetch_url(domain, prov_page)
if error or int(response.status) != 200:
print "%s points to an invalid provisioning page: https://%s%s" % (domain, domain, prov_page)
return error
if 'public-key' not in details:
print "%s is missing a public key." % domain
return 2
if auth_page and prov_page:
print '%s is a primary authority for BrowserID.' % domain
print ' Authentication: https://%s%s' % (domain, auth_page)
print ' Provisioning: https://%s%s' % (domain, prov_page)
elif not auth_page and not prov_page:
print '%s looks like a secondary authority for BrowserID.' % domain
elif prov_page:
print '%s has a provisioning page but no authentication page.' % domain
return 2
elif auth_page:
print '%s has an authentication page but no provisioning page.' % domain
return 2
print ' Public key: (algorightm=%s)' % details['public-key']['algorithm']
return 0
def parse_response_headers(headers):
if 'cache-control' in headers:
cache_control = headers['cache-control'].split(', ')
for elem in cache_control:
if elem.lower().startswith('max-age='):
max_age = int(elem[8:])
expiry = (time.time() + max_age) * 1000
print ' Expiry: %s' % stringify_time(expiry)
return 0
elif 'expires' in headers:
# TODO: parse this format and then use stringify_time()
print ' Expiry: %s' % headers['expires']
return 0
print ' Expiry: unknown'
return 0
def check_domain(domain):
(response, content, error) = fetch_url(domain, WELLKNOWN_FILENAME)
if error:
return error
if 404 == int(response['status']):
print "No '%s' file available on %s." % (WELLKNOWN_FILENAME, domain)
return 1
if int(response['status']) != 200:
print 'Received a %s status code while trying to retrieve the well-known file.' % response['status']
return 2
if 'application/json' not in response['content-type']:
print "Received a '%s' response (instead of 'application/json') while trying to retrieve the well-known file." % response['content-type']
return 2
exit_code = parse_wellknown_file(domain, content)
if exit_code != 0:
return exit_code
return parse_response_headers(response)
def main(argv=None):
if argv is None:
argv = sys.argv
domain = None
if len(argv) > 1:
domain = argv[1]
else:
print "Usage: %s <domain>" % argv[0]
return 3
return check_domain(domain)
if __name__ == "__main__":
sys.exit(main())