Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promote Changes to QA - 2/11/2020 #202

Merged
merged 27 commits into from
Feb 12, 2020
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
83a4372
Update testing to allow for nonadmin and start RonR removal
wcmitchell Jan 16, 2020
61b1279
Shows error when proxy encounter exception
astrozzc Jan 17, 2020
76afbd9
Merge pull request #191 from astrozzc/show_error
astrozzc Jan 20, 2020
7fd6f0f
Clean up unused arguments, move tests to group rather than access
wcmitchell Jan 21, 2020
549deaa
Merge branch 'master' into drop_RonR_perms
wcmitchell Jan 21, 2020
e8816dc
Merge pull request #190 from wcmitchell/drop_RonR_perms
astrozzc Jan 22, 2020
d9e4f51
Add migration aimed at removing RBAC on RBAC roles
wcmitchell Jan 24, 2020
b2e663a
Remove left in pdb breakpoint
wcmitchell Jan 24, 2020
13a4421
Incorporate PR suggestions
wcmitchell Jan 27, 2020
c1fb096
Merge pull request #192 from wcmitchell/RonR_removal_migration
wcmitchell Jan 28, 2020
dba0ad9
Add data migration to remove default seeded roles
coderbydesign Jan 29, 2020
1cefbb8
Update name of data migration method
coderbydesign Jan 31, 2020
debb5b0
Merge pull request #193 from coderbydesign/remove-default-roles
coderbydesign Feb 3, 2020
2389fef
Remove default `limit` on `/access/` requests
coderbydesign Feb 4, 2020
199c1fb
Update openapi.json spec with responses for `/access/`
coderbydesign Feb 4, 2020
432d9ff
Add accessCount to /roles/ and /roles/<uuid>/ endpoints
coderbydesign Feb 4, 2020
e9b9e65
Add accessCount to openapi.json spec
coderbydesign Feb 4, 2020
c16707b
Merge pull request #195 from coderbydesign/remove-default-limit-on-ac…
coderbydesign Feb 5, 2020
54ff2f6
Merge branch 'master' into add-permissions-count-to-roles-endpoint
coderbydesign Feb 5, 2020
a55b610
Merge pull request #197 from coderbydesign/add-permissions-count-to-r…
coderbydesign Feb 5, 2020
6af7b4b
Add GET /roles/<uuid>/access/ endpoint
coderbydesign Feb 5, 2020
1a8e156
Update openapi.json spec for GET /roles/<uuid>/access/
coderbydesign Feb 6, 2020
a916e58
Remove superfluous conditional
coderbydesign Feb 7, 2020
8cd6128
Merge pull request #198 from coderbydesign/add-role-access-get-endpoint
coderbydesign Feb 11, 2020
b6b8c5e
Add settings for smoke test run
catastrophe-brandon Feb 12, 2020
84b357a
Fix whitespace
catastrophe-brandon Feb 12, 2020
f64985f
Merge pull request #205 from catastrophe-brandon/jenkinsfile-smoke-se…
coderbydesign Feb 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions docs/source/specs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,89 @@
}
}
},
"/roles/{uuid}/access/": {
"get": {
"tags": [
"Role"
],
"summary": "Get access for a role in the tenant",
"operationId": "getRoleAccess",
"parameters": [
{
"name": "uuid",
"in": "path",
"description": "ID of the role",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"$ref": "#/components/parameters/QueryLimit"
},
{
"$ref": "#/components/parameters/QueryOffset"
}
],
"responses": {
"200": {
"description": "A paginated list of the access objects for a role",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/AccessPagination"
}
}
}
}
}
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Insufficient permissions to get access for role",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error403"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"500": {
"description": "Unexpected Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/policies/": {
"post": {
"tags": [
Expand Down Expand Up @@ -1417,19 +1500,34 @@
}
},
{
"$ref": "#/components/parameters/QueryLimit"
"$ref": "#/components/parameters/QueryLimitNoDefault"
},
{
"$ref": "#/components/parameters/QueryOffset"
}
],
"responses": {
"200": {
"description": "A paginated list of access objects",
"description": "A list of access objects. By default, this request will not be paginated. To received a paginated response, include the `/?limit=` query parameter.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccessPagination"
"oneOf": [
{
"$ref": "#/components/schemas/AccessNoPagination"
},
{
"$ref": "#/components/schemas/AccessPagination"
}
]
},
"examples": {
"AccessNoPagination": {
"$ref": "#/components/examples/AccessNoPagination"
},
"AccessPagination": {
"$ref": "#/components/examples/AccessPagination"
}
}
}
}
Expand Down Expand Up @@ -1491,6 +1589,17 @@
"maximum": 1000
}
},
"QueryLimitNoDefault": {
"in": "query",
"name": "limit",
"required": false,
"description": "Parameter for selecting the amount of data returned.",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 1000
}
},
"NameFilter": {
"in": "query",
"name": "name",
Expand Down Expand Up @@ -2057,6 +2166,10 @@
"type": "integer",
"minimum": 0
},
"accessCount": {
"type": "integer",
"minimum": 0
},
"applications": {
"type": "array",
"items": {
Expand Down Expand Up @@ -2214,6 +2327,24 @@
}
]
},
"AccessNoPagination": {
"allOf": [
{
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Access"
}
}
}
}
]
},
"Status": {
"required": [
"api_version"
Expand Down Expand Up @@ -2265,6 +2396,39 @@
}
}
}
},
"examples": {
"AccessNoPagination": {
"value": {
"data": [
{
"permission": "app-name:*:*",
"resourceDefinitions": []
}
]
}
},
"AccessPagination": {
"value": {
"meta": {
"count": 1,
"limit": 10,
"offset": 0
},
"links": {
"first": "/access/?application=app-name&limit=10",
"next": null,
"previous": null,
"last": "/access/?application=app-name&limit=10"
},
"data": [
{
"permission": "app-name:*:*",
"resourceDefinitions": []
}
]
}
}
}
}
}
9 changes: 5 additions & 4 deletions rbac/management/access/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"""View for principal access."""
from management.querysets import get_access_queryset
from management.role.serializer import AccessSerializer
from rest_framework import status
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.settings import api_settings
Expand Down Expand Up @@ -83,17 +82,19 @@ def get_queryset(self):

def get(self, request):
"""Provide access data for prinicpal."""
page = self.paginate_queryset(self.get_queryset())
queryset = self.get_queryset()
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.serializer_class(page, many=True)
return self.get_paginated_response(serializer.data)
return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)

return Response({'data': self.serializer_class(queryset, many=True).data})

@property
def paginator(self):
"""Return the paginator instance associated with the view, or `None`."""
if not hasattr(self, '_paginator'):
if self.pagination_class is None:
if self.pagination_class is None or 'limit' not in self.request.query_params:
self._paginator = None
else:
self._paginator = self.pagination_class()
Expand Down
8 changes: 6 additions & 2 deletions rbac/management/group/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ def add_principals(self, group, principals, account):
"""Process list of principals and add them to the group."""
users = [principal.get('username') for principal in principals]
resp = self.proxy.request_filtered_principals(users, account, limit=len(users))
if 'errors' in resp:
return resp
for item in resp.get('data', []):
username = item['username']
try:
Expand Down Expand Up @@ -354,8 +356,10 @@ def principals(self, request, uuid=None):
serializer = GroupPrincipalInputSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
principals = serializer.data.pop('principals')
group = self.add_principals(group, principals, account)
output = GroupSerializer(group)
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)
return Response(status=status.HTTP_200_OK, data=output.data)
else:
if USERNAMES_KEY not in request.query_params:
Expand Down
36 changes: 36 additions & 0 deletions rbac/management/migrations/0012_remove_RonR_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 2.2.4 on 2019-11-26 17:03

from django.db import migrations, models


def remove_rbac_roles(apps, schema_editor):
# get all permissions/access objects for RBAC
Access = apps.get_model('management', 'Access')
rbac_permissions = Access.objects.filter(permission__contains='rbac:')

# iterate through all RBAC permissions
for rbac_permission in rbac_permissions:
# get the role for the permission (bubbling up)
role = rbac_permission.role

# check to see if there are any access objects that are not RBAC
non_rbac_permissions = role.access.exclude(permission__contains='rbac:')

# if so, just delete the access object we know is RBAC, and leave the role
if non_rbac_permissions:
# this will still delete the resource definitions for the access object
rbac_permission.delete()
else:
# otherwise, we only have RBAC access objects, so delete everything
role.delete()


class Migration(migrations.Migration):

dependencies = [
('management', '0011_group_naming'),
]

operations = [
migrations.RunPython(remove_rbac_roles)
]
27 changes: 27 additions & 0 deletions rbac/management/migrations/0013_auto_20200128_2030.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 2.2.4 on 2020-01-28 20:30

from django.db import migrations


def remove_unnecessary_platform_default_role(apps, schema_editor):
role_names_to_remove = [
'Ansible Automation Access',
'Ansible Hub Access',
'Catalog Access',
'Remediations Access',
'Sources Access',
'Subscriptions Access',
]

Role = apps.get_model('management', 'Role')
Role.objects.filter(system=True, name__in=role_names_to_remove).delete()

class Migration(migrations.Migration):

dependencies = [
('management', '0012_remove_RonR_resources'),
]

operations = [
migrations.RunPython(remove_unnecessary_platform_default_role),
]
3 changes: 2 additions & 1 deletion rbac/management/querysets.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ def get_group_queryset(request):
def get_role_queryset(request):
"""Obtain the queryset for roles."""
scope = request.query_params.get(SCOPE_KEY, ACCOUNT_SCOPE)
base_query = Role.objects.prefetch_related('access').annotate(policyCount=Count('policies', distinct=True))
base_query = Role.objects.prefetch_related('access').annotate(policyCount=Count('policies', distinct=True),
accessCount=Count('access', distinct=True))
if scope != ACCOUNT_SCOPE:
return get_object_principal_queryset(request, scope, Role,
**{'prefetch_lookups_for_ids': 'access',
Expand Down
6 changes: 4 additions & 2 deletions rbac/management/role/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class RoleSerializer(serializers.ModelSerializer):
description = serializers.CharField(allow_null=True, required=False)
access = AccessSerializer(many=True)
policyCount = serializers.IntegerField(read_only=True)
accessCount = serializers.IntegerField(read_only=True)
applications = serializers.SerializerMethodField()
system = serializers.BooleanField(read_only=True)
platform_default = serializers.BooleanField(read_only=True)
Expand All @@ -81,7 +82,7 @@ class Meta:

model = Role
fields = ('uuid', 'name', 'description',
'access', 'policyCount',
'access', 'policyCount', 'accessCount',
'applications', 'system',
'platform_default', 'created',
'modified')
Expand Down Expand Up @@ -142,6 +143,7 @@ class RoleMinimumSerializer(serializers.ModelSerializer):
created = serializers.DateTimeField(read_only=True)
modified = serializers.DateTimeField(read_only=True)
policyCount = serializers.IntegerField(read_only=True)
accessCount = serializers.IntegerField(read_only=True)
applications = serializers.SerializerMethodField()
system = serializers.BooleanField(read_only=True)
platform_default = serializers.BooleanField(read_only=True)
Expand All @@ -151,7 +153,7 @@ class Meta:

model = Role
fields = ('uuid', 'name', 'description', 'created', 'modified', 'policyCount',
'applications', 'system', 'platform_default')
'accessCount', 'applications', 'system', 'platform_default')

def get_applications(self, obj):
"""Get the list of applications in the role."""
Expand Down
Loading