Commit ca9af7e5 authored by Yakubov, Sergey's avatar Yakubov, Sergey
Browse files

added authorization

parent 7f157310
Loading
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
[report]
omit =
    tests/*
    app/brokers/local/*
 No newline at end of file
    app/brokers/filesys/*
    app/auth/keycloak.py
    app/main.py
 No newline at end of file

app/auth/__init__.py

0 → 100644
+3 −0
Original line number Diff line number Diff line
from app.auth.abstract import AuthBroker

__all__ = ["AuthBroker"]

app/auth/abstract.py

0 → 100644
+11 −0
Original line number Diff line number Diff line
from abc import ABC, abstractmethod

from app.common import UserInfo


class AuthBroker(ABC):
    """an abstract class for auth broker"""

    @abstractmethod
    def process_user_token(self, token: str) -> UserInfo:
        pass

app/auth/keycloak.py

0 → 100644
+39 −0
Original line number Diff line number Diff line
import jwt
import requests

from app.auth import AuthBroker
from app.common import AuthError, ServiceError, UserInfo
from app.settings import settings


class KeycloakBroker(AuthBroker):
    """Keycloak broker"""

    def _refresh_token(self, token: str) -> UserInfo:
        data = {
            "grant_type": "refresh_token",
            "client_id": settings.keycloak_client,
            "client_secret": settings.keycloak_secret,
            "refresh_token": token,
        }
        response = requests.post(settings.keycloak_url, data=data, timeout=3)
        token = response.json()["access_token"]
        username = jwt.decode(token, options={"verify_signature": False})[
            "preferred_username"
        ]
        return UserInfo(user_name=username)

    def process_user_token(self, token: str) -> UserInfo:
        if not settings.rdb_authorize:
            return UserInfo(user_name=token)
        try:
            user_info = self._refresh_token(token)
        except requests.HTTPError as e:
            print(e.response.status_code)
            if e.response.status_code == 401:
                raise AuthError from e
            raise ServiceError from e
        except Exception as e:
            raise ServiceError from e

        return user_info
+19 −7
Original line number Diff line number Diff line
@@ -2,8 +2,9 @@ import base64
import os
import shutil

from app.auth import AuthBroker
from app.brokers import RemoteDataBroker
from app.common import DownloadData, UploadData
from app.common import DownloadData, UploadData, UserInfo
from app.settings import settings


@@ -15,9 +16,9 @@ def b64d(value: str) -> str:
    return base64.b64decode(value).decode()


def encode_filename(data: UploadData) -> str:
def encode_filename(user_info: UserInfo, data: UploadData) -> str:
    encoded = (
        b64e(data.user)
        b64e(user_info.user_name)
        + "%"
        + b64e(data.dataset)
        + "%"
@@ -31,7 +32,8 @@ def decode_filename(encoded: str) -> str:
    return decoded


def copy_complete(source: str, target: str) -> None:
def copy_complete(_user_info: UserInfo, source: str, target: str) -> None:
    # TODO : check user from _user_info allowed to read/write a file
    # copy content, stat-info (mode too), timestamps...
    shutil.copy2(source, target)
    # copy owner and group
@@ -42,13 +44,23 @@ def copy_complete(source: str, target: str) -> None:
class FilesysBroker(RemoteDataBroker):
    """a broker that uses a (local) filesystem to store remote data"""

    def __init__(self, broker: AuthBroker):
        self._auth_broker = broker

    def _authorize(self, token: str) -> UserInfo:
        return self._auth_broker.process_user_token(token)

    def upload(self, data: UploadData) -> str:
        uid = encode_filename(data)
        copy_complete(data.input_path, settings.rdb_storage_path + "/" + uid)
        user_info = self._authorize(data.token)
        uid = encode_filename(user_info, data)
        copy_complete(user_info, data.input_path, settings.rdb_storage_path + "/" + uid)
        return uid

    def download(self, data: DownloadData) -> None:
        user_info = self._authorize(data.token)
        fname = decode_filename(data.uid)
        copy_complete(
            settings.rdb_storage_path + "/" + data.uid, data.output_path + "/" + fname
            user_info,
            settings.rdb_storage_path + "/" + data.uid,
            data.output_path + "/" + fname,
        )
Loading