Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .dev/dev-jwt-key
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
14 changes: 14 additions & 0 deletions .dev/dev-jwt-key.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8DAocd7+LjrW0NucSPC
cBnO7Inu7soRVCmaOjt1HcQHdCV48WzPKAWxz/FQyVqHbUf+UZkw1ryi7CASf9n3
5Aia/JrYnW5hG1ti455GhgEUcItvB7dpscK9N3DeeyNv4tk3FokdhiG/92LvujhM
xFPjO60jex0H2yieR7Osx/AwCEHNh6opct+EYNkoD1G2cXfCOCdZxpzBttU6jsvO
fX3lDykWrZHSC0yfYpZU+9M4qtnjZbpKK/Vpw4Ic5qTpYm9rBkF3rDbQeY2O5nw+
3S996ckMR5jKXb4aRxnX2LawQ2MmKmmYTRKMc7KG/vXPOH2qDcr/+caP5ZP+epTo
5Rz4t88tuhTlj+KRefs1LM3dbq5rLnIbe7zmTuyzTSlA+qTMkmt42dZ4mAH0huEH
Nd931owRDlLvl/Py3by4D+RZo+er8D+wrkUQk4O+s6SYNqfdYphSIXgIbTeKny48
E3Ph87fXQz4vgbJPFk1dGi9xm1dsNLrkMoapvZwdN7bSJ5zqjro71M4HnFRUAGdY
nM353W5uKwEHSmR6TcOUastQ7qJDY6DYNTKCte/XXQmgcResBtWRl2LVz7KepXHJ
rXjXcLv5OaJMRe9PklrWM3SOGpKfQ2CP3XNvDvu2x1kb3sikzjVdtl4glcEI4Ow6
8Ani73dDyAIVcXPu2CtGyksCAwEAAQ==
-----END PUBLIC KEY-----
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ test: build
test-coverage:
${DOCKER_COMPOSE} run ${RESOURCES_CONTAINER} py.test --cov-report html --cov=app/ tests/

# Usage: make test-single tests/unit/test_api_key.py::test_get_api_key
.PHONY: test-single
test-single: build
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has nothing to do with this PR in particular, I just realized it was useful and wanted to use it

${DOCKER_COMPOSE} run ${RESOURCES_CONTAINER} /bin/bash -c "py.test --cov=app/ $(shell echo ${ARGS})"

.PHONY: lint
lint:
${DOCKER_COMPOSE} run ${RESOURCES_CONTAINER} flake8 . --exclude migrations --statistics --count
Expand Down
48 changes: 47 additions & 1 deletion app/api/auth.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import uuid
import os
from enum import Enum

import requests
from app import db
from app.models import Key
from app.utils import setup_logger, standardize_response
from flask import g, request

from jwt import decode, InvalidSignatureError, ExpiredSignatureError

PUBLIC_KEY = os.environ.get('JWT_PUBLIC_KEY', open(".dev/dev-jwt-key.pub").read())

auth_logger = setup_logger('auth_logger')
create_logger = setup_logger('create_auth_logger')
update_logger = setup_logger('update_auth_logger')
Expand Down Expand Up @@ -85,10 +91,50 @@ def rotate_key(key, session):
return None


def jwt_to_key():
auth_header = request.headers.get("authorization")
if not auth_header:
return None
auth_parts = auth_header.split(" ")
if len(auth_parts) != 2:
return None
_, token = auth_parts
try:
decoded_token = decode(
token, PUBLIC_KEY, algorithms="RS256"
)
request.decoded_token = decoded_token
except InvalidSignatureError:
return None
except ExpiredSignatureError:
return None
if 'exp' not in decoded_token:
return None
return get_api_key_from_authenticated_email(decoded_token['email'])


# NOTE: this function assumes the email has already been authenticated
def get_api_key_from_authenticated_email(email):
apikey = Key.query.filter_by(email=email).first()

if apikey and apikey.blacklisted:
return None

if not apikey:
apikey = create_new_apikey(email, db.session)
if not apikey:
raise Exception
return apikey


def authenticate(func):
def wrapper(*args, **kwargs):
apikey = request.headers.get('x-apikey')
key = Key.query.filter_by(apikey=apikey, blacklisted=False).first()
try:
filters = {'apikey': apikey, 'blacklisted': False}
key = Key.query.filter_by(**filters).first() if apikey else jwt_to_key()
except Exception:
return standardize_response(status_code=500)

if not key:
return standardize_response(status_code=401)
Expand Down
Loading