diff --git a/.gitignore b/.gitignore index c3861c8..f317753 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ dist/ __pycache__/ .tox test-results/ +.env \ No newline at end of file diff --git a/accounts/middleware.py b/accounts/middleware.py new file mode 100644 index 0000000..46b939d --- /dev/null +++ b/accounts/middleware.py @@ -0,0 +1,54 @@ +from django.http import HttpResponseForbidden, HttpResponseBadRequest, HttpResponseServerError +from django.shortcuts import redirect +from django.conf import settings +import requests +import re +from jwcrypto import jwt, jwk +from accounts.views import get_redirect_uri + +class LoginRequiredMiddleware: + def __init__(self, get_response): + self.get_response = get_response + self.EXEMPT_URLS = [ + r"^accounts/login/$", + r"^accounts/callback/$", + r"^accounts/logout/$", + r"^accounts/token/$", + ] + + def handle_no_permission(self, request): + return redirect(get_redirect_uri(request)) + + def add_new_exempt_urls(self): + pass + # EXAMPLE USAGE + # self.EXEMPT_URLS.append(r"^accounts/new_exempt_url/$") + # This can be overriden in the subclass + + def __call__(self, request): + self.add_new_exempt_urls() + regex_list = [re.compile(url) for url in self.EXEMPT_URLS] + if any(url.match(request.path) for url in regex_list): + return self.get_response(request) + + try: + key = jwk.JWK() + key.import_key(**(requests.get("https://platform.pennlabs.org/accounts/.well-known/jwks.json").json()['keys'][0])) + + token = request.headers.get("Authorization") + if token is None: + return HttpResponseBadRequest(content="No Authorization header") + + token = token.split(" ") + if len(token) != 2 or token[0] != "Bearer": + return HttpResponseBadRequest(content="Invalid Authorization header") + + try: + token = jwt.JWT(key=key, jwt=token[1]) + except Exception as e: + return HttpResponseForbidden(content="Invalid token") + + return self.get_response(request) + except Exception as e: + print(e) + return HttpResponseServerError(content=str(e)) \ No newline at end of file diff --git a/tests/accounts/test_authentication.py b/tests/accounts/test_authentication.py index b74ccd8..62db38a 100644 --- a/tests/accounts/test_authentication.py +++ b/tests/accounts/test_authentication.py @@ -18,7 +18,7 @@ def setUp(self): self.csrf_client = APIClient(enforce_csrf_checks=True) self.path = "/token/" self.header_prefix = "Bearer " - self.auth = f"{self.header_prefix}abc" + self.auth = f"{self.header_prefix}eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJSUzI1NiIsICJraWQiOiAiZ2JoaHZzMmRTX2NDcjYwN0tzb1kzdjBNdjFpRlJkUUV2Z2xfSUVKZjBHYyJ9.eyJhdWQiOiAiNG12aUxodGo4N05LaHFCRFhsVjZDaXRmNWZZb015UXpSR05tWmRpaCIsICJpYXQiOiAxNzMxODY4MjQyLCAiYXRfaGFzaCI6ICIyRkZIeHVVaVpoRWE4MHBVWkRMR3d3IiwgInN1YiI6ICIwNjQ1MTgwMy01MWNhLTQ4OWUtYmY0OC05NWI3Y2Q0OTViOTEiLCAibmFtZSI6ICJTcml0YW4gTW90YXRpIiwgImVtYWlsIjogInNyaXRhbkBzZWFzLnVwZW5uLmVkdSIsICJwZW5ua2V5IjogInNyaXRhbiIsICJwZW5uaWQiOiA3NzcwOTE2MywgImlzX3N0YWZmIjogZmFsc2UsICJpc19hY3RpdmUiOiB0cnVlLCAiaXNzIjogImh0dHA6Ly9wbGF0Zm9ybS5wZW5ubGFicy5vcmcvYWNjb3VudCIsICJleHAiOiAxNzMxOTA0MjQyLCAiYXV0aF90aW1lIjogMTczMTcwOTEzMSwgImp0aSI6ICJmMjVhMGQ5NS0yZDJhLTRkOWYtYTNiNC05Yzk4Y2Y4NGZkYTIifQ.CpMIQVHBeQgvfqw0nGknYOXttNfiOphFGsFvlVVO3Jv1zSR577nOSIU-CQ_NBSmryY0DbWdvoMfcnmUgwmTUZa65HwKPfiSZD3UW47yqKhRSsPZqCDFCNrAl8o5ooVi3glmJuj4H4MQeCg7o44jXQk8jn2wzDW21Q7Tp_D6ubj_u1vMjcQ0ioa_EUj7ycV3A6SFCbhbaV1zyo_Trbz_4bDsnB9Ze4wkDW2ml5C1epqHnc12LyWeYGlptadchQoel5i9Dp4OGUj-fSVHKQzzggyhwiBk664GYnq1pIZiA-BVssFxp3fxBwe4-z6RVIY5n_mGDFfwtRngql5aGv-iyuK5d9Evvt-bTkSmU_uobhgGrbL-HiRcGrf2zOmS4rXGiiHpX4nIFKPWMJfS4k_gjegyz6rfu41iogto5IyCtmOEHx3-DbRUBi1qzSPCDURGODgjRY3vYEpmyPWJpOq0MazwtEytQMvFTPmBuRrvbJtCLF169xEb1d-km5K98KqLCJXZ8JftFLTYuyNP0NlWf3vDj9n25NQEG2fgzhbjl16XPmFB8Cri6tilD5Zr4nIE9JfTSmADgnjiHyXInhD9zx6rvr723R5_03QJRiR8W4xQpBaM1-4zZ99kkSRS9LaQoPoaVoGIWo_O--LAHRuWCvIv1itnqCcpdoH-c30x1pF8" self.user = User.objects.create(id=123, username="username") self.headers = {} diff --git a/tests/settings.py b/tests/settings.py index d16374d..c6ba934 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -21,6 +21,7 @@ "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", + "accounts.middleware.LoginRequiredMiddleware" ] ROOT_URLCONF = "tests.urls"