Skip to content

Commit 9458e7f

Browse files
fix: revoking and approving access on identity change (#72)
revoking and approving the access when changing the access adding a new method for the grant and revoke access changing the off-board method, adding transactions and calling the new revoke method
1 parent 1e03380 commit 9458e7f

File tree

4 files changed

+131
-76
lines changed

4 files changed

+131
-76
lines changed

Access/background_task_manager.py

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
from Access import helpers
1010
from bootprocess import general
1111
from BrowserStackAutomation.settings import AUTOMATED_EXEC_IDENTIFIER
12-
from Access.models import UserAccessMapping, User
12+
from Access.models import UserAccessMapping, ApprovalType
1313
from Access import notifications
1414

1515
logger = logging.getLogger(__name__)
1616

17+
1718
with open("config.json") as data_file:
1819
background_task_manager_type = json.load(data_file)["background_task_manager"][
1920
"type"
@@ -30,7 +31,8 @@ def background_task(func, *args):
3031
elif func == "run_accept_request":
3132
run_accept_request.delay(*args)
3233
elif func == "run_access_revoke":
33-
run_access_revoke.delay(*args)
34+
request_id = args[0]
35+
run_access_revoke.delay(request_id)
3436
else:
3537
if func == "run_access_grant":
3638
request_id = args[0]
@@ -56,7 +58,7 @@ def background_task(func, *args):
5658
)
5759
def run_access_grant(request_id):
5860
user_access_mapping = UserAccessMapping.get_access_request(request_id=request_id)
59-
access_type = user_access_mapping.access.access_tag
61+
access_tag = user_access_mapping.access.access_tag
6062
user = user_access_mapping.user_identity.user
6163
approver = user_access_mapping.approver_1.user.username
6264
message = ""
@@ -75,6 +77,10 @@ def run_access_grant(request_id):
7577
user_access_mapping.grant_fail_access(
7678
fail_reason="Failed since identity is blank for user identity"
7779
)
80+
notifications.send_mail_for_request_granted_failure(
81+
user, approver, access_tag, request_id
82+
)
83+
7884
logger.debug(
7985
{
8086
"requestId": request_id,
@@ -85,7 +91,7 @@ def run_access_grant(request_id):
8591
)
8692
return False
8793

88-
access_module = helpers.get_available_access_module_from_tag(access_type)
94+
access_module = helpers.get_available_access_module_from_tag(access_tag)
8995
if not access_module:
9096
return False
9197

@@ -132,10 +138,10 @@ def run_access_grant(request_id):
132138
}
133139
)
134140
try:
135-
destination = access_module.access_mark_revoke_permission(access_type)
141+
destination = access_module.access_mark_revoke_permission(access_tag)
136142
notifications.send_mail_for_access_grant_failed(
137143
destination,
138-
access_type.upper(),
144+
access_tag.upper(),
139145
user.email,
140146
request_id=request_id,
141147
message=message,
@@ -157,37 +163,36 @@ def run_access_grant(request_id):
157163
@shared_task(
158164
autoretry_for=(Exception,), retry_kwargs={"max_retries": 3, "countdown": 5}
159165
)
160-
def run_access_revoke(data):
161-
data = json.loads(data)
162-
access_mapping = UserAccessMapping.get_access_request(data["request_id"])
166+
def run_access_revoke(request_id):
167+
access_mapping = UserAccessMapping.get_access_request(request_id=request_id)
163168
if not access_mapping:
164169
# TODO: Have to add the email targets for failure
165170
targets = []
166171
message = "Request not found"
167172
notifications.send_revoke_failure_mail(
168-
targets, data["request_id"], data["revoker_email"], 0, message
173+
targets, request_id, access_mapping.revoker.email, 0, message
169174
)
170-
return {"status": False}
175+
return False
171176
elif access_mapping.status == "Revoked":
172-
return {"status": True}
177+
return True
173178
access = access_mapping.access
174179
user_identity = access_mapping.user_identity
175180

176-
revoker = User.get_user_by_email(data["revoker_email"])
181+
revoker = access_mapping.revoker
177182
if not revoker:
178183
# TODO: Have to add the email targets for failure
179184
targets = []
180185
message = "Revoker not found"
181186
notifications.send_revoke_failure_mail(
182187
targets,
183-
data["request_id"],
184-
data["revoker_email"],
188+
request_id,
189+
access_mapping.revoker.email,
185190
0,
186191
message,
187192
access.access_tag,
188193
)
189194
user_identity.mark_revoke_failed_for_approved_access_mapping(access)
190-
return {"status": False}
195+
return False
191196

192197
access_modules = helpers.get_available_access_modules()
193198

@@ -227,7 +232,7 @@ def run_access_revoke(data):
227232
user_identity.mark_revoke_failed_for_approved_access_mapping(access)
228233
raise Exception("Failed to revoke the access due to: " + str(message))
229234

230-
return {"status": True}
235+
return True
231236

232237

233238
@task_success.connect(sender=run_access_grant)
@@ -278,6 +283,7 @@ def run_accept_request(data):
278283
result = background_task("run_access_grant", request_id)
279284
if result:
280285
return {"status": True}
286+
281287
notifications.send_mail_for_request_granted_failure(
282288
user, approver, access_type, request_id
283289
)
@@ -291,3 +297,38 @@ def run_accept_request(data):
291297
)
292298

293299
return {"status": False}
300+
301+
302+
def accept_request(user_access_mapping, approval_type="", approver=None):
303+
result = None
304+
305+
if approval_type == ApprovalType.Primary:
306+
user_access_mapping.approver_1 = approver
307+
elif approval_type == ApprovalType.Secondary:
308+
user_access_mapping.approver_2 = approver
309+
elif user_access_mapping.approver_1 or user_access_mapping.approver_2:
310+
raise Exception("Request Not approved")
311+
312+
user_access_mapping.processing()
313+
try:
314+
result = run_access_grant.delay(user_access_mapping.request_id)
315+
except Exception:
316+
user_access_mapping.grant_fail_access(fail_reason="Task could not be queued")
317+
318+
if result:
319+
return True
320+
return False
321+
322+
323+
def revoke_request(user_access_mapping, revoker=None):
324+
result = None
325+
# change the status to revoke processing
326+
user_access_mapping.revoking(revoker)
327+
try:
328+
result = run_access_revoke.delay(user_access_mapping.request_id)
329+
except Exception:
330+
user_access_mapping.RevokeFailed(fail_reason="Task could not be queued")
331+
332+
if result:
333+
return True
334+
return False

Access/group_helper.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -738,9 +738,7 @@ def remove_member(request):
738738
"run_access_revoke",
739739
json.dumps(
740740
{
741-
"request_id": user_identity.get_granted_access_mapping(access)
742-
.first()
743-
.request_id,
741+
"request_id": request_id,
744742
"revoker_email": request.user.user.email,
745743
}
746744
),

Access/models.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22
from django.db import models, transaction
33
from BrowserStackAutomation.settings import USER_STATUS_CHOICES, PERMISSION_CONSTANTS
44
import datetime
5+
import enum
56

67

8+
class ApprovalType(enum.Enum):
9+
Primary = "Primary"
10+
Secondary = "Secondary"
11+
12+
713
class Permission(models.Model):
814
"""
915
Permission to perform actions on enigma
@@ -793,6 +799,9 @@ def is_pending(self):
793799
def is_secondary_pending(self):
794800
return self.status == "SecondaryPending"
795801

802+
def is_grantfailed(self):
803+
return self.status == "GrantFailed"
804+
796805
def decline_access(self, decline_reason=None):
797806
self.status = "Declined"
798807
self.decline_reason = decline_reason
@@ -815,11 +824,26 @@ def grant_fail_access(self, fail_reason=None):
815824
self.fail_reason = fail_reason
816825
self.save()
817826

827+
def revoke_failed(self, fail_reason=None):
828+
self.status = "RevokeFailed"
829+
self.fail_reason = fail_reason
830+
self.save()
831+
832+
def decline_access(self, decline_reason=None):
833+
self.status = "Declined"
834+
self.decline_reason = decline_reason
835+
self.save()
836+
818837
def approve_access(self):
819838
self.status = "Approved"
820839
self.save()
821840

822-
def set_processing(self):
841+
def revoking(self, revoker):
842+
self.revoker = revoker
843+
self.status = "ProcessingRevoke"
844+
self.save()
845+
846+
def processing(self):
823847
self.status = "Processing"
824848
self.save()
825849

@@ -1081,13 +1105,12 @@ def get_all_granted_access_mappings(self):
10811105

10821106
def get_all_non_approved_access_mappings(self):
10831107
return self.user_access_mapping.filter(
1084-
status__in=["approvefailed", "pending", "secondarypending", "grantfailed"],
1085-
access__access_tag=self.access_tag,
1108+
status__in=["approvefailed", "pending", "secondarypending", "grantfailed"]
10861109
)
10871110

1088-
def decline_all_non_approved_access_mappings(self):
1111+
def decline_all_non_approved_access_mappings(self, decline_reason):
10891112
user_mapping = self.get_all_non_approved_access_mappings()
1090-
user_mapping.update(status="Declined")
1113+
user_mapping.update(status="Declined", decline_reason = decline_reason)
10911114

10921115
def get_granted_access_mapping(self, access):
10931116
return self.user_access_mapping.filter(
@@ -1099,10 +1122,10 @@ def get_non_approved_access_mapping(self, access):
10991122
status__in=["approvefailed", "pending", "secondarypending", "grantfailed"],
11001123
access=access,
11011124
)
1102-
1103-
def decline_non_approved_access_mapping(self, access):
1125+
1126+
def decline_non_approved_access_mapping(self, access, decline_reason):
11041127
user_mapping = self.get_non_approved_access_mapping(access)
1105-
user_mapping.update(status="Declined")
1128+
user_mapping.update(status="Declined", decline_reason = decline_reason)
11061129

11071130
def offboarding_approved_access_mapping(self, access):
11081131
user_mapping = self.get_granted_access_mapping(access)
@@ -1133,7 +1156,7 @@ def replicate_active_access_membership_for_module(
11331156
for i, user_access in enumerate(existing_user_access_mapping):
11341157
base_datetime_prefix = datetime.datetime.utcnow().strftime("%Y%m%d%H%M%S")
11351158
request_id = (
1136-
self.user.username
1159+
self.user.user.username
11371160
+ "-"
11381161
+ user_access.access_type
11391162
+ "-"
@@ -1148,7 +1171,6 @@ def replicate_active_access_membership_for_module(
11481171
new_user_access_mapping.append(
11491172
self.user_access_mapping.create(
11501173
request_id=request_id,
1151-
user=self,
11521174
access=user_access.access,
11531175
approver_1=user_access.approver_1,
11541176
approver_2=user_access.approver_2,
@@ -1157,7 +1179,6 @@ def replicate_active_access_membership_for_module(
11571179
status=access_status,
11581180
)
11591181
)
1160-
user_access.deactivate()
11611182
return new_user_access_mapping
11621183

11631184
def create_access_mapping(

0 commit comments

Comments
 (0)