Exemple #1
0
    def retrieve(self, request, *args, **kwargs):
        """Get a group.

        @api {get} /api/v1/groups/:uuid   Get a group
        @apiName getGroup
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Get a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Group unique identifier.

        @apiSuccess {String} uuid Group unique identifier
        @apiSuccess {String} name Group name
        @apiSuccess {Array} principals Array of principals
        @apiSuccess {Array} roles Array of roles
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "uuid": "16fd2706-8baf-433b-82eb-8c7fada847da",
                "name": "GroupA",
                "principals": [
                    { "username": "******" }
                ],
                "roles": [
                    {
                        "name": "RoleA",
                        "uuid": "4df211e0-2d88-49a4-8802-728630224d15"
                    }
                ]
            }
        """
        validate_uuid(kwargs.get("uuid"), "group uuid validation")
        return super().retrieve(request=request, args=args, kwargs=kwargs)
Exemple #2
0
    def partial_update(self, request, *args, **kwargs):
        """Patch a cross-account request."""
        validate_uuid(kwargs.get("pk"),
                      "cross-account request uuid validation")
        for field in request.data:
            if field not in VALID_PATCH_FIELDS:
                self.throw_validation_error(
                    "cross-accont partial update",
                    f"Field '{field}' is not supported. Please use one or more of: {VALID_PATCH_FIELDS}",
                )

        with tenant_context(Tenant.objects.get(schema_name="public")):
            current = self.get_object()

            if current.status != "pending":
                self.throw_validation_error(
                    "cross-account partial update",
                    "Only pending requests may be updated.")

            self.validate_and_format_input(request.data)

            kwargs["partial"] = True
            response = super().update(request=request, *args, **kwargs)
            if response.status_code and response.status_code is http_status.HTTP_200_OK:
                if request.data.get("status"):
                    self.update_status(current, request.data.get("status"))
                    return Response(
                        CrossAccountRequestDetailSerializer(current).data)
            return response
Exemple #3
0
    def update(self, request, *args, **kwargs):
        """Update a group.

        @api {post} /api/v1/groups/:uuid   Update a group
        @apiName updateGroup
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Update a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Group unique identifier

        @apiSuccess {String} uuid Group unique identifier
        @apiSuccess {String} name Group name
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "uuid": "16fd2706-8baf-433b-82eb-8c7fada847da",
                "name": "GroupA"
            }
        """
        validate_uuid(kwargs.get("uuid"), "group uuid validation")
        self.protect_default_groups("update")
        return super().update(request=request, args=args, kwargs=kwargs)
Exemple #4
0
    def update(self, request, *args, **kwargs):
        """Update a cross-account request."""
        validate_uuid(kwargs.get("pk"),
                      "cross-account request uuid validation")

        with tenant_context(Tenant.objects.get(schema_name="public")):
            current = self.get_object()
            if current.status != "pending":
                self.throw_validation_error(
                    "cross-account update",
                    "Only pending requests may be updated.")
            if "target_account" in request.data and str(
                    request.data.get(
                        "target_account")) != current.target_account:
                self.throw_validation_error(
                    "cross-account-update",
                    "Target account may not be updated.")

            self.validate_and_format_input(request.data)

            response = super().update(request=request,
                                      args=args,
                                      kwargs=kwargs)
            if response.status_code and response.status_code is http_status.HTTP_200_OK:
                if request.data.get("status"):
                    self.update_status(current, request.data.get("status"))
                    return Response(
                        CrossAccountRequestDetailSerializer(current).data)
            return response
Exemple #5
0
    def update(self, request, *args, **kwargs):
        """Update a group.

        @api {post} /api/v1/groups/:uuid   Update a group
        @apiName updateGroup
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Update a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Group unique identifier

        @apiSuccess {String} uuid Group unique identifier
        @apiSuccess {String} name Group name
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "uuid": "16fd2706-8baf-433b-82eb-8c7fada847da",
                "name": "GroupA"
            }
        """
        validate_uuid(kwargs.get("uuid"), "group uuid validation")
        self.protect_default_groups("update")
        group_name = Group.objects.get(uuid=kwargs.get("uuid")).name
        with tenant_context(Tenant.objects.get(schema_name="public")):
            group_in_public, _ = Group.objects.update_or_create(
                name=group_name, tenant=request.tenant, defaults=request.data)
        return super().update(request=request, args=args, kwargs=kwargs)
Exemple #6
0
    def destroy(self, request, *args, **kwargs):
        """Delete a role.

        @api {delete} /api/v1/roles/:uuid   Delete a role
        @apiName deleteRole
        @apiGroup Role
        @apiVersion 1.0.0
        @apiDescription Delete a role

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} uuid Role unique identifier

        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 204 NO CONTENT
        """
        validate_uuid(kwargs.get("uuid"), "role uuid validation")
        role = self.get_object()
        if role.system or role.platform_default:
            key = "role"
            message = "System roles cannot be deleted."
            error = {key: [_(message)]}
            raise serializers.ValidationError(error)
        with transaction.atomic():
            # Remove role in public schema.
            with tenant_context(Tenant.objects.get(schema_name="public")):
                role_public = Role.objects.get(name=role.name,
                                               tenant=request.tenant)
                self.delete_policies_if_no_role_attached(role_public)
                role_public.delete()

            self.delete_policies_if_no_role_attached(role)
            return super().destroy(request=request, args=args, kwargs=kwargs)
Exemple #7
0
    def destroy(self, request, *args, **kwargs):
        """Delete a role.

        @api {delete} /api/v1/roles/:uuid   Delete a role
        @apiName deleteRole
        @apiGroup Role
        @apiVersion 1.0.0
        @apiDescription Delete a role

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} uuid Role unique identifier

        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 204 NO CONTENT
        """
        validate_uuid(kwargs.get("uuid"), "role uuid validation")
        role = self.get_object()
        if role.system or role.platform_default:
            key = "role"
            message = "System roles cannot be deleted."
            error = {key: [_(message)]}
            raise serializers.ValidationError(error)
        with transaction.atomic():
            policies = role.policies.all()
            for policy in policies:
                if policy.roles.count() == 1:
                    policy.delete()
            return super().destroy(request=request, args=args, kwargs=kwargs)
Exemple #8
0
    def access(self, request, uuid=None):
        """Return access objects for specified role."""
        validate_uuid(uuid, "role uuid validation")
        try:
            role = Role.objects.get(uuid=uuid)
        except (Role.DoesNotExist, ValidationError):
            raise Http404()

        access = AccessSerializer(role.access, many=True).data
        page = self.paginate_queryset(access)
        return self.get_paginated_response(page)
Exemple #9
0
 def partial_update(self, request, *args, **kwargs):
     """Patch a role."""
     validate_uuid(kwargs.get("uuid"), "role uuid validation")
     payload = json.loads(request.body)
     for field in payload:
         if field not in VALID_PATCH_FIELDS:
             key = "role"
             message = f"Field '{field}' is not supported. Please use one or more of: {VALID_PATCH_FIELDS}."
             error = {key: [_(message)]}
             raise serializers.ValidationError(error)
     return super().update(request=request, args=args, kwargs=kwargs)
Exemple #10
0
    def update(self, request, *args, **kwargs):
        """Update a cross-account request."""
        validate_uuid(kwargs.get("pk"), "cross-account request uuid validation")

        with tenant_context(Tenant.objects.get(schema_name="public")):
            current = self.get_object()
            self.check_update_permission(request, current)

            request.data["target_account"] = current.target_account
            self.validate_and_format_input(request.data)

            response = super().update(request=request, args=args, kwargs=kwargs)
            if response.status_code and response.status_code is http_status.HTTP_200_OK:
                if request.data.get("status"):
                    self.update_status(current, request.data.get("status"))
                    return Response(CrossAccountRequestDetailSerializer(current).data)
            return response
Exemple #11
0
    def destroy(self, request, *args, **kwargs):
        """Delete a group.

        @api {delete} /api/v1/groups/:uuid   Delete a group
        @apiName deleteGroup
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Delete a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} uuid Group unique identifier

        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 204 NO CONTENT
        """
        validate_uuid(kwargs.get("uuid"), "group uuid validation")
        self.protect_default_groups("delete")
        return super().destroy(request=request, args=args, kwargs=kwargs)
Exemple #12
0
    def retrieve(self, request, *args, **kwargs):
        """Get a role.

        @api {get} /api/v1/roles/:uuid   Get a role
        @apiName getRole
        @apiGroup Role
        @apiVersion 1.0.0
        @apiDescription Get a role

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Role unique identifier.

        @apiSuccess {String} uuid Role unique identifier
        @apiSuccess {String} name Role name
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "uuid": "16fd2706-8baf-433b-82eb-8c7fada847da",
                "name": "RoleA",
                "display_name": "RoleA",
                "access": [
                    {
                    "permission": "app:*:read",
                    "resourceDefinitions": [
                        {
                            "attributeFilter": {
                                "key": "app.attribute.case",
                                "operation": "equal",
                                "value": "thevalue"
                            }
                        }
                    ]
                    }
                ]
            }
        """
        validate_uuid(kwargs.get("uuid"), "role uuid validation")
        return super().retrieve(request=request, args=args, kwargs=kwargs)
Exemple #13
0
    def destroy(self, request, *args, **kwargs):
        """Delete a group.

        @api {delete} /api/v1/groups/:uuid   Delete a group
        @apiName deleteGroup
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Delete a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} uuid Group unique identifier

        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 204 NO CONTENT
        """
        validate_uuid(kwargs.get("uuid"), "group uuid validation")
        self.protect_default_groups("delete")
        group_name = Group.objects.get(uuid=kwargs.get("uuid")).name
        with tenant_context(Tenant.objects.get(schema_name="public")):
            Group.objects.filter(name=group_name, tenant=request.tenant).delete()
        return super().destroy(request=request, args=args, kwargs=kwargs)
Exemple #14
0
 def uuid_filter(self, queryset, field, values):
     """Filter for group uuid lookup."""
     uuids = values.split(",")
     for uuid in uuids:
         validate_uuid(uuid, "groups uuid filter")
     return CommonFilters.multiple_values_in(self, queryset, field, values)
Exemple #15
0
    def principals(self, request, uuid=None):
        """Get, add or remove principals from a group."""
        """
        @api {get} /api/v1/groups/:uuid/principals/    Get principals for a group
        @apiName getPrincipals
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Get principals for a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Group unique identifier

        @apiSuccess {String} uuid Group unique identifier
        @apiSuccess {String} name Group name
        @apiSuccess {Array} principals Array of principals
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "principals": [
                    { "username": "******" }
                ]
            }
        """
        """
        @api {post} /api/v1/groups/:uuid/principals/   Add principals to a group
        @apiName addPrincipals
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Add principals to a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Group unique identifier

        @apiParam (Request Body) {String} username Principal username
        @apiParamExample {json} Request Body:
            {
                "principals": [
                    {
                        "username": "******"
                    },
                    {
                        "username": "******"
                    }
                ]
            }

        @apiSuccess {String} uuid Group unique identifier
        @apiSuccess {String} name Group name
        @apiSuccess {Array} principals Array of principals
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "uuid": "16fd2706-8baf-433b-82eb-8c7fada847da",
                "name": "GroupA",
                "principals": [
                    { "username": "******" }
                ]
            }
        """
        """
        @api {delete} /api/v1/groups/:uuid/principals/   Remove principals from group
        @apiName removePrincipals
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Remove principals from a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Group unique identifier

        @apiParam (Query) {String} usernames List of comma separated principal usernames

        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 204 NO CONTENT
        """
        principals = []
        validate_uuid(uuid, "group uuid validation")
        group = self.get_object()
        account = self.request.user.account
        if request.method == "POST":
            serializer = GroupPrincipalInputSerializer(data=request.data)
            if serializer.is_valid(raise_exception=True):
                principals = serializer.data.pop("principals")
            resp = self.add_principals(group, principals, account)
            if isinstance(resp, dict) and "errors" in resp:
                return Response(status=resp["status_code"],
                                data=resp["errors"])
            output = GroupSerializer(resp)
            response = Response(status=status.HTTP_200_OK, data=output.data)
        elif request.method == "GET":
            principals_from_params = self.filtered_principals(group, request)
            page = self.paginate_queryset(principals_from_params)
            serializer = PrincipalSerializer(page, many=True)
            principal_data = serializer.data
            if principal_data:
                username_list = [
                    principal["username"] for principal in principal_data
                ]
            else:
                username_list = []
            proxy = PrincipalProxy()
            all_valid_fields = VALID_PRINCIPAL_ORDER_FIELDS + [
                "-" + field for field in VALID_PRINCIPAL_ORDER_FIELDS
            ]
            if request.query_params.get(ORDERING_PARAM):
                sort_field = validate_and_get_key(request.query_params,
                                                  ORDERING_PARAM,
                                                  all_valid_fields, "username")
                sort_order = "des" if sort_field == "-username" else "asc"
            else:
                sort_order = None
            resp = proxy.request_filtered_principals(username_list,
                                                     account,
                                                     sort_order=sort_order)
            if isinstance(resp, dict) and "errors" in resp:
                return Response(status=resp.get("status_code"),
                                data=resp.get("errors"))
            response = self.get_paginated_response(resp.get("data"))
        else:
            if USERNAMES_KEY not in request.query_params:
                key = "detail"
                message = "Query parameter {} is required.".format(
                    USERNAMES_KEY)
                raise serializers.ValidationError({key: _(message)})
            username = request.query_params.get(USERNAMES_KEY, "")
            principals = [name.strip() for name in username.split(",")]
            self.remove_principals(group, principals, account)
            response = Response(status=status.HTTP_204_NO_CONTENT)
        return response
Exemple #16
0
    def roles(self, request, uuid=None):
        """Get, add or remove roles from a group."""
        """
        @api {get} /api/v1/groups/:uuid/roles/   Get roles for a group
        @apiName getRoles
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Get roles for a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Group unique identifier.

        @apiParam (Query) {String} order_by Determine ordering of returned roles.

        @apiSuccess {Array} data Array of roles
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "data": [
                    {
                        "name": "RoleA",
                        "uuid": "4df211e0-2d88-49a4-8802-728630224d15",
                        "description": "RoleA Description",
                        "policyCount: 0,
                        "applications": [],
                        "system": false,
                        "platform_default": false
                    }
                ]
            }
        """
        """
        @api {post} /api/v1/groups/:uuid/roles/   Add roles to a group
        @apiName addRoles
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Add roles to a group
        @apiHeader {String} token User authorization token
        @apiParam (Path) {String} id Group unique identifier
        @apiParam (Request Body) {Array} roles Array of role UUIDs
        @apiParamExample {json} Request Body:
            {
                "roles": [
                    "4df211e0-2d88-49a4-8802-728630224d15"
                ]
            }
        @apiSuccess {String} uuid Group unique identifier
        @apiSuccess {String} name Group name
        @apiSuccess {Array} roles Array of roles
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "data": [
                    {
                        "name": "RoleA",
                        "uuid": "4df211e0-2d88-49a4-8802-728630224d15",
                        "description": "RoleA Description",
                        "policyCount: 0,
                        "applications": [],
                        "system": false,
                        "platform_default": false
                    }
                ]
            }
        """
        """
        @api {delete} /api/v1/groups/:uuid/roles/   Remove roles from group
        @apiName removeRoles
        @apiGroup Group
        @apiVersion 1.0.0
        @apiDescription Remove roles from a group

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Group unique identifier

        @apiParam (Query) {String} roles List of comma separated role UUIDs

        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 204 NO CONTENT
        """
        roles = []
        validate_uuid(uuid, "group uuid validation")
        group = self.get_object()
        if request.method == "POST":
            serializer = GroupRoleSerializerIn(data=request.data)
            if serializer.is_valid(raise_exception=True):
                roles = request.data.pop(ROLES_KEY, [])
            add_roles(group, roles)
            set_system_flag_post_update(group)
            response_data = GroupRoleSerializerIn(group)
        elif request.method == "GET":
            serialized_roles = self.obtain_roles(request, group)
            page = self.paginate_queryset(serialized_roles)
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        else:
            if ROLES_KEY not in request.query_params:
                key = "detail"
                message = "Query parameter {} is required.".format(ROLES_KEY)
                raise serializers.ValidationError({key: _(message)})

            role_ids = request.query_params.get(ROLES_KEY, "").split(",")
            serializer = GroupRoleSerializerIn(data={"roles": role_ids})
            if serializer.is_valid(raise_exception=True):
                remove_roles(group, role_ids)
                set_system_flag_post_update(group)

            return Response(status=status.HTTP_204_NO_CONTENT)

        return Response(status=status.HTTP_200_OK, data=response_data.data)
Exemple #17
0
    def update(self, request, *args, **kwargs):
        """Update a group.

        @api {post} /api/v1/roles/:uuid   Update a role
        @apiName updateRole
        @apiGroup Role
        @apiVersion 1.0.0
        @apiDescription Update a role

        @apiHeader {String} token User authorization token

        @apiParam (Path) {String} id Role unique identifier

        @apiParam (Request Body) {String} name Role name
        @apiParam (Request Body) {Array} access Access definition
        @apiParamExample {json} Request Body:
            {
                "name": "RoleA",
                "access": [
                    {
                    "permission": "app:*:read",
                    "resourceDefinitions": [
                        {
                            "attributeFilter": {
                                "key": "app.attribute.case",
                                "operation": "equal",
                                "value": "change_value"
                            }
                        }
                    ]
                    }
                ]
            }

        @apiSuccess {String} uuid Role unique identifier
        @apiSuccess {String} name Role name
        @apiSuccessExample {json} Success-Response:
            HTTP/1.1 200 OK
            {
                "uuid": "16fd2706-8baf-433b-82eb-8c7fada847da",
                "name": "RoleA",
                "display_name": "RoleA",
                "access": [
                    {
                    "permission": "app:*:read",
                    "resourceDefinitions": [
                        {
                            "attributeFilter": {
                                "key": "app.attribute.case",
                                "operation": "equal",
                                "value": "change_value"
                            }
                        }
                    ]
                    }
                ]
            }
        """
        validate_uuid(kwargs.get("uuid"), "role uuid validation")
        access_list = self.validate_and_get_access_list(request.data)
        if access_list:
            for perm in access_list:
                app = perm.get("permission").split(":")[0]
                if app not in settings.ROLE_CREATE_ALLOW_LIST:
                    key = "role"
                    message = "Custom roles cannot be created for {}".format(
                        app)
                    error = {key: [_(message)]}
                    raise serializers.ValidationError(error)
        return super().update(request=request, args=args, kwargs=kwargs)