Commit b9fc86c3c5f84bb4ca1baf542a78c50f626d4724
1 parent
16f69d07
Exists in
master
Secure the admin a little.
Showing
6 changed files
with
51 additions
and
12 deletions
Show diff stats
README.md
flaskr/__init__.py
1 | 1 | #! ../venv/bin/python |
2 | +import os | |
3 | +from dotenv import load_dotenv, find_dotenv | |
4 | +load_dotenv(find_dotenv()) | |
2 | 5 | |
3 | -from flask import Flask | |
6 | + | |
7 | +from flask import Flask, url_for | |
4 | 8 | from flask.cli import ScriptInfo |
5 | 9 | from webassets.loaders import PythonLoader as PythonAssetsLoader |
6 | 10 | |
... | ... | @@ -14,7 +18,8 @@ from flaskr.extensions import ( |
14 | 18 | cache, |
15 | 19 | assets_env, |
16 | 20 | debug_toolbar, |
17 | - login_manager | |
21 | + login_manager, | |
22 | + basic_auth | |
18 | 23 | ) |
19 | 24 | |
20 | 25 | from flaskr.content import content |
... | ... | @@ -48,6 +53,7 @@ def create_app(object_name): |
48 | 53 | login_manager.init_app(app) |
49 | 54 | admin.init_app(app) |
50 | 55 | admin.add_view(EstimationView(Estimation, db.session)) |
56 | + basic_auth.init_app(app) | |
51 | 57 | |
52 | 58 | # Import and register the different asset bundles |
53 | 59 | assets_env.init_app(app) |
... | ... | @@ -58,6 +64,9 @@ def create_app(object_name): |
58 | 64 | # register our blueprints |
59 | 65 | app.register_blueprint(main) |
60 | 66 | |
67 | + app.config['BASIC_AUTH_USERNAME'] = os.getenv('ADMIN_USERNAME') | |
68 | + app.config['BASIC_AUTH_PASSWORD'] = os.getenv('ADMIN_PASSWORD') | |
69 | + | |
61 | 70 | # VERSION (move to version.py is necessary) |
62 | 71 | version = "0.0.0" |
63 | 72 | with open('VERSION', 'r') as version_file: |
... | ... | @@ -76,4 +85,20 @@ def create_app(object_name): |
76 | 85 | def markdown_filter(text): |
77 | 86 | return markdown(text) |
78 | 87 | |
88 | + # Authentication Gate for the Admin | |
89 | + @app.before_first_request | |
90 | + def restrict_admin_url(): | |
91 | + | |
92 | + # print('VF', app.view_functions) | |
93 | + | |
94 | + endpoint = 'admin.index' | |
95 | + url = url_for(endpoint) | |
96 | + admin_index = app.view_functions.pop(endpoint) | |
97 | + | |
98 | + @app.route(url, endpoint=endpoint) | |
99 | + @basic_auth.required | |
100 | + # @roles_required('admin') | |
101 | + def secure_admin_index(): | |
102 | + return admin_index() | |
103 | + | |
79 | 104 | return app | ... | ... |
flaskr/controllers/main_controller.py
... | ... | @@ -6,7 +6,7 @@ from flask import Blueprint, render_template, flash, request, redirect, \ |
6 | 6 | url_for, abort, send_from_directory |
7 | 7 | from os.path import join |
8 | 8 | |
9 | -from flaskr.extensions import cache | |
9 | +from flaskr.extensions import cache, basic_auth | |
10 | 10 | from flaskr.forms import LoginForm, EstimateForm |
11 | 11 | from flaskr.models import db, User, Estimation, StatusEnum |
12 | 12 | from flaskr.geocoder import CachedGeocoder |
... | ... | @@ -54,7 +54,7 @@ def estimate(): |
54 | 54 | estimation.status = StatusEnum.pending |
55 | 55 | estimation.origin_addresses = form.origin_addresses.data |
56 | 56 | estimation.destination_addresses = form.destination_addresses.data |
57 | - estimation.compute_optimal_destination = form.compute_optimal_destination.data | |
57 | + # estimation.compute_optimal_destination = form.compute_optimal_destination.data | |
58 | 58 | |
59 | 59 | db.session.add(estimation) |
60 | 60 | db.session.commit() |
... | ... | @@ -376,8 +376,8 @@ def compute(): # process the queue of estimation requests |
376 | 376 | return _respond(response) |
377 | 377 | |
378 | 378 | |
379 | -@main.route("/estimation/<public_id>.<format>") | |
380 | -def consult_estimation(public_id, format): | |
379 | +@main.route("/estimation/<public_id>.<extension>") | |
380 | +def consult_estimation(public_id, extension): | |
381 | 381 | try: |
382 | 382 | estimation = Estimation.query \ |
383 | 383 | .filter_by(public_id=public_id) \ |
... | ... | @@ -394,7 +394,7 @@ def consult_estimation(public_id, format): |
394 | 394 | |
395 | 395 | unavailable_statuses = [StatusEnum.pending, StatusEnum.working] |
396 | 396 | |
397 | - if format in ['xhtml', 'html', 'htm']: | |
397 | + if extension in ['xhtml', 'html', 'htm']: | |
398 | 398 | |
399 | 399 | if estimation.status in unavailable_statuses: |
400 | 400 | return render_template( |
... | ... | @@ -407,14 +407,14 @@ def consult_estimation(public_id, format): |
407 | 407 | estimation=estimation |
408 | 408 | ) |
409 | 409 | |
410 | - elif format in ['yaml', 'yml']: | |
410 | + elif extension in ['yaml', 'yml']: | |
411 | 411 | |
412 | 412 | if estimation.status in unavailable_statuses: |
413 | 413 | abort(404) |
414 | 414 | |
415 | 415 | return estimation.output_yaml |
416 | 416 | |
417 | - elif 'csv' == format: | |
417 | + elif 'csv' == extension: | |
418 | 418 | |
419 | 419 | if estimation.status in unavailable_statuses: |
420 | 420 | abort(404) |
... | ... | @@ -447,3 +447,11 @@ def consult_estimation(public_id, format): |
447 | 447 | |
448 | 448 | else: |
449 | 449 | abort(404) |
450 | + | |
451 | + | |
452 | +@main.route("/test") | |
453 | +@basic_auth.required | |
454 | +def dev_test(): | |
455 | + import os | |
456 | + | |
457 | + return os.getenv('ADMIN_USERNAME') | ... | ... |
flaskr/extensions.py
1 | 1 | from flask_admin import Admin |
2 | +from flask_basicauth import BasicAuth | |
2 | 3 | from flask_caching import Cache |
3 | 4 | from flask_debugtoolbar import DebugToolbarExtension |
4 | 5 | from flask_login import LoginManager |
... | ... | @@ -19,6 +20,7 @@ login_manager.login_view = "main.login" |
19 | 20 | login_manager.login_message_category = "warning" |
20 | 21 | |
21 | 22 | admin = Admin() |
23 | +basic_auth = BasicAuth() | |
22 | 24 | |
23 | 25 | |
24 | 26 | @login_manager.user_loader | ... | ... |
flaskr/templates/estimate.html
... | ... | @@ -73,9 +73,9 @@ |
73 | 73 | {{ render_field(form.destination_addresses) }} |
74 | 74 | <small class="form-text text-muted">Provide multiple destinations to compare them.</small> |
75 | 75 | </div> |
76 | - <div class="form-check form-group"> | |
77 | - {{ render_checkbox(form.compute_optimal_destination) }} | |
78 | - </div> | |
76 | +{# <div class="form-check form-group">#} | |
77 | +{# {{ render_checkbox(form.compute_optimal_destination) }}#} | |
78 | +{# </div>#} | |
79 | 79 | <div class="form-check form-group"> |
80 | 80 | {{ render_checkbox(form.use_atmosfair_rfi) }} |
81 | 81 | <small class="form-text text-muted">Disabled. Work in Progress. RFI=1.9</small> | ... | ... |
requirements.txt
... | ... | @@ -3,6 +3,7 @@ Flask==1.1.1 |
3 | 3 | # Flask Extensions |
4 | 4 | Flask-Admin==1.5.4 |
5 | 5 | Flask-Assets==0.12 |
6 | +Flask-BasicAuth==0.2.0 | |
6 | 7 | Flask-Caching==1.7.2 |
7 | 8 | Flask-DebugToolbar==0.10.0 |
8 | 9 | Flask-Login==0.4.0 |
... | ... | @@ -19,6 +20,7 @@ Markdown==3.1.1 |
19 | 20 | numpy==1.16.5 |
20 | 21 | enum34==1.1.6 |
21 | 22 | geopy==1.20.0 |
23 | +python-dotenv==0.10.3 | |
22 | 24 | |
23 | 25 | # Testing |
24 | 26 | pytest==3.0.5 | ... | ... |