• Remember Mailing List

  • Error trying to access member properties

    from duffyd on Jun 26, 2009 08:46 PM
    Hi,
    
    1) I'm overriding the 'fullname' field on my remember-based member type
    as follows:
    
        atapi.ComputedField('fullname',
            required        = False,
            searchable      = False,
            expression      = "context.getName()",
            widget          = atapi.ComputedWidget(
                label=_(u"Fullname")),
        ),
    
    This is because the member type has separate firstname and lastname
    fields and the getName method just concatenates these. This works all
    fine and dandy, but I've just recently come across an issue where the
    password reset tool errors as it expects fullname to be an attribute on
    the member object. For e.g. the mail_password_template.pt does the
    following:
    
    tal:define="fullname python: test(member.fullname, ' ' +
    member.fullname, '')"
    
    I get an error that says something like can't concatenate instance
    method and string. When I jump into the debugger it is in fact a method
    but if I do something like: mymemberobject.email I get back
    u'bob@...'. What have I done wrong with my 'fullname' field?
    
    Hunting through the remember code I notice that there is a
    user_property=True property set on the fullname field, which I did then
    set on my customised fullname field but still no dice. I even tried to
    make the fullname field an ATFieldProperty (as per standard Plone 3
    archetype development practice; and of course set the storage to
    AnnotationStorage) but again it didn't work, even though my custom
    fields work fine if I go: mymemberobject.my_custom_field. This will
    return something like: 'myvalue'.
    
    Any tips?
    
    2) One other issue I'm experiencing is when using betahaus.emaillogin it
    allows you to specify your email address when doing a password reset.
    The python script that is run after specifying your email address then
    runs through all the users and checks their email 'property' as follows:
    
    email = REQUEST.get('email', None)
    if email:
        for user in context.acl_users.getUsers():
            if email == user.getProperty('email'):
                REQUEST.set('userid', user.getId())
                break
    
    When doing the user.getProperty('email') call it prompts the user to
    logon. Even setting the 'Manager' role as a proxy on the script doesn't
    resolve this, it still prompts the user to logon. Once again looking
    through the code everything seems fine and I can't see why the site
    would prompt them to logon. Once again any tips greatly appreciated.
    
    Thanks in advance,
    Tim
    
    
    Thread Outline:
  • Re: Error trying to access member properties

    from ra on Jun 29, 2009 03:57 PM
    Tim Knapp wrote:
    > Hi,
    > 
    > 1) I'm overriding the 'fullname' field on my remember-based member type
    > as follows:
    > 
    >     atapi.ComputedField('fullname',
    >         required        = False,
    >         searchable      = False,
    >         expression      = "context.getName()",
    >         widget          = atapi.ComputedWidget(
    >             label=_(u"Fullname")),
    >     ),
    > 
    > This is because the member type has separate firstname and lastname
    > fields and the getName method just concatenates these. This works all
    > fine and dandy, but I've just recently come across an issue where the
    > password reset tool errors as it expects fullname to be an attribute on
    > the member object. For e.g. the mail_password_template.pt does the
    > following:
    > 
    > tal:define="fullname python: test(member.fullname, ' ' +
    > member.fullname, '')"
    > 
    > I get an error that says something like can't concatenate instance
    > method and string. When I jump into the debugger it is in fact a method
    > but if I do something like: mymemberobject.email I get back
    > u'bob@...'. What have I done wrong with my 'fullname' field?
    
    you haven't done anything wrong.  i consider it a bug in the PasswordResetTool 
    that it assumes that the fullname will be stored as an attribute on the member 
    object.  i think that if that code were changed to 
    "member.getProperty('fullname')" you'd have better luck.
    
    > 2) One other issue I'm experiencing is when using betahaus.emaillogin it
    > allows you to specify your email address when doing a password reset.
    > The python script that is run after specifying your email address then
    > runs through all the users and checks their email 'property' as follows:
    > 
    > email = REQUEST.get('email', None)
    > if email:
    >     for user in context.acl_users.getUsers():
    >         if email == user.getProperty('email'):
    >             REQUEST.set('userid', user.getId())
    >             break
    > 
    > When doing the user.getProperty('email') call it prompts the user to
    > logon. Even setting the 'Manager' role as a proxy on the script doesn't
    > resolve this, it still prompts the user to logon. Once again looking
    > through the code everything seems fine and I can't see why the site
    > would prompt them to logon. Once again any tips greatly appreciated.
    
    remember has some interesting security challenges w.r.t. the 'getProperty' 
    call.  AT lets you specify separate read and write permissions for each field. 
      these are usually enforced automatically by the AT infrastructure; calling 
    an accessor or a mutator from untrusted code will cause the security check to 
    happen.
    
    the canonical way of retrieving data points from a user or member object is 
    using getProperty.  remember implements a getProperty method which simply 
    delegates to the AT accessors.  however, this getProperty method is trusted 
    code, which means that the AT security will never be checked.  put another 
    way, the simplest implementation of member.getProperty will allow that method 
    to be used to bypass any field level security you may have specified in your 
    member schema.  member.getEmail() may fail for an untrusted user, but 
    member.getProperty('email') will work.  no bueno.
    
    remember tries to prevent this with a fairly brutal hack.  the getProperty 
    method tries to determine whether or not the calling code was trusted, by 
    examining the call stack (see BaseMember._callerIsTrustable).  if the calling 
    code is not trusted, then getProperty will explicitly enforce the AT field 
    security, closing the information leak.  this is almost certainly what's 
    biting you.
    
    there's another issue here, as well.. that code snippet you include is 
    actually iterating through the entire user set of the entire site.  that's 
    ridiculously inefficient if you get more than a handful of users.
    
    so what i'd do in your shoes is to override the offending python to delegate 
    to some trusted code that i'd put in my product.  this trusted code would do a 
    membrane_tool.unrestrictedSearchResults(getEmail=email) to look for a member 
    with a matching email address.
    
    -r