handle auth via redirect with parameter

This commit is contained in:
dandds 2018-06-12 15:07:45 -04:00
parent 234bbcea0f
commit 4e61b08330
5 changed files with 49 additions and 50 deletions

View File

@ -4,6 +4,7 @@ import tornado.web
from tornado.web import url from tornado.web import url
from atst.handlers.main import MainHandler from atst.handlers.main import MainHandler
from atst.handlers.home import Home
from atst.handlers.login import Login from atst.handlers.login import Login
from atst.handlers.workspace import Workspace from atst.handlers.workspace import Workspace
from atst.handlers.request import Request from atst.handlers.request import Request
@ -20,7 +21,7 @@ def make_app(config):
authnid_client = ApiClient(config["default"]["AUTHNID_BASE_URL"]) authnid_client = ApiClient(config["default"]["AUTHNID_BASE_URL"])
routes = [ routes = [
url(r"/", Login, {"page": "login"}, name="main"), url(r"/", Home, {"page": "login"}, name="main"),
url(r"/login", Login, {"page": "login"}, name="login"), url(r"/login", Login, {"page": "login"}, name="login"),
url(r"/home", MainHandler, {"page": "home"}, name="home"), url(r"/home", MainHandler, {"page": "home"}, name="home"),
url( url(
@ -47,7 +48,7 @@ def make_app(config):
app = tornado.web.Application( app = tornado.web.Application(
routes, routes,
login_url="/login", login_url="/",
template_path = home.child('templates'), template_path = home.child('templates'),
static_path = home.child('static'), static_path = home.child('static'),
cookie_secret=config["default"]["COOKIE_SECRET"], cookie_secret=config["default"]["COOKIE_SECRET"],

View File

@ -22,17 +22,9 @@ helpers = {
def authenticated(method): def authenticated(method):
@functools.wraps(method) @functools.wraps(method)
@tornado.gen.coroutine
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
if not self.current_user: if not self.current_user:
if self.get_cookie('bearer-token'): if self.request.method in ("GET", "HEAD"):
bearer_token = self.get_cookie('bearer-token')
valid = yield validate_login_token(self.application.authnid_client, bearer_token)
if valid:
self._start_session()
else:
raise NotImplementedError
elif self.request.method in ("GET", "HEAD"):
url = self.get_login_url() url = self.get_login_url()
self.redirect(url) self.redirect(url)
return return
@ -41,17 +33,6 @@ def authenticated(method):
return method(self, *args, **kwargs) return method(self, *args, **kwargs)
return wrapper return wrapper
@tornado.gen.coroutine
def validate_login_token(client, token):
try:
response = yield client.post('/api/v1/validate', raise_error=False, json={"token": token})
return response.code == 200
except tornado.httpclient.HTTPError as error:
if error.response.code == 401:
return False
else:
raise error
class BaseHandler(tornado.web.RequestHandler): class BaseHandler(tornado.web.RequestHandler):
def get_template_namespace(self): def get_template_namespace(self):

10
atst/handlers/home.py Normal file
View File

@ -0,0 +1,10 @@
import tornado
from atst.handler import BaseHandler
class Home(BaseHandler):
def initialize(self, page):
self.page = page
def get(self):
self.render( '%s.html.to' % self.page, page = self.page )

View File

@ -1,10 +1,37 @@
import tornado import tornado
from atst.handler import BaseHandler from atst.handler import BaseHandler
class Login(BaseHandler): class Login(BaseHandler):
def initialize(self, page): def initialize(self, page):
self.page = page self.page = page
@tornado.gen.coroutine
def get(self): def get(self):
self.render( '%s.html.to' % self.page, page = self.page ) token = self.get_query_argument("bearer-token")
if token:
valid = yield self._validate_login_token(token)
if valid:
self._start_session()
self.redirect("/home")
return
url = self.get_login_url()
self.redirect(url)
return
@tornado.gen.coroutine
def _validate_login_token(self, token):
try:
response = yield self.application.authnid_client.post(
"/api/v1/validate", json={"token": token}
)
return response.code == 200
except tornado.httpclient.HTTPError as error:
if error.response.code == 401:
return False
else:
raise error

View File

@ -1,7 +1,6 @@
import pytest import pytest
import tornado.web import tornado.web
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from atst.handler import validate_login_token
class MockApiResponse(): class MockApiResponse():
@ -11,27 +10,6 @@ class MockApiResponse():
self.json = json self.json = json
@pytest.mark.gen_test
def test_successful_validate_login_token(monkeypatch, app):
monkeypatch.setattr(
"atst.api_client.ApiClient.get",
lambda x,
y,
json=None: MockApiResponse(200, {"status": "success"}),
)
assert validate_login_token(app.authnid_client, "abc-123")
@pytest.mark.gen_test
def test_unsuccessful_validate_login_token(monkeypatch, app):
monkeypatch.setattr(
"atst.api_client.ApiClient.get",
lambda x,y,json=None: MockApiResponse(401, {"status": "error"}),
)
valid = yield validate_login_token(app.authnid_client, "abc-123")
assert not valid
@pytest.mark.gen_test @pytest.mark.gen_test
def test_redirects_when_not_logged_in(http_client, base_url): def test_redirects_when_not_logged_in(http_client, base_url):
response = yield http_client.fetch( response = yield http_client.fetch(
@ -39,22 +17,24 @@ def test_redirects_when_not_logged_in(http_client, base_url):
) )
assert response.code == 302 assert response.code == 302
assert response.error assert response.error
assert response.headers["Location"] == "/login" assert response.headers["Location"] == "/"
@pytest.mark.gen_test @pytest.mark.gen_test
def test_login_with_valid_bearer_token(app, monkeypatch, http_client, base_url): def test_login_with_valid_bearer_token(app, monkeypatch, http_client, base_url):
with ThreadPoolExecutor(max_workers=1) as executor: with ThreadPoolExecutor(max_workers=1) as executor:
monkeypatch.setattr( monkeypatch.setattr(
"atst.handler.validate_login_token", "atst.handlers.login.Login._validate_login_token",
lambda c,t: executor.submit(lambda: True), lambda c,t: executor.submit(lambda: True),
) )
response = yield http_client.fetch( response = yield http_client.fetch(
base_url + "/home", headers={"Cookie": "bearer-token=anything"} base_url + "/login?bearer-token=abc-123",
follow_redirects=False,
raise_error=False
) )
assert response.headers["Set-Cookie"].startswith("atst") assert response.headers["Set-Cookie"].startswith("atst")
assert response.code == 200 assert response.headers['Location'] == '/home'
assert not response.error assert response.code == 302
@pytest.mark.gen_test @pytest.mark.gen_test