Skip to content

Commit

Permalink
Merge pull request #204 from CanDIG/daisieh/site-admin
Browse files Browse the repository at this point in the history
Only site admins can POST
  • Loading branch information
daisieh authored May 16, 2022
2 parents bcf4705 + 5ca0b34 commit 06978d7
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 64 deletions.
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ RUN sed -i s@\<CANDIG_OPA_SECRET\>@${opa_secret}@ config.ini \
&& sed -i s@\<MINIO_URL\>@${minio_url}@ config.ini \
&& sed -i s@\<MINIO_BUCKET_NAME\>@${minio_bucket_name}@ config.ini

RUN touch initial_setup
RUN python setup.py install && pip install --no-cache-dir -r requirements.txt
RUN touch initial_setup && pip install --no-cache-dir -r requirements.txt

RUN sqlite3 data/files.db -init data/files.sql

Expand Down
64 changes: 38 additions & 26 deletions htsget_server/authz.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import requests
import json
import os
from config import AUTHZ, TEST_KEY
from config import AUTHZ, TEST_KEY, CANDIG_OPA_SITE_ADMIN_KEY
from flask import Flask
import drs_operations

Expand All @@ -19,7 +19,8 @@ def is_authed(id_, request):
app.logger.warning("WARNING: TEST MODE, AUTHORIZATION IS DISABLED")
return 200 # no auth
if "Authorization" in request.headers:
authed_datasets = get_opa_res(request.headers, request.path, request.method)
token = get_auth_token(request.headers)
authed_datasets = get_opa_datasets(token, request.path, request.method)
obj, code2 = drs_operations.get_object(id_)
if code2 == 200:
for dataset in obj["datasets"]:
Expand All @@ -35,7 +36,36 @@ def is_authed(id_, request):
return 403


def get_opa_token_from_request(headers):
def is_site_admin(request):
"""
Is the user associated with the token a site admin?
"""
if AUTHZ["CANDIG_AUTHORIZATION"] != "OPA":
print("WARNING: AUTHORIZATION IS DISABLED")
app.logger.warning("WARNING: AUTHORIZATION IS DISABLED")
return True # no auth
if request.headers.get("Test_Key") == TEST_KEY:
print("WARNING: TEST MODE, AUTHORIZATION IS DISABLED")
app.logger.warning("WARNING: TEST MODE, AUTHORIZATION IS DISABLED")
return True # no auth
if "Authorization" in request.headers:
token = get_auth_token(request.headers)
response = requests.post(
AUTHZ['CANDIG_OPA_URL'] + "/v1/data/idp/" + CANDIG_OPA_SITE_ADMIN_KEY,
headers={"Authorization": f"Bearer {AUTHZ['CANDIG_OPA_SECRET']}"},
json={
"input": {
"token": token
}
}
)
response.raise_for_status()
if 'result' in response.json():
return True
return False


def get_auth_token(headers):
"""
Extracts token from request's header Authorization
"""
Expand All @@ -45,42 +75,24 @@ def get_opa_token_from_request(headers):
return token.split()[1]


def get_request_body(headers, path, method):
def get_opa_datasets(token, path, method):
"""
Returns request body required to query OPA
Get allowed dataset result from OPA
"""
return {
body = {
"input": {
"token": get_opa_token_from_request(headers),
"token": token,
"body": {
"path": path,
"method": method
}
}
}


def get_opa_res(headers, path, method):
"""
Get allowed dataset result from OPA
"""
response = requests.post(
AUTHZ['CANDIG_OPA_URL'] + "/v1/data/permissions/datasets",
headers={"Authorization": f"Bearer {AUTHZ['CANDIG_OPA_SECRET']}"},
json=get_request_body(headers, path, method)
json=body
)
response.raise_for_status()
allowed_datasets = response.json()["result"]
return allowed_datasets


def is_site_admin(headers):
response = requests.post(
AUTHZ['CANDIG_OPA_URL'] + "/v1/data/idp/trusted_researcher",
headers={"Authorization": f"Bearer {AUTHZ['CANDIG_OPA_SECRET']}"},
json=get_request_body(headers, "", "")
)
response.raise_for_status()
if response.json()['result'] == 'true':
return True
return False
3 changes: 3 additions & 0 deletions htsget_server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
config.read('./config.ini')

AUTHZ = config['authz']
CANDIG_OPA_SITE_ADMIN_KEY = os.environ.get("CANDIG_OPA_SITE_ADMIN_KEY")
if CANDIG_OPA_SITE_ADMIN_KEY is None:
CANDIG_OPA_SITE_ADMIN_KEY = "site_admin"

DB_PATH = config['paths']['DBPath']
LOCAL_FILE_PATH = config['paths']['LocalFilesPath']
Expand Down
16 changes: 5 additions & 11 deletions htsget_server/drs_openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ paths:
schema:
type: object
/objects:
parameters:
- $ref: '#/components/parameters/BearerAuth'
get:
summary: List all DRS objects
description: >-
Returns object metadata, and a list of access methods that can be used to fetch object bytes.
operationId: drs_operations.list_objects
parameters:
- $ref: '#/components/parameters/BearerAuth'
responses:
200:
description: The `DrsObject` was found successfully
Expand All @@ -50,8 +50,6 @@ paths:
post:
summary: Add a DrsObject to the db
operationId: drs_operations.post_object
parameters:
- $ref: '#/components/parameters/BearerAuth'
requestBody:
$ref: '#/components/requestBodies/DrsObjectRequest'
responses:
Expand Down Expand Up @@ -83,7 +81,6 @@ paths:
Returns object metadata, and a list of access methods that can be used to fetch object bytes.
operationId: drs_operations.get_object
parameters:
- $ref: '#/components/parameters/BearerAuth'
- $ref: '#/components/parameters/Expand'
responses:
200:
Expand Down Expand Up @@ -125,11 +122,11 @@ paths:
tags:
- Objects
/datasets:
parameters:
- $ref: '#/components/parameters/BearerAuth'
get:
description: List all datasets available
operationId: drs_operations.list_datasets
parameters:
- $ref: '#/components/parameters/BearerAuth'
responses:
200:
description: ok
Expand All @@ -143,8 +140,6 @@ paths:
post:
description: Create a dataset
operationId: drs_operations.post_dataset
parameters:
- $ref: '#/components/parameters/BearerAuth'
requestBody:
$ref: '#/components/requestBodies/DatasetRequest'
responses:
Expand All @@ -158,11 +153,10 @@ paths:
/datasets/{dataset_id}:
parameters:
- $ref: "#/components/parameters/DatasetId"
- $ref: '#/components/parameters/BearerAuth'
get:
description: Describe a dataset
operationId: drs_operations.get_dataset
parameters:
- $ref: '#/components/parameters/BearerAuth'
responses:
200:
description: ok
Expand Down
9 changes: 9 additions & 0 deletions htsget_server/drs_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from config import LOCAL_FILE_PATH, get_minio_client
from flask import request
import os
import authz

# API endpoints
def get_service_info():
Expand Down Expand Up @@ -47,6 +48,8 @@ def get_access_url(object_id, access_id):


def post_object():
if not authz.is_site_admin(request):
return {"message": "User is not authorized to POST"}, 403
client, bucket = get_minio_client()
new_object = database.create_drs_object(connexion.request.json)
if "access_methods" in new_object:
Expand All @@ -71,6 +74,8 @@ def post_object():


def delete_object(object_id):
if not authz.is_site_admin(request):
return {"message": "User is not authorized to POST"}, 403
try:
new_object = database.delete_drs_object(object_id)
return new_object, 200
Expand All @@ -84,6 +89,8 @@ def list_datasets():


def post_dataset():
if not authz.is_site_admin(request):
return {"message": "User is not authorized to POST"}, 403
new_dataset = database.create_dataset(connexion.request.json)
return new_dataset, 200

Expand All @@ -96,6 +103,8 @@ def get_dataset(dataset_id):


def delete_dataset(dataset_id):
if not authz.is_site_admin(request):
return {"message": "User is not authorized to POST"}, 403
try:
new_dataset = database.delete_dataset(dataset_id)
return new_dataset, 200
Expand Down
25 changes: 0 additions & 25 deletions setup.cfg

This file was deleted.

0 comments on commit 06978d7

Please sign in to comment.