Skip to content

Commit 493be8f

Browse files
authored
[Issue #6537] pre load roles when checking access (#6977)
## Summary <!-- Use "Fixes" to automatically close issue upon PR merge. Use "Work for" when UAT is required. --> Fixes / Work for #6537 ## Changes proposed Wrapper function around can_access method to reduce database calls to fetch roles. Update code to use wrapper function Tests updated
1 parent a7b524f commit 493be8f

18 files changed

+158
-76
lines changed

api/src/auth/endpoint_access_util.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import logging
22
from typing import Any
33

4+
from src.adapters import db
45
from src.api.route_utils import raise_flask_error
56
from src.constants.lookup_constants import Privilege
67
from src.db.models.agency_models import Agency
78
from src.db.models.competition_models import Application
89
from src.db.models.entity_models import Organization
910
from src.db.models.user_models import Role, User
11+
from src.services.users.get_roles_and_privileges import get_roles_and_privileges
1012

1113
logger = logging.getLogger(__name__)
1214

@@ -113,3 +115,16 @@ def get_log_info_for_resource(resource: Organization | Application | Agency | No
113115
log_info["agency_code"] = resource.agency_code
114116

115117
return log_info
118+
119+
120+
def check_user_access(
121+
db_session: db.Session,
122+
user: User,
123+
allowed_privileges: set[Privilege],
124+
resource: Organization | Application | Agency | None,
125+
) -> None:
126+
"""Wrapper function to preload all roles and privileges for the given user
127+
then checks access using the in-memory data."""
128+
user_with_role = get_roles_and_privileges(db_session, user.user_id)
129+
if not user_with_role or not can_access(user_with_role, allowed_privileges, resource):
130+
raise_flask_error(403, "Forbidden")

api/src/services/applications/add_organization_to_application.py

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import src.adapters.db as db
88
from src.api.route_utils import raise_flask_error
9-
from src.auth.endpoint_access_util import can_access
9+
from src.auth.endpoint_access_util import check_user_access
1010
from src.constants.lookup_constants import (
1111
ApplicationAuditEvent,
1212
CompetitionOpenToApplicant,
@@ -52,28 +52,20 @@ def add_organization_to_application(
5252

5353
# Get the organization (raises 404 if not found)
5454
organization = get_organization(db_session, organization_id)
55-
5655
# Check user has MODIFY_APPLICATION privilege for the application
57-
if not can_access(user, {Privilege.MODIFY_APPLICATION}, application):
58-
logger.info(
59-
"User does not have MODIFY_APPLICATION privilege",
60-
extra={
61-
"user_id": user.user_id,
62-
"application_id": application_id,
63-
},
64-
)
65-
raise_flask_error(403, "Forbidden")
66-
56+
check_user_access(
57+
db_session,
58+
user,
59+
{Privilege.MODIFY_APPLICATION},
60+
application,
61+
)
6762
# Check user has START_APPLICATION privilege for the organization
68-
if not can_access(user, {Privilege.START_APPLICATION}, organization):
69-
logger.info(
70-
"User does not have START_APPLICATION privilege for organization",
71-
extra={
72-
"user_id": user.user_id,
73-
"organization_id": organization_id,
74-
},
75-
)
76-
raise_flask_error(403, "Forbidden")
63+
check_user_access(
64+
db_session,
65+
user,
66+
{Privilege.START_APPLICATION},
67+
organization,
68+
)
7769

7870
# Validate application is in progress
7971
validate_application_in_progress(application, ApplicationAction.MODIFY)

api/src/services/applications/create_application.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import src.adapters.db as db
99
from src.api.route_utils import raise_flask_error
10-
from src.auth.endpoint_access_util import can_access
10+
from src.auth.endpoint_access_util import check_user_access
1111
from src.constants.lookup_constants import (
1212
ApplicationAuditEvent,
1313
ApplicationStatus,
@@ -130,8 +130,12 @@ def create_application(
130130
raise_flask_error(404, "Organization not found")
131131

132132
# Check privileges
133-
if not can_access(user, {Privilege.START_APPLICATION}, organization):
134-
raise_flask_error(403, "Forbidden")
133+
check_user_access(
134+
db_session,
135+
user,
136+
{Privilege.START_APPLICATION},
137+
organization,
138+
)
135139

136140
# Verify the competition is open
137141
validate_competition_open(competition, ApplicationAction.START)

api/src/services/applications/create_application_attachment.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import src.util.file_util as file_util
99
from src.adapters.aws import S3Config
1010
from src.api.route_utils import raise_flask_error
11-
from src.auth.endpoint_access_util import can_access
11+
from src.auth.endpoint_access_util import check_user_access
1212
from src.constants.lookup_constants import ApplicationAuditEvent, Privilege, SubmissionIssue
1313
from src.db.models.competition_models import Application, ApplicationAttachment
1414
from src.db.models.user_models import User
@@ -25,8 +25,7 @@ def create_application_attachment(
2525
application = get_application(db_session, application_id, user)
2626

2727
# Check privileges
28-
if not can_access(user, {Privilege.MODIFY_APPLICATION}, application):
29-
raise_flask_error(403, "Forbidden")
28+
check_user_access(db_session, user, {Privilege.MODIFY_APPLICATION}, application)
3029

3130
application_attachment = upsert_application_attachment(
3231
db_session=db_session,

api/src/services/applications/delete_application_attachment.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
import uuid
33

44
import src.adapters.db as db
5-
from src.api.route_utils import raise_flask_error
6-
from src.auth.endpoint_access_util import can_access
5+
from src.auth.endpoint_access_util import check_user_access
76
from src.constants.lookup_constants import ApplicationAuditEvent, Privilege
87
from src.db.models.user_models import User
98
from src.services.applications.application_audit import add_audit_event
@@ -26,9 +25,9 @@ def delete_application_attachment(
2625
db_session, application_id, application_attachment_id, user
2726
)
2827
# Check privileges
29-
if not can_access(user, {Privilege.MODIFY_APPLICATION}, application_attachment.application):
30-
raise_flask_error(403, "Forbidden")
31-
28+
check_user_access(
29+
db_session, user, {Privilege.MODIFY_APPLICATION}, application_attachment.application
30+
)
3231
# Delete the file from s3
3332
logger.info("Deleting application attachment from s3")
3433
file_util.delete_file(application_attachment.file_location)

api/src/services/applications/get_application.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import src.adapters.db as db
88
from src.api.response import ValidationErrorDetail
99
from src.api.route_utils import raise_flask_error
10-
from src.auth.endpoint_access_util import can_access
11-
from src.constants.lookup_constants import Privilege, SubmissionIssue
10+
from src.auth.endpoint_access_util import check_user_access
11+
from src.constants.lookup_constants import Privilege
1212
from src.db.models.competition_models import (
1313
Application,
1414
ApplicationForm,
@@ -132,15 +132,12 @@ def get_application_with_auth(
132132
if not user and not is_internal_user:
133133
raise Exception("No user found, but not marked as internal auth")
134134
# Check privileges
135-
if user and not can_access(user, {Privilege.VIEW_APPLICATION}, application):
136-
logger.info(
137-
"User attempted to access an application they are not associated with",
138-
extra={
139-
"user_id": user.user_id,
140-
"application_id": application.application_id,
141-
"submission_issue": SubmissionIssue.UNAUTHORIZED_APPLICATION_ACCESS,
142-
},
135+
if user:
136+
check_user_access(
137+
db_session,
138+
user,
139+
{Privilege.VIEW_APPLICATION},
140+
application,
143141
)
144-
raise_flask_error(403, "Forbidden")
145142

146143
return application

api/src/services/applications/submit_application.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
from uuid import UUID
33

44
import src.adapters.db as db
5-
from src.api.route_utils import raise_flask_error
6-
from src.auth.endpoint_access_util import can_access
5+
from src.auth.endpoint_access_util import check_user_access
76
from src.constants.lookup_constants import ApplicationAuditEvent, ApplicationStatus, Privilege
87
from src.db.models.competition_models import Application
98
from src.db.models.user_models import User
@@ -31,8 +30,12 @@ def submit_application(db_session: db.Session, application_id: UUID, user: User)
3130
application = get_application(db_session, application_id, user)
3231

3332
# Check privileges
34-
if not can_access(user, {Privilege.SUBMIT_APPLICATION}, application):
35-
raise_flask_error(403, "Forbidden")
33+
check_user_access(
34+
db_session,
35+
user,
36+
{Privilege.SUBMIT_APPLICATION},
37+
application,
38+
)
3639

3740
# Run validations
3841
validate_application_in_progress(application, ApplicationAction.SUBMIT)

api/src/services/applications/update_application.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
from uuid import UUID
44

55
import src.adapters.db as db
6-
from src.api.route_utils import raise_flask_error
7-
from src.auth.endpoint_access_util import can_access
6+
from src.auth.endpoint_access_util import check_user_access
87
from src.constants.lookup_constants import ApplicationAuditEvent, Privilege
98
from src.db.models.competition_models import Application
109
from src.db.models.user_models import User
@@ -39,8 +38,12 @@ def update_application(
3938
# Get application (this will check if it exists and if user has access)
4039
application = get_application(db_session, application_id, user)
4140
# Check privileges
42-
if not can_access(user, {Privilege.MODIFY_APPLICATION}, application):
43-
raise_flask_error(403, "Forbidden")
41+
check_user_access(
42+
db_session,
43+
user,
44+
{Privilege.MODIFY_APPLICATION},
45+
application,
46+
)
4447

4548
# Don't let a user update an existing application
4649
validate_application_in_progress(application, ApplicationAction.MODIFY)

api/src/services/applications/update_application_attachment.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33

44
import src.adapters.db as db
55
import src.util.file_util as file_util
6-
from src.api.route_utils import raise_flask_error
7-
from src.auth.endpoint_access_util import can_access
6+
from src.auth.endpoint_access_util import check_user_access
87
from src.constants.lookup_constants import ApplicationAuditEvent, Privilege
98
from src.db.models.competition_models import ApplicationAttachment
109
from src.db.models.user_models import User
@@ -28,8 +27,12 @@ def update_application_attachment(
2827
db_session, application_id, application_attachment_id, user
2928
)
3029
# Check privileges
31-
if not can_access(user, {Privilege.MODIFY_APPLICATION}, application_attachment.application):
32-
raise_flask_error(403, "Forbidden")
30+
check_user_access(
31+
db_session,
32+
user,
33+
{Privilege.MODIFY_APPLICATION},
34+
application_attachment.application,
35+
)
3336

3437
# Store the old file location before updating
3538
old_s3_file_location = application_attachment.file_location

api/src/services/applications/update_application_form.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import src.adapters.db as db
77
from src.api.response import ValidationErrorDetail
88
from src.api.route_utils import raise_flask_error
9-
from src.auth.endpoint_access_util import can_access
9+
from src.auth.endpoint_access_util import check_user_access
1010
from src.constants.lookup_constants import ApplicationAuditEvent, Privilege, SubmissionIssue
1111
from src.db.models.competition_models import ApplicationForm, CompetitionForm
1212
from src.db.models.user_models import User
@@ -63,8 +63,12 @@ def update_application_form(
6363
application = get_application(db_session, application_id, user)
6464

6565
# Check privileges
66-
if not can_access(user, {Privilege.MODIFY_APPLICATION}, application):
67-
raise_flask_error(403, "Forbidden")
66+
check_user_access(
67+
db_session,
68+
user,
69+
{Privilege.MODIFY_APPLICATION},
70+
application,
71+
)
6872

6973
# Validate the application is in progress and can be modified
7074
validate_application_in_progress(application, ApplicationAction.MODIFY)

0 commit comments

Comments
 (0)