Exemplo n.º 1
0
    def auth_request(self, data):
        """
        Return:
            bool: authorization response
        """
        authed = False
        response = requests.post(self._auth_url.rstrip("/") + "/request",
                                 json=data)
        if response.status_code == 200:
            authed = bool(response.json()["auth"])
        elif response.status_code == 500:
            msg = "request to arborist failed: {}".format(response.json())
            raise ArboristError(message=msg, code=500)
        else:
            # arborist could send back a 400 for things like, the user has some policy
            # that it doesn't recognize, or the request is structured incorrectly; for
            # these cases we will default to unauthorized
            msg = "arborist denied auth request"
            try:
                detail = response.json()["error"]
                raise Forbidden("{}: {}".format(msg, detail))
            except (KeyError, ValueError):
                raise Forbidden(msg)

        return authed
Exemplo n.º 2
0
 def delete_role(self, role_id):
     response = requests.delete(self._role_url + role_id)
     if response.status_code == 404:
         # already doesn't exist, this is fine
         return
     elif response.status_code >= 400:
         raise ArboristError("could not delete role in arborist: {}".format(
             response.json()["error"]))
Exemplo n.º 3
0
 def update_resource(self, path, resource_json):
     response = _request_get_json(requests.put(path, json=resource_json))
     if "error" in response:
         msg = response["error"].get("message", str(response["error"]))
         self.logger.error(
             "could not update resource `{}` in arborist: {}".format(
                 path, msg))
         raise ArboristError(response["error"])
     self.logger.info("updated resource {}".format(resource_json["name"]))
     return response
Exemplo n.º 4
0
    def update_client(self, client_id, policies):
        # retrieve existing client, create one if not found
        response = requests.get("/".join((self._client_url, client_id)))
        if response.status_code == 404:
            self.create_client(client_id, policies)
            return

        # unpack the result
        data = _request_get_json(response)
        if "error" in data:
            self.logger.error(
                "could not fetch client `{}` in arborist: {}".format(
                    client_id, data["error"]))
            raise ArboristError(data["error"])
        current_policies = set(data["policies"])
        policies = set(policies)

        # find newly granted policies, revoke all if needed
        url = "/".join((self._client_url, client_id, "policy"))
        if current_policies.difference(policies):
            # if some policies must be removed, revoke all and re-grant later
            response = requests.delete(url)
            if response.status_code != 204:
                data = _request_get_json(response)
                self.logger.error(
                    "could not revoke policies from client `{}` in arborist: {}"
                    .format(client_id, data.get("error")))
                raise ArboristError(data.get("error"))
        else:
            # do not add policies that already exist
            policies.difference_update(current_policies)

        # grant missing policies
        for policy in policies:
            response = requests.post(url, json=dict(policy=policy))
            if response.status_code != 204:
                data = _request_get_json(response)
                self.logger.error(
                    "could not grant policy `{}` to client `{}` in arborist: {}"
                    .format(policy, client_id, data["error"]))
                raise ArboristError(data["error"])
        self.logger.info("updated policies for client {}".format(client_id))
Exemplo n.º 5
0
 def create_client(self, client_id, policies):
     response = requests.post(self._client_url,
                              json=dict(clientID=client_id,
                                        policies=policies or []))
     data = _request_get_json(response)
     if "error" in data:
         self.logger.error(
             "could not create client `{}` in arborist: {}".format(
                 client_id, data["error"]))
         raise ArboristError(data["error"])
     self.logger.info("created client {}".format(client_id))
     return data
Exemplo n.º 6
0
 def update_resource(self, path, resource_json, create_parents=False):
     path = self._resource_url + path
     if create_parents:
         path = path + "?p"
     response = _request_get_json(requests.put(path, json=resource_json))
     if "error" in response:
         self.logger.error(
             "could not update resource `{}` in arborist: {}".format(
                 path, response["error"]))
         raise ArboristError(response["error"])
     self.logger.info("updated resource {}".format(resource_json["name"]))
     return response
Exemplo n.º 7
0
 def create_policy(self, policy_json, skip_if_exists=True):
     response = requests.post(self._policy_url, json=policy_json)
     data = _request_get_json(response)
     if response.status_code == 409:
         return None
     if "error" in data:
         self.logger.error(
             "could not create policy `{}` in arborist: {}".format(
                 policy_json["id"], data["error"]))
         raise ArboristError(data["error"])
     self.logger.info("created policy {}".format(policy_json["id"]))
     return data
Exemplo n.º 8
0
    def create_role(self, role_json):
        """
        Create a new role in arborist (does not affect fence database or
        otherwise have any interaction with userdatamodel).

        Used for syncing project permissions from dbgap into arborist roles.

        Example schema for the role JSON:

            {
                "id": "role",
                "description": "...",
                "permissions": [
                    {
                        "id": "permission",
                        "description": "...",
                        "action": {
                            "service": "...",
                            "method": "..."
                        },
                        "constraints": {
                            "key": "value",
                        }
                    }
                ]
            }

        ("description" fields are optional, as is the "constraints" field in
        the permission.)

        Args:
            role_json (dict): dictionary of information about the role

        Return:
            dict: response JSON from arborist

        Raises:
            - ArboristError: if the operation failed (couldn't create role)
        """
        response = requests.post(self._role_url, json=role_json)
        if response.status_code == 409:
            # already exists; this is ok
            return None
        data = _request_get_json(response)
        if "error" in data:
            self.logger.error(
                "could not create role `{}` in arborist: {}".format(
                    role_json["id"], data["error"]))
            raise ArboristError(data["error"])
        self.logger.info("created role {}".format(role_json["id"]))
        return data
Exemplo n.º 9
0
 def create_user_if_not_exist(self, username):
     self.logger.info("making sure user exists: `{}`".format(username))
     user_json = {"name": username}
     response = requests.post(self._user_url, json=user_json)
     data = _request_get_json(response)
     if response.status_code == 409:
         return None
     if "error" in data:
         self.logger.error(
             "could not create user `{}` in arborist: {}".format(
                 username, data["error"]))
         raise ArboristError(data["error"])
     self.logger.info("created user {}".format(username))
     return data
Exemplo n.º 10
0
    def list_resources_for_user(self, username):
        """
        Args:
            username (str)

        Return:
            List[str]: list of resource paths which the user has any access to
        """
        url = "{}/{}/resources".format(self._user_url, username)
        response = requests.get(url)
        data = _request_get_json(response)
        if response.status_code != 200:
            raise ArboristError(
                data.get("error", "unhelpful response from arborist"))
        return data["resources"]
Exemplo n.º 11
0
    def create_policy(self, policy_json, overwrite=False):
        if overwrite:
            response = requests.put(self._policy_url, json=policy_json)
        else:
            response = requests.post(self._policy_url, json=policy_json)

        data = _request_get_json(response)

        self.logger.info("arborist data: {}".format(data))

        if response.status_code == 409:
            # already exists; this is ok, but leave warning
            self.logger.warn("policy `{}` already exists in arborist".format(
                policy_json["id"]))
            return None
        if isinstance(data, dict) and "error" in data:
            self.logger.error(
                "could not create policy `{}` in arborist: {}".format(
                    policy_json["id"], data["error"]))
            raise ArboristError(data["error"])
        self.logger.info("created policy {}".format(policy_json["id"]))
        return data
Exemplo n.º 12
0
    def create_resource(self,
                        parent_path,
                        resource_json,
                        create_parents=False):
        """
        Create a new resource in arborist (does not affect fence database or
        otherwise have any interaction with userdatamodel).

        Used for syncing projects from dbgap into arborist resources.

        Example schema for resource JSON:

            {
                "name": "some_resource",
                "description": "..."
                "subresources": [
                    {
                        "name": "subresource",
                        "description": "..."
                    }
                ]
            }

        Supposing we have some ``"parent_path"``, then the new resource will be
        created as ``/parent_path/some_resource`` in arborist.

        ("description" fields are optional, as are subresources, which default
        to empty.)

        Args:
            parent_path (str):
                the path (like a filepath) to the parent resource above this
                one; if this one is in the root level, then use "/"
            resource_json (dict):
                dictionary of resource information (see the example above)

        Return:
            dict: response JSON from arborist

        Raises:
            - ArboristError: if the operation failed (couldn't create resource)
        """
        # To add a subresource, all we actually have to do is POST the resource
        # JSON to its parent in arborist:
        #
        #     POST /resource/parent
        #
        # and now the new resource will exist here:
        #
        #     /resource/parent/new_resource
        #
        path = self._resource_url + parent_path
        if create_parents:
            path = path + "?p"

        response = requests.post(path, json=resource_json)
        data = _request_get_json(response)
        if isinstance(data, dict) and "error" in data:
            msg = data["error"]
            if isinstance(data["error"], dict):
                msg = data["error"].get("message", msg)
            resource = resource_json.get("path",
                                         "/" + resource_json.get("name"))
            self.logger.error(
                "could not create resource `{}` in arborist: {}".format(
                    resource, msg))
            raise ArboristError(data["error"])
        self.logger.info("created resource {}".format(resource_json["name"]))
        return data