Skip to content

Commit

Permalink
Revert "fix(migrate): improve acl->authz migration, remove deprecated…
Browse files Browse the repository at this point in the history
… endpoints (#336)" (#337)

This reverts commit 98146f5.

Co-authored-by: Alexander VT <[email protected]>
  • Loading branch information
Avantol13 and Avantol13-machine-user authored Sep 28, 2022
1 parent 98146f5 commit 6d7b337
Show file tree
Hide file tree
Showing 8 changed files with 500 additions and 369 deletions.
36 changes: 3 additions & 33 deletions bin/migrate_acl_authz.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@

from indexd.index.drivers.alchemy import IndexRecord, IndexRecordAuthz

from yaml import safe_load

logger = get_logger("migrate_acl_authz", log_level="debug")
logger = get_logger("migrate_acl_authz")


def main():
Expand All @@ -50,10 +49,7 @@ def main():
driver = settings["config"]["INDEX"]["driver"]
try:
acl_converter = ACLConverter(
args.arborist,
getattr(args, "sheepdog"),
getattr(args, "use_tags"),
getattr(args, "user_yaml_path"),
args.arborist, getattr(args, "sheepdog"), getattr(args, "use_tags")
)
except EnvironmentError:
logger.error("can't continue without database connection")
Expand Down Expand Up @@ -123,18 +119,11 @@ def parse_args():
dest="start_did",
help="did to start at (records processed in lexographical order)",
)
parser.add_argument(
"--user-yaml-path",
dest="user_yaml_path",
help="path to user yaml for pulling authz mapping",
)
return parser.parse_args()


class ACLConverter(object):
def __init__(
self, arborist_url, sheepdog_db=None, use_tags=False, user_yaml_path=None
):
def __init__(self, arborist_url, sheepdog_db=None, use_tags=False):
self.arborist_url = arborist_url.rstrip("/")
self.programs = set()
self.projects = dict()
Expand All @@ -145,21 +134,6 @@ def __init__(
else:
logger.info("not using any auth namespace")
self.use_sheepdog_db = bool(sheepdog_db)
self.mapping = {}

if user_yaml_path:
with open(user_yaml_path, "r") as f:
user_yaml = safe_load(f)
user_yaml_authz = user_yaml.get("authz", dict())
if not user_yaml_authz:
user_yaml_authz = user_yaml.get("rbac", dict())

project_to_resource = user_yaml_authz.get(
"user_project_to_resource", dict()
)
self.mapping = project_to_resource

logger.info(f"got mapping: {self.mapping}")

# if "use_tags" is True, map resource paths to tags in arborist so
# we can save http calls
Expand Down Expand Up @@ -220,10 +194,6 @@ def acl_to_authz(self, record):
if not acl_item:
# ignore empty string
continue
# prefer user.yaml authz mapping if provided
elif acl_item in self.mapping:
path = self.mapping[acl_item]
projects_found += 1
elif acl_item == "*":
# if there's a * it should just be open. return early
path = "/open"
Expand Down
5 changes: 5 additions & 0 deletions indexd/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .guid.blueprint import blueprint as indexd_drs_blueprint
from .blueprint import blueprint as cross_blueprint

from indexd.fence_client import FenceClient
from indexd.urls.blueprint import blueprint as index_urls_blueprint

import os
Expand All @@ -21,6 +22,10 @@ def app_init(app, settings=None):
from .default_settings import settings
app.config.update(settings["config"])
app.auth = settings["auth"]
app.fence_client = FenceClient(
url=os.environ.get("PRESIGNED_FENCE_URL")
or "http://presigned-url-fence-service"
)
app.hostname = os.environ.get("HOSTNAME") or "http://example.io"
app.register_blueprint(indexd_bulk_blueprint)
app.register_blueprint(indexd_index_blueprint)
Expand Down
20 changes: 20 additions & 0 deletions indexd/drs/blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ def list_drs_records():
return flask.jsonify(ret), 200


@blueprint.route(
"/ga4gh/drs/v1/objects/<path:object_id>/access",
defaults={"access_id": None},
methods=["GET"],
)
@blueprint.route(
"/ga4gh/drs/v1/objects/<path:object_id>/access/<path:access_id>", methods=["GET"]
)
def get_signed_url(object_id, access_id):
if not access_id:
raise (UserError("Access ID/Protocol is required."))
res = flask.current_app.fence_client.get_signed_url_for_object(
object_id=object_id, access_id=access_id
)
if not res:
raise IndexNoRecordFound("No signed url found")

return res, 200


def create_drs_uri(did):
"""
Return ga4gh-compilant drs format uri
Expand Down
55 changes: 55 additions & 0 deletions indexd/fence_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from cdislogging import get_logger

import flask
import requests


from indexd.index.errors import NoRecordFound as IndexNoRecordFound
from indexd.errors import IndexdUnexpectedError
from indexd.auth.errors import AuthError, AuthzError


logger = get_logger(__name__)


class FenceClient(object):
def __init__(self, url):
self.url = url

def get_signed_url_for_object(self, object_id, access_id):
fence_server = self.url
api_url = fence_server.rstrip("/") + "/data/download/"
url = api_url + object_id
headers = flask.request.headers
if "AUTHORIZATION" not in headers:
logger.error("Bearer Token not available.")
raise AuthError("Not Authorized. Access Token Required.")
if access_id:
url += "?protocol=" + access_id
if flask.request.query_string:
url = f"{url}&{flask.request.query_string.decode()}"
try:
req = requests.get(url, headers=headers)
except Exception as e:
logger.error("failed to reach fence at {0}: {1}".format(url + object_id, e))
raise IndexdUnexpectedError("Failed to retrieve access url")
if req.status_code == 404:
logger.error(
"Not found. Fence could not find {}: {} with access id: {}".format(
url + object_id, req.text, access_id
)
)
raise IndexNoRecordFound(
"No document with id:{} with access_id:{}".format(object_id, access_id)
)
if req.status_code == 401:
raise AuthzError("Unauthorized: Access denied due to invalid credentials.")
elif req.status_code != 200:
err_msg = "Unable to get presigned URL from Fence"
logger.error(
"{} - code: {} - details:\n{}".format(
err_msg, req.status_code, req.text
)
)
raise IndexdUnexpectedError(code=req.status_code, message=err_msg)
return req.json()
64 changes: 64 additions & 0 deletions openapis/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,70 @@ paths:
- authToken: []
tags:
- DRS
'/ga4gh/drs/v1/objects/{object_id}/access/{access_id}':
get:
summary: Get a URL for fetching bytes.
description: >-
Returns a URL that can be used to fetch the bytes of a DrsObject.
This method only needs to be called when using an AccessMethod that contains an access_id
(e.g., for servers that use signed URLs for fetching object bytes).
operationId: GetAccessURL
responses:
'200':
description: The access URL was found successfully.
schema:
$ref: '#/definitions/AccessURL'
# '202':
# description: >
# The operation is delayed and will continue asynchronously.
# The client should retry this same request after the delay specified by Retry-After header.
# headers:
# Retry-After:
# description: >
# Delay in seconds. The client should retry this same request after waiting for this duration.
# To simplify client response processing, this must be an integral relative time in seconds.
# This value SHOULD represent the minimum duration the client should wait before attempting
# the operation again with a reasonable expectation of success. When it is not feasible
# for the server to determine the actual expected delay, the server may return a
# brief, fixed value instead.
# type: integer
# format: int64
'400':
description: The request is malformed.
schema:
$ref: '#/definitions/Error'
'401':
description: The request is unauthorized.
schema:
$ref: '#/definitions/Error'
'404':
description: The requested access URL wasn't found
schema:
$ref: '#/definitions/Error'
'403':
description: The requester is not authorized to perform this action.
schema:
$ref: '#/definitions/Error'
'500':
description: An unexpected error occurred.
schema:
$ref: '#/definitions/Error'
parameters:
- name: object_id
in: path
required: true
type: string
description: An id of a DrsObject
- name: access_id
in: path
required: true
type: string
description: An access_id from the access_methods list of a DrsObject
security:
- authToken: []
tags:
- DRS
x-swagger-router-controller: ga4gh.drs.server
'/bundle':
post:
tags:
Expand Down
Loading

0 comments on commit 6d7b337

Please sign in to comment.