8
8
import experiment_server_controller as control
9
9
from amt_services import MTurkServices
10
10
from db import db_session
11
+ from functools import wraps
11
12
12
13
config = PsiturkConfig ()
13
14
17
18
template_folder = os .path .join (os .path .dirname (__file__ ), "templates_dashboard" ),
18
19
static_folder = os .path .join (os .path .dirname (__file__ ), "static_dashboard" ))
19
20
21
+
22
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
23
+ # Authentication functions
24
+ #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
25
+
26
+ def check_auth (username , password ):
27
+ """This function is called to check if a username /
28
+ password combination is valid.
29
+ """
30
+ true_user = config .get ('Dashboard Parameters' , 'login_username' )
31
+ true_pass = config .get ('Dashboard Parameters' , 'login_pw' )
32
+ return username == true_user and password == true_pass
33
+
34
+
35
+ def authenticate ():
36
+ """Sends a 401 response that enables basic auth"""
37
+ return Response (
38
+ 'Could not verify your access level for that URL.\n '
39
+ 'You have to login with proper credentials' , 401 ,
40
+ {'WWW-Authenticate' : 'Basic realm="Login Required"' })
41
+
42
+
43
+ def requires_auth (f ):
44
+ @wraps (f )
45
+ def decorated (* args , ** kwargs ):
46
+ auth = request .authorization
47
+ if not auth or not check_auth (auth .username , auth .password ):
48
+ return authenticate ()
49
+ return f (* args , ** kwargs )
50
+
51
+ # don't require authorization if there is no username or password
52
+ # defined
53
+ true_user = config .get ('Dashboard Parameters' , 'login_username' )
54
+ true_pass = config .get ('Dashboard Parameters' , 'login_pw' )
55
+ if true_user == '' or true_pass == '' :
56
+ return f
57
+ else :
58
+ return decorated
59
+
20
60
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21
61
# Some supporting classes needed by the dashboard_server
22
62
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -42,13 +82,15 @@ def __str__(self):
42
82
# Routes for handling dashboard interactivity
43
83
#----------------------------------------------
44
84
@app .route ('/dashboard' , methods = ['GET' ])
85
+ @requires_auth
45
86
def dashboard ():
46
87
"""
47
88
Serves dashboard.
48
89
"""
49
90
return render_template ('dashboard.html' )
50
91
51
92
@app .route ('/dashboard_model' , methods = ['GET' , 'POST' ])
93
+ @requires_auth
52
94
def dashboard_model ():
53
95
"""
54
96
Sync for dashboard model.
@@ -68,6 +110,7 @@ def dashboard_model():
68
110
return render_template ('dashboard.html' )
69
111
70
112
@app .route ('/at_a_glance_model' , methods = ['GET' ])
113
+ @requires_auth
71
114
def at_a_glance_model ():
72
115
"""
73
116
Sync for dashboard at-a-glance pane.
@@ -82,6 +125,7 @@ def at_a_glance_model():
82
125
return jsonify (error = "unable to access aws" )
83
126
84
127
@app .route ('/verify_aws_login' , methods = ['POST' ])
128
+ @requires_auth
85
129
def verify_aws ():
86
130
"""
87
131
Verifies current aws login keys are valid
@@ -93,6 +137,7 @@ def verify_aws():
93
137
return jsonify (aws_accnt = is_valid )
94
138
95
139
@app .route ('/mturk_services' , methods = ['POST' ])
140
+ @requires_auth
96
141
def turk_services ():
97
142
"""
98
143
"""
@@ -115,6 +160,7 @@ def turk_services():
115
160
return jsonify (error = "psiTurk failed to recognize your request." )
116
161
117
162
@app .route ('/get_log' , methods = ['POST' ])
163
+ @requires_auth
118
164
def get_log ():
119
165
"""
120
166
provides an jsonified interface to the log file in the dashbaord
@@ -124,6 +170,7 @@ def get_log():
124
170
return jsonify (error = "did not specify the log level correctly" )
125
171
126
172
@app .route ('/get_hits' , methods = ['GET' ])
173
+ @requires_auth
127
174
def get_hits ():
128
175
"""
129
176
provides an jsonified collection of active hits
@@ -132,6 +179,7 @@ def get_hits():
132
179
return jsonify (hits = services .get_active_hits ())
133
180
134
181
@app .route ('/get_workers' , methods = ['GET' ])
182
+ @requires_auth
135
183
def get_workers ():
136
184
"""
137
185
provides an jsonified collection of workers pending review
@@ -140,6 +188,7 @@ def get_workers():
140
188
return jsonify (workers = services .get_workers ())
141
189
142
190
@app .route ('/reject_worker' , methods = ['POST' ])
191
+ @requires_auth
143
192
def reject_worker ():
144
193
if "assignmentId" in request .json :
145
194
services = MTurkServices (config )
@@ -148,6 +197,7 @@ def reject_worker():
148
197
return ("Error: Missing assignment id" )
149
198
150
199
@app .route ('/approve_worker' , methods = ['POST' ])
200
+ @requires_auth
151
201
def approve_worker ():
152
202
CREDITED = 5
153
203
if "assignmentId" in request .json :
@@ -166,6 +216,7 @@ def approve_worker():
166
216
return ("Error: Missing assignment id" )
167
217
168
218
@app .route ('/is_port_available' , methods = ['POST' ])
219
+ @requires_auth
169
220
def is_port_available_route ():
170
221
"""
171
222
Check if port is available on localhost
@@ -180,6 +231,7 @@ def is_port_available_route():
180
231
return "port check"
181
232
182
233
@app .route ('/is_internet_available' , methods = ['GET' ])
234
+ @requires_auth
183
235
def is_internet_on ():
184
236
try :
185
237
response = urllib2 .urlopen ('http://www.google.com' , timeout = 1 )
@@ -188,17 +240,20 @@ def is_internet_on():
188
240
return "false"
189
241
190
242
@app .route ("/server_status" , methods = ["GET" ])
243
+ @requires_auth
191
244
def status ():
192
245
return (jsonify (state = server_controller .is_port_available ()))
193
246
194
247
# this function appears unimplemented in the dashboard currently
195
248
# @app.route("/participant_status", methods=["GET"])
249
+ # @requires_auth
196
250
# def participant_status():
197
251
# database = Dashboard.Database()
198
252
# status = database.get_participant_status()
199
253
# return status
200
254
201
255
@app .route ("/favicon.ico" )
256
+ @requires_auth
202
257
def favicon ():
203
258
"""
204
259
Serving a favicon
@@ -207,6 +262,7 @@ def favicon():
207
262
return app .send_static_file ('favicon.ico' )
208
263
209
264
@app .route ("/data/<filename>" , methods = ["GET" ])
265
+ @requires_auth
210
266
def download_datafile (filename ):
211
267
if filename [- 4 :] != ".csv" :
212
268
raise Exception ("/data received Invalid filename: %s" % filename )
@@ -231,6 +287,7 @@ def download_datafile(filename):
231
287
return response
232
288
233
289
@app .route ("/launch_log" , methods = ["GET" ])
290
+ @requires_auth
234
291
def launch_log ():
235
292
logfilename = config .get ('Server Parameters' , 'logfile' )
236
293
if sys .platform == "darwin" :
@@ -245,18 +302,21 @@ def launch_log():
245
302
# routes for interfacing with ExperimentServerController
246
303
#----------------------------------------------
247
304
@app .route ("/launch" , methods = ["GET" ])
305
+ @requires_auth
248
306
def launch_experiment_server ():
249
307
server_controller .startup ()
250
308
return "Experiment Server launching..."
251
309
252
310
@app .route ("/shutdown_dashboard" , methods = ["GET" ])
311
+ @requires_auth
253
312
def shutdown_dashboard ():
254
313
print ("Attempting to shut down." )
255
314
#server_controller.shutdown() # Must do this; otherwise zombie server remains on dashboard port; not sure why
256
315
request .environ .get ('werkzeug.server.shutdown' )()
257
316
return ("shutting down dashboard server..." )
258
317
259
318
@app .route ("/shutdown_psiturk" , methods = ["GET" ]) ## TODO: Kill psiturk reference
319
+ @requires_auth
260
320
def shutdown_experiment_server ():
261
321
server_controller .shutdown ()
262
322
return ("shutting down Experiment Server..." )
@@ -289,6 +349,6 @@ def launch():
289
349
port = config .getint ('Server Parameters' , 'port' )
290
350
print "Serving on " , "http://" + dashboard_ip + ":" + str (dashboard_port )
291
351
app .run (debug = True , use_reloader = False , port = dashboard_port , host = dashboard_ip )
292
-
352
+
293
353
if __name__ == "__main__" :
294
354
launch ()
0 commit comments