Example #1
0
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")
Example #2
0
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")
Example #3
0
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")
Example #4
0
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
Example #5
0
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")
Example #6
0
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)
Example #8
0
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")