Skip to content

Commit bc72b79

Browse files
committed
Optimize getLogRecords()
1 parent 95dad66 commit bc72b79

File tree

6 files changed

+42
-29
lines changed

6 files changed

+42
-29
lines changed

gmn/src/d1_gmn/app/auth.py

-17
Original file line numberDiff line numberDiff line change
@@ -196,23 +196,6 @@ def is_allowed(request, level, pid):
196196
).exists()
197197

198198

199-
# TODO: Change "trusted" / "fully trusted" to something like admin / superuser.
200-
def is_redacted_log(request, pid):
201-
"""Determine if ``ipAddress`` and ``subject`` fields must be redacted on
202-
any ``LogEntry``s for the SciObj that are returned to the client.
203-
204-
If access to ``LogEntry``s for the SciObj is denied for the client,
205-
this function will return True, indicating that ``LogEntry``s must
206-
be redacted. However, the result is irrelevant since no
207-
``LogEntry``s for the SciObj will be returned to the caller.
208-
"""
209-
if is_trusted_subject(request):
210-
return False
211-
if is_allowed(request, WRITE_LEVEL, pid):
212-
return False
213-
return True
214-
215-
216199
def has_create_update_delete_permission(request):
217200
whitelisted_subject_set = get_whitelisted_subject_set()
218201
logging.debug('Whitelisted subjects: {}'.format(', '.join(whitelisted_subject_set)))

gmn/src/d1_gmn/app/db_filter.py

+30
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,51 @@
3535
return: QuerySet
3636
"""
3737

38+
import d1_gmn.app.auth
3839
import d1_gmn.app.did
3940
import d1_gmn.app.models
4041
import d1_gmn.app.revision
4142
import d1_gmn.app.views.assert_db
4243
import d1_gmn.app.views.util
4344

45+
import django.db.models
4446

4547
def add_access_policy_filter(request, query, column_name):
48+
"""Filter records that do not have ``read`` or better access for one or
49+
more of the active subjects.
50+
51+
Since ``read`` is the lowest access level that a subject can have,
52+
this method only has to filter on the presence of the subject.
53+
"""
4654
q = d1_gmn.app.models.Subject.objects.filter(
4755
subject__in=request.all_subjects_set
4856
).values('permission__sciobj')
4957
filter_arg = '{}__in'.format(column_name)
5058
return query.filter(**{filter_arg: q})
5159

5260

61+
def add_redact_annotation(request, query):
62+
"""Flag LogEntry records that require ``ipAddress`` and ``subject`` fields
63+
to be redacted before being returned to the client.
64+
65+
Only trusted subjects and subjects with ``write`` or ``changePermission`` on a
66+
SciObj receive unredacted ``ipAddress`` and ``subject`` in LogEntry records for the
67+
associated SciObj.
68+
69+
Subjects with only ``read`` access receive redacted records.
70+
"""
71+
return query.annotate(
72+
redact=django.db.models.Exists(
73+
d1_gmn.app.models.Permission.objects.filter(
74+
sciobj=django.db.models.OuterRef('sciobj'),
75+
subject__subject__in=request.all_subjects_set,
76+
level__gte=d1_gmn.app.auth.WRITE_LEVEL,
77+
),
78+
negated=True,
79+
)
80+
)
81+
82+
5383
def add_replica_filter(request, query):
5484
param_name = 'replicaStatus'
5585
bool_val = request.GET.get(param_name, True)

gmn/src/d1_gmn/app/middleware/response_handler.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,15 @@ def _generate_log_records(self, request, db_query, start, total):
180180
logEntry = d1_gmn.app.views.util.dataoneTypes(request).LogEntry()
181181
logEntry.entryId = str(row.id)
182182
logEntry.identifier = row.sciobj.pid.did
183-
logEntry.ipAddress = row.ip_address.ip_address
183+
# Redact ipAddress and subject on records for which client has only "read"
184+
# access.
185+
if getattr(row, 'redact', False):
186+
logEntry.ipAddress = '<NotAuthorized>'
187+
logEntry.subject = '<NotAuthorized>'
188+
else:
189+
logEntry.ipAddress = row.ip_address.ip_address
190+
logEntry.subject = row.subject.subject
184191
logEntry.userAgent = row.user_agent.user_agent
185-
logEntry.subject = row.subject.subject
186192
logEntry.event = row.event.event
187193
logEntry.dateLogged = d1_common.date_time.normalize_datetime_to_utc(
188194
row.timestamp

gmn/src/d1_gmn/app/models.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,8 @@ class Event(django.db.models.Model):
356356

357357

358358
def event(event_str):
359-
# In v2.0, events are no longer restricted to this set. However, GMN still
360-
# only records these types of events, so we'll leave it in while that
361-
# remains the case.
359+
# In v2.0, events are no longer restricted to this set. However, GMN still only
360+
# records these types of events, so we'll leave it in while that remains the case.
362361
assert event_str in [
363362
'create',
364363
'read',

gmn/src/d1_gmn/app/views/external.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,12 @@ def get_log(request):
136136
137137
Sorted by timestamp, id.
138138
"""
139-
# TODO: Check if select_related() gives better performance
140-
query = (
141-
d1_gmn.app.models.EventLog.objects.all()
142-
.select_related()
143-
.order_by('timestamp', 'id')
144-
)
139+
query = d1_gmn.app.models.EventLog.objects.all().order_by('timestamp', 'id')
145140
if not d1_gmn.app.auth.is_trusted_subject(request):
146141
query = d1_gmn.app.db_filter.add_access_policy_filter(
147142
request, query, 'sciobj__id'
148143
)
144+
query = d1_gmn.app.db_filter.add_redact_annotation(request, query)
149145
query = d1_gmn.app.db_filter.add_datetime_filter(
150146
request, query, 'timestamp', 'fromDate', 'gte'
151147
)

gmn/src/d1_gmn/app/views/util.py

-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ def http_response_with_boolean_true_type():
146146
def query_object_list(request, type_name):
147147
query = (
148148
d1_gmn.app.models.ScienceObject.objects.all()
149-
.select_related()
150149
.annotate(timestamp=django.db.models.F('modified_timestamp'))
151150
.order_by('modified_timestamp', 'id')
152151
)

0 commit comments

Comments
 (0)