Hi all, I try to solve some problems with LDAPRoleTwiddler an inherited version from BasicUserFolder I currently use a validate()-function which I saw similar in BasicUserFolder and in LDAPRoleExtender (modifications from Shane) My problem is that if self.authorize(user, a, c, n, v, roles): return user.__of__(self) in validate() does not work, but return user.__of__(self) work better, but does not the same as the API (which I don't know) expect. Can anybody give a hint ? Regards, Dirk used python code: # This must stay accessible to everyone def validate( self, request, auth='', roles=_noroles ): """ The main engine """ v = request['PUBLISHED'] # the published object a, c, n, v = self._getobcontext(v, request) name, password = self.identify(auth) user = self.authenticate(name, password, request) if user is not None: if user is not None: # On my Test-System it works with authorize() # On my Integration-System it works only without authorize() #if self.authorize(user, a, c, n, v, roles): return user.__of__(self) # Could not twiddle a user. Defer to other user folders. return None def authenticate(self, name, password, request): super = self._emergency_user if name is None: return None if super and name == super.getUserName(): user = super else: user = self.getUser(name, password) if user is not None and user.authenticate(password, request): return user else: return None
why is that code no longer referring to the real userfolder anymore? it should not make calls to authorize/identify/authorize on "self" but on the LDAPUserFolder it is using as the user source. jens On Thursday, Oct 17, 2002, at 03:39 US/Eastern, Dirk Datzert wrote:
Hi all,
I try to solve some problems with LDAPRoleTwiddler an inherited version from BasicUserFolder
I currently use a validate()-function which I saw similar in BasicUserFolder and in LDAPRoleExtender (modifications from Shane)
My problem is that if self.authorize(user, a, c, n, v, roles): return user.__of__(self) in validate() does not work, but return user.__of__(self) work better, but does not the same as the API (which I don't know) expect.
Can anybody give a hint ?
Regards, Dirk
used python code:
# This must stay accessible to everyone def validate( self, request, auth='', roles=_noroles ): """ The main engine """
v = request['PUBLISHED'] # the published object a, c, n, v = self._getobcontext(v, request)
name, password = self.identify(auth) user = self.authenticate(name, password, request)
if user is not None: if user is not None: # On my Test-System it works with authorize() # On my Integration-System it works only without authorize() #if self.authorize(user, a, c, n, v, roles): return user.__of__(self)
# Could not twiddle a user. Defer to other user folders. return None
def authenticate(self, name, password, request): super = self._emergency_user
if name is None: return None
if super and name == super.getUserName(): user = super else: user = self.getUser(name, password)
if user is not None and user.authenticate(password, request): return user else: return None
<Dirk Datzert.vcf>
Hi Jens,
why is that code no longer referring to the real userfolder anymore? it should not make calls to authorize/identify/authorize on "self" but on the LDAPUserFolder it is using as the user source.
self.identify() should be the same as if getLUF().identify() since LDAPUserFolder and LDAPRoleTwiddler both inherited this from BasicUserFolder. self.authenticate() does a self.getUser() which refers to getLUF().getUser() and does twiddling in one step and return the right user-object which the API would expect. I think that self.authorize(user,...) is better than self.getLUF().authorize(user,...) because the authorize does the following in 1st line: def authorize(self, user,... ): (inherited from BasicUserFolder) user = getattr(user, 'aq_base', user).__of__(self) this would be different for self.authorize, where self would be the LRT and self.getLUF().authorize() where self would be the LUF. The user is seen in 2 different contexts by .__of__(self) . Maybe I'm think too complicated, Your opinion ? Regards, Dirk
being explicit is almost always better. you are relying on internal magic and it's not apparent from looking at the code you wrote. the validate implementation in the LDAPRoleExtender is the "most correct" one. shane worked on it for a while to make sure it does the most correct thing possible, and if anyone knows about the vagaries of acquisition/security and all its possible permutations it is him. jens On Thursday, Oct 17, 2002, at 08:37 US/Eastern, Dirk Datzert wrote:
Hi Jens,
why is that code no longer referring to the real userfolder anymore? it should not make calls to authorize/identify/authorize on "self" but on the LDAPUserFolder it is using as the user source.
self.identify() should be the same as if getLUF().identify() since LDAPUserFolder and LDAPRoleTwiddler both inherited this from BasicUserFolder.
self.authenticate() does a self.getUser() which refers to getLUF().getUser() and does twiddling in one step and return the right user-object which the API would expect.
I think that self.authorize(user,...) is better than self.getLUF().authorize(user,...) because the authorize does the following in 1st line:
def authorize(self, user,... ): (inherited from BasicUserFolder) user = getattr(user, 'aq_base', user).__of__(self)
this would be different for self.authorize, where self would be the LRT and self.getLUF().authorize() where self would be the LUF.
The user is seen in 2 different contexts by .__of__(self) .
Maybe I'm think too complicated, Your opinion ?
Regards, Dirk
Jens Vagelpohl wrote:
being explicit is almost always better. you are relying on internal magic and it's not apparent from looking at the code you wrote.
the validate implementation in the LDAPRoleExtender is the "most correct" one. shane worked on it for a while to make sure it does the most correct thing possible, and if anyone knows about the vagaries of acquisition/security and all its possible permutations it is him.
:-) Well, I tried to get it right, but I'm sure I could have missed something.
On Thursday, Oct 17, 2002, at 08:37 US/Eastern, Dirk Datzert wrote:
Hi Jens,
why is that code no longer referring to the real userfolder anymore? it should not make calls to authorize/identify/authorize on "self" but on the LDAPUserFolder it is using as the user source.
self.identify() should be the same as if getLUF().identify() since LDAPUserFolder and LDAPRoleTwiddler both inherited this from BasicUserFolder.
self.authenticate() does a self.getUser() which refers to getLUF().getUser() and does twiddling in one step and return the right user-object which the API would expect.
I think that self.authorize(user,...) is better than self.getLUF().authorize(user,...) because the authorize does the following in 1st line:
def authorize(self, user,... ): (inherited from BasicUserFolder) user = getattr(user, 'aq_base', user).__of__(self)
this would be different for self.authorize, where self would be the LRT and self.getLUF().authorize() where self would be the LUF.
The user is seen in 2 different contexts by .__of__(self) .
Maybe I'm think too complicated, Your opinion ?
The idea behind LDAPRoleExtender is to give the user global roles if the user accesses a context where extra roles would be given. In order to grant global roles, the context of the user is always the LDAPUserFolder, not the role extender. Role computation applied this way has a nasty side effect, unfortunately: if the user is allowed to write any kind of script, the user can access anything protected by the supposedly local roles. Don't ever grant the "Manager" role using LDAPRoleExtender unless you fully trust the user. I don't know anything about LDAPRoleTwiddler. But I would recommend you install the VerboseSecurity product, which will tell you a lot more about the Unauthorized error. And if you're interested, I know how we can make LDAPRoleExtender much safer, based on conversations with Jens. Shane
Hi Shane, thanks for answering.
Maybe I'm think too complicated, Your opinion ?
The idea behind LDAPRoleExtender is to give the user global roles if the
I don't know anything about LDAPRoleTwiddler. But I would recommend you install the VerboseSecurity product, which will tell you a lot more about the Unauthorized error.
The LDAPRoleTwiddler (LRT) should act as a LDAPUserFolder (LUF). He uses a LUF or a LRT in upper directory to retrieve the user data and changes the roles he got there depending on group-to-role mapping. example: user has following LDAP groups dir1_VISITOR, dir2_AUTHOR /acl_users (LUF) /dir1/acl_users (LRT) map dir1_VISITOR to role Visitor /dir2/acl_users (LRT) map dir2_AUTHOR to role Author the user has the roles Anonymous,Authenticated and Visitor in dir1. the user has the roles Anonymous,Authenticated and Author in dir2. the user has the roles Anonymous,Authenticated in alle other dirs.
And if you're interested, I know how we can make LDAPRoleExtender much safer, based on conversations with Jens.
Sure I'm interessted. Regards, Dirk
Dirk Datzert wrote:
And if you're interested, I know how we can make LDAPRoleExtender much safer, based on conversations with Jens.
Sure I'm interessted.
Ok. All User objects have a getRolesInContext() method. All this method does right now is scan the acquisition context for __ac_local_roles__ attributes. (See AccessControl/User.py) Since LDAPRoleExtender substitutes the User object with something of a class of its choosing, LDAPRoleExtender just needs to override getRolesInContext() in its User class. The new getRolesInContext() could look for LDAP-provided local roles in addition to the static local roles. This would give you "true" dynamic local roles. It sounds like LDAPRoleTwiddler is a substitute for LDAPUserFolder that rolls the functionality of LDAPUserFolder + LDAPRoleExtender into one object. If that's the case, you could use the same strategy to improve LDAPRoleTwiddler. Shane
Shane Hathaway schrieb:
Dirk Datzert wrote:
And if you're interested, I know how we can make LDAPRoleExtender much safer, based on conversations with Jens.
Sure I'm interessted.
Ok. All User objects have a getRolesInContext() method. All this method does right now is scan the acquisition context for __ac_local_roles__ attributes. (See AccessControl/User.py)
ok, LDAPUser from LDAPUserFolder inherits getRolesInContext from BasicUser, right ? LDAPRoleTwiddler caches LDAPUser entries with changed 'local' roles. What user object will be used if you talk about 'user objects' ? user objects out of LDAPUserFolder, or user object out of LDAPRoleTwiddler, or the user object in the context of the object needs the getRolesInContext() Method of LDAPUser go to the next LDAPRoleTwiddler look for the twiddled user object and take out the local roles ? rather complicated to describe something I not really understand, sorry about confusing questions :-) my strategy for getRolesInContext() would something like this: def getRolesInContext(self, obj): lrt = obj.acl_users # get nearest acl_users for obj (not really sure if this works ?) user = lrt.getUser ( self.getId(), self._getPassword() ) return user.getRoles()
Dirk Datzert wrote:
LDAPUser from LDAPUserFolder inherits getRolesInContext from BasicUser, right ?
LDAPRoleTwiddler caches LDAPUser entries with changed 'local' roles.
Where is the LDAPUser class located?
What user object will be used if you talk about 'user objects' ? user objects out of LDAPUserFolder, or user object out of LDAPRoleTwiddler,
or the user object in the context of the object needs the getRolesInContext() Method of LDAPUser go to the next LDAPRoleTwiddler look for the twiddled user object and take out the local roles ?
rather complicated to describe something I not really understand, sorry about confusing questions :-)
Since I have not looked at LDAPRoleTwiddler, I can do little to advise for now.
my strategy for getRolesInContext() would something like this:
def getRolesInContext(self, obj): lrt = obj.acl_users # get nearest acl_users for obj (not really sure if this works ?) user = lrt.getUser ( self.getId(), self._getPassword() ) return user.getRoles()
Hmm, no, the user object is simply "self". Shane
Dirk Datzert wrote:
LDAPUser from LDAPUserFolder inherits getRolesInContext from BasicUser, right ? LDAPRoleTwiddler caches LDAPUser entries with changed 'local' roles.
Where is the LDAPUser class located?
imported from the LDAPUserFolder module jens
Jens Vagelpohl wrote:
Dirk Datzert wrote:
LDAPUser from LDAPUserFolder inherits getRolesInContext from BasicUser, right ? LDAPRoleTwiddler caches LDAPUser entries with changed 'local' roles.
Where is the LDAPUser class located?
imported from the LDAPUserFolder module
Ok, that does make it a little more complicated. We'll have to talk about how we can make this all work sometime. Shane
Where is the LDAPUser class located?
imported from the LDAPUserFolder module
Ok, that does make it a little more complicated.
Why ? For me it is the same if I import LDAPUser from LDAPUserFolder and overwrite some functions, or import LDAPUser from LDAPRoleTwiddler (which currently is not possible) Dirk
def getRolesInContext(self, obj): lrt = obj.acl_users # get nearest acl_users for obj (not really sure if this works ?) user = lrt.getUser ( self.getId(), self._getPassword() ) return user.getRoles()
Hmm, no, the user object is simply "self".
yes wrong question ;-) having the follow folder structure: /acl_users (LUF) /dir1/acl_users (LRT1) /dir2/acl_users (LRT2) if I access /dir1/index_html comes the user object from LRT1 or LUF ? I would expect LRT1. if I access /dir2/index_html comes the user object from LRT2 ? what if I access in /dir2/index_html aq_parent.dir1.index_html. Will the AUTHENTICATED_USER change ? will the user object come from LRT2 ? Dirk
Dirk Datzert wrote:
def getRolesInContext(self, obj): lrt = obj.acl_users # get nearest acl_users for obj (not really sure if this works ?) user = lrt.getUser ( self.getId(), self._getPassword() ) return user.getRoles()
Hmm, no, the user object is simply "self".
yes wrong question ;-)
having the follow folder structure:
/acl_users (LUF) /dir1/acl_users (LRT1) /dir2/acl_users (LRT2)
if I access /dir1/index_html comes the user object from LRT1 or LUF ? I would expect LRT1.
You might expect that, but you probably shouldn't. :-) The user may have roles in places other than /dir1. Let's say there's a shared calendar object at /calendar, only certain people can access it, and for those people it gets displayed on every page throughout the site. If you put users in the context of the role twiddler, they won't be able to access /dir1 and /calendar in the same request. You would be tempted to "fix" the context checking by disabling it. You'd open a big hole. ;-) It's better for users to exist in the context of the LUF.
if I access /dir2/index_html comes the user object from LRT2 ? what if I access in /dir2/index_html aq_parent.dir1.index_html. Will the AUTHENTICATED_USER change ? will the user object come from LRT2 ?
No, it will not. Only one user ever applies to a request. And whether you get access to /dir1/index_html depends on the context of the user: if the user appears to be in the context of /acl_users, you'll get access (possibly excessive access), but if the user appears to be in the context of /dir1/index_html, you won't get access, regardless of permissions and roles. In the real world, you don't want either extreme. You want the user to be in the context of /acl_users, but you don't want to grant temporary global roles like LDAPRoleExtender currently does, since that can also open security holes. You want dynamic local roles. And the right way to do this in Zope 2 is to override getRolesInContext(). Shane
if I access /dir2/index_html comes the user object from LRT2 ? what if I access in /dir2/index_html aq_parent.dir1.index_html. Will the AUTHENTICATED_USER change ? will the user object come from LRT2 ?
No, it will not. Only one user ever applies to a request.
And that exactly what is my problem: AUTHENTICATED_USER.has_permission('View', /dir1/index_html) always returns 0, if AUTHENTICATED_USER comes from /acl_users and doesn't take care about the local roles coming out of /dir1/acl_users . What is about the strategy I was talking about getRolesInContext ? Dirk
i was always under the impression that getRolesInContext is not getting called in all places where it should be called. that was one of the reasons i went for a "replace all global user roles" approach. i might be wrong... (which would be nice because using shane's idea sounds like it could simplify the product) jens On Thursday, Oct 17, 2002, at 12:17 US/Eastern, Shane Hathaway wrote:
Dirk Datzert wrote:
And if you're interested, I know how we can make LDAPRoleExtender much safer, based on conversations with Jens.
Sure I'm interessted.
Ok. All User objects have a getRolesInContext() method. All this method does right now is scan the acquisition context for __ac_local_roles__ attributes. (See AccessControl/User.py)
Since LDAPRoleExtender substitutes the User object with something of a class of its choosing, LDAPRoleExtender just needs to override getRolesInContext() in its User class. The new getRolesInContext() could look for LDAP-provided local roles in addition to the static local roles.
This would give you "true" dynamic local roles. It sounds like LDAPRoleTwiddler is a substitute for LDAPUserFolder that rolls the functionality of LDAPUserFolder + LDAPRoleExtender into one object. If that's the case, you could use the same strategy to improve LDAPRoleTwiddler.
Shane
_______________________________________________ Zope-Dev maillist - Zope-Dev@zope.org http://lists.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - http://lists.zope.org/mailman/listinfo/zope-announce http://lists.zope.org/mailman/listinfo/zope )
Jens Vagelpohl wrote:
i was always under the impression that getRolesInContext is not getting called in all places where it should be called. that was one of the reasons i went for a "replace all global user roles" approach.
i might be wrong... (which would be nice because using shane's idea sounds like it could simplify the product)
I'm sure that was the case before Zope 2.2, when security got an overhaul. Now it should be quite reliable. Shane
Hi Jens, if I take the following code: # This must stay accessible to everyone def validate( self, request, auth='', roles=_noroles ): """ The main engine """ luf = self.getLUF() v = request['PUBLISHED'] # the published object a, c, n, v = luf._getobcontext(v, request) name, password = luf.identify(auth) user = luf.authenticate(name, password, request) if user is not None: twiddled_user = self.getUser ( user.getId(), user._getPassword() ) if twiddled_user is not None: # On my Test-System it works with authorize() # On my Integration-System it works only without authorize() if luf.authorize(twiddled_user, a, c, n, v, roles): return twiddled_user.__of__(luf) # Could not twiddle a user. Defer to other user folders. return None I get an error if I access a protected DTMLMethod: Site Error An error was encountered while publishing this resource. Unauthorized You are not authorized to access content. Traceback (innermost last): File /usr/share/zope/lib/python/ZPublisher/Publish.py, line 224, in publish_module File /usr/share/zope/lib/python/ZPublisher/Publish.py, line 187, in publish File /usr/share/zope/lib/python/ZPublisher/Publish.py, line 171, in publish File /usr/share/zope/lib/python/ZPublisher/mapply.py, line 160, in mapply (Object: index_html) File /usr/share/zope/lib/python/ZPublisher/Publish.py, line 112, in call_object (Object: index_html) File /usr/share/zope/lib/python/Products/EasyEditor/EasyEditable.py, line 372, in index_html (Object: ElementWithAttributes) File /usr/share/zope/lib/python/Products/EasyEditor/EasyTemplates/EasyViews.py, line 94, in __call__ (Object: default) File /usr/share/zope/lib/python/OFS/DTMLMethod.py, line 197, in __call__ (Object: default) File /usr/share/zope/lib/python/DocumentTemplate/DT_String.py, line 540, in __call__ (Object: default) File /usr/share/zope/lib/python/OFS/DTMLMethod.py, line 269, in validate (Object: default) File /usr/share/zope/lib/python/AccessControl/SecurityManager.py, line 144, in validate File /usr/share/zope/lib/python/AccessControl/ZopeSecurityPolicy.py, line 225, in validate Unauthorized: (see above) But if I'm a user with role manager everything is ok. I found out that if the LDAPUser goes into the auth-SimpleCache of the LRT, I got no Unauthorized exception, but than I have a problem with AUTHORIZED_USER.has_permission('View', obj) which returns 0 on each protected obj under the LRT path. Dirk
if shane's "validate" does not work then i assume there is a separate issue independent from it. jens On Thursday, Oct 17, 2002, at 08:56 US/Eastern, Dirk Datzert wrote:
Hi Jens,
if I take the following code:
# This must stay accessible to everyone def validate( self, request, auth='', roles=_noroles ): """ The main engine """
luf = self.getLUF() v = request['PUBLISHED'] # the published object a, c, n, v = luf._getobcontext(v, request)
name, password = luf.identify(auth) user = luf.authenticate(name, password, request)
if user is not None: twiddled_user = self.getUser ( user.getId(), user._getPassword() ) if twiddled_user is not None: # On my Test-System it works with authorize() # On my Integration-System it works only without authorize() if luf.authorize(twiddled_user, a, c, n, v, roles): return twiddled_user.__of__(luf)
# Could not twiddle a user. Defer to other user folders. return None
I get an error if I access a protected DTMLMethod:
Site Error An error was encountered while publishing this resource.
Unauthorized
You are not authorized to access content. Traceback (innermost last): File /usr/share/zope/lib/python/ZPublisher/Publish.py, line 224, in publish_module File /usr/share/zope/lib/python/ZPublisher/Publish.py, line 187, in publish File /usr/share/zope/lib/python/ZPublisher/Publish.py, line 171, in publish File /usr/share/zope/lib/python/ZPublisher/mapply.py, line 160, in mapply (Object: index_html) File /usr/share/zope/lib/python/ZPublisher/Publish.py, line 112, in call_object (Object: index_html) File /usr/share/zope/lib/python/Products/EasyEditor/EasyEditable.py, line 372, in index_html (Object: ElementWithAttributes) File /usr/share/zope/lib/python/Products/EasyEditor/EasyTemplates/ EasyViews.py, line 94, in __call__ (Object: default) File /usr/share/zope/lib/python/OFS/DTMLMethod.py, line 197, in __call__ (Object: default) File /usr/share/zope/lib/python/DocumentTemplate/DT_String.py, line 540, in __call__ (Object: default) File /usr/share/zope/lib/python/OFS/DTMLMethod.py, line 269, in validate (Object: default) File /usr/share/zope/lib/python/AccessControl/SecurityManager.py, line 144, in validate File /usr/share/zope/lib/python/AccessControl/ZopeSecurityPolicy.py, line 225, in validate Unauthorized: (see above)
But if I'm a user with role manager everything is ok.
I found out that if the LDAPUser goes into the auth-SimpleCache of the LRT, I got no Unauthorized exception, but than I have a problem with AUTHORIZED_USER.has_permission('View', obj) which returns 0 on each protected obj under the LRT path.
Dirk
participants (3)
-
Dirk Datzert -
Jens Vagelpohl -
Shane Hathaway