From a836ad14422e55ec07fb51d6a6e0f5e5a211bf5a Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Tue, 14 Nov 2023 12:53:24 +1300 Subject: [PATCH] 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 Reviewed-by: Andrew Bartlett --- python/samba/tests/conditional_ace_claims.py | 499 +++++++++++++++++++ selftest/knownfail.d/conditional_ace_claims | 4 + 2 files changed, 503 insertions(+) create mode 100644 selftest/knownfail.d/conditional_ace_claims diff --git a/python/samba/tests/conditional_ace_claims.py b/python/samba/tests/conditional_ace_claims.py index e7fef5aed43..4790a88dd99 100644 --- a/python/samba/tests/conditional_ace_claims.py +++ b/python/samba/tests/conditional_ace_claims.py @@ -17,9 +17,11 @@ """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 @@ -400,3 +402,500 @@ class DenyTests(ConditionalAceClaimsBase): "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))') + ), + ] diff --git a/selftest/knownfail.d/conditional_ace_claims b/selftest/knownfail.d/conditional_ace_claims new file mode 100644 index 00000000000..8fb6730b6f8 --- /dev/null +++ b/selftest/knownfail.d/conditional_ace_claims @@ -0,0 +1,4 @@ +^samba.tests.conditional_ace_claims.+ConditionalAceLargeComposites.test_allow_002-0-vs-0 +^samba.tests.conditional_ace_claims.+ConditionalAceLargeComposites.test_deny_001-90-disorderly-strings-claim-vs-claim-case-sensitive-with-dupes +^samba.tests.conditional_ace_claims.+ConditionalAceLargeComposites.test_deny_022-102+1-dupe-vs-102+1-dupe +^samba.tests.conditional_ace_claims.+ConditionalAceLargeComposites.test_deny_024-2+1-dupe-vs-2+1-dupe