validate bearer tokens against authnid
This commit is contained in:
parent
7e689dd120
commit
234bbcea0f
@ -33,7 +33,7 @@ class ApiClient(object):
|
|||||||
kwargs['body'] = dumps(kwargs['json'])
|
kwargs['body'] = dumps(kwargs['json'])
|
||||||
del kwargs['json']
|
del kwargs['json']
|
||||||
headers = kwargs.get('headers', {})
|
headers = kwargs.get('headers', {})
|
||||||
headers['Content-Type'] = 'application-json'
|
headers['Content-Type'] = 'application/json'
|
||||||
kwargs['headers'] = headers
|
kwargs['headers'] = headers
|
||||||
|
|
||||||
response = yield self.client.fetch(url, method=method, **kwargs)
|
response = yield self.client.fetch(url, method=method, **kwargs)
|
||||||
|
@ -17,6 +17,7 @@ ENV = os.getenv("TORNADO_ENV", "dev")
|
|||||||
def make_app(config):
|
def make_app(config):
|
||||||
|
|
||||||
authz_client = ApiClient(config["default"]["AUTHZ_BASE_URL"])
|
authz_client = ApiClient(config["default"]["AUTHZ_BASE_URL"])
|
||||||
|
authnid_client = ApiClient(config["default"]["AUTHNID_BASE_URL"])
|
||||||
|
|
||||||
routes = [
|
routes = [
|
||||||
url(r"/", Login, {"page": "login"}, name="main"),
|
url(r"/", Login, {"page": "login"}, name="main"),
|
||||||
@ -52,6 +53,7 @@ def make_app(config):
|
|||||||
cookie_secret=config["default"]["COOKIE_SECRET"],
|
cookie_secret=config["default"]["COOKIE_SECRET"],
|
||||||
debug=config['default'].getboolean('DEBUG')
|
debug=config['default'].getboolean('DEBUG')
|
||||||
)
|
)
|
||||||
|
app.authnid_client = authnid_client
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,11 +22,13 @@ 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.get_cookie('bearer-token'):
|
||||||
bearer_token = self.get_cookie('bearer-token')
|
bearer_token = self.get_cookie('bearer-token')
|
||||||
if validate_login_token(bearer_token):
|
valid = yield validate_login_token(self.application.authnid_client, bearer_token)
|
||||||
|
if valid:
|
||||||
self._start_session()
|
self._start_session()
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@ -39,9 +41,16 @@ def authenticated(method):
|
|||||||
return method(self, *args, **kwargs)
|
return method(self, *args, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
def validate_login_token(token):
|
@tornado.gen.coroutine
|
||||||
# check against authnid
|
def validate_login_token(client, token):
|
||||||
pass
|
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):
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
[default]
|
[default]
|
||||||
|
PORT=8000
|
||||||
ENVIRONMENT = dev
|
ENVIRONMENT = dev
|
||||||
DEBUG = true
|
DEBUG = true
|
||||||
AUTHZ_BASE_URL = http://localhost
|
AUTHZ_BASE_URL = http://localhost
|
||||||
PORT = 8000
|
AUTHNID_BASE_URL= http://localhost
|
||||||
COOKIE_SECRET = some-secret-please-replace
|
COOKIE_SECRET = some-secret-please-replace
|
||||||
|
@ -1,5 +1,35 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import tornado.web
|
import tornado.web
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
from atst.handler import validate_login_token
|
||||||
|
|
||||||
|
|
||||||
|
class MockApiResponse():
|
||||||
|
|
||||||
|
def __init__(self, code, json):
|
||||||
|
self.code = code
|
||||||
|
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
|
||||||
@ -11,25 +41,32 @@ def test_redirects_when_not_logged_in(http_client, base_url):
|
|||||||
assert response.error
|
assert response.error
|
||||||
assert response.headers["Location"] == "/login"
|
assert response.headers["Location"] == "/login"
|
||||||
|
|
||||||
|
|
||||||
@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):
|
||||||
monkeypatch.setattr("atst.handler.validate_login_token", lambda t: True)
|
with ThreadPoolExecutor(max_workers=1) as executor:
|
||||||
response = yield http_client.fetch(
|
monkeypatch.setattr(
|
||||||
base_url + "/home", headers={"Cookie": "bearer-token=anything"}
|
"atst.handler.validate_login_token",
|
||||||
)
|
lambda c,t: executor.submit(lambda: True),
|
||||||
assert response.headers['Set-Cookie'].startswith('atst')
|
)
|
||||||
assert response.code == 200
|
response = yield http_client.fetch(
|
||||||
assert not response.error
|
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.gen_test
|
||||||
def test_login_with_via_dev_endpoint(app, monkeypatch, http_client, base_url):
|
def test_login_with_via_dev_endpoint(app, monkeypatch, http_client, base_url):
|
||||||
response = yield http_client.fetch(
|
response = yield http_client.fetch(
|
||||||
base_url + "/login-dev", raise_error=False, follow_redirects=False
|
base_url + "/login-dev", raise_error=False, follow_redirects=False
|
||||||
)
|
)
|
||||||
assert response.headers['Set-Cookie'].startswith('atst')
|
assert response.headers["Set-Cookie"].startswith("atst")
|
||||||
assert response.code == 302
|
assert response.code == 302
|
||||||
assert response.headers["Location"] == "/home"
|
assert response.headers["Location"] == "/home"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gen_test
|
@pytest.mark.gen_test
|
||||||
@pytest.mark.skip(reason="need to work out auth error user paths")
|
@pytest.mark.skip(reason="need to work out auth error user paths")
|
||||||
def test_login_with_invalid_bearer_token(monkeypatch, http_client, base_url):
|
def test_login_with_invalid_bearer_token(monkeypatch, http_client, base_url):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user