From ef79daa2398d2c55c39f4ada118d6d7f331cf416 Mon Sep 17 00:00:00 2001 From: Nivesh Mittapally Date: Mon, 13 Feb 2023 13:05:25 +0530 Subject: [PATCH 1/6] feat: mark revoke access for group --- Access/group_helper.py | 59 ++++++++++++++++++++++++++++++++-- Access/models.py | 14 +++++--- Access/views.py | 13 ++++++++ BrowserStackAutomation/urls.py | 6 ++-- 4 files changed, 83 insertions(+), 9 deletions(-) diff --git a/Access/group_helper.py b/Access/group_helper.py index 295fa34f..25be63ae 100644 --- a/Access/group_helper.py +++ b/Access/group_helper.py @@ -1,4 +1,4 @@ -from Access.models import User, GroupV2, MembershipV2, AccessV2 +from Access.models import GroupAccessMapping, User, GroupV2, MembershipV2, AccessV2 from Access import helpers, views_helper, notifications, accessrequest_helper from django.db import transaction import datetime @@ -201,6 +201,7 @@ def get_group_access_list(request, group_name): context["genericAccesses"] = [ get_generic_access(group_mapping) for group_mapping in group_mappings ] + print(group_mappings) if context["genericAccesses"] == [{}]: context["genericAccesses"] = [] @@ -769,7 +770,7 @@ def remove_member(request): ] other_memberships_groups = ( - user.get_all_memberships() + user.get_all_approved_memberships() .exclude(group=membership.group) .values_list("group", flat=True) ) @@ -800,3 +801,57 @@ def remove_member(request): membership.revoke_membership() return {"message": "Successfully removed user from group"} + + +def mark_revoked(request): + try: + request_id = request.POST.get("request_id") + if not request_id: + logger.debug("Cannot find request_id in the http request.") + raise Exception("Request id not found in the request.") + + mapping = GroupAccessMapping.get_by_id(request_id) + if not mapping: + logger.debug("Group Access Mapping not found in the database") + raise Exception("Group Access Mapping not found in the database") + except Exception as e: + logger.exception(str(e)) + return {"error": ERROR_MESSAGE} + + group = mapping.group + auth_user = request.user + if auth_user.user.has_permission("ALLOW_USER_OFFBOARD") and group.member_is_owner(auth_user.user): + raise Exception("User Unauthorized to perfrom the action") + + should_continue = False + for membership in group.get_all_approved_members(): + other_memberships_groups = ( + membership.user.get_all_approved_memberships() + .exclude(group=membership.group) + .values_list("group", flat=True) + ) + + for group in other_memberships_groups: + if group.access_exist(mapping.access): + should_continue = True + break + + if(should_continue): + should_continue = False + continue + + user_access_identity = membership.user.get_active_identity(mapping.access.access_tag) + user_access_mapping = user_access_identity.get_granted_access_mapping(mapping.access) + + + background_task( + "run_access_revoke", + json.dumps( + { + "request_id": user_access_mapping.request_id, + "revoker_email": auth_user.user.email + } + ), + ) + + return {"message": "Successfully initiated the revoke"} diff --git a/Access/models.py b/Access/models.py index e97753d8..ca276f1f 100644 --- a/Access/models.py +++ b/Access/models.py @@ -179,8 +179,8 @@ def getOwnedGroups(self): def isAdminOrOps(self): return self.is_ops or self.user.is_superuser - def get_all_memberships(self): - return self.membership_user.all() + def get_all_approved_memberships(self): + return self.membership_user.filter(status="Approved") def is_allowed_admin_actions_on_group(self, group): return ( @@ -490,7 +490,7 @@ def member_is_owner(self, user): return self.membership_group.get(user=user).is_owner def get_active_accesses(self): - return self.groupaccessmapping_set.filter( + return self.group_access_mapping.filter( status__in=["Approved", "Pending", "Declined", "SecondaryPending"] ) @@ -539,7 +539,7 @@ def get_all_approved_members(self): self.membership_group.filter(status="Approved") def get_approved_accesses(self): - return self.groupaccessmapping_set.filter(status="Approved") + return self.group_access_mapping.filter(status="Approved") def __str__(self): return self.name @@ -813,6 +813,12 @@ def getAccessRequestDetails(self, access_module): return access_request_data + def get_by_id(request_id): + try: + return GroupAccessMapping.objects.get(request_id=request_id) + except GroupAccessMapping.DoesNotExist: + return None + diff --git a/Access/views.py b/Access/views.py index 085c10bc..a97dbda1 100644 --- a/Access/views.py +++ b/Access/views.py @@ -395,3 +395,16 @@ def mark_revoked(request): json_response["error"] = str(e) status = 403 return JsonResponse(json_response, status=status) + + +def revoke_group_access(request): + try: + response = group_helper.revoke_access(request) + if("error" in response): + return JsonResponse(response, status=400) + + return JsonResponse(response) + except Exception as e: + logger.exception(str(e)) + logger.debug("Something went wrong while revoking group access") + return JsonResponse({"message": "Failed to revoke group Access"}, status=400) diff --git a/BrowserStackAutomation/urls.py b/BrowserStackAutomation/urls.py index 4780ecac..6fe41ece 100644 --- a/BrowserStackAutomation/urls.py +++ b/BrowserStackAutomation/urls.py @@ -38,7 +38,7 @@ update_group_owners, remove_group_member, ) -from Access.helpers import getAvailableAccessModules +# from Access.helpers import getAvailableAccessModules urlpatterns = [ re_path(r"^admin/", admin.site.urls), @@ -83,5 +83,5 @@ ), ] -for each_module in getAvailableAccessModules(): - urlpatterns.extend(each_module.urlpatterns) +# for each_module in getAvailableAccessModules(): +# urlpatterns.extend(each_module.urlpatterns) From 891d4af5814b382db96469ccefdac499d492a6f3 Mon Sep 17 00:00:00 2001 From: Nivesh Mittapally Date: Mon, 13 Feb 2023 13:55:55 +0530 Subject: [PATCH 2/6] refactor: revoke group Access --- Access/group_helper.py | 5 ++- Access/models.py | 2 +- Access/userlist_helper.py | 34 +++++++++---------- BrowserStackAutomation/urls.py | 2 ++ .../generic_accesses_tab.html | 8 ++++- 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/Access/group_helper.py b/Access/group_helper.py index 25be63ae..640ac0b9 100644 --- a/Access/group_helper.py +++ b/Access/group_helper.py @@ -201,7 +201,6 @@ def get_group_access_list(request, group_name): context["genericAccesses"] = [ get_generic_access(group_mapping) for group_mapping in group_mappings ] - print(group_mappings) if context["genericAccesses"] == [{}]: context["genericAccesses"] = [] @@ -803,7 +802,7 @@ def remove_member(request): return {"message": "Successfully removed user from group"} -def mark_revoked(request): +def revoke_access(request): try: request_id = request.POST.get("request_id") if not request_id: @@ -820,7 +819,7 @@ def mark_revoked(request): group = mapping.group auth_user = request.user - if auth_user.user.has_permission("ALLOW_USER_OFFBOARD") and group.member_is_owner(auth_user.user): + if not (auth_user.user.has_permission("ALLOW_USER_OFFBOARD") and group.member_is_owner(auth_user.user)): raise Exception("User Unauthorized to perfrom the action") should_continue = False diff --git a/Access/models.py b/Access/models.py index ca276f1f..8b174be0 100644 --- a/Access/models.py +++ b/Access/models.py @@ -536,7 +536,7 @@ def check_access_exist(self, access): return False def get_all_approved_members(self): - self.membership_group.filter(status="Approved") + return self.membership_group.filter(status="Approved") def get_approved_accesses(self): return self.group_access_mapping.filter(status="Approved") diff --git a/Access/userlist_helper.py b/Access/userlist_helper.py index 0d04b57e..6e29d9c4 100644 --- a/Access/userlist_helper.py +++ b/Access/userlist_helper.py @@ -41,24 +41,24 @@ def get_identity_templates(auth_user): context["configured_identity_template"] = [] context["unconfigured_identity_template"] = [] all_modules = helper.get_available_access_modules() - for user_identity in user_identities: - is_identity_configured = _is_valid_identity_json(identity=user_identity.identity) - if is_identity_configured: - module = all_modules[user_identity.access_tag] - context["configured_identity_template"].append( - { - "accessUserTemplatePath": module.get_identity_template(), - "identity" : user_identity.identity - } - ) - all_modules.pop(user_identity.access_tag) + # for user_identity in user_identities: + # is_identity_configured = _is_valid_identity_json(identity=user_identity.identity) + # if is_identity_configured: + # module = all_modules[user_identity.access_tag] + # context["configured_identity_template"].append( + # { + # "accessUserTemplatePath": module.get_identity_template(), + # "identity" : user_identity.identity + # } + # ) + # all_modules.pop(user_identity.access_tag) - for mod in all_modules.values(): - context["unconfigured_identity_template"].append( - { - "accessUserTemplatePath": mod.get_identity_template(), - } - ) + # for mod in all_modules.values(): + # context["unconfigured_identity_template"].append( + # { + # "accessUserTemplatePath": mod.get_identity_template(), + # } + # ) # context["aws_username"] = "some name" return context diff --git a/BrowserStackAutomation/urls.py b/BrowserStackAutomation/urls.py index 6fe41ece..52a4fda7 100644 --- a/BrowserStackAutomation/urls.py +++ b/BrowserStackAutomation/urls.py @@ -18,6 +18,7 @@ from django.contrib.auth import views as auth_views from django.urls import re_path, include from Access.views import ( + revoke_group_access, showAccessHistory, pendingRequests, pendingFailure, @@ -81,6 +82,7 @@ re_path( r"^group/removeGroupMember$", remove_group_member, name="remove_group_member" ), + re_path(r"^group/revokeAccess", revoke_group_access, name="revoke_group_access") ] # for each_module in getAvailableAccessModules(): diff --git a/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html b/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html index eb86f558..a411f6e5 100644 --- a/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html +++ b/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html @@ -28,8 +28,14 @@ $(document).on('click', '.group-revoke-button', function(){ id = $(this).attr("id"); - urlBuilder = "/group/markGroupAccessRevoked?requestId="+id + + urlBuilder = "/group/revokeAccess" $.ajax({url: urlBuilder, + method: "POST", + data: { + request_id: id, + csrfmiddlewaretoken: '{{ csrf_token }}' + }, success: function(result){ document.getElementById("inactive-"+id+"-revoke-button").innerHTML = "Access Marked Revoked"; }, From 3b0507ccd893fd6693cc50311457551bf2d97a56 Mon Sep 17 00:00:00 2001 From: Nivesh Mittapally Date: Mon, 13 Feb 2023 19:29:42 +0530 Subject: [PATCH 3/6] refactor: revoke access from grouo --- Access/group_helper.py | 76 ++++++++----------- Access/views.py | 1 + .../generic_accesses_tab.html | 18 +---- 3 files changed, 35 insertions(+), 60 deletions(-) diff --git a/Access/group_helper.py b/Access/group_helper.py index 640ac0b9..ac3553bc 100644 --- a/Access/group_helper.py +++ b/Access/group_helper.py @@ -751,6 +751,22 @@ def validate_group_access_create_request(group, auth_user): return None +def revoke_user_access(user, access, revoker_email): + user_identity = user.get_active_identity(access.access_tag) + user_identity.decline_non_approved_access_mapping(access) + user_identity.offboarding_approved_access_mapping(access) + background_task( + "run_access_revoke", + json.dumps( + { + "request_id": user_identity.get_granted_access_mapping(access) + .first() + .request_id, + "revoker_email": revoker_email, + } + ), + ) + def remove_member(request): try: membership_id = request.POST.get("membershipId") @@ -782,27 +798,26 @@ def remove_member(request): revoke_accesses = list(set(revoke_group_accesses) - set(other_group_accesses)) for access in revoke_accesses: - user_identity = user.get_active_identity(access.access_tag) - user_identity.decline_non_approved_access_mapping(access) - user_identity.offboarding_approved_access_mapping(access) - background_task( - "run_access_revoke", - json.dumps( - { - "request_id": user_identity.get_granted_access_mapping(access) - .first() - .request_id, - "revoker_email": request.user.user.email, - } - ), - ) + revoke_user_access(user, access, request.user.user.email) membership.revoke_membership() return {"message": "Successfully removed user from group"} +def access_exist_in_other_groups_of_user(membership, group, access): + other_memberships_groups = ( + membership.user.get_all_approved_memberships() + .exclude(group=membership.group) + .values_list("group", flat=True) + ) + for group in other_memberships_groups: + if group.access_exist(access): + return True + + return False + -def revoke_access(request): +def revoke_access_from_group(request): try: request_id = request.POST.get("request_id") if not request_id: @@ -821,36 +836,11 @@ def revoke_access(request): auth_user = request.user if not (auth_user.user.has_permission("ALLOW_USER_OFFBOARD") and group.member_is_owner(auth_user.user)): raise Exception("User Unauthorized to perfrom the action") - - should_continue = False - for membership in group.get_all_approved_members(): - other_memberships_groups = ( - membership.user.get_all_approved_memberships() - .exclude(group=membership.group) - .values_list("group", flat=True) - ) - for group in other_memberships_groups: - if group.access_exist(mapping.access): - should_continue = True - break - - if(should_continue): - should_continue = False + for membership in group.get_all_approved_members(): + if access_exist_in_other_groups(membership, group, mapping.access): continue - user_access_identity = membership.user.get_active_identity(mapping.access.access_tag) - user_access_mapping = user_access_identity.get_granted_access_mapping(mapping.access) - - - background_task( - "run_access_revoke", - json.dumps( - { - "request_id": user_access_mapping.request_id, - "revoker_email": auth_user.user.email - } - ), - ) + revoke_user_access(membership.user, mapping.access, auth_user.user.email) return {"message": "Successfully initiated the revoke"} diff --git a/Access/views.py b/Access/views.py index 2caba7e5..39086430 100644 --- a/Access/views.py +++ b/Access/views.py @@ -162,6 +162,7 @@ def user_offboarding(request): @login_required def requestAccess(request): if request.POST: + print((request.POST)) context = create_request( auth_user=request.user, access_request_form=request.POST ) diff --git a/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html b/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html index a411f6e5..5075235a 100644 --- a/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html +++ b/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html @@ -43,18 +43,6 @@ alert("Error occured while marking revoke! - "+result["responseJSON"]["error"]) }}); }); - - $(document).on('click', '.inactive-access-button', function(){ - id = $(this).attr("id"); - urlBuilder = "/group/markGroupAccessInactive?requestId="+id - $.ajax({url: urlBuilder, - success: function(result){ - document.getElementById(id+"-revoke-button").innerHTML = "Access Marked Inactive"; - }, - error: function(result){ - alert("Error occured while marking revoke! - "+result["responseJSON"]["error"]) - }}); - });

{% if genericAccesses %} @@ -78,12 +66,8 @@ {{ eachAccess.status }} {{ eachAccess.accessMeta }} - {% if user.is_owner %} -
(Existing accesses are not revoked)

- {% endif %} - {% if allowRevoke and eachAccess.status == 'Approved' %} -
(Existing accesses are marked revoked) +
{% endif %} From 0817bccefd5c723b122db99e6b93319d597b117b Mon Sep 17 00:00:00 2001 From: Nivesh Mittapally Date: Tue, 14 Feb 2023 12:07:57 +0530 Subject: [PATCH 4/6] refactor(group_helper): typo fixed --- Access/group_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Access/group_helper.py b/Access/group_helper.py index ac3553bc..1bd00b81 100644 --- a/Access/group_helper.py +++ b/Access/group_helper.py @@ -838,7 +838,7 @@ def revoke_access_from_group(request): raise Exception("User Unauthorized to perfrom the action") for membership in group.get_all_approved_members(): - if access_exist_in_other_groups(membership, group, mapping.access): + if access_exist_in_other_groups_of_user(membership, group, mapping.access): continue revoke_user_access(membership.user, mapping.access, auth_user.user.email) From 316485c8bd509d84ec2a322fd0bcdbe2998487b4 Mon Sep 17 00:00:00 2001 From: Nivesh Mittapally Date: Tue, 14 Feb 2023 16:43:38 +0530 Subject: [PATCH 5/6] refactor: marked revoke after revoke all member access of group --- Access/group_helper.py | 2 ++ Access/models.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/Access/group_helper.py b/Access/group_helper.py index d7267c48..53526817 100644 --- a/Access/group_helper.py +++ b/Access/group_helper.py @@ -791,6 +791,8 @@ def revoke_access_from_group(request): continue revoke_user_access(membership.user, mapping.access, auth_user.user.email) + + mapping.mark_revoked(auth_user.user) return {"message": "Successfully initiated the revoke"} diff --git a/Access/models.py b/Access/models.py index cd78828b..1e381b6a 100644 --- a/Access/models.py +++ b/Access/models.py @@ -930,6 +930,11 @@ def get_by_id(request_id): return GroupAccessMapping.objects.get(request_id=request_id) except GroupAccessMapping.DoesNotExist: return None + + def mark_revoked(self, revoker): + self.status = "Revoked" + self.revoker = revoker + self.save() From 12643d8bd20aa2de5672d41554fc89ea9379cba1 Mon Sep 17 00:00:00 2001 From: Nivesh Mittapally Date: Fri, 17 Mar 2023 15:36:05 +0530 Subject: [PATCH 6/6] fix: updated authonization for revoke group access --- Access/group_helper.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Access/group_helper.py b/Access/group_helper.py index 7452b8ce..fde52ad7 100644 --- a/Access/group_helper.py +++ b/Access/group_helper.py @@ -743,7 +743,10 @@ def validate_group_access_create_request(group, auth_user): def revoke_user_access(user, access, revoker, decline_message): user_identity = user.get_active_identity(access.access_tag) user_identity.decline_non_approved_access_mapping(access, decline_message) - revoke_request(user_identity.get_granted_access_mapping(access).first(), revoker) + access_mapping = user_identity.get_granted_access_mapping(access).first() + if not access_mapping: + return False + revoke_request(access_mapping, revoker) def remove_member(request): try: @@ -812,7 +815,7 @@ def revoke_access_from_group(request): group = mapping.group auth_user = request.user - if not (auth_user.user.has_permission("ALLOW_USER_OFFBOARD") and group.member_is_owner(auth_user.user)): + if not (auth_user.user.has_permission("ALLOW_USER_OFFBOARD") or group.member_is_owner(auth_user.user)): return {"error": USER_UNAUTHORIZED_MESSAGE} revoke_access_memberships = []