@@ -10,81 +10,75 @@ class WebhookRequestHandler(SimpleHTTPRequestHandler, object):
10
10
HTTP requests."""
11
11
12
12
def __init__ (self , * args , ** kwargs ):
13
- self ._config = config
14
- self ._event_store = event_store
15
- self ._server_status = server_status
16
- self ._is_https = is_https
17
- super (WebhookRequestHandler , self ).__init__ (* args , ** kwargs )
13
+ self ._config = config
14
+ self ._event_store = event_store
15
+ self ._server_status = server_status
16
+ self ._is_https = is_https
17
+ super (WebhookRequestHandler , self ).__init__ (* args , ** kwargs )
18
18
19
- def end_headers (self ):
19
+ def end_headers (self ):
20
20
self .send_header ('Access-Control-Allow-Origin' , '*' )
21
21
SimpleHTTPRequestHandler .end_headers (self )
22
22
23
23
def do_HEAD (self ):
24
- import json
25
24
26
- if not self . _config [ 'web-ui- enabled' ]:
27
- self .send_error ( 403 , "Web UI is not enabled" )
25
+ # Web UI needs to be enabled
26
+ if not self .validate_web_ui_enabled ():
28
27
return
29
28
30
- if not self ._is_https and self ._config ['web-ui-require-https' ]:
31
-
32
- # Attempt to redirect the request to HTTPS
33
- server_status = self .get_server_status ()
34
- if 'https-uri' in server_status :
35
- self .send_response (307 )
36
- self .send_header ('Location' , '%s%s' % (server_status ['https-uri' ], self .path ))
37
- self .end_headers ()
38
- return
29
+ # Web UI might require HTTPS
30
+ if not self .validate_web_ui_https ():
31
+ return
39
32
40
- self .send_error (403 , "Web UI is only accessible through HTTPS" )
33
+ # Client needs to be whitelisted
34
+ if not self .validate_web_ui_whitelist ():
41
35
return
42
36
43
- if not self . client_address [ 0 ] in self . _config [ 'web-ui-whitelist' ]:
44
- self . send_error ( 403 , "%s is not allowed access" % self .client_address [ 0 ])
37
+ # Client needs to authenticate
38
+ if not self .validate_web_ui_authentication ():
45
39
return
46
40
47
41
return SimpleHTTPRequestHandler .do_HEAD (self )
48
42
49
43
def do_GET (self ):
50
- import json
51
44
52
- if not self . _config [ 'web-ui- enabled' ]:
53
- self .send_error ( 403 , "Web UI is not enabled" )
45
+ # Web UI needs to be enabled
46
+ if not self .validate_web_ui_enabled ():
54
47
return
55
48
56
- if not self ._is_https and self ._config ['web-ui-require-https' ]:
57
-
58
- # Attempt to redirect the request to HTTPS
59
- server_status = self .get_server_status ()
60
- if 'https-uri' in server_status :
61
- self .send_response (307 )
62
- self .send_header ('Location' , '%s%s' % (server_status ['https-uri' ], self .path ))
63
- self .end_headers ()
64
- return
49
+ # Web UI might require HTTPS
50
+ if not self .validate_web_ui_https ():
51
+ return
65
52
66
- self .send_error (403 , "Web UI is only accessible through HTTPS" )
53
+ # Client needs to be whitelisted
54
+ if not self .validate_web_ui_whitelist ():
67
55
return
68
56
69
- if not self . client_address [ 0 ] in self . _config [ 'web-ui-whitelist' ]:
70
- self . send_error ( 403 , "%s is not allowed access" % self .client_address [ 0 ])
57
+ # Client needs to authenticate
58
+ if not self .validate_web_ui_authentication ():
71
59
return
72
60
61
+ # Handle API call
73
62
if self .path == "/api/status" :
74
- data = {
75
- 'events' : self ._event_store .dict_repr (),
76
- }
77
-
78
- data .update (self .get_server_status ())
79
-
80
- self .send_response (200 , 'OK' )
81
- self .send_header ('Content-type' , 'application/json' )
82
- self .end_headers ()
83
- self .wfile .write (json .dumps (data ).encode ('utf-8' ))
63
+ self .handle_status_api ()
84
64
return
85
65
66
+ # Serve static file
86
67
return SimpleHTTPRequestHandler .do_GET (self )
87
68
69
+ def handle_status_api (self ):
70
+ import json
71
+ data = {
72
+ 'events' : self ._event_store .dict_repr (),
73
+ }
74
+
75
+ data .update (self .get_server_status ())
76
+
77
+ self .send_response (200 , 'OK' )
78
+ self .send_header ('Content-type' , 'application/json' )
79
+ self .end_headers ()
80
+ self .wfile .write (json .dumps (data ).encode ('utf-8' ))
81
+
88
82
def do_POST (self ):
89
83
"""Invoked on incoming POST requests"""
90
84
from threading import Timer
@@ -235,17 +229,83 @@ def save_test_case(self, test_case):
235
229
236
230
def get_server_status (self ):
237
231
"""Generate a copy of the server status object that contains the public IP or hostname."""
232
+
238
233
server_status = {}
239
234
for item in self ._server_status .items ():
240
235
key , value = item
241
236
public_host = self .headers .get ('host' ).split (':' )[0 ]
237
+
242
238
if key == 'http-uri' :
243
239
server_status [key ] = value .replace (self ._config ['http-host' ], public_host )
240
+
244
241
if key == 'https-uri' :
245
242
server_status [key ] = value .replace (self ._config ['https-host' ], public_host )
243
+
246
244
if key == 'wss-uri' :
247
245
server_status [key ] = value .replace (self ._config ['wss-host' ], public_host )
246
+
248
247
return server_status
249
248
250
- return WebhookRequestHandler
249
+ def validate_web_ui_enabled (self ):
250
+ """Verify that the Web UI is enabled"""
251
+
252
+ if self ._config ['web-ui-enabled' ]:
253
+ return True
254
+
255
+ self .send_error (403 , "Web UI is not enabled" )
256
+ return False
257
+
258
+ def validate_web_ui_https (self ):
259
+ """Verify that the request is made over HTTPS"""
260
+
261
+ if self ._is_https and self ._config ['web-ui-require-https' ]:
262
+ return True
263
+
264
+ # Attempt to redirect the request to HTTPS
265
+ server_status = self .get_server_status ()
266
+ if 'https-uri' in server_status :
267
+ self .send_response (307 )
268
+ self .send_header ('Location' , '%s%s' % (server_status ['https-uri' ], self .path ))
269
+ self .end_headers ()
270
+ return False
251
271
272
+ self .send_error (403 , "Web UI is only accessible through HTTPS" )
273
+ return False
274
+
275
+ def validate_web_ui_whitelist (self ):
276
+ """Verify that the client address is whitelisted"""
277
+
278
+ # Allow all if whitelist is empty
279
+ if len (self ._config ['web-ui-whitelist' ]) == 0 :
280
+ return True
281
+
282
+ # Verify that client IP is whitelisted
283
+ if self .client_address [0 ] in self ._config ['web-ui-whitelist' ]:
284
+ return True
285
+
286
+ self .send_error (403 , "%s is not allowed access" % self .client_address [0 ])
287
+ return False
288
+
289
+ def validate_web_ui_authentication (self ):
290
+ """Authenticate the user"""
291
+ import base64
292
+
293
+ # Verify that a username and password is specified in the config
294
+ if self ._config ['web-ui-username' ] is None or self ._config ['web-ui-password' ] is None :
295
+ self .send_error (403 , "Authentication credentials missing in config" )
296
+ return False
297
+
298
+ # Verify that the provided username and password matches the ones in the config
299
+ key = base64 .b64encode ("%s:%s" % (self ._config ['web-ui-username' ], self ._config ['web-ui-password' ]))
300
+ if self .headers .getheader ('Authorization' ) == 'Basic ' + key :
301
+ return True
302
+
303
+ # Let the client know that authentication is required
304
+ self .send_response (401 )
305
+ self .send_header ('WWW-Authenticate' , 'Basic realm=\" GAD\" ' )
306
+ self .send_header ('Content-type' , 'text/html' )
307
+ self .end_headers ()
308
+ self .wfile .write ('Not authenticated' )
309
+ return False
310
+
311
+ return WebhookRequestHandler
0 commit comments