def authenticate(r: request) -> [str, abort]: """Authenticates a request using Globus Auth. If user is authenticated, return client_id from Globus introspection object, else abort. Parameters ---------- r : request Flask request object as made by the user. Returns ------- [str, abort] Returns client ID or abort message. """ if "Authorization" not in r.headers: abort(401, "You must be logged in to perform this function.") else: token = request.headers.get("Authorization") token = str.replace(str(token), "Bearer ", "") conf_app = ConfidentialAppAuthClient(app.config["GLOBUS_CLIENT"], app.config["GLOBUS_KEY"]) intro_obj = conf_app.oauth2_token_introspect(token) if "client_id" in intro_obj: return str(intro_obj["client_id"]) else: abort(400, "Failed to authenticate user")
def convert(): if 'Authorization' not in request.headers: abort(401, 'You must be logged in to perform this function.') token = request.headers.get('Authorization') token = str.replace(str(token), 'Bearer ', '') conf_app = ConfidentialAppAuthClient(os.environ["GL_CLIENT"], os.environ["GL_CLIENT_SECRET"]) intro_obj = conf_app.oauth2_token_introspect(token) if "client_id" in intro_obj: client_id = str(intro_obj["client_id"]) definition_entry = select_by_column( "definition", definition_id=request.json["definition_id"]) if definition_entry is not None and len(definition_entry) == 1: definition_entry = definition_entry[0] if definition_entry["definition_owner"] != client_id: abort(400, "You don't have permission to use this definition file") else: return convert_definition_file(definition_entry) else: abort(400, "Definition ID not valid") else: abort(400, "Failed to authenticate user")
def repo2docker(): if 'Authorization' not in request.headers: abort(401, 'You must be logged in to perform this function.') token = request.headers.get('Authorization') token = str.replace(str(token), 'Bearer ', '') conf_app = ConfidentialAppAuthClient(os.environ["GL_CLIENT"], os.environ["GL_CLIENT_SECRET"]) intro_obj = conf_app.oauth2_token_introspect(token) if "client_id" in intro_obj: client_id = str(intro_obj["client_id"]) build_id = str(uuid.uuid4()) if request.json is not None and "git_repo" in request.json and "container_name" in request.json: put_message({ "function_name": "repo2docker_container", "client_id": client_id, "build_id": build_id, "target": request.json["git_repo"], "container_name": request.json["container_name"] }) manager.start_thread() return build_id elif 'file' in request.files: file = request.files['file'] if file.filename == '': abort(400, "No file selected") if file: file_path = tempfile.mkstemp()[1] with open(file_path, "wb") as f: f.write(file.read()) put_message({ "function_name": "repo2docker_container", "client_id": client_id, "build_id": build_id, "target": file_path, "container_name": file.filename }) manager.start_thread() return build_id else: return abort(400, "Failed to upload file") else: abort(400, "No git repo or file") else: abort(400, "Failed to authenticate user")
def get_uid_from_token(auth_token): # Step 1: Get Auth Client with Secrets. client_id = os.getenv("GLOBUS_FUNCX_CLIENT") secret = os.getenv("GLOBUS_FUNCX_SECRET") # Step 2: Transform token and introspect it. conf_app_client = ConfidentialAppAuthClient(client_id, secret) token = str.replace(str(auth_token), 'Bearer ', '') auth_detail = conf_app_client.oauth2_token_introspect(token) try: uid = auth_detail['username'] except KeyError as e: raise ValueError(str(e)) return uid
def pull(): if 'Authorization' not in request.headers: abort(401, 'You must be logged in to perform this function.') token = request.headers.get('Authorization') token = str.replace(str(token), 'Bearer ', '') conf_app = ConfidentialAppAuthClient(os.environ["GL_CLIENT"], os.environ["GL_CLIENT_SECRET"]) intro_obj = conf_app.oauth2_token_introspect(token) if "client_id" in intro_obj: client_id = intro_obj["client_id"] params = request.json if "build_id" in params: build_id = params["build_id"] build_entry = select_by_column("build", build_id=build_id) if build_entry is not None and len(build_entry) == 1: build_entry = build_entry[0] if build_entry["container_owner"] != client_id: abort(400, "You do not have access to this definition file") else: abort(400, "Invalid build ID") try: file_name = pull_container(build_entry) response = send_file(os.path.basename(file_name)) if os.path.exists(file_name): os.remove(file_name) return response except Exception as e: file_name = build_id + (".tar" if build_entry["container_type"] == "docker" else ".sif") if os.path.exists(file_name): os.remove(file_name) print(f"Exception {e}") abort(400, f"Failed to pull {build_id}") else: abort(400, "No build ID") else: abort(400, "Failed to authenticate user")
def upload_file(): if 'Authorization' not in request.headers: abort(401, 'You must be logged in to perform this function.') token = request.headers.get('Authorization') token = str.replace(str(token), 'Bearer ', '') conf_app = ConfidentialAppAuthClient(os.environ["GL_CLIENT"], os.environ["GL_CLIENT_SECRET"]) intro_obj = conf_app.oauth2_token_introspect(token) if "client_id" in intro_obj: client_id = str(intro_obj["client_id"]) if 'file' not in request.files: abort(400, "No file") file = request.files['file'] if file.filename == '': abort(400, "No file selected") if file: filename = file.filename definition_id = str(uuid.uuid4()) create_table_entry("definition", definition_id=definition_id, definition_type="docker" if filename == "Dockerfile" else "singularity", definition_name=filename, location="s3", definition_owner=client_id) s3 = boto3.client('s3') s3.upload_fileobj(file, "xtract-container-service", f'{definition_id}/{filename}') return definition_id else: return abort(400, "Failed to upload file") else: abort(400, "Failed to authenticate user")
class GlobusClientUtil: def __init__(self, *args, **kwargs): # GlobusClientUtil(<filename>) reads client id and secret from <filename> # GlobusClientUtil() is equivalent to GlobusClientUtil('/home/secrets/oauth2/client_secret_globus.json') # GlobusClientUtil(client_id, client_secret) uses the specified id and secret instead of reading from a file. cred_file = CLIENT_CRED_FILE if len(args) == 1: cred_file=args[0] if len(args) < 2: f=open(cred_file, 'r') config=json.load(f) f.close() self.initialize(config['web'].get('client_id'), config['web'].get('client_secret')) elif len(args) == 2: self.initialize(args[0], args[1]) def initialize(self, client_id, client_secret): self.client = ConfidentialAppAuthClient(client_id, client_secret) self.client_id = client_id def list_all_scopes(self): r = self.client.get("/v2/api/scopes") return r.text def list_scope(self, scope): r = self.client.get("/v2/api/scopes/{s}".format(s=scope)) return r.text def create_scope(self, scope): # if "scope" is a dict, use it. Otherwise, see if it's a json string or a file containing json. if not isinstance(scope, dict): try: scope = json.loads(scope) except ValueError: # if this fails, we have nothing left to try, so don't bother catching errors f = open(scope, 'r') scope = json.load(f) f.close() r = self.client.post("/v2/api/clients/{client_id}/scopes".format(client_id = self.client_id), json_body=scope) return r.text def update_scope(self, scope_id, args): r = self.client.put("/v2/api/scopes/{scope_id}".format(scope_id = scope_id), json_body={"scope" : args}) return r.text def add_fqdn_to_client(self, fqdn): r = self.client.post('/v2/api/clients/{client_id}/fqdns'.format(client_id=self.client_id), json_body={'fqdn':fqdn}) return r.text def get_clients(self): r = self.client.get('/v2/api/clients') return r.text def verify_access_token(self, token): r = self.client.oauth2_validate_token(token) return r.text def introspect_access_token(self, token): r = self.client.oauth2_token_introspect(token) return r.text def create_private_client(self, name, redirect_uris): nih_client_dict = { "client" : { "name" : name, "public_client" : False, "redirect_uris" : redirect_uris } } r = self.client.post("/v2/api/clients", json_body = nih_client_dict) return r.text def add_redirect_uris(self, redirect_uris): d={ "client": { "redirect_uris" : redirect_uris } } r = self.client.put("/v2/api/clients/{client_id}".format(client_id=self.client_id), json_body=d) return r.text def get_my_client(self): r = self.client.get('/v2/api/clients/{client_id}'.format(client_id=self.client_id)) return r.text def get_scopes_by_name(self, sname_string): scopes = self.client.get('/v2/api/scopes?scope_strings={sname}'.format(sname=sname_string)) if scopes == None: return None else: return scopes.get("scopes") def get_scopes_by_id(self, id_string): scopes = self.client.get('/v2/api/scopes?ids={ids}'.format(ids=id_string)) if scopes == None: return None else: return scopes.get("scopes") def my_scope_ids(self): c = self.client.get('/v2/api/clients/{client_id}'.format(client_id=self.client_id)) me = c.get("client") if me == None or me.get('scopes') == None: return [] else: return me.get('scopes') def my_scope_names(self): snames = [] scope_ids=self.my_scope_ids() if scope_ids != None: ids=",".join(scope_ids) print(str(ids)) scopes=self.get_scopes_by_id(ids) for s in scopes: snames.append(s.get('scope_string')) return snames def get_grant_types(self): grant_types=None c = self.client.get('/v2/api/clients/{client_id}'.format(client_id=self.client_id)) me = c.get("client") if me != None: grant_types = me.get('grant_types') return(grant_types) def add_scopes(self, new_scopes): scopes=set(self.my_scope_ids()) for s in self.get_scopes_by_name(",".join(new_scopes)): scopes.add(s.get('id')) d = { "client": { "scopes" : list(scopes) } } r=self.client.put('/v2/api/clients/{client_id}'.format(client_id=self.client_id), json_body=d) return r.text def add_dependent_scopes(self, parent_scope_name, child_scope_names): child_scope_ids = set() parent_scopes = self.get_scopes_by_name(parent_scope_name) if parent_scopes == None: return "no parent scope" if len(parent_scopes) != 1: return "{l} parent scopes: {p}".format(l=str(len(parent_scopes)), p=str(parent_scopes)) parent_scope_id = parent_scopes[0].get("id") for s in parent_scopes[0].get('dependent_scopes'): child_scope_ids.add(s.get('id')) new_child_scopes = self.get_scopes_by_name(",".join(child_scope_names)) for s in new_child_scopes: child_scope_ids.add(s.get('id')) dependent_scopes = [] for id in child_scope_ids: dependent_scopes.append({'scope' : id, 'optional' : False, 'requires_refresh_token' : False}) d = { "scope" : { "dependent_scopes" : dependent_scopes } } print(str(d)) r = self.client.put('/v2/api/scopes/{i}'.format(i=parent_scope_id), json_body=d) return r.text def create_scope_with_deps(self, name, description, suffix, dependent_scopes=[], advertised=True, allow_refresh_tokens=True): dependent_scope_arg = [] if len(dependent_scopes) > 0: child_scopes=self.get_scopes_by_name(",".join(dependent_scopes)) for s in child_scopes: dependent_scope_arg.append({ "scope" : s.get("id"), "optional" : False, "requires_refresh_token" : False }) scope = { "scope" : { "name" : name, "description" : description, "scope_suffix" : suffix, "dependent_scopes" : dependent_scope_arg, "advertised" : advertised, "allows_refresh_tokens": allow_refresh_tokens } } r = self.client.post("/v2/api/clients/{client_id}/scopes".format(client_id = self.client_id), json_body=scope) return r.text def delete_scope(self, scope_string): scopes = self.get_scopes_by_name(scope_string) if scopes == None or len(scopes) != 1: return "null or multiple scopes" scope_id = scopes[0].get('id') if scope_id == None: return "no scope id" r = self.client.delete('/v2/api/scopes/{scope_id}'.format(scope_id = scope_id)) return r.text def get_dependent_scopes(self, scope): result = {"scope_string" : scope.get("scope_string"), "dependent_scopes" : []} for ds in scope.get("dependent_scopes"): ds_id = ds.get('scope') ds_info = {"id" : ds_id} d = self.get_scopes_by_id(ds_id) if d != None: ds_info['scope_string'] = d[0].get('scope_string') result['dependent_scopes'].append(ds_info) return(result)
def build(): if 'Authorization' not in request.headers: abort(401, "You must be logged in to perform this function.") token = request.headers.get('Authorization') token = str.replace(str(token), 'Bearer ', '') conf_app = ConfidentialAppAuthClient(os.environ["GL_CLIENT"], os.environ["GL_CLIENT_SECRET"]) intro_obj = conf_app.oauth2_token_introspect(token) if "client_id" in intro_obj: client_id = str(intro_obj["client_id"]) if request.method == "POST": params = request.json required_params = {"definition_id", "to_format", "container_name"} if set(params.keys()) >= required_params and params[ "to_format"] in ["docker", "singularity"]: definition_entry = select_by_column( "definition", definition_id=params["definition_id"]) if definition_entry is not None and len(definition_entry) == 1: definition_entry = definition_entry[0] if definition_entry["definition_owner"] != client_id: abort( 400, "You don't have permission to use this definition file" ) else: build_entry = select_by_column( "build", definition_id=params["definition_id"], container_type=params["to_format"]) if build_entry is not None and len(build_entry) == 1: build_entry = build_entry[0] build_id = build_entry["build_id"] build_entry["build_status"] = "pending" update_table_entry("build", build_id, **build_entry) else: build_id = str(uuid.uuid4()) build_entry = build_schema build_entry[ "build_id"] = build_id if build_id is not None else str( uuid.uuid4()) build_entry["container_name"] = params[ "container_name"] build_entry["definition_id"] = params[ "definition_id"] build_entry["container_type"] = params["to_format"] build_entry["container_owner"] = client_id build_entry["build_status"] = "pending" create_table_entry("build", **build_entry) put_message({ "function_name": "build_container", "build_entry": build_entry, "to_format": params["to_format"], "container_name": params["container_name"] }) manager.start_thread() return build_id else: abort( 400, f"""No definition DB entry for {params["definition_id"]}""" ) else: abort(400, f"Missing {set(params.keys())} parameters") elif request.method == "GET": build_entry = select_by_column("build", container_owner=client_id, build_id=request.json["build_id"]) if build_entry is not None and len(build_entry) == 1: return build_entry[0] else: abort(400, "Build ID not valid") else: abort(400, "Failed to authenticate user")