Opened 8 years ago
Closed 8 years ago
#12649 closed enhancement (fixed)
Simplify configuration parsing in svn_authz module
Reported by: | Ryan J Ollos | Owned by: | Ryan J Ollos |
---|---|---|---|
Priority: | normal | Milestone: | 1.3.2 |
Component: | general | Version: | |
Severity: | normal | Keywords: | |
Cc: | Branch: | ||
Release Notes: |
Fixed case-insensitive usernames in AuthzPolicy, a regression introduced in Trac 1.2. |
||
API Changes: |
|
||
Internal Changes: |
Description
While working on #12637 I saw some places we could simplify the code and make the configuration parsing more robust.
Attachments (1)
Change History (17)
comment:1 by , 8 years ago
comment:2 by , 8 years ago
Owner: | set to |
---|---|
Status: | new → assigned |
comment:3 by , 8 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Committed to trunk in [15345:15346].
comment:4 by , 8 years ago
In Subversion and Trac, user name is case-sensitive by default. However, after changes, the user names are converted to lower case.
>>> from pprint import pprint >>> from trac.versioncontrol.svn_authz import AuthzSourcePolicy >>> from trac.versioncontrol.svn_authz import parse >>> with open('/tmp/svnauthz.txt', 'w') as f: ... f.write("""\ ... [/path/to] ... foo1 = rw ... [mod:/path/to] ... foo2 = rw ... [/Path/To] ... Bar1 = rw ... [Mod:/Path/To] ... Bar2 = rw ... """) ... >>> result = parse('/tmp/svnauthz.txt', ['', 'mod', 'Mod']) >>> pprint(result) {'': {u'/Path/To': {u'bar1': True}, u'/path/to': {u'foo1': True}}, u'Mod': {u'/Path/To': {u'bar2': True}}, u'mod': {u'/path/to': {u'foo2': True}}}
follow-up: 7 comment:5 by , 8 years ago
comment:6 by , 8 years ago
Resolution: | fixed |
---|---|
Status: | closed → reopened |
comment:7 by , 8 years ago
Replying to Jun Omae:
See also python - ConfigParser reads capital keys and make them lower case - Stack Overflow.
Based on that, I'd propose the following patch, which passes tests on OSX:
-
trac/versioncontrol/svn_authz.py
diff --git a/trac/versioncontrol/svn_authz.py b/trac/versioncontrol/svn_authz.py index be61197eb..1ee799b8f 100644
a b def parse(authz_file, modules): 46 46 are retained. 47 47 """ 48 48 parser = UnicodeConfigParser() 49 parser.optionxform = str 49 50 parser.read(authz_file) 50 51 51 52 groups = {} -
trac/versioncontrol/tests/svn_authz.py
diff --git a/trac/versioncontrol/tests/svn_authz.py b/trac/versioncontrol/tests/svn_authz.py index b7b33a0df..904e5f381 100644
a b foo = rw 61 61 ; Unicode module names 62 62 [module:/c/résumé] 63 63 bar = rw 64 Foo = rw 65 BAZ = r 64 66 65 67 ; Unused module, not parsed 66 68 [unused:/some/path] … … foo = r 88 90 }, 89 91 u'/c/résumé': { 90 92 u'bar': True, 93 u'Foo': True, 94 u'BAZ': True, 91 95 }, 92 96 }, 93 97 }, authz) … … user = 191 195 [scoped:/scope/dir1] 192 196 joe = r 193 197 [scoped:/scope/dir2] 194 jane = r198 Jane = r 195 199 196 200 # multiple entries 197 201 [/multiple] … … $authenticated = 203 207 [/multiple/bar] 204 208 * = 205 209 john = r 206 jane = r210 Jane = r 207 211 $anonymous = r 208 212 [/multiple/baz] 209 213 $anonymous = r 210 214 * = 211 jane = r215 Jane = r 212 216 [module:/multiple/bar] 213 217 joe = r 214 218 john = … … joe = r 359 363 joe = r 360 364 denied = 361 365 [module:/otherpath] 362 jane = r366 Jane = r 363 367 $anonymous = r 364 368 [inactive:/not-in-this-instance] 365 369 unknown = r … … unknown = r 370 374 self.assertRevPerm(None, 'denied') 371 375 self.assertPathPerm(True, 'joe') 372 376 self.assertRevPerm(True, 'joe') 373 self.assertPathPerm(True, ' jane')374 self.assertRevPerm(True, ' jane')377 self.assertPathPerm(True, 'Jane') 378 self.assertRevPerm(True, 'Jane') 375 379 self.assertPathPerm(True, 'anonymous') 376 380 self.assertRevPerm(True, 'anonymous') 377 381 378 382 def test_default_permission(self): 379 383 # By default, permissions are undecided 380 384 self.assertPathPerm(None, 'joe', '', '/not_defined') 381 self.assertPathPerm(None, ' jane', 'repo', '/not/defined/either')385 self.assertPathPerm(None, 'Jane', 'repo', '/not/defined/either') 382 386 383 387 def test_read_write(self): 384 388 # Allow 'r' and 'rw' entries, deny 'w' and empty entries … … unknown = r 415 419 # The * wildcard matches all users, including anonymous 416 420 self.assertPathPerm(True, 'anonymous', '', '/wildcard') 417 421 self.assertPathPerm(True, 'joe', '', '/wildcard') 418 self.assertPathPerm(True, ' jane', '', '/wildcard')422 self.assertPathPerm(True, 'Jane', '', '/wildcard') 419 423 420 424 def test_special_tokens(self): 421 425 # The $anonymous token matches only anonymous users … … unknown = r 424 428 # The $authenticated token matches all authenticated users 425 429 self.assertPathPerm(None, 'anonymous', '', '/special/authenticated') 426 430 self.assertPathPerm(True, 'joe', '', '/special/authenticated') 427 self.assertPathPerm(True, ' jane', '', '/special/authenticated')431 self.assertPathPerm(True, 'Jane', '', '/special/authenticated') 428 432 429 433 def test_groups(self): 430 434 # Groups are specified in a separate section and used with an @ prefix … … unknown = r 460 464 self.assertPathPerm(True, 'joe', 'scoped', '/dir1') 461 465 self.assertPathPerm(None, 'joe', 'scoped', '/dir2') 462 466 self.assertPathPerm(True, 'joe', 'scoped', '/') 463 self.assertPathPerm(None, ' jane', 'scoped', '/dir1')464 self.assertPathPerm(True, ' jane', 'scoped', '/dir2')465 self.assertPathPerm(True, ' jane', 'scoped', '/')467 self.assertPathPerm(None, 'Jane', 'scoped', '/dir1') 468 self.assertPathPerm(True, 'Jane', 'scoped', '/dir2') 469 self.assertPathPerm(True, 'Jane', 'scoped', '/') 466 470 467 471 def test_multiple_entries(self): 468 472 self.assertPathPerm(True, 'anonymous', '', '/multiple/foo') … … unknown = r 471 475 self.assertPathPerm(False, 'joe', '', '/multiple/bar') 472 476 self.assertPathPerm(True, 'john', '', '/multiple/bar') 473 477 self.assertPathPerm(True, 'anonymous', '', '/multiple/baz') 474 self.assertPathPerm(True, ' jane', '', '/multiple/baz')478 self.assertPathPerm(True, 'Jane', '', '/multiple/baz') 475 479 self.assertPathPerm(False, 'joe', '', '/multiple/baz') 476 480 self.assertPathPerm(True, 'anonymous', 'module', '/multiple/foo') 477 481 self.assertPathPerm(True, 'joe', 'module', '/multiple/foo') … … unknown = r 479 483 self.assertPathPerm(True, 'joe', 'module', '/multiple/bar') 480 484 self.assertPathPerm(False, 'john', 'module', '/multiple/bar') 481 485 self.assertPathPerm(True, 'anonymous', 'module', '/multiple/baz') 482 self.assertPathPerm(True, ' jane', 'module', '/multiple/baz')486 self.assertPathPerm(True, 'Jane', 'module', '/multiple/baz') 483 487 self.assertPathPerm(False, 'joe', 'module', '/multiple/baz') 484 488 485 489 def test_multiple_entries_with_module_and_parent_directory(self): … … unknown = r 527 531 self.assertRevPerm(True, 'joe', 'scoped', 123) 528 532 self.assertRevPerm(None, 'joe', 'scoped', 456) 529 533 self.assertRevPerm(True, 'joe', 'scoped', 789) 530 self.assertRevPerm(None, ' jane', 'scoped', 123)531 self.assertRevPerm(True, ' jane', 'scoped', 456)532 self.assertRevPerm(True, ' jane', 'scoped', 789)534 self.assertRevPerm(None, 'Jane', 'scoped', 123) 535 self.assertRevPerm(True, 'Jane', 'scoped', 456) 536 self.assertRevPerm(True, 'Jane', 'scoped', 789) 533 537 self.assertRevPerm(None, 'user', 'scoped', 123) 534 538 self.assertRevPerm(None, 'user', 'scoped', 456) 535 539 self.assertRevPerm(True, 'user', 'scoped', 789)
by , 8 years ago
Attachment: | t12649_case_sensitive.diff added |
---|
comment:8 by , 8 years ago
AuthzSourcePolicy
has the same issue. Proposed changes in jomae.git@t12649.1.
comment:9 by , 8 years ago
Changes look good. [9deaf78c/jomae.git] will probably be needed on 1.2-stable since UnicodeConfigParser
replaced ConfigObj
in #11982.
comment:10 by , 8 years ago
I was surprised when seeing str
here in your patch instead of unicode
, but indeed the cast happens on the "raw" str
in ConfigParser.
The tests pass for me on Windows as well, for the patch and for t12649.1.
follow-up: 15 comment:11 by , 8 years ago
I noticed another issue. ConfigParser
ignores a line started with rem
as a comment. User named rem
cannot be used in.
>>> from trac.versioncontrol.svn_authz import parse >>> from trac.util import read_file >>> print(read_file('/tmp/svnauthz.txt')) [/path/to] foo = rw REM = rw Rem = rw rem = rw >>> parse('/tmp/svnauthz.txt', ['']) {'': {u'/path/to': {u'foo': True}}}
comment:12 by , 8 years ago
Well, considering all the features the standard ConfigParser has which we don't use or go in the way, it would probably be way more efficient to roll our own at this point.
comment:13 by , 8 years ago
I guess we would have the same problem if a plugin named an option rem
. I favor either overriding the _read
method, or copying the entire ConfigParser
class as UnicodeConfigParser
and modifying to fit our needs.
comment:14 by , 8 years ago
Status: | reopened → assigned |
---|
Proposed changes in log:rjollos.git:t12649_authzsourcepolicy_refactoring. The changes are based on the branch from #12637. Changes to
parse
and remove ofjoin
function are API changes, but in practice I don't expect a plugin would have any reason to use the functions.