Skip to content

Commit 249f4fb

Browse files
committed
Add tests for log record redaction
1 parent c55f0d4 commit 249f4fb

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
# This work was created by participants in the DataONE project, and is
5+
# jointly copyrighted by participating institutions in DataONE. For
6+
# more information on DataONE, see our web site at http://dataone.org.
7+
#
8+
# Copyright 2009-2016 DataONE
9+
#
10+
# Licensed under the Apache License, Version 2.0 (the "License");
11+
# you may not use this file except in compliance with the License.
12+
# You may obtain a copy of the License at
13+
#
14+
# http://www.apache.org/licenses/LICENSE-2.0
15+
#
16+
# Unless required by applicable law or agreed to in writing, software
17+
# distributed under the License is distributed on an "AS IS" BASIS,
18+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+
# See the License for the specific language governing permissions and
20+
# limitations under the License.
21+
"""Test getLogRecords() access control.
22+
"""
23+
24+
import pytest
25+
import responses
26+
import freezegun
27+
import datetime
28+
29+
import d1_gmn.tests.gmn_mock
30+
import d1_gmn.tests.gmn_test_case
31+
import d1_gmn.tests.gmn_test_client
32+
33+
import d1_common.const
34+
import d1_common.replication_policy
35+
import d1_common.system_metadata
36+
import d1_common.types.dataoneTypes
37+
import d1_common.types.exceptions
38+
import d1_common.util
39+
import d1_common.xml
40+
41+
import d1_test.d1_test_case
42+
import d1_test.instance_generator.subject
43+
44+
PERM_LIST = [
45+
# Private objects
46+
{
47+
"pid": "glr_authz_1",
48+
"rights_holder": "glr_subj_rights_1",
49+
"permission_list": [
50+
# (["glr_subj_1"], ["read"]),
51+
# (["glr_subj_2", "glr_subj_3", "glr_subj_4"], ["read", "write"]),
52+
(["glr_subj_9", "glr_subj_10", "glr_subj_11", "glr_subj_12"], ["changePermission"]),
53+
],
54+
},
55+
{
56+
"pid": "glr_authz_2",
57+
"rights_holder": "glr_subj_rights_2",
58+
"permission_list": [
59+
# (["glr_subj_1"], ["read"]),
60+
# (["glr_subj_2", "glr_subj_3", "glr_subj_4"], ["read", "write"]),
61+
(["glr_subj_9", "glr_subj_10", "glr_subj_11", "glr_subj_12"], ["changePermission"]),
62+
],
63+
},
64+
{
65+
"pid": "glr_authz_3",
66+
"rights_holder": "glr_subj_rights_2",
67+
"permission_list": [
68+
(["glr_subj_1"], ["read"]),
69+
(["glr_subj_2", "glr_subj_3", "glr_subj_4"], ["read"]),
70+
# (["glr_subj_9", "glr_subj_10", "glr_subj_11", "glr_subj_12"], ["changePermission"]),
71+
],
72+
},
73+
{
74+
"pid": "glr_authz_4",
75+
"rights_holder": "glr_subj_rights_2",
76+
"permission_list": [
77+
(["glr_subj_1"], ["read"]),
78+
(["glr_subj_2"], ["write"]),
79+
(["glr_subj_3", "glr_subj_4"], ["read", "write"]),
80+
# (["glr_subj_9", "glr_subj_10", "glr_subj_11", "glr_subj_12"], ["changePermission"]),
81+
],
82+
},
83+
{
84+
"pid": "glr_authz_5",
85+
"rights_holder": "glr_subj_rights_3",
86+
"permission_list": [
87+
(["glr_subj_1", "glr_subj_rights_2"], ["read"]),
88+
(["glr_subj_2", "glr_subj_3", "glr_subj_4"], ["read", "write"]),
89+
(["glr_subj_5", "glr_subj_6", "glr_subj_7", "glr_subj_8"], ["read", "changePermission"]),
90+
],
91+
},
92+
]
93+
94+
@d1_test.d1_test_case.reproducible_random_decorator("TestGetLogRecordsAuth")
95+
@freezegun.freeze_time("1977-05-28")
96+
class TestGetLogRecordsAuth(d1_gmn.tests.gmn_test_case.GMNTestCase):
97+
def _create_test_objs(self, client):
98+
d = datetime.datetime(1977, 5, 28)
99+
obj_list = []
100+
for perm in PERM_LIST:
101+
with freezegun.freeze_time(d):
102+
obj_list.append(self.create_obj(client, **perm, now_dt=d))
103+
d += datetime.timedelta(days=1)
104+
return obj_list
105+
106+
107+
def _log_entry_pids(self, log):
108+
return [
109+
d1_common.xml.get_req_val(v.identifier) for v in log.logEntry
110+
]
111+
112+
113+
def _is_redacted(self, log_entry):
114+
return (
115+
log_entry.ipAddress == '<NotAuthorized>' and
116+
d1_common.xml.get_req_val(log_entry.subject) == '<NotAuthorized>'
117+
)
118+
119+
120+
@responses.activate
121+
def test_1000(self, gmn_client_v1_v2):
122+
"""getLogRecords() authz: Subject receives empty result if there are no matching records"""
123+
self._create_test_objs(gmn_client_v1_v2)
124+
with d1_gmn.tests.gmn_mock.set_auth_context(
125+
active_subj_list=['glr_unk_subj'],
126+
trusted_subj_list=[],
127+
):
128+
log = gmn_client_v1_v2.getLogRecords()
129+
assert self._log_entry_pids(log) == []
130+
self.sample.assert_equals(log, 'empty_result_no_match', gmn_client_v1_v2)
131+
132+
133+
@responses.activate
134+
def test_1001(self, gmn_client_v1_v2):
135+
"""getLogRecords() authz: Subject receives redacted records for objects where
136+
they have only 'read' access"""
137+
self._create_test_objs(gmn_client_v1_v2)
138+
with d1_gmn.tests.gmn_mock.set_auth_context(
139+
active_subj_list=['glr_subj_1'],
140+
trusted_subj_list=[],
141+
):
142+
log = gmn_client_v1_v2.getLogRecords()
143+
# Subject has read on objects 3, 4, and 5
144+
assert self._log_entry_pids(log) == ['glr_authz_3', 'glr_authz_4', 'glr_authz_5']
145+
# Subject has only read access and receives redacted records
146+
assert self._is_redacted(log.logEntry[0])
147+
assert self._is_redacted(log.logEntry[1])
148+
assert self._is_redacted(log.logEntry[2])
149+
# Store complete result to detect unexpected changes in the remaining fields.
150+
self.sample.assert_equals(log, 'read_access_redacted', gmn_client_v1_v2)
151+
152+
@responses.activate
153+
def test_1002(self, gmn_client_v1_v2):
154+
"""getLogRecords() authz: Subject receives a mix of unredacted and redacted
155+
records depending on access level"""
156+
self._create_test_objs(gmn_client_v1_v2)
157+
with d1_gmn.tests.gmn_mock.set_auth_context(
158+
active_subj_list=['glr_subj_2'],
159+
trusted_subj_list=[],
160+
):
161+
log = gmn_client_v1_v2.getLogRecords()
162+
# Subject has read or better on objects 3, 4, and 5
163+
assert self._log_entry_pids(log) == ['glr_authz_3', 'glr_authz_4', 'glr_authz_5']
164+
# Subject has only read access on object 3
165+
assert self._is_redacted(log.logEntry[0])
166+
# Subject has write or better on objects 4 and 5
167+
assert not self._is_redacted(log.logEntry[1])
168+
assert not self._is_redacted(log.logEntry[2])
169+
# Store complete result to detect unexpected changes in the remaining fields.
170+
self.sample.assert_equals(log, 'mixed_access_redacted', gmn_client_v1_v2)
171+
172+
173+
@responses.activate
174+
def test_1003(self, gmn_client_v1_v2):
175+
"""getLogRecords() authz: RightsHolder always receives unredacted records"""
176+
self._create_test_objs(gmn_client_v1_v2)
177+
with d1_gmn.tests.gmn_mock.set_auth_context(
178+
active_subj_list=['glr_subj_rights_2'],
179+
trusted_subj_list=[],
180+
):
181+
log = gmn_client_v1_v2.getLogRecords()
182+
# Subject is rightsholder on objects 2, 3, 4, and has "read" on object 5.
183+
assert self._log_entry_pids(log) == ['glr_authz_2', 'glr_authz_3', 'glr_authz_4', 'glr_authz_5']
184+
# Subject is rightsHolder on objects 2, 3 and 4
185+
assert not self._is_redacted(log.logEntry[0])
186+
assert not self._is_redacted(log.logEntry[1])
187+
assert not self._is_redacted(log.logEntry[2])
188+
# Subject has only read access on object 5
189+
assert self._is_redacted(log.logEntry[3])
190+
# Store complete result to detect unexpected changes in the remaining fields.
191+
self.sample.assert_equals(log, 'rightsholder_access_redacted', gmn_client_v1_v2)
192+
193+
194+
@responses.activate
195+
def test_1004(self, gmn_client_v1_v2):
196+
"""getLogRecords() authz: Trusted subject receives all records unredacted"""
197+
self._create_test_objs(gmn_client_v1_v2)
198+
with d1_gmn.tests.gmn_mock.set_auth_context(
199+
active_subj_list=['glr_trusted'],
200+
trusted_subj_list=['glr_trusted'],
201+
):
202+
log = gmn_client_v1_v2.getLogRecords(count=200)
203+
for log_entry in log.logEntry:
204+
assert not self._is_redacted(log_entry)

0 commit comments

Comments
 (0)