Exemple #1
0
    def get(self, request):
        """List principals for account."""
        user = request.user
        path = request.path
        query_params = request.query_params
        default_limit = StandardResultsSetPagination.default_limit
        usernames_filter = ""
        options = {}
        try:
            limit = int(query_params.get("limit", default_limit))
            offset = int(query_params.get("offset", 0))
            options["sort_order"] = validate_and_get_key(
                query_params, SORTORDER_KEY, VALID_SORTORDER_VALUE, "asc")
            options["status"] = validate_and_get_key(query_params, STATUS_KEY,
                                                     VALID_STATUS_VALUE,
                                                     "enabled")
        except ValueError:
            error = {
                "detail":
                "Values for limit and offset must be positive numbers.",
                "source": "principals",
                "status": str(status.HTTP_400_BAD_REQUEST),
            }
            errors = {"errors": [error]}
            return Response(status=status.HTTP_400_BAD_REQUEST, data=errors)

        previous_offset = 0
        if offset - limit > 0:
            previous_offset = offset - limit

        resp, usernames_filter = self.users_from_proxy(user, query_params,
                                                       options, limit, offset)

        status_code = resp.get("status_code")
        response_data = {}
        if status_code == status.HTTP_200_OK:
            data = resp.get("data", [])
            if isinstance(data, dict):
                count = data.get("userCount")
                data = data.get("users")
            elif isinstance(data, list):
                count = len(data)
            else:
                count = None
            response_data["meta"] = {"count": count}
            response_data["links"] = {
                "first": f"{path}?limit={limit}&offset=0{usernames_filter}",
                "next":
                f"{path}?limit={limit}&offset={offset + limit}{usernames_filter}",
                "previous":
                f"{path}?limit={limit}&offset={previous_offset}{usernames_filter}",
                "last": None,
            }
            response_data["data"] = data
        else:
            response_data = resp
            del response_data["status_code"]

        return Response(status=status_code, data=response_data)
Exemple #2
0
    def retrieve(self, request, *args, **kwargs):
        """Retrive cross account requests by request_id."""
        with tenant_context(Tenant.objects.get(schema_name="public")):
            result = super().retrieve(request=request,
                                      args=args,
                                      kwargs=kwargs)

        if validate_and_get_key(self.request.query_params, QUERY_BY_KEY,
                                VALID_QUERY_BY_KEY, ACCOUNT) == ACCOUNT:
            user_id = result.data.pop("user_id")
            principal = PROXY.request_filtered_principals([user_id],
                                                          account=None,
                                                          options={
                                                              "query_by":
                                                              "user_id",
                                                              "return_id": True
                                                          }).get("data")[0]

            # Replace the user_id with user's info
            result.data.update({
                "first_name": principal["first_name"],
                "last_name": principal["last_name"],
                "email": principal["email"],
            })
        return result
Exemple #3
0
 def get_queryset(self):
     """Get query set based on the queryBy key word."""
     if self.request.method in ["PATCH", "PUT"]:
         return CrossAccountRequest.objects.all()
     if validate_and_get_key(self.request.query_params, QUERY_BY_KEY, VALID_QUERY_BY_KEY, ACCOUNT) == ACCOUNT:
         return CrossAccountRequest.objects.filter(target_account=self.request.user.account)
     return CrossAccountRequest.objects.filter(user_id=self.request.user.user_id)
Exemple #4
0
    def name_filter(self, queryset, field, value, name_field="name"):
        """Filter to lookup name, partial or exact."""
        match_criteria = validate_and_get_key(self.request.query_params, NAME_MATCH_KEY, VALID_NAME_MATCHES, "partial")

        if match_criteria == "partial":
            return queryset.filter(**{f"{name_field}__icontains": value})
        elif match_criteria == "exact":
            return queryset.filter(**{f"{name_field}__iexact": value})
Exemple #5
0
    def list(self, request, *args, **kwargs):
        """List cross account requests for account/user_id."""
        validate_limit_and_offset(self.request.query_params)

        result = super().list(request=request, args=args, kwargs=kwargs)
        # The approver's view requires requester's info such as first name, last name, email address.
        if validate_and_get_key(self.request.query_params, QUERY_BY_KEY, VALID_QUERY_BY_KEY, ACCOUNT) == ACCOUNT:
            return self.replace_user_id_with_info(result)
        return result
Exemple #6
0
 def validate_and_get_param(self, params):
     """Validate input parameters and get ordering and sub_key."""
     validate_limit_and_offset(params)
     app = params.get(APPLICATION_KEY)
     sub_key = app
     ordering = validate_and_get_key(params, ORDER_FIELD, VALID_ORDER_VALUES, required=False)
     if ordering:
         sub_key = f"{app}&order:{ordering}"
     return sub_key, ordering
Exemple #7
0
 def exclude_globals_filter(self, queryset, field, value):
     """Filter to filter out global permissions from results."""
     query_field = validate_and_get_key(self.request.query_params, field,
                                        VALID_EXCLUDE_GLOBALS_VALUES,
                                        "false")
     if query_field == "true":
         exclude_set = Q(application="*") | Q(resource_type="*") | Q(
             verb="*")
         return queryset.exclude(exclude_set)
     return queryset
Exemple #8
0
    def users_from_proxy(self, user, query_params, options, limit, offset):
        """Format principal request for proxy and return prepped result."""
        proxy = PrincipalProxy()
        usernames = query_params.get(USERNAMES_KEY)
        email = query_params.get(EMAIL_KEY)
        match_criteria = validate_and_get_key(query_params, MATCH_CRITERIA_KEY,
                                              VALID_MATCH_VALUE, "exact")

        if not usernames and not email:
            options["admin_only"] = validate_and_get_key(
                query_params, ADMIN_ONLY_KEY, VALID_ADMIN_ONLY_VALUE, "false")
            resp = proxy.request_principals(user.account,
                                            limit=limit,
                                            offset=offset,
                                            options=options)
            return resp, ""
        proxyInput = {}
        resp = None
        if usernames:
            principals = usernames.split(",")
            if match_criteria != "partial":
                resp = proxy.request_filtered_principals(
                    principals,
                    account=user.account,
                    limit=limit,
                    offset=offset,
                    options={"sort_order": options["sort_order"]},
                )
                usernames_filter = f"&usernames={usernames}"
                return resp, usernames_filter
            else:
                proxyInput["principalStartsWith"] = principals[0]
        if email:
            if match_criteria == "partial":
                proxyInput["emailStartsWith"] = email
            else:
                proxyInput["primaryEmail"] = email
        resp = proxy.request_principals(user.account,
                                        input=proxyInput,
                                        limit=limit,
                                        offset=offset,
                                        options=options)
        return resp, ""
Exemple #9
0
    def obtain_roles(self, request, group):
        """Obtain roles based on request, supports exclusion."""
        exclude = validate_and_get_key(request.query_params, EXCLUDE_KEY, VALID_EXCLUDE_VALUES, "false")

        roles = group.roles_with_access() if exclude == "false" else self.obtain_roles_with_exclusion(request, group)

        filtered_roles = self.filtered_roles(roles, request)

        annotated_roles = filtered_roles.annotate(policyCount=Count("policies", distinct=True))

        if ORDERING_PARAM in request.query_params:
            ordered_roles = self.order_queryset(
                annotated_roles, VALID_ROLE_ORDER_FIELDS, request.query_params.get(ORDERING_PARAM)
            )

            return [RoleMinimumSerializer(role).data for role in ordered_roles]
        return [RoleMinimumSerializer(role).data for role in annotated_roles]
Exemple #10
0
    def roles_filter(self, queryset, field, values):
        """Filter for group to lookup list of role name."""
        if not values:
            key = "groups_filter"
            message = "No value of roles provided to filter groups!"
            error = {key: [_(message)]}
            raise serializers.ValidationError(error)
        roles_list = [value.lower() for value in values.split(",")]

        discriminator = validate_and_get_key(
            self.request.query_params, ROLE_DISCRIMINATOR_KEY, VALID_ROLE_ROLE_DISCRIMINATOR, "any"
        )

        if discriminator == "any":
            return queryset.filter(policies__roles__name__iregex=r"(" + "|".join(roles_list) + ")")

        for role_name in roles_list:
            queryset = queryset.filter(policies__roles__name__icontains=role_name)
        return queryset
    def has_permission(self, request, view):
        """Check permission based on identity and query by."""
        if request._request.path.startswith(reverse("cross-list")):
            if request.method == "POST":
                # Only allow associates create the request
                return request.user.internal

            query_by = validate_and_get_key(request.query_params, QUERY_BY_KEY,
                                            VALID_QUERY_BY_KEY, ACCOUNT)
            if query_by == ACCOUNT:
                return request.user.admin
            elif query_by == USER_ID:
                return request.user.internal
            return False

        if request.method not in permissions.SAFE_METHODS:
            return False

        return True
Exemple #12
0
    def options(self, request):
        """Get options of applications."""
        """
        @api {get} /api/v1/permissions/options/   Get option of permission
        @apiName getPermissionOption
        @apiGroup Permission
        @apiVersion 1.0.0
        @apiDescription Get option of permission

        @apiHeader {String} token User authorization token

        @apiParam (Query) {String} field The field to return.

        @apiParam (Query) {String} application Filter by permission name.
        @apiParam (Query) {String} resource_type Filter by resource_type.
        @apiParam (Query) {String} verb Filter by verb.

        @apiSuccess {Object[]} data  The array of results.

            HTTP/1.1 200 OK
        {
          "data": [
            catalog, approval
          ]
        }
        """
        filters = {}
        query_field = validate_and_get_key(request.query_params, QUERY_FIELD,
                                           PERMISSION_FIELD_KEYS, None)

        for key in PERMISSION_FIELD_KEYS:
            context = request.query_params.get(key)
            if context:
                filters[f"{key}__in"] = context.split(",")

        query_set = Permission.objects.distinct(query_field).filter(
            **filters).values_list(query_field, flat=True)

        if "limit" not in self.request.query_params:
            self.paginator.default_limit = self.paginator.max_limit
        page = self.paginate_queryset(query_set)
        return self.get_paginated_response(page)
Exemple #13
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 #14
0
    def get(self, request):
        """List principals for account."""
        proxy = PrincipalProxy()
        user = self.request.user
        path = self.request.path
        query_params = self.request.query_params
        default_limit = StandardResultsSetPagination.default_limit
        usernames = None
        usernames_filter = ""
        options = {}
        try:
            limit = int(query_params.get("limit", default_limit))
            offset = int(query_params.get("offset", 0))
            usernames = query_params.get(USERNAMES_KEY)
            email = query_params.get(EMAIL_KEY)
            options["sort_order"] = validate_and_get_key(
                query_params, SORTORDER_KEY, VALID_SORTORDER_VALUE, "asc")
            options["status"] = validate_and_get_key(query_params, STATUS_KEY,
                                                     VALID_STATUS_VALUE,
                                                     "enabled")
            options["admin_only"] = validate_and_get_key(
                query_params, ADMIN_ONLY_KEY, VALID_ADMIN_ONLY_VALUE, "false")
        except ValueError:
            error = {
                "detail":
                "Values for limit and offset must be positive numbers.",
                "source": "principals",
                "status": str(status.HTTP_400_BAD_REQUEST),
            }
            errors = {"errors": [error]}
            return Response(status=status.HTTP_400_BAD_REQUEST, data=errors)

        previous_offset = 0
        if offset - limit > 0:
            previous_offset = offset - limit
        if usernames:
            principals = usernames.split(",")
            resp = proxy.request_filtered_principals(
                principals,
                account=user.account,
                limit=limit,
                offset=offset,
                sort_order=options["sort_order"])
            usernames_filter = f"&usernames={usernames}"
        elif email:
            resp = proxy.request_principals(
                user.account,
                email=email,
                limit=limit,
                offset=offset,
                options={"sort_order": options["sort_order"]})
        else:
            resp = proxy.request_principals(user.account,
                                            limit=limit,
                                            offset=offset,
                                            options=options)
        status_code = resp.get("status_code")
        response_data = {}
        if status_code == status.HTTP_200_OK:
            data = resp.get("data", [])
            if isinstance(data, dict):
                count = data.get("userCount")
                data = data.get("users")
            elif isinstance(data, list):
                count = len(data)
            else:
                count = None
            response_data["meta"] = {"count": count}
            response_data["links"] = {
                "first": f"{path}?limit={limit}&offset=0{usernames_filter}",
                "next":
                f"{path}?limit={limit}&offset={offset + limit}{usernames_filter}",
                "previous":
                f"{path}?limit={limit}&offset={previous_offset}{usernames_filter}",
                "last": None,
            }
            response_data["data"] = data
        else:
            response_data = resp
            del response_data["status_code"]

        return Response(status=status_code, data=response_data)
Exemple #15
0
    def get(self, request):
        """List prinicpals for account."""
        proxy = PrincipalProxy()
        user = self.request.user
        path = self.request.path
        query_params = self.request.query_params
        default_limit = StandardResultsSetPagination.default_limit
        usernames = None
        usernames_filter = ''
        try:
            limit = int(query_params.get('limit', default_limit))
            offset = int(query_params.get('offset', 0))
            usernames = query_params.get(USERNAMES_KEY)
            email = query_params.get(EMAIL_KEY)
            sort_order = validate_and_get_key(query_params, SORTORDER_KEY,
                                              VALID_SORTORDER_VALUE, 'asc')
        except ValueError:
            error = {
                'detail':
                'Values for limit and offset must be positive numbers.',
                'source': 'principals',
                'status': status.HTTP_400_BAD_REQUEST
            }
            errors = {'errors': [error]}
            return Response(status=status.HTTP_400_BAD_REQUEST, data=errors)

        previous_offset = 0
        if offset - limit > 0:
            previous_offset = offset - limit
        if usernames:
            principals = usernames.split(',')
            resp = proxy.request_filtered_principals(principals,
                                                     account=user.account,
                                                     limit=limit,
                                                     offset=offset,
                                                     sort_order=sort_order)
            usernames_filter = f'&usernames={usernames}'
        elif email:
            resp = proxy.request_principals(user.account,
                                            email=email,
                                            limit=limit,
                                            offset=offset,
                                            sort_order=sort_order)
        else:
            resp = proxy.request_principals(user.account,
                                            limit=limit,
                                            offset=offset,
                                            sort_order=sort_order)
        status_code = resp.get('status_code')
        response_data = {}
        if status_code == status.HTTP_200_OK:
            data = resp.get('data', [])
            if isinstance(data, dict):
                count = data.get('userCount')
                data = data.get('users')
            elif isinstance(data, list):
                count = len(data)
            else:
                count = None
            response_data['meta'] = {'count': count}
            response_data['links'] = {
                'first': f'{path}?limit={limit}&offset=0{usernames_filter}',
                'next':
                f'{path}?limit={limit}&offset={offset + limit}{usernames_filter}',
                'previous':
                f'{path}?limit={limit}&offset={previous_offset}{usernames_filter}',
                'last': None,
            }
            response_data['data'] = data
        else:
            response_data = resp
            del response_data['status_code']

        return Response(status=status_code, data=response_data)