Skip to content

Commit

Permalink
Add APIs and logic for internal API integration
Browse files Browse the repository at this point in the history
Signed-off-by: Chris Mitchell <[email protected]>
  • Loading branch information
wcmitchell committed Jun 1, 2022
1 parent e69cda8 commit e96c179
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 8 deletions.
61 changes: 61 additions & 0 deletions rbac/internal/integration_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#
# Copyright 2020 Red Hat, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#

"""View for OCM group/role API."""
from audioop import reverse
import datetime
import json
import logging

import pytz
from django.conf import settings
from django.db import transaction
from django.db.migrations.recorder import MigrationRecorder
from django.http import Http404, HttpResponse
from django.shortcuts import redirect, reverse
from management import views
from management.cache import TenantCache
from management.models import Group, Role


from api.models import Tenant


logger = logging.getLogger(__name__)
TENANTS = TenantCache()

def groups(request, account_number):
username = request.GET.get("username")
if username:
base_url = reverse("group-list")
url = f'{base_url}?principals={username}'
return redirect(url)
else:
return Http404

def groups_for_principal(request, account_number, username):
base_url = reverse("group-list")
url = f'{base_url}?principals={username}'
return redirect(url)

def roles_from_group(request, account_number, uuid):
return redirect("group-roles", uuid=uuid)

def roles_for_group(request, account_number, username, uuid):
base_url = reverse("group-roles", kwargs={'uuid': uuid})
url = f'{base_url}?principals={username}'
return redirect(url)
11 changes: 10 additions & 1 deletion rbac/internal/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@

from django.conf import settings
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404
from django.urls import resolve
from django.utils.deprecation import MiddlewareMixin

from api.common import RH_IDENTITY_HEADER
from api.models import User
from api.models import User, Tenant
from api.serializers import extract_header
from rbac.middleware import IdentityHeaderMiddleware


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -58,8 +61,14 @@ def process_request(self, request):
logger.error("Malformed X-RH-Identity header.")
return HttpResponseForbidden()

if "integration" in resolve(request.path).url_name:
return IdentityHeaderMiddleware.process_request(self, request)

request.user = user

def process_response(self, request, response):
"""Process responses for internal identity middleware."""
return response

def get_tenant(self, request):
request.tenant = get_object_or_404(Tenant, tenant_name=self.tenant_re.match(request.path_info).group('tenant_id'))
6 changes: 5 additions & 1 deletion rbac/internal/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@

from django.urls import path

from . import views
from . import integration_views, views
from .views import trigger_error

urlpatterns = [
path("api/tenant/unmodified/", views.list_unmodified_tenants),
path("api/tenant/", views.list_tenants),
path("api/tenant/<str:tenant_name>/", views.tenant_view),
path("api/tenant/<str:account_number>/groups/", integration_views.groups, name="integration-groups"),
path("api/tenant/<str:account_number>/groups/<str:uuid>/roles/", integration_views.roles_from_group, name="integration-group-roles"),
path("api/tenant/<str:account_number>/principal/<str:username>/groups/", integration_views.groups_for_principal, name="integration-princ-groups"),
path("api/tenant/<str:account_number>/principal/<str:username>/groups/<str:uuid>/roles/", integration_views.roles_for_group, name="integration-princ-roles"),
path("api/migrations/run/", views.run_migrations),
path("api/migrations/progress/", views.migration_progress),
path("api/seeds/run/", views.run_seeds),
Expand Down
17 changes: 16 additions & 1 deletion rbac/management/group/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,31 @@ def roles_filter(self, queryset, field, values):
queryset = queryset.filter(policies__roles__name__icontains=role_name)
return queryset

def principal_filter(self, queryset, field, values):
"""Filter for groups containing principals."""
if not values:
key = "groups_filter"
message = "No principals provided to filter groups!"
error = {key: [_(message)]}
raise serializers.ValidationError(error)
principals = [value.lower() for value in values.split(",")]

for principal in principals:
queryset = queryset.filter(principals__username__icontains=principal)

return queryset

name = filters.CharFilter(field_name="name", method="name_filter")
role_names = filters.CharFilter(field_name="role_names", method="roles_filter")
uuid = filters.CharFilter(field_name="uuid", method="uuid_filter")
principals = filters.CharFilter(field_name="principals", method="principal_filter")
system = filters.BooleanFilter(field_name="system")
platform_default = filters.BooleanFilter(field_name="platform_default")
admin_default = filters.BooleanFilter(field_name="admin_default")

class Meta:
model = Group
fields = ["name", "role_names", "uuid"]
fields = ["name", "role_names", "uuid", "principals"]


class GroupViewSet(
Expand Down
4 changes: 2 additions & 2 deletions rbac/rbac/dev_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ def process_request(self, request): # pylint: disable=no-self-use
"identity": {
"account_number": "10001",
"org_id": "11111",
"type": "User",
"user": {
"type": "Associate",
"associate": {
"username": "user_dev",
"email": "[email protected]",
"is_org_admin": True,
Expand Down
10 changes: 7 additions & 3 deletions rbac/rbac/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class IdentityHeaderMiddleware(MiddlewareMixin):

header = RH_IDENTITY_HEADER

def get_tenant(self, model, hostname, request):
def get_tenant(self, request):
"""Override the tenant selection logic."""
if settings.AUTHENTICATE_WITH_ORG_ID:
tenant_name = create_tenant_name(request.user.account)
Expand Down Expand Up @@ -184,7 +184,11 @@ def process_request(self, request): # pylint: disable=R1710
_, json_rh_auth = extract_header(request, self.header)
user.account = json_rh_auth.get("identity", {})["account_number"]
user.org_id = json_rh_auth.get("identity", {}).get("org_id")
user_info = json_rh_auth.get("identity", {}).get("user", {})
usertype = json_rh_auth.get("identity", {}).get("type")
if usertype.lower() == "associate":
user_info = json_rh_auth.get("identity", {}).get("associate", {})
else:
user_info = json_rh_auth.get("identity", {}).get("user", {})
user.username = user_info["username"]
user.admin = user_info.get("is_org_admin")
user.internal = user_info.get("is_internal")
Expand Down Expand Up @@ -239,7 +243,7 @@ def process_request(self, request): # pylint: disable=R1710
raise error
if user.username and (user.account or user.org_id):
request.user = user
request.tenant = self.get_tenant(model=None, hostname=None, request=request)
request.tenant = self.get_tenant(request=request)

def process_response(self, request, response): # pylint: disable=no-self-use
"""Process response for identity middleware.
Expand Down

0 comments on commit e96c179

Please sign in to comment.