From be079a62dc5ef5ae9099a1d3100e6630618177ce Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 6 Aug 2018 10:43:44 -0400 Subject: [PATCH] apply auth requirement to virtually all endpoints --- atst/domain/auth.py | 2 +- .../routes/requests/financial_verification.py | 4 ++++ atst/routes/requests/index.py | 2 ++ atst/routes/requests/requests_form.py | 6 ++++- atst/routes/workspaces.py | 4 ++++ tests/conftest.py | 9 ++++++++ tests/routes/test_financial_verification.py | 1 + tests/routes/test_request_new.py | 6 +++-- tests/routes/test_request_submit.py | 6 +++-- tests/test_auth.py | 23 ++++++++++++++++++- tests/test_routes.py | 7 +++--- 11 files changed, 59 insertions(+), 11 deletions(-) diff --git a/atst/domain/auth.py b/atst/domain/auth.py index d1a8ec36..7d1f4aa7 100644 --- a/atst/domain/auth.py +++ b/atst/domain/auth.py @@ -1,5 +1,5 @@ from functools import wraps -from flask import g, request, redirect, url_for, session +from flask import g, redirect, url_for, session from atst.domain.users import Users diff --git a/atst/routes/requests/financial_verification.py b/atst/routes/requests/financial_verification.py index 38420287..d4b64923 100644 --- a/atst/routes/requests/financial_verification.py +++ b/atst/routes/requests/financial_verification.py @@ -4,9 +4,11 @@ from flask import request as http_request from . import requests_bp from atst.domain.requests import Requests from atst.forms.financial import FinancialForm +from atst.domain.auth import login_required @requests_bp.route("/requests/verify/", methods=["GET"]) +@login_required def financial_verification(request_id=None): request = Requests.get(request_id) form = FinancialForm(data=request.body.get("financial_verification")) @@ -16,6 +18,7 @@ def financial_verification(request_id=None): @requests_bp.route("/requests/verify/", methods=["POST"]) +@login_required def update_financial_verification(request_id): post_data = http_request.form existing_request = Requests.get(request_id) @@ -40,5 +43,6 @@ def update_financial_verification(request_id): @requests_bp.route("/requests/financial_verification_submitted") +@login_required def financial_verification_submitted(): pass diff --git a/atst/routes/requests/index.py b/atst/routes/requests/index.py index 0de74bd2..b415163b 100644 --- a/atst/routes/requests/index.py +++ b/atst/routes/requests/index.py @@ -3,6 +3,7 @@ from flask import render_template, g from . import requests_bp from atst.domain.requests import Requests +from atst.domain.auth import login_required def map_request(user, request): @@ -20,6 +21,7 @@ def map_request(user, request): @requests_bp.route("/requests", methods=["GET"]) +@login_required def requests_index(): requests = [] if ( diff --git a/atst/routes/requests/requests_form.py b/atst/routes/requests/requests_form.py index cd12fbcd..8ebd20ca 100644 --- a/atst/routes/requests/requests_form.py +++ b/atst/routes/requests/requests_form.py @@ -3,10 +3,11 @@ from flask import g, redirect, render_template, url_for, request as http_request from . import requests_bp from atst.domain.requests import Requests from atst.routes.requests.jedi_request_flow import JEDIRequestFlow +from atst.domain.auth import login_required -@requests_bp.route("/requests/new", defaults={"screen": 1}) @requests_bp.route("/requests/new/", methods=["GET"]) +@login_required def requests_form_new(screen): jedi_flow = JEDIRequestFlow(screen, request=None) @@ -25,6 +26,7 @@ def requests_form_new(screen): "/requests/new/", methods=["GET"], defaults={"request_id": None} ) @requests_bp.route("/requests/new//", methods=["GET"]) +@login_required def requests_form_update(screen=1, request_id=None): request = Requests.get(request_id) if request_id is not None else None jedi_flow = JEDIRequestFlow(screen, request, request_id=request_id) @@ -45,6 +47,7 @@ def requests_form_update(screen=1, request_id=None): "/requests/new/", methods=["POST"], defaults={"request_id": None} ) @requests_bp.route("/requests/new//", methods=["POST"]) +@login_required def requests_update(screen=1, request_id=None): screen = int(screen) post_data = http_request.form @@ -89,6 +92,7 @@ def requests_update(screen=1, request_id=None): @requests_bp.route("/requests/submit/", methods=["POST"]) +@login_required def requests_submit(request_id=None): request = Requests.get(request_id) Requests.submit(request) diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py index e614c08c..50c96dd6 100644 --- a/atst/routes/workspaces.py +++ b/atst/routes/workspaces.py @@ -1,6 +1,7 @@ from flask import Blueprint, render_template from atst.domain.workspaces import Projects, Members +from atst.domain.auth import login_required bp = Blueprint("workspaces", __name__) @@ -16,11 +17,13 @@ mock_workspaces = [ @bp.route("/workspaces") +@login_required def workspaces(): return render_template("workspaces.html", page=5, workspaces=mock_workspaces) @bp.route("/workspaces//projects") +@login_required def workspace_projects(workspace_id): projects_repo = Projects() projects = projects_repo.get_many(workspace_id) @@ -30,6 +33,7 @@ def workspace_projects(workspace_id): @bp.route("/workspaces//members") +@login_required def workspace_members(workspace_id): members_repo = Members() members = members_repo.get_many(workspace_id) diff --git a/tests/conftest.py b/tests/conftest.py index 34dc3d41..bdc59286 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ import alembic.command from atst.app import make_app, make_config from atst.database import db as _db +from .mocks import MOCK_USER @pytest.fixture(scope='session') @@ -79,3 +80,11 @@ def dummy_form(): @pytest.fixture def dummy_field(): return DummyField() + +@pytest.fixture +def user_session(monkeypatch): + + def set_user_session(user = MOCK_USER): + monkeypatch.setattr("atst.domain.auth.get_current_user", lambda *args: user) + + return set_user_session diff --git a/tests/routes/test_financial_verification.py b/tests/routes/test_financial_verification.py index 35502523..d7c29e18 100644 --- a/tests/routes/test_financial_verification.py +++ b/tests/routes/test_financial_verification.py @@ -32,6 +32,7 @@ class TestPENumberInForm: def _set_monkeypatches(self, monkeypatch): monkeypatch.setattr("atst.forms.financial.FinancialForm.validate", lambda s: True) monkeypatch.setattr("atst.domain.requests.Requests.get", lambda i: MOCK_REQUEST) + monkeypatch.setattr("atst.domain.auth.get_current_user", lambda *args: MOCK_USER) def submit_data(self, client, data): response = client.post( diff --git a/tests/routes/test_request_new.py b/tests/routes/test_request_new.py index 5e9b6c19..320802b9 100644 --- a/tests/routes/test_request_new.py +++ b/tests/routes/test_request_new.py @@ -15,7 +15,8 @@ MOCK_REQUEST = RequestFactory.create( ) -def test_submit_invalid_request_form(monkeypatch, client): +def test_submit_invalid_request_form(monkeypatch, client, user_session): + user_session() response = client.post( "/requests/new/1", headers={"Content-Type": "application/x-www-form-urlencoded"}, @@ -24,7 +25,8 @@ def test_submit_invalid_request_form(monkeypatch, client): assert re.search(ERROR_CLASS, response.data.decode()) -def test_submit_valid_request_form(monkeypatch, client): +def test_submit_valid_request_form(monkeypatch, client, user_session): + user_session() monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) response = client.post( diff --git a/tests/routes/test_request_submit.py b/tests/routes/test_request_submit.py index 3df719df..428e056e 100644 --- a/tests/routes/test_request_submit.py +++ b/tests/routes/test_request_submit.py @@ -7,7 +7,8 @@ def _mock_func(*args, **kwargs): return RequestFactory.create() -def test_submit_reviewed_request(monkeypatch, client): +def test_submit_reviewed_request(monkeypatch, client, user_session): + user_session() monkeypatch.setattr("atst.domain.requests.Requests.get", _mock_func) monkeypatch.setattr("atst.domain.requests.Requests.submit", _mock_func) monkeypatch.setattr("atst.models.request.Request.status", "pending") @@ -22,7 +23,8 @@ def test_submit_reviewed_request(monkeypatch, client): assert "modal" not in response.headers["Location"] -def test_submit_autoapproved_reviewed_request(monkeypatch, client): +def test_submit_autoapproved_reviewed_request(monkeypatch, client, user_session): + user_session() monkeypatch.setattr("atst.domain.requests.Requests.get", _mock_func) monkeypatch.setattr("atst.domain.requests.Requests.submit", _mock_func) monkeypatch.setattr("atst.models.request.Request.status", "approved") diff --git a/tests/test_auth.py b/tests/test_auth.py index 8d6c2e60..f72483f0 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,4 +1,4 @@ -from flask import session +from flask import session, url_for from .mocks import DOD_SDN @@ -31,3 +31,24 @@ def test_unsuccessful_login_redirect(client, monkeypatch): assert resp.status_code == 302 assert "unauthorized" in resp.headers["Location"] assert "user_id" not in session + +UNPROTECTED_ROUTES = ["/", "/login-dev", "/login-redirect", "/unauthorized"] + +# checks that all of the routes in the app are protected by auth +def test_protected_route(client, app): + for rule in app.url_map.iter_rules(): + args = [1] * len(rule.arguments) + mock_args = dict(zip(rule.arguments, args)) + _n, route = rule.build(mock_args) + if route in UNPROTECTED_ROUTES or "/static" in route: + continue + + if "GET" in rule.methods: + resp = client.get(route) + assert resp.status_code == 302 + assert resp.headers["Location"] == "http://localhost/" + + if "POST" in rule.methods: + resp = client.post(route) + assert resp.status_code == 302 + assert resp.headers["Location"] == "http://localhost/" diff --git a/tests/test_routes.py b/tests/test_routes.py index 1c050c84..74860472 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -5,14 +5,13 @@ import pytest "/home", "/workspaces", "/requests", - "/requests/new", - "/requests/new/2", + "/requests/new/1", "/users", "/reports", "/calculator", )) -def test_routes(path, client, monkeypatch): - monkeypatch.setattr("atst.domain.auth.get_current_user", lambda *args: True) +def test_routes(path, client, user_session): + user_session() response = client.get(path) assert response.status_code == 200