1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00
samba-mirror/python/samba/tests/conditional_ace_claims.py
Douglas Bagnall a836ad1442 pytest: conditional_ace_claims tests large composite comparisons
Our composite comparisons are currently all wrong.

Soon they will be fixed, but we are going to have an inflection point
where we switch from the naive compare-everything approach to a sort
based comparison, and we want to test both sides. Also, we use these
tests for a little bit of timing, which reveals it is all fast enough.

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-11-27 22:37:32 +00:00

902 lines
34 KiB
Python

# Unix SMB/CIFS implementation.
# Copyright © Catalyst IT 2023
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""Tests for Conditional ACEs, claims, and security tokens."""
import random
from samba.dcerpc import security
from samba.security import access_check
from samba.tests.token_factory import token as Token
from samba.tests.token_factory import list_to_claim
from samba.dcerpc.security import CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1
from samba.tests import TestCase, DynamicTestCase, get_env_dir
from samba.colour import c_RED, c_GREEN
import os
from samba import NTSTATUSError
from samba.ntstatus import NT_STATUS_ACCESS_DENIED
DEFAULT_ACCESS = security.SEC_FILE_ALL
DEFAULT_ACCESS2 = (security.SEC_STD_READ_CONTROL |
security.SEC_ADS_LIST |
security.SEC_ADS_READ_PROP)
def write_c_test_on_failure(f):
"""This is a function decorator that writes a function for
/libcli/security/tests/test_run_conditional_ace.c that runs the
equivalent test. Why?! Because iterating over a test to debug the
failure is slower in Python tests, but adding new tests is faster
in Python. So the flow goes like this:
1. add python tests, run them
2. if nothing fails, goto 1
3. copy the test_something() text into test_run_conditional_ace.c,
rename it, and add it to main().
4. `make bin/test_run_conditional_ace && rr bin/test_run_conditional_ace`
5. `rr replay`
and you're away. You can also just work from the Python, but a few
runs of `make -j` after touching something in libcli/security will
make you see why this exists.
You might be thinking that this surely took longer to write than
waiting 100 times for a 30 second compile, but that misses the
point that debugging needs to be ergonomic and fun.
"""
from json import dumps as q # JSON quoting is C quoting, more or less
def wrapper(name, token, sddl, access_desired):
try:
f(name, token, sddl, access_desired)
except Exception:
print()
print('static void test_something(void **state)')
print('{')
print('\tINIT();')
for s in ('sids', 'device_sids'):
if s in token:
macro = ('user_sids' if s == 'sids' else s).upper()
v = ', '.join(q(x) for x in token[s])
print(f'\t{macro}({v});')
for s in ('user_claims', 'device_claims'):
if s in token:
macro = s.upper()
for name, values in token[s].items():
if isinstance(values,
CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1):
v = '...'
else:
if not isinstance(values, (list, tuple)):
values = [values]
v = ', '.join(q(x) for x in values)
v = q(f"{v}")
print(f'\t{macro}({q(name)}, {v});')
print(f'\tSD({q(sddl)});')
if 'allow' in f.__name__:
print(f'\tALLOW_CHECK({access_desired:#x});')
else:
print(f'\tDENY_CHECK({access_desired:#x});')
print('}')
print()
raise
return wrapper
class ConditionalAceClaimsBase(TestCase):
maxDiff = 0
@classmethod
def setUpDynamicTestCases(cls):
cls.domain_sid = security.dom_sid("S-1-22-333-4444")
seen = set()
for i, row in enumerate(cls.data):
token, sddl, access_desired = row
name = f'{i+1:03}-{token}-{sddl}-{access_desired}'
if len(name) > 150:
name = f"{name[:125]}+{len(name) - 125}-more-characters"
if name in seen:
print(f"seen {row} after {len(seen)}")
seen.add(name)
if cls.allow:
cls.generate_dynamic_test('test_allow',
name, token, sddl, access_desired)
else:
cls.generate_dynamic_test('test_deny',
name, token, sddl, access_desired)
fuzz_seed_dir = get_env_dir('SAMBA_WRITE_FUZZ_STRINGS_DIR')
if fuzz_seed_dir is not None:
cls._write_sddl_strings_for_fuzz_seeds(fuzz_seed_dir)
@classmethod
def _write_sddl_strings_for_fuzz_seeds(cls, fuzz_seed_dir):
"""write all the SDDL strings we have into a directory as individual
files, using a naming convention beloved of fuzzing engines.
To run this set an environment variable; see
cls.setUpDynamicTestCases(), below.
Note this will only run in subclasses annotated with @DynamicTestCase.
"""
from hashlib import md5
for _, sddl, _ in cls.data:
name = md5(sddl.encode()).hexdigest()
with open(os.path.join(fuzz_seed_dir, name), 'w') as f:
f.write(sddl)
@write_c_test_on_failure
def _test_allow_with_args(self, _token, sddl, access_desired):
if isinstance(_token, dict):
token = Token(**_token)
else:
token = _token
sd = security.descriptor.from_sddl(sddl, self.domain_sid)
try:
granted = access_check(sd, token, access_desired)
except NTSTATUSError as e:
print(c_RED(sddl))
print(c_RED(_token))
if e.args[0] != NT_STATUS_ACCESS_DENIED:
raise
self.fail("access was denied")
self.assertEqual(granted, access_desired)
@write_c_test_on_failure
def _test_deny_with_args(self, token, sddl, access_desired):
if isinstance(token, dict):
token = Token(**token)
sd = security.descriptor.from_sddl(sddl, self.domain_sid)
try:
granted = access_check(sd, token, access_desired)
except NTSTATUSError as e:
if e.args[0] == NT_STATUS_ACCESS_DENIED:
return
self.fail(f"failed with {e}, not access denied")
self.fail("access allowed")
@DynamicTestCase
class AllowTests(ConditionalAceClaimsBase):
name = "allow"
allow = True
data = [
( # device_claims
{'sids': ['WD', 'AA'],
'device_claims': {"colour":["orange", "blue"]}},
('D:(XA;;0x1f;;;AA;'
'(@Device.colour == {"orange", "blue"}))'),
0x10),
( # device_claims, int >=
{'sids': ['WD', 'AA'],
'device_claims': {"legs": 4}},
('D:(XA;;0x1f;;;AA;(@Device.legs >= 1))'),
0x10),
( # device_claims, int
{'sids': ['WD', 'AA'],
'device_claims': {"legs": 1}},
('D:(XA;;0x1f;;;AA;(@Device.legs == 1))'),
0x10),
( # device_member_of && member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(Device_Member_of{SID(BA)} && Member_of{SID(WD)}))"),
0x10),
( # device_member_of || member_of, both true
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(Device_Member_of{SID(AA)} || Member_of{SID(WD)}))"),
0x10),
( # device_member_of || member_of, second true
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(Device_Member_of{SID(AA)} || Member_of{SID(WD)}))"),
0x10),
( # device_member_of || member_of, first true
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(Device_Member_of{SID(BG)} || Member_of{SID(WR)}))"),
0x10),
( # single SID, Member_of_Any
{'sids': ['S-1-222-333']},
("D:(XA;;0x1ff;;;S-1-222-333;(Member_of_Any{SID(S-1-222-333)}))"),
0x1),
({'sids': ['S-1-1-0']}, "O:S-1-1-0D:(A;;0x1ff;;;WD)", DEFAULT_ACCESS),
({'sids': ['S-1-1-0']},
"O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)}))",
DEFAULT_ACCESS),
({'sids': ['S-1-1-0', 'S-1-222-333']},
"O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)}))",
DEFAULT_ACCESS),
({'sids': ['WD', 'S-1-222-333']},
"O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)}))",
DEFAULT_ACCESS),
( # a single SID, not a composite
{'sids': ['S-1-1-0', 'S-1-222-333']},
"O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of SID(S-1-1-0)))",
DEFAULT_ACCESS),
( # a single SID, not a composite, without space after Member_of
{'sids': ['S-1-1-0', 'S-1-222-333']},
"O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of\nSID(S-1-1-0)))",
DEFAULT_ACCESS),
( # a single SID, not a composite, Member_of_Any
{'sids': ['S-1-1-0', 'S-1-222-333']},
"O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any SID(S-1-1-0)))",
DEFAULT_ACCESS),
( # Member_of_Any
{'sids': ['S-1-1-0', 'S-1-222-333']},
"O:S-1-1-0D:(XA;;0x1;;;WD;(Member_of_Any{SID(AS),SID(WD)}))",
0x1),
({'sids': ['S-1-1-0', 'S-1-222-333']},
("O:S-1-1-0D:"
"(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-0), SID(S-1-222-333)}))"),
DEFAULT_ACCESS),
({'sids': ['S-1-1-0', 'S-1-222-333']},
("O:S-1-1-0D:"
"(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-334), SID(S-1-222-333)}))"),
DEFAULT_ACCESS),
({'sids': ['S-1-1-0', 'S-1-222-333']},
("D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)}))"),
DEFAULT_ACCESS),
({'sids': ['S-1-77-88-99', 'AA']},
"D:(XA;;0x1f;;;AA;(Member_of{SID(S-1-77-88-99)}))",
0x10),
( # device_member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)}))",
0x10),
( # device_member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)}))",
0x10),
( # not (!) member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(! (Member_of{SID(BA)})))",
0x10),
( # not not (!!) member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(!(! (Member_of{SID(AA)}))))",
0x10),
( # not * 8 (!!!! !!!!) member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(!(!(!(!(!(!(!(!( Member_of{SID(AA)}))))))))))",
0x10),
( # not * 9 (!!! !!! !!!) member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(!(!(!( !(!(!( !(!(!(Member_of{SID(BA)})))))))))))",
0x10),
( # not * 9 (!!! !!! !!!) Not_Member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(!(!(!( !(!(!( !(!(!( Not_Member_of{SID(AA)})))))))))))"),
0x10),
( #resource ACE
{'sids': ['WD', 'AA'],
'device_claims': {"colour": ["blue"]}},
('D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))'
'S:(RA;;;;;WD;("colour",TS,0,"blue"))'),
0x10),
( #resource ACE ==
{'sids': ['WD', 'AA'],
'device_claims': {"colour": ["blue"]}},
('D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))'
'S:(RA;;;;;WD;("colour",TS,0,"blue"))'),
0x10),
( # device_claims, comparing single to single
{'sids': ['WD', 'AA'],
'device_claims': {"colour": "blue"}},
('D:(XA;;0x1f;;;AA;(@Device.colour == "blue"))'),
0x10),
( # device_claims == user_claims
{'sids': ['WD', 'AA'],
'user_claims': {"colour": "blue"},
'device_claims': {"colour": "blue"}},
('D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour))'),
0x10),
( #resource ACE multi
{'sids': ['WD', 'AA'],
'device_claims': {"colour": ["blue", "red"]}},
('D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))'
'S:(RA;;;;;WD;("colour",TS,0,"blue", "red"))'),
0x10),
]
@DynamicTestCase
class DenyTests(ConditionalAceClaimsBase):
name = "allow"
allow = False
data = [
({}, "", DEFAULT_ACCESS),
({'sids': ['S-1-1-0']}, "O:S-1-1-0D:(A;;0x1fe;;;WD)", DEFAULT_ACCESS),
({}, "O:WDD:(A;;GACR;;;CO)", DEFAULT_ACCESS),
({'sids': ['S-1-1-0', 'S-1-222-444']},
("D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)}))"),
0x1),
( # Without explicit 'everyone' SID in list of SIDs, this is
# denied because the ACE SID 'WD' doesn't match.
{'sids': ['S-1-222-333']},
("D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)}))"),
0x1),
( # device_member_of && member_of, both false
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(Device_Member_of{SID(AA)} && Member_of{SID(WR)}))"),
0x10),
( # device_member_of && member_of, first false
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(Device_Member_of{SID(AA)} && Member_of{SID(WD)}))"),
0x10),
( # device_member_of && member_of, second false
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(Device_Member_of{SID(BA)} && Member_of{SID(BA)}))"),
0x10),
( # device_member_of || member_of, both false
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
("D:(XA;;0x1f;;;AA;"
"(Device_Member_of{SID(AA)} || Member_of{SID(WR)}))"),
0x10),
( # device_claims, comparing composite to single
{'sids': ['WD', 'AA'],
'device_claims': {"colour": ["orange", "blue"]}},
('D:(XA;;0x1f;;;AA;(@Device.colour == "blue"))'),
0x10),
( # not (!) member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(! (Member_of{SID(AA)})))",
0x10),
( # not not (!!) member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(!(!( Member_of{SID(BA)}))))",
0x10),
( # not * 8 (!!!! !!!!) member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(!(!( !(!( !(!( !(!(Member_of{SID(BA)}))))))))))",
0x10),
( # not * 3 (!!!) member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(!(!(!(Member_of{SID(AA)})))))",
0x10),
( # not * 3 (!!!) Not_Member_of
{'sids': ['WD', 'AA'],
'device_sids': ['BA', 'BG']},
"D:(XA;;0x1f;;;AA;(!(!(!(Not_Member_of{SID(BA)})))))",
0x10),
]
def _int_range(n, n_dupes=0, random_seed=None):
"""Makes a list of stringified integers.
If n_unique is specified and less than n, there will be that many unique
values (and hence some duplicates). If random_seed is set, the list will be
shuffled.
"""
claims = [str(x) for x in range(n)]
if random_seed is None:
if n_dupes:
claims *= 1 + (n + n_dupes) // n
return claims[:n + n_dupes]
random.seed(random_seed)
for i in range(n_dupes):
# this purposefully skews the distribution.
claims.append(random.choice(claims))
random.shuffle(claims)
return claims
def _str_range(n, n_dupes=0, random_seed=None, mix_case=False):
"""Create a list of strings with somewhat controllable disorder.
"""
ints = _int_range(n, n_dupes, random_seed)
claims = [f'a{i}' for i in ints]
if mix_case:
if random_seed is None:
random.seed(0)
for i in range(len(claims)):
if random.random() < 0.5:
claims[i] = claims[i].upper()
return claims
def claim_str_range(*args, name="foo", case_sensitive=False, **kwargs):
"""String value range as a CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1"""
vals = _str_range(*args, **kwargs)
claim = list_to_claim(name, vals, case_sensitive=case_sensitive)
return claim
def claim_int_range(*args, name="foo", case_sensitive=False, **kwargs):
"""Int value range as a CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1"""
vals = _int_range(*args, **kwargs)
claim = list_to_claim(name, vals, case_sensitive=case_sensitive)
return claim
def ra_str_range(*args, name="foo", case_sensitive=False, **kwargs):
"""Make a string claim as a resource attribute"""
claim = _str_range(*args, **kwargs)
values = '","'.join(claim)
c = (2 if case_sensitive else 0)
return f'(RA;;;;;WD;("{name}",TS,{c},"{values}"))'
def ra_int_range(*args, name="foo", unsigned=False, **kwargs):
"""Return an integer claim range as a resource attribute."""
ints = _int_range(*args, **kwargs)
values = ','.join(str(x) for x in ints)
return f'(RA;;;;;WD;("{name}",T{"U" if unsigned else "I"},0,{values}))'
def composite_int(*args, **kwargs):
"""Integer conditional ACE composite"""
claim = _int_range(*args, **kwargs)
values = ', '.join(claim)
return '{' + values + '}'
def composite_str(*args, **kwargs):
"""String conditional ACE composite"""
claim = _str_range(*args, **kwargs)
values = '", "'.join(claim)
return '{"' + values + '"}'
@DynamicTestCase
class ConditionalAceLargeComposites(ConditionalAceClaimsBase):
"""Here we are dynamically generating claims and composites with large numbers
of members, and using them in comparisons. Sometimes the comparisons are
meant to fail, and sometimes not.
"""
maxDiff = 0
@classmethod
def setUpDynamicTestCases(cls):
cls.domain_sid = security.dom_sid("S-1-22-333-4444")
for i, row in enumerate(cls.data):
name, allow, token, sddl = row
name = f'{i+1:03}-{name}'
if 'sids' not in token:
token['sids'] = ['AU', 'WD']
if allow:
cls.generate_dynamic_test('test_allow',
name, token, sddl, 0x10)
else:
cls.generate_dynamic_test('test_deny',
name, token, sddl, 0x10)
fuzz_seed_dir = get_env_dir('SAMBA_WRITE_FUZZ_STRINGS_DIR')
if fuzz_seed_dir is not None:
cls._write_sddl_strings_for_fuzz_seeds(fuzz_seed_dir)
data = [
(
"90-disorderly-strings-claim-vs-claim-case-sensitive-with-dupes",
False,
{'user_claims': {"c": claim_str_range(90,
random_seed=2),
"d": claim_str_range(90, 90,
case_sensitive=True,
random_seed=3)}},
('D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
# this one currently fails before we get to compare_composites()
"0-vs-0",
True,
{'user_claims': {"c": claim_str_range(0)}},
('D:(XA;;FA;;;WD;(@USER.c == @USER.c))')
),
(
"50-orderly-strings",
True,
{'user_claims': {"c": claim_str_range(50)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(50)}))')
),
(
"50-disorderly-strings-same-disorder",
True,
{'user_claims': {"c": claim_str_range(50, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(50, random_seed=1)}))')
),
(
"200-disorderly-strings",
True,
{'user_claims': {"c": claim_str_range(200, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(200, random_seed=2)}))')
),
(
"50-orderly-vs-disorderly-strings",
True,
{'user_claims': {"c": claim_str_range(50)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(50, random_seed=1)}))')
),
(
"50-disorderly-vs-orderly-strings",
True,
{'user_claims': {"c": claim_str_range(50, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(50)}))')
),
(
"99-orderly-strings",
True,
{'user_claims': {"c": claim_str_range(99)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(99)}))')
),
(
"99-disorderly-strings",
True,
{'user_claims': {"c": claim_str_range(99, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(99, random_seed=2)}))')
),
(
"99-orderly-vs-disorderly-strings",
True,
{'user_claims': {"c": claim_str_range(99)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(99, random_seed=1)}))')
),
(
"99-disorderly-vs-orderly-strings",
True,
{'user_claims': {"c": claim_str_range(99, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(99)}))')
),
(
"39-orderly-strings-vs-39+60-dupes",
True,
{'user_claims': {"c": claim_str_range(39)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(39, 60)}))')
),
(
"39-disorderly-strings-vs-39+60-dupes",
True,
{'user_claims': {"c": claim_str_range(39, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(39, 60, random_seed=1)}))')
),
(
"39-orderly-vs-disorderly-strings-vs-39+60-dupes",
True,
{'user_claims': {"c": claim_str_range(39)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(39, 60, random_seed=1)}))')
),
(
"39-disorderly-vs-orderly-strings-vs-39+60-dupes",
True,
{'user_claims': {"c": claim_str_range(39, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(39, 60)}))')
),
(
"3-orderly-strings-vs-3+60-dupes",
True,
{'user_claims': {"c": claim_str_range(3)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(3, 60)}))')
),
(
"3-disorderly-strings-vs-3+60-dupes",
True,
{'user_claims': {"c": claim_str_range(3, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(3, 60, random_seed=1)}))')
),
(
"3-orderly-vs-disorderly-strings-vs-3+60-dupes",
True,
{'user_claims': {"c": claim_str_range(3)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(3, 60, random_seed=1)}))')
),
(
"3-disorderly-vs-orderly-strings-vs-3+60-dupes",
True,
{'user_claims': {"c": claim_str_range(3, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(3, 60)}))')
),
(
"3-orderly-strings-vs-3+61-dupes",
True,
{'user_claims': {"c": claim_str_range(3)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(3, 61)}))')
),
(
"63-orderly-strings-vs-62+1-dupe",
False,
{'user_claims': {"c": claim_str_range(63)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(62, 1)}))')
),
(
"102+1-dupe-vs-102+1-dupe",
False,
# this is an invalid claim
{'user_claims': {"c": claim_str_range(102, 1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(102, 1)}))')
),
(
"0-vs-1",
False,
{'user_claims': {"c": claim_str_range(0),
"d": claim_str_range(1)}},
('D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"2+1-dupe-vs-2+1-dupe",
False,
{'user_claims': {"c": claim_str_range(2, 1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(2, 1)}))')
),
(
"63-disorderly-strings-vs-62+1-dupe",
False,
{'user_claims': {"c": claim_str_range(63, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(62, 1, random_seed=1)}))')
),
(
"63-disorderly-strings-vs-63+800-dupe",
True,
{'user_claims': {"c": claim_str_range(63, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(63, 800, random_seed=1)}))')
),
(
"63-disorderly-strings-vs-62+800-dupe",
False,
{'user_claims': {"c": claim_str_range(63, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(62, 800, random_seed=1)}))')
),
(
"9-orderly-strings",
True,
{'user_claims': {"c": claim_str_range(9)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(9)}))')
),
(
"9-orderly-strings-claim-vs-itself",
True,
{'user_claims': {"c": claim_str_range(9)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.c))')
),
(
"300-orderly-strings-claim-vs-itself",
True,
{'user_claims': {"c": claim_str_range(300)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.c))')
),
(
"900-disorderly-strings-claim-vs-claim",
True,
{'user_claims': {"c": claim_str_range(900, random_seed=1),
"d": claim_str_range(900, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"9-orderly-strings-claim-mixed-case-vs-claim-case-sensitive",
False,
{'user_claims': {"c": claim_str_range(9, mix_case=True),
"d": claim_str_range(9, case_sensitive=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"9-disorderly-strings-claim-vs-claim-case-sensitive-mixed-case",
False,
{'user_claims': {"c": claim_str_range(9,random_seed=1),
"d": claim_str_range(9,
mix_case=True,
case_sensitive=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"9-disorderly-strings-claim-vs-claim-case-sensitive-both-mixed-case",
False,
{'user_claims': {"c": claim_str_range(9,
mix_case=True,
random_seed=1),
"d": claim_str_range(9,
mix_case=True,
case_sensitive=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"9-disorderly-strings-claim-vs-claim-case-sensitive-ne",
True,
{'user_claims': {"c": claim_str_range(9,random_seed=1),
"d": claim_str_range(9,
mix_case=True,
case_sensitive=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c != @USER.d))')
),
(
"5-disorderly-strings-claim-vs-claim-case-sensitive-with-dupes-all-mixed-case",
False,
{'user_claims': {"c": claim_str_range(5,
mix_case=True,
random_seed=2),
"d": claim_str_range(5, 5,
mix_case=True,
random_seed=3,
case_sensitive=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"90-disorderly-strings-claim-vs-int-claim",
False,
{'user_claims': {"c": claim_str_range(90,
random_seed=2),
"d": claim_int_range(90,
random_seed=3)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"90-disorderly-ints-claim-vs-string-claim",
False,
{'user_claims': {"c": claim_int_range(90,
random_seed=2),
"d": claim_str_range(90,
random_seed=3)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"9-disorderly-strings-vs-9+90-dupes",
True,
{'user_claims': {"c": claim_str_range(9, random_seed=1)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(9, 90, random_seed=1)}))')
),
(
"9-disorderly-strings-vs-9+90-dupes-case-sensitive",
True,
{'user_claims': {"c": claim_str_range(9, random_seed=1, case_sensitive=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(9, 90, random_seed=2)}))')
),
(
"9-disorderly-strings-vs-9+90-dupes-mixed-case",
True,
{'user_claims': {"c": claim_str_range(9, random_seed=1, mix_case=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(9, 90, random_seed=2, mix_case=True)}))')
),
(
"9-disorderly-strings-vs-9+90-dupes-mixed-case-case-sensitive",
False,
{'user_claims': {"c": claim_str_range(9, random_seed=1, mix_case=True,
case_sensitive=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(9, 90, random_seed=2, mix_case=True)}))')
),
(
"99-disorderly-strings-vs-9+90-dupes-mixed-case",
False,
{'user_claims': {"c": claim_str_range(99, random_seed=1, mix_case=True)}},
(f'D:(XA;;FA;;;WD;(@USER.c == {composite_str(9, 90, random_seed=2, mix_case=True)}))')
),
(
"RA-99-disorderly-strings-vs-9+90-dupes-mixed-case",
False,
{},
('D:(XA;;FA;;;WD;(@RESOURCE.c == '
f'{composite_str(9, 90, random_seed=1, mix_case=True)}))'
f'S:{ra_str_range(99, random_seed=2, mix_case=True)}'
)
),
(
"RA-9+90-dupes-disorderly-strings-vs-9+90-dupes-mixed-case",
False,
{},
('D:(XA;;FA;;;WD;(@RESOURCE.c == '
f'{composite_str(9, 90, random_seed=1, mix_case=True)}))'
f'S:{ra_str_range(9, 90, random_seed=2, mix_case=True)}'
)
),
(
"90-disorderly-strings-claim-vs-missing-claim",
False,
{'user_claims': {"c": claim_str_range(90,
random_seed=2)}},
(f'D:(XA;;FA;;;WD;(@USER.c == @USER.d))')
),
(
"missing-claim-vs-90-disorderly-strings",
False,
{'user_claims': {"c": claim_str_range(90,
random_seed=2)}},
(f'D:(XA;;FA;;;WD;(@USER.z == @USER.c))')
),
(
"RA-9-disorderly-strings-vs-9-mixed-case",
False,
{'user_claims': {"c": claim_str_range(9,
random_seed=1,
mix_case=True),
}
},
('D:(XA;;FA;;;WD;(@RESOURCE.c == @User.c))'
f'S:{ra_str_range(9, random_seed=2, mix_case=True)}'
)
),
(
"9-disorderly-strings-vs-9-RA-mixed-case",
False,
{'user_claims': {"c": claim_str_range(9,
random_seed=1,
mix_case=True),
}
},
('D:(XA;;FA;;;WD;(@user.c == @resource.c))'
f'S:{ra_str_range(9, random_seed=2, mix_case=True)}'
)
),
(
"RA-29-disorderly-strings-vs-29-mixed-case",
False,
{'user_claims': {"c": claim_str_range(29,
random_seed=1,
mix_case=True),
}
},
('D:(XA;;FA;;;WD;(@RESOURCE.c == @User.c))'
f'S:{ra_str_range(29, random_seed=2, mix_case=True)}'
)
),
(
"0-vs-0-ne",
False,
{'user_claims': {"c": claim_str_range(0)}},
('D:(XA;;FA;;;WD;(@USER.c != @USER.c))')
),
(
"1-vs-1",
True,
{'user_claims': {"c": claim_str_range(1)}},
('D:(XA;;FA;;;WD;(@USER.c == @USER.c))')
),
(
"1-vs-1-ne",
False,
{'user_claims': {"c": claim_str_range(1)}},
('D:(XA;;FA;;;WD;(@USER.c != @USER.c))')
),
]