def require_auth(): """ Check if a request is authenticated. """ check_user_credential() if not flask.g.user: raise AuthError('This endpoint requires authentication')
def get_user_projects(self, user): if not user: raise AuthError('Please authenticate as a user') if not flask.g.user: flask.g.user = FederatedUser(user) results = (flask_sqlalchemy_session.current_session.query( userdatamodel.user.Project.auth_id, AccessPrivilege).join(AccessPrivilege.project).filter( AccessPrivilege.user_id == flask.g.user.id).all()) return_res = {} if not results: raise AuthError('No project access') for item in results: dbgap_no, user_access = item return_res[dbgap_no] = user_access.privilege return return_res
def authorize_and_call(program, project, *args, **kwargs): project_id = '{}-{}'.format(program, project) check_user_credential() # Get intersection of user's roles and requested roles if not set(flask.g.user.roles[project_id]) & set(roles): raise AuthError( role_error_msg(flask.g.user.username, roles, project_id)) return func(program, project, *args, **kwargs)
def get_secret_key_and_user(access_key): hmac_keypair = (current_session.query(HMACKeyPair).filter( HMACKeyPair.access_key == access_key).first()) if not hmac_keypair: raise AuthError( "Access key doesn't exist, or the key in use does not match any" " existing entries") if not hasattr(flask.g, 'user'): flask.g.user = FederatedUser(hmac_keypair=hmac_keypair) key = Fernet(bytes(flask.current_app.config['HMAC_ENCRYPTION_KEY'])) return key.decrypt(bytes(hmac_keypair.secret_key))
def check_user_credential(): try: username = cdis_oauth2client.get_username() get_user(username) except OAuth2Error as oauth2_error: try: verify_hmac(flask.request, 'submission', get_secret_key_and_user) except HMAC4Error as hmac_error: flask.current_app.logger.exception('Failed to verify OAuth') flask.current_app.logger.exception('Failed to verify hmac') raise AuthError(oauth2_error.message + '; ' + hmac_error.message)
def check_nodes(self, nodes): """ Check if user have access to all of the dids, return 403 if user doesn't have access on any of the file, 404 if any of the file is not in psqlgraph, 200 if user can access all dids """ for node in nodes: node_acl = node.acl if node_acl == ['open']: continue elif node_acl == []: raise AuthError( 'Requested file %s does not allow read access' % node.node_id, code=403) else: if flask.g.user.token is None: raise AuthError('Please specify a X-Auth-Token') else: user_acl = (flask.g.user.get_phs_ids(self.get_role(node))) if not (set(node_acl) & set(user_acl)): raise AuthError("You don't have access to the data") return 200
def get_role_by_dbgap(self, dbgap_no): project = ( flask_sqlalchemy_session.current_session .query(userdatamodel.user.Project) .filter(userdatamodel.user.Project.auth_id == dbgap_no) .first() ) if not project: raise InternalError("Don't have project with {0}".format(dbgap_no)) roles = ( flask_sqlalchemy_session.current_session .query(AccessPrivilege) .filter(AccessPrivilege.user_id == flask.g.user.id) .filter(AccessPrivilege.project_id == project.id) .first() ) if not roles: raise AuthError("You don't have access to the data") return roles
def file_operations(program, project, file_uuid): """ Handle molecular file operations. This will only be available once the user has created a file entity with GDC id ``uuid`` via the ``/<program>/<project>/`` endppoint. This endpoint is an S3 compatible endpoint as described here: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectOps.html Supported operations: PUT /<program>/<project>/files/<uuid> Upload data using single PUT. The request body should contain binary data of the file PUT /internal/<program>/<project>/files/<uuid>/reassign Manually (re)assign the S3 url for a given node DELETE /<program>/<project>/files/<uuid> Delete molecular data from object storage. POST /<program>/<project>/files/<uuid>?uploads Initiate Multipart Upload. PUT /<program>/<project>/files/<uuid>?partNumber=PartNumber&uploadId=UploadId Upload Part. POST /<program>/<project>/files/<uuid>?uploadId=UploadId Complete Multipart Upload DELETE /<program>/<project>/files/<uuid>?uploadId=UploadId Abort Multipart Upload GET /<program>/<project>/files/<uuid>?uploadId=UploadId List Parts :param str program: |program_id| :param str project: |project_id| :param str uuid: The GDC id of the file to upload. :reqheader Content-Type: |reqheader_Content-Type| :reqheader Accept: |reqheader_Accept| :reqheader X-Auth-Token: |reqheader_X-Auth-Token| :resheader Content-Type: |resheader_Content-Type| :statuscode 200: Success. :statuscode 404: File not found. :statuscode 403: Unauthorized request. :statuscode 405: Method Not Allowed. :statuscode 400: Bad Request. """ headers = { k: v for k, v in flask.request.headers.iteritems() if v and k != 'X-Auth-Token' } url = flask.request.url.split('?') args = url[-1] if len(url) > 1 else '' if flask.request.method == 'GET': if flask.request.args.get('uploadId'): action = 'list_parts' else: raise UserError('Method GET not allowed on file', code=405) elif flask.request.method == 'POST': if flask.request.args.get('uploadId'): action = 'complete_multipart' elif flask.request.args.get('uploads') is not None: action = 'initiate_multipart' else: action = 'upload' elif flask.request.method == 'PUT': if reassign: # admin only auth.admin_auth() action = 'reassign' elif flask.request.args.get('partNumber'): action = 'upload_part' else: action = 'upload' elif flask.request.method == 'DELETE': if flask.request.args.get('uploadId'): action = 'abort_multipart' else: action = 'delete' else: raise UserError('Unsupported file operation', code=405) project_id = program + '-' + project role = PERMISSIONS[action] if role not in flask.g.user.roles[project_id]: raise AuthError( "You don't have {} role to do '{}'".format(role, action) ) resp = utils.proxy_request( project_id, file_uuid, flask.request.stream, args, headers, flask.request.method, action, dry_run, ) if dry_run or action == 'reassign': return resp return flask.Response( resp.read(), status=resp.status, headers=resp.getheaders(), mimetype='text/xml' )
def get_user(username): user = (current_session.query(User).filter( User.username == username).first()) if not user: raise AuthError("User doesn't exist.") flask.g.user = flask.g.get('user', FederatedUser(user=user))
def admin_auth(): check_user_credential() if not flask.g.user.user.is_admin: raise AuthError("You don't have admin access to perform this action")
def file_operations(program, project, file_uuid): """ Handle molecular file operations. This will only be available once the user has created a file entity with GDC id ``uuid`` via the ``/<program>/<project>/`` endppoint. This endpoint is an S3 compatible endpoint as described here: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectOps.html Supported operations: PUT /<program>/<project>/files/<uuid> Upload data using single PUT. The request body should contain binary data of the file PUT /internal/<program>/<project>/files/<uuid>/reassign Manually (re)assign the S3 url for a given node DELETE /<program>/<project>/files/<uuid> Delete molecular data from object storage. POST /<program>/<project>/files/<uuid>?uploads Initiate Multipart Upload. PUT /<program>/<project>/files/<uuid>?partNumber=PartNumber&uploadId=UploadId Upload Part. POST /<program>/<project>/files/<uuid>?uploadId=UploadId Complete Multipart Upload DELETE /<program>/<project>/files/<uuid>?uploadId=UploadId Abort Multipart Upload GET /<program>/<project>/files/<uuid>?uploadId=UploadId List Parts Tags: file Args: program (str): |program_id| project (str): |project_id| uuid (str): The GDC id of the file to upload. Responses: 200: Success. 400: Bad Request 404: File not found. 405: Method Not Allowed. 403: Unauthorized request. :reqheader Content-Type: |reqheader_Content-Type| :reqheader Accept: |reqheader_Accept| :reqheader X-Auth-Token: |reqheader_X-Auth-Token| :resheader Content-Type: |resheader_Content-Type| """ headers = { k: v for k, v in flask.request.headers.iteritems() if v and k != "X-Auth-Token" } url = flask.request.url.split("?") args = url[-1] if len(url) > 1 else "" if flask.request.method == "GET": if flask.request.args.get("uploadId"): action = "list_parts" else: raise UserError("Method GET not allowed on file", code=405) elif flask.request.method == "POST": if flask.request.args.get("uploadId"): action = "complete_multipart" elif flask.request.args.get("uploads") is not None: action = "initiate_multipart" else: action = "upload" elif flask.request.method == "PUT": if reassign: # admin only auth.current_user.require_admin() action = "reassign" elif flask.request.args.get("partNumber"): action = "upload_part" else: action = "upload" elif flask.request.method == "DELETE": if flask.request.args.get("uploadId"): action = "abort_multipart" else: action = "delete" else: raise UserError("Unsupported file operation", code=405) project_id = program + "-" + project role = PERMISSIONS[action] roles = auth.get_program_project_roles(*project_id.split("-", 1)) if role not in roles: raise AuthError("You don't have {} role to do '{}'".format( role, action)) resp = utils.proxy_request( project_id, file_uuid, flask.request.stream, args, headers, flask.request.method, action, dry_run, ) if dry_run or action == "reassign": return resp return flask.Response( resp.read(), status=resp.status, headers=resp.getheaders(), mimetype="text/xml", )