Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "fix(migrate): improve acl->authz migration, remove deprecated… #337

Merged
merged 1 commit into from
Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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