From 25db6fabbe28b390877072e85191ca15add3bb3c Mon Sep 17 00:00:00 2001 From: dandds Date: Mon, 11 Jun 2018 15:54:16 -0400 Subject: [PATCH] WIP: authentication handling for ATST --- atst/app.py | 4 +++- atst/handler.py | 33 +++++++++++++++++++++++++++++++++ atst/handlers/login.py | 10 ++++++++++ atst/handlers/main.py | 4 +++- atst/handlers/request.py | 3 ++- atst/handlers/request_new.py | 3 ++- atst/handlers/workspace.py | 6 ++---- tests/test_auth.py | 34 ++++++++++++++++++++++++++++++++++ 8 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 atst/handlers/login.py create mode 100644 tests/test_auth.py diff --git a/atst/app.py b/atst/app.py index 2cbe86f0..07f35cc2 100644 --- a/atst/app.py +++ b/atst/app.py @@ -4,6 +4,7 @@ import tornado.web from tornado.web import url from atst.handlers.main import MainHandler +from atst.handlers.login import Login from atst.handlers.workspace import Workspace from atst.handlers.request import Request from atst.handlers.request_new import RequestNew @@ -16,7 +17,8 @@ def make_app(config): authz_client = ApiClient(config['default']['AUTHZ_BASE_URL']) app = tornado.web.Application([ - url( r"/", MainHandler, {'page': 'login'}, name='login' ), + url( r"/", Login, {'page': 'login'}, name='main' ), + url( r"/login", Login, {'page': 'login'}, name='login' ), url( r"/home", MainHandler, {'page': 'home'}, name='home' ), url( r"/workspaces", Workspace, diff --git a/atst/handler.py b/atst/handler.py index baa6f0ef..8af83bf3 100644 --- a/atst/handler.py +++ b/atst/handler.py @@ -1,4 +1,5 @@ import os +import functools from webassets import Environment, Bundle import tornado.web from atst.home import home @@ -19,9 +20,41 @@ helpers = { 'assets': assets } +def authenticated(method): + @functools.wraps(method) + def wrapper(self, *args, **kwargs): + if not self.current_user: + if self.get_cookie('bearer-token'): + bearer_token = self.get_cookie('bearer-token') + if validate_login_token(bearer_token): + self._start_session() + else: + raise NotImplementedError + elif self.request.method in ("GET", "HEAD"): + url = self.get_login_url() + self.redirect(url) + return + else: + raise tornado.web.HTTPError(403) + return method(self, *args, **kwargs) + return wrapper + +def validate_login_token(token): + # check against authnid + pass + class BaseHandler(tornado.web.RequestHandler): def get_template_namespace(self): ns = super(BaseHandler, self).get_template_namespace() ns.update(helpers) return ns + + def get_current_user(self): + if self.get_secure_cookie('atst'): + return True + else: + False + + def _start_session(self): + self.set_secure_cookie('atst', 'valid-user-session') diff --git a/atst/handlers/login.py b/atst/handlers/login.py new file mode 100644 index 00000000..b3012288 --- /dev/null +++ b/atst/handlers/login.py @@ -0,0 +1,10 @@ +import tornado +from atst.handler import BaseHandler + +class Login(BaseHandler): + + def initialize(self, page): + self.page = page + + def get(self): + self.render( '%s.html.to' % self.page, page = self.page ) diff --git a/atst/handlers/main.py b/atst/handlers/main.py index 62c6fa7e..05772b19 100644 --- a/atst/handlers/main.py +++ b/atst/handlers/main.py @@ -1,9 +1,11 @@ -from atst.handler import BaseHandler +import atst +from atst.handler import BaseHandler, authenticated class MainHandler(BaseHandler): def initialize(self, page): self.page = page + @authenticated def get(self): self.render( '%s.html.to' % self.page, page = self.page ) diff --git a/atst/handlers/request.py b/atst/handlers/request.py index 3ec27477..1041cbd8 100644 --- a/atst/handlers/request.py +++ b/atst/handlers/request.py @@ -1,4 +1,4 @@ -from atst.handler import BaseHandler +from atst.handler import BaseHandler, authenticated mock_requests = [ { @@ -31,5 +31,6 @@ class Request(BaseHandler): def initialize(self, page): self.page = page + @authenticated def get(self): self.render('requests.html.to', page = self.page, requests = mock_requests ) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index aa405e3a..ad20554d 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -1,4 +1,4 @@ -from atst.handler import BaseHandler +from atst.handler import BaseHandler, authenticated class RequestNew(BaseHandler): screens = [ @@ -22,6 +22,7 @@ class RequestNew(BaseHandler): def initialize(self, page): self.page = page + @authenticated def get(self, screen = 1): self.render( 'requests/screen-%d.html.to' % int(screen), page = self.page, diff --git a/atst/handlers/workspace.py b/atst/handlers/workspace.py index bbed8f6d..05600208 100644 --- a/atst/handlers/workspace.py +++ b/atst/handlers/workspace.py @@ -1,5 +1,4 @@ -from atst.handler import BaseHandler -import requests +from atst.handler import BaseHandler, authenticated import tornado.gen mock_workspaces = [ @@ -13,8 +12,6 @@ mock_workspaces = [ } ] -session = requests.Session() - class Workspace(BaseHandler): def initialize(self, page, authz_client): @@ -22,5 +19,6 @@ class Workspace(BaseHandler): self.authz_client = authz_client @tornado.gen.coroutine + @authenticated def get(self): self.render( 'workspaces.html.to', page = self.page, workspaces = mock_workspaces ) diff --git a/tests/test_auth.py b/tests/test_auth.py new file mode 100644 index 00000000..edcd356e --- /dev/null +++ b/tests/test_auth.py @@ -0,0 +1,34 @@ +import pytest +import tornado.web + + +@pytest.mark.gen_test +def test_redirects_when_not_logged_in(http_client, base_url): + response = yield http_client.fetch( + base_url + "/home", raise_error=False, follow_redirects=False + ) + assert response.code == 302 + assert response.error + assert response.headers["Location"] == "/login" + + +@pytest.mark.gen_test +def test_login_with_valid_bearer_token(app, monkeypatch, http_client, base_url): + monkeypatch.setattr("atst.handler.validate_login_token", lambda t: True) + response = yield http_client.fetch( + base_url + "/home", headers={"Cookie": "bearer-token=anything"} + ) + assert response.headers['Set-Cookie'].startswith('atst') + assert response.code == 200 + assert not response.error + + +@pytest.mark.gen_test +@pytest.mark.skip(reason="need to work out auth error user paths") +def test_login_with_invalid_bearer_token(monkeypatch, http_client, base_url): + monkeypatch.setattr("atst.handler.validate_login_token", lambda t: False) + response = yield http_client.fetch( + base_url + "/home", + raise_error=False, + headers={"Cookie": "bearer-token=anything"}, + )