Edgewall Software
Modify

Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#11509 closed defect (fixed)

Fragment in PermissionError msg results in TypeError

Reported by: Ryan J Ollos Owned by: Ryan J Ollos
Priority: normal Milestone: 1.0.2
Component: general Version:
Severity: normal Keywords:
Cc: Jun Omae Branch:
Release Notes:

PermissionError.__unicode__ returns a unicode instance and PermissionError with Fragment is rendered to HTML. Improved error message in exception when subject can't be added to group because actor lacks necessary permission.

API Changes:

Added keyword argument message to PermissionCache.require, allowing the exception message to be directly specified. Added message and title properties to HTTPException.

Description (last modified by Ryan J Ollos)

>>> from genshi.builder import tag
>>> from trac.core import TracError
>>> from trac.perm import PermissionError
>>> from trac.util.translation import tag_
>>> from trac.util.text import to_unicode
>>> e1 = TracError(tag_("This is a %(fragment)s", fragment=tag.em("Fragment")))
>>> to_unicode(e1)
u'This is a <em>Fragment</em>'
>>> e2 = PermissionError(msg=tag_("This is a %(fragment)s", fragment=tag.em("Fragment")))
>>> to_unicode(e2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "trac/util/text.py", line 74, in to_unicode
    return unicode(text)
TypeError: coercing to Unicode: need string or buffer, LazyProxy found

Attachments (0)

Change History (13)

comment:1 by Ryan J Ollos, 5 years ago

Description: modified (diff)
Milestone: 0.12.61.0.2
Owner: set to Ryan J Ollos
Status: newassigned

The proposed change that led to discovering this issue, as well as a proposed fix, can be found in log:rjollos.git:t11509. If the proposed change looks okay, unit tests for PermissionError should be added and the TracDev/Exceptions#CustomTracExceptions page needs to be updated.

comment:2 by Peter Suter, 5 years ago

Maybe I'm missing something but in changeset:d6f2c6e1/rjollos.git you replace a check with unconditionally raising an exception:

- req.perm.require(action)
+ raise PermissionError( 

Did you maybe forget a if not action in req.perm:?

Last edited 5 years ago by Peter Suter (previous) (diff)

comment:3 by Ryan J Ollos, 5 years ago

Yes, I messed-up the changes when cherry-picking between branches. Thanks for catching it. Added to log:rjollos.git:t11509.

comment:4 by Ryan J Ollos, 5 years ago

Changes have been improved and additional tests added in log:rjollos.git:t11509.2.

comment:5 by Jun Omae, 5 years ago

Root cause is that PermissionError.__unicode__() doesn't return a unicode instance. __unicode__ magic method must return a unicode instance.

The same issue can be produced without tag_.

>>> from trac.perm import PermissionError
>>> from trac.util.text import to_unicode
>>> to_unicode(PermissionError(action='WIKI_VIEW'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "trac/util/text.py", line 74, in to_unicode
    return unicode(text)
TypeError: coercing to Unicode: need string or buffer, LazyProxy found
  • trac/perm.py

    diff --git a/trac/perm.py b/trac/perm.py
    index 300ee71..a00f5da 100644
    a b class PermissionError(StandardError):  
    4949    def __unicode__ (self):
    5050        if self.action:
    5151            if self.resource:
    52                 return _('%(perm)s privileges are required to perform '
    53                          'this operation on %(resource)s. You don\'t have the '
    54                          'required permissions.',
    55                          perm=self.action,
    56                          resource=get_resource_name(self.env, self.resource))
     52                msg = _('%(perm)s privileges are required to perform '
     53                        'this operation on %(resource)s. You don\'t have the '
     54                        'required permissions.',
     55                        perm=self.action,
     56                        resource=get_resource_name(self.env, self.resource))
    5757            else:
    58                 return _('%(perm)s privileges are required to perform this '
    59                          'operation. You don\'t have the required '
    60                          'permissions.', perm=self.action)
     58                msg = _('%(perm)s privileges are required to perform this '
     59                        'operation. You don\'t have the required '
     60                        'permissions.', perm=self.action)
    6161        elif self.msg:
    62             return self.msg
     62            msg = self.msg
    6363        else:
    64             return _('Insufficient privileges to perform this operation.')
     64            msg = _('Insufficient privileges to perform this operation.')
     65        return unicode(msg)
    6566
    6667
    6768class IPermissionRequestor(Interface):

After the patch;

>>> e2 = PermissionError(msg=tag_("This is a %(fragment)s", fragment=tag.em("Fragment")))
>>> to_unicode(e2)
u'This is a <em>Fragment</em>'
>>> to_unicode(PermissionError(action='WIKI_VIEW'))
u"WIKI_VIEW privileges are required to perform this operation. You don't have the required permissions."

Also I don't think we should change base class of PermissionError on 1.0-stable, that is okay on trunk.

in reply to:  5 ; comment:6 by Jun Omae, 5 years ago

Also I don't think we should change base class of PermissionError on 1.0-stable, that is okay on trunk.

I reconsider it. I think changing the base class to TracError is not okay on trunk, now.

Currently, the except TracError statement is not intent to catch a PermissionError exception, e.g. tags/trac-1.0.1/trac/attachment.py@:758,767-768#L750. It is not good idea to verify such all except statements in Trac core and all plugins.

comment:7 by Ryan J Ollos, 5 years ago

Proposed changes can be found in log:rjollos.git:t11509.3.

in reply to:  6 ; comment:8 by Jun Omae, 5 years ago

Replying to jomae:

Also I don't think we should change base class of PermissionError on 1.0-stable, that is okay on trunk.

I reconsider it. I think changing the base class to TracError is not okay on trunk, now.

How about adding TracBaseError as base class of all exceptions on trunk to keep backward-compatibilities and consistencies?

 * Exception
   * TracBaseError
     * TracError
       * AdminCommandError
       * ConfigurationError
       * (all subclasses of TracError...)
     * PermissionError
     * BackupError
     * HTTPException
     * RequestDone
     * ParseError
     * GitError
       * GitErrorSha

in reply to:  8 comment:9 by Ryan J Ollos, 5 years ago

Replying to jomae:

How about adding TracBaseError as base class of all exceptions on trunk to keep backward-compatibilities and consistencies?

That might make sense. I will give it some additional thought.

More changes:

In the initial changes I had some markup in the exception message - emphasis on the user, group and permission. While I think this might be a good idea, we should follow a consistent pattern, so I don't like the idea of making the change to a single exception message as part of this ticket. Therefore I'm planning to address those changes later on, and probably use spans with classes rather than em elements.

With the changes posted in comment:7, a Fragment in a PermissionError message is not rendered to HTML. The changes in [0f0da2e5/rjollos.git] are intended to address that.

I've added additional change that I'm still considering, which is to encapsulate code from _send_user_error into the HTTPException: [44a4f215/rjollos.git] and [c58a627a/rjollos.git]. I think this would make the code more maintainable, but I need to test more and think through the consequences.

comment:10 by Jun Omae, 5 years ago

I got the following failure with only Python 2.5. But all tests passed with Python 2.6 and 2.7.

======================================================================
FAIL: TracError should be raised when navigating to the attachment
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/run/shm/c58a627a37684f941c99549269644437815657ee/src-py25-sqlite/trac/tests/functional/testcases.py", line 31, in runTest
    tc.find('<h1>Trac Error</h1>\s+<p class="message">'
  File "/run/shm/c58a627a37684f941c99549269644437815657ee/src-py25-sqlite/trac/tests/functional/better_twill.py", line 225, in better_find
    raise twill.errors.TwillAssertionError(*args)
TwillAssertionError: ('no match to \'<h1>Trac Error</h1>\\s+<p class="message">Parent resource NonexistentPage doesn\'t exist</p>\'', '/run/shm/c58a627a37684f941c99549269644437815657ee/src-py25-sqlite/testenv/trac/log/TestAttachmentNonexistentParent.html')

----------------------------------------------------------------------
Ran 174 tests in 206.724s

FAILED (failures=1)

comment:11 by Ryan J Ollos, 5 years ago

I added the TracBaseError class and fixed the failure in comment:10 (fixed in [51e244a6/rjollos.git]). It didn't seem necessary to have trac.db.tests.api​.Error inherit from TracBaseError since I wouldn't expect the class to be used outside of the trac.db.tests.api module. I'll add the TracBaseError class to Error if anyone thinks its necessary.

There's a refactoring to use add_notice. add_notice was added in [6379#file2]. I'm assuming it was just an oversight that it wasn't used in [7494].

I attempted to clean up the changes from [44a4f215/rjollos.git] and [c58a627a/rjollos.git] by moving the code to class properties.

There are some additional issues mentioned in the changeset messages. Some tests need to be written. I'm just posting this now to get feedback on the changes and the questions I've raised.

comment:12 by Ryan J Ollos, 5 years ago

I made a mess in [12636:12637,12648]. Sorry about that.

Last edited 5 years ago by Ryan J Ollos (previous) (diff)

comment:13 by Ryan J Ollos, 5 years ago

API Changes: modified (diff)
Release Notes: modified (diff)
Resolution: fixed
Status: assignedclosed

Committed/merged changes in [12638:12639], [12640:12641], [12642:12643], [12644:12645], [12646:12647].

#11568 is a follow-on ticket for the proposed changes to the exception hierarchy.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Ryan J Ollos.
The resolution will be deleted.
to The owner will be changed from Ryan J Ollos to the specified user.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.