Skip to content
Snippets Groups Projects
Commit e8298f03 authored by Christian Boettcher's avatar Christian Boettcher
Browse files

add authenticaiton to api

addtoken  endpoint, add me endpoint
add token management and verification
parent 8eeaef64
Branches
Tags
No related merge requests found
from typing import Optional from typing import Optional
from typing import Dict from typing import Dict
from fastapi import FastAPI from fastapi import FastAPI, HTTPException, status
from fastapi import HTTPException from fastapi.param_functions import Depends
from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
from pydantic import BaseModel from datetime import timedelta
from .storage import JsonFileStorageAdapter from .storage import JsonFileStorageAdapter
from .storage import AbstractLocationDataStorageAdapter from .storage import AbstractLocationDataStorageAdapter
...@@ -13,16 +14,26 @@ from .storage import LocationDataType ...@@ -13,16 +14,26 @@ from .storage import LocationDataType
from .config import ApiserverSettings from .config import ApiserverSettings
from .security import User, AbstractDBInterface, JsonDBInterface, get_current_user, authenticate_user, create_access_token, Token, ACCESS_TOKEN_EXPIRES_MINUTES
from enum import Enum from enum import Enum
class ReservedPaths(Enum):
TOKEN: str = 'token'
HASH: str = 'hash'
AUTH: str = "auth"
ME: str = "me"
settings = ApiserverSettings()
app = FastAPI( app = FastAPI(
title="API-Server for the Data Catalog" title="API-Server for the Data Catalog"
) )
settings: ApiserverSettings = ApiserverSettings()
adapter: AbstractLocationDataStorageAdapter = JsonFileStorageAdapter(settings) adapter: AbstractLocationDataStorageAdapter = JsonFileStorageAdapter(settings)
userdb: AbstractDBInterface = JsonDBInterface(settings)
oauth2_scheme: OAuth2PasswordBearer = OAuth2PasswordBearer(tokenUrl="token")
#### A NOTE ON IDS #### A NOTE ON IDS
# the id of a dataset is not yet defined, it could be simply generated, it could be based on some hash of the metadata or simple be the name, which would then need to be enforced to be unique # the id of a dataset is not yet defined, it could be simply generated, it could be based on some hash of the metadata or simple be the name, which would then need to be enforced to be unique
...@@ -31,24 +42,44 @@ adapter: AbstractLocationDataStorageAdapter = JsonFileStorageAdapter(settings) ...@@ -31,24 +42,44 @@ adapter: AbstractLocationDataStorageAdapter = JsonFileStorageAdapter(settings)
# list types of data locations, currently datasets (will be provided by the pillars) and targets (possible storage locations for worklfow results or similar) # list types of data locations, currently datasets (will be provided by the pillars) and targets (possible storage locations for worklfow results or similar)
@app.get("/") @app.get("/")
def get_types(): async def get_types():
return [{element.value : "/" + element.value} for element in LocationDataType] return [{element.value : "/" + element.value} for element in LocationDataType]
# return information about the currently logged in user
@app.get("/me", response_model=User)
async def read_users_me(token: str = Depends(oauth2_scheme)):
user = get_current_user(token, userdb)
return user
# authenticate with username/ password, return an auth-token
@app.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(userdb, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRES_MINUTES)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
# list id and name of every registered dataset for the specified type # list id and name of every registered dataset for the specified type
@app.get("/{location_data_type}") @app.get("/{location_data_type}")
def list_datasets(location_data_type : LocationDataType): async def list_datasets(location_data_type : LocationDataType):
return adapter.getList(location_data_type) return adapter.getList(location_data_type)
# register a new dataset, the response will contain the new dataset and its id # register a new dataset, the response will contain the new dataset and its id
@app.put("/{location_data_type}") @app.put("/{location_data_type}")
def add_dataset(location_data_type : LocationDataType, dataset : LocationData): async def add_dataset(location_data_type : LocationDataType, dataset : LocationData, token: str = Depends(oauth2_scheme)):
usr: str = "testuser" usr: str = "testuser"
return adapter.addNew(location_data_type, dataset, usr) return adapter.addNew(location_data_type, dataset, usr)
# returns all information about a specific dataset, identified by id # returns all information about a specific dataset, identified by id
@app.get("/{location_data_type}/{dataset_id}") @app.get("/{location_data_type}/{dataset_id}")
def get_specific_dataset(location_data_type : LocationDataType, dataset_id: str): async def get_specific_dataset(location_data_type : LocationDataType, dataset_id: str):
try: try:
return adapter.getDetails(location_data_type, dataset_id) return adapter.getDetails(location_data_type, dataset_id)
except FileNotFoundError: except FileNotFoundError:
...@@ -56,7 +87,7 @@ def get_specific_dataset(location_data_type : LocationDataType, dataset_id: str) ...@@ -56,7 +87,7 @@ def get_specific_dataset(location_data_type : LocationDataType, dataset_id: str)
# update the information about a specific dataset, identified by id # update the information about a specific dataset, identified by id
@app.put("/{location_data_type}/{dataset_id}") @app.put("/{location_data_type}/{dataset_id}")
def update_specific_dataset(location_data_type : LocationDataType, dataset_id: str, dataset : LocationData): async def update_specific_dataset(location_data_type : LocationDataType, dataset_id: str, dataset : LocationData, token: str = Depends(oauth2_scheme)):
usr: str = "testuser" usr: str = "testuser"
try: try:
return adapter.updateDetails(location_data_type, dataset_id, dataset, usr) return adapter.updateDetails(location_data_type, dataset_id, dataset, usr)
...@@ -65,7 +96,7 @@ def update_specific_dataset(location_data_type : LocationDataType, dataset_id: s ...@@ -65,7 +96,7 @@ def update_specific_dataset(location_data_type : LocationDataType, dataset_id: s
# delete a specific dataset # delete a specific dataset
@app.delete("/{location_data_type}/{dataset_id}") @app.delete("/{location_data_type}/{dataset_id}")
def delete_specific_dataset(location_data_type : LocationDataType, dataset_id: str): async def delete_specific_dataset(location_data_type : LocationDataType, dataset_id: str, token: str = Depends(oauth2_scheme)):
usr: str = "testuser" usr: str = "testuser"
try: try:
return adapter.delete(location_data_type, dataset_id, usr) return adapter.delete(location_data_type, dataset_id, usr)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment