Skip to content
68 changes: 61 additions & 7 deletions Access/group_helper.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -24,6 +24,9 @@
"msg": "Error Occured while loading the page. Please contact admin",
}

USER_UNAUTHORIZED_MESSAGE = "User unauthorised to perform the action."
GROUP_ACCESS_MAPPING_NOT_FOUND = "Group Access Mapping not found in the database."

NEW_GROUP_CREATE_ERROR_GROUP_EXISTS = {
"error_msg": "Invalid Group Name",
"msg": "A group with name {group_name} already exists. Please choose a new name.",
Expand Down Expand Up @@ -745,6 +748,14 @@ def validate_group_access_create_request(group, auth_user):
return None


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)
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:
membership_id = request.POST.get("membershipId")
Expand All @@ -763,7 +774,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)
)
Expand All @@ -775,16 +786,59 @@ def remove_member(request):

accesses = list(set(group_accesses) - set(other_group_accesses))

for access in 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)
revoke_request(user_access_mapping=access, revoker=request.user.user)
with transaction.atomic():
for access in accesses:
revoke_user_access(user, access, request.user.user, "User removed from the group")

membership.revoke_membership()

return {"message": "Successfully removed user from group"}

def access_exist_in_other_groups_of_user(membership, group, access):
other_memberships = (
membership.user.get_all_approved_memberships()
.exclude(group=membership.group)
)
for membership in other_memberships:
if membership.group.check_access_exist(access):
return True

return False


def revoke_access_from_group(request):
try:
request_id = request.POST.get("request_id")
if not request_id:
logger.debug("Cannot find request_id in the http request.")
return {"error": ERROR_MESSAGE}

mapping = GroupAccessMapping.get_by_id(request_id)
if not mapping:
logger.debug("Group Access Mapping not found in the database")
return {"error": GROUP_ACCESS_MAPPING_NOT_FOUND}
except Exception as e:
logger.exception(str(e))
return {"error": ERROR_MESSAGE}

group = mapping.group
auth_user = request.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 = []
for membership in group.get_all_approved_members():
if access_exist_in_other_groups_of_user(membership, group, mapping.access):
continue
revoke_access_memberships.append(membership)

with transaction.atomic():
for membership in revoke_access_memberships:
revoke_user_access(membership.user, mapping.access, auth_user.user, "Access revoked for the group")

mapping.mark_revoked(auth_user.user)

return {"message": "Successfully initiated the revoke"}

def get_selected_users_by_email(user_emails):
selected_users = User.get_users_by_emails(emails=user_emails)
Expand Down
17 changes: 15 additions & 2 deletions Access/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,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 (
Expand Down Expand Up @@ -1026,6 +1026,19 @@ def getAccessRequestDetails(self, access_module):
access_request_data["grantOwner"] = ",".join(access_module.grant_owner())

return access_request_data

def get_by_id(request_id):
try:
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()



@staticmethod
def get_by_request_id(request_id):
Expand Down
13 changes: 13 additions & 0 deletions Access/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ def request_access(request):
HTTPResponse: Access request form template or the status of access save request.
"""
if request.POST:
print((request.POST))
context = create_request(
auth_user=request.user, access_request_form=request.POST
)
Expand Down Expand Up @@ -639,3 +640,15 @@ def individual_resolve(request):
logger.exception(str(e))
json_response['error'] = {'error_msg': "Bad request", 'msg': "Error in request not found OR Invalid request type"}
return render(request,'BSOps/accessStatus.html',json_response)

def revoke_group_access(request):
try:
response = group_helper.revoke_access_from_group(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)
2 changes: 2 additions & 0 deletions BrowserStackAutomation/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
user_offboarding,
show_access_history,
pending_requests,
Expand Down Expand Up @@ -91,6 +92,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"),
re_path(r"^individual_resolve$", individual_resolve, name="individual_resolve")
]

Expand Down
26 changes: 8 additions & 18 deletions templates/BSOps/group_access_list_tabs/generic_accesses_tab.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,16 @@

$(document).on('click', '.group-revoke-button', function(){
id = $(this).attr("id");
urlBuilder = "/group/markGroupAccessRevoked?requestId="+id
$.ajax({url: urlBuilder,
success: function(result){
document.getElementById("inactive-"+id+"-revoke-button").innerHTML = "Access Marked Revoked";
},
error: function(result){
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
urlBuilder = "/group/revokeAccess"
$.ajax({url: urlBuilder,
method: "POST",
data: {
request_id: id,
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success: function(result){
document.getElementById(id+"-revoke-button").innerHTML = "Access Marked Inactive";
document.getElementById("inactive-"+id+"-revoke-button").innerHTML = "Access Marked Revoked";
},
error: function(result){
alert("Error occured while marking revoke! - "+result["responseJSON"]["error"])
Expand Down Expand Up @@ -72,12 +66,8 @@
<td>{{ eachAccess.status }}</td>
<td>{{ eachAccess.accessMeta }}</td>
<td id="inactive-{{ eachAccess.requestId }}-revoke-button">
{% if user.is_owner %}
<button class="btn btn-danger inactive-access-button" id="inactive-{{ eachAccess.requestId }}">Mark Inactive</button><br>(Existing accesses are not revoked)<br><br>
{% endif %}

{% if allowRevoke and eachAccess.status == 'Approved' %}
<button class="btn btn-danger group-revoke-button" id="{{ eachAccess.requestId }}">Mark Revoked</button><br>(Existing accesses are marked revoked)
<button class="btn btn-danger group-revoke-button" id="{{ eachAccess.requestId }}">Mark Revoked</button><br>
{% endif %}
</td>
</tr>
Expand Down