summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-api/opendc/exts.py
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-07-02 16:47:40 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2021-07-02 18:09:58 +0200
commitfa7ffd9d1594a5bc9dba4fc65af0a4100988341b (patch)
treee3ce768109e3cb02a4ae4bfb9cda32ebf0e066e2 /opendc-web/opendc-web-api/opendc/exts.py
parenta2a5979bfb392565b55e489b6020aa391e782eb0 (diff)
api: Restrict API scopes
This change adds support for restricting API scopes in the OpenDC API server. This is necessary to make a distinction between runners and regular users.
Diffstat (limited to 'opendc-web/opendc-web-api/opendc/exts.py')
-rw-r--r--opendc-web/opendc-web-api/opendc/exts.py36
1 files changed, 35 insertions, 1 deletions
diff --git a/opendc-web/opendc-web-api/opendc/exts.py b/opendc-web/opendc-web-api/opendc/exts.py
index d24f7197..17dacd5e 100644
--- a/opendc-web/opendc-web-api/opendc/exts.py
+++ b/opendc-web/opendc-web-api/opendc/exts.py
@@ -2,10 +2,11 @@ import os
from functools import wraps
from flask import g, _request_ctx_stack
+from jose import jwt
from werkzeug.local import LocalProxy
from opendc.database import Database
-from opendc.auth import AuthContext, AsymmetricJwtAlgorithm, get_token
+from opendc.auth import AuthContext, AsymmetricJwtAlgorithm, get_token, AuthError
def get_db():
@@ -56,3 +57,36 @@ def requires_auth(f):
current_user = LocalProxy(lambda: getattr(_request_ctx_stack.top, 'current_user', None))
+
+
+def has_scope(required_scope):
+ """Determines if the required scope is present in the Access Token
+ Args:
+ required_scope (str): The scope required to access the resource
+ """
+ token = get_token()
+ unverified_claims = jwt.get_unverified_claims(token)
+ if unverified_claims.get("scope"):
+ token_scopes = unverified_claims["scope"].split()
+ for token_scope in token_scopes:
+ if token_scope == required_scope:
+ return True
+ return False
+
+
+def requires_scope(required_scope):
+ """Determines if the required scope is present in the Access Token
+ Args:
+ required_scope (str): The scope required to access the resource
+ """
+ def decorator(f):
+ @wraps(f)
+ def decorated(*args, **kwargs):
+ if not has_scope(required_scope):
+ raise AuthError({
+ "code": "Unauthorized",
+ "description": "You don't have access to this resource"
+ }, 403)
+ return f(*args, **kwargs)
+ return decorated
+ return decorator