Hello Daniel, thank you for replay.
Неділя, 4 листопада 2012 р. 20:14:55 UTC+2 користувач Daniel Nouri написав:
>On 11/04/2012 03:14 PM, Ivan Gudym wrote:
>> Hi
>> Can someone explain me Kotty security scheme?
>Kotti's security theme closely resembles that found in the Plone CMS
>(and DCWorkflow).
>When you're using workflows (which you are by default), Kotti uses the
>mapping from roles to permissions defined in workflow.zcml. Without
>workflows, it will use the `kotti.security.SITE_ACL` list, which it
>puts on `root.__acl__`.
>Both workflow and static permissions can be configured to your liking
>from within your add-on, without the need to patch Kotti's source.
>When using workflow, you can use the 'kotti.use_workflow' setting in
>your INI file to point to a different workflow.zcml file, e.g.:
> kotti.use_workflow = myapp:workflow.zcml
I had not time yet to learn workflows in detail but in looks good and
promising. But now I want to understand simple basic authorization.
>> I spent some time trying to understand Kotti security and I found it:
>> - simplified, confusing, unusual compared to common CMS, broken. Most
>> confusing part is 'role:owner' - who is he?
>The Owner role ('role:owner'), like any other role, can be given to
>anyone, be it global or local. It's special in that the event
>listener in 'kotti.events.set_owner' will set the Owner role
>automatically for newly created items. So if you create a new
>Document, you're automatically it's Owner. (So your
>ACLAuthorizationPolicy tweak should really be unnecessary as far as I
>can tell.)
Kotti authorization scheme in relation to ownership differ from others in
two features: global owners and possibility to have several o none owners.
I personally don't see any benefits of this feature but see some drawback,
but more on this later.
>> Usual security scheme found in modern common CMS is similar to:
>>
>> 1. Anonymous, not authenticated user, can view pages marked as public
>> 2. Role 'viewer' - authenticated user, can view pages, useful to protect
>> part of site from anonymous access
>> 3. Role 'author' - can add new documents, edit their own documents only
>> 4. Role 'owner' is special - it can't be assigned to user, user have
>> 'owner' role if he 'owns' the resource
>> 4. Role 'editor' - can add documents and edit all documents including
>> other's documents
>> 5. Role 'admin' - can change system setting and manage users
>So Kotti has this:
> - Everyone: view
> - Viewer: view
> - Editor: view, add, edit, state_change
> - Owner: view, add, edit, manage, state_change
>Most of these are self-explanatory. 'state_change' means you can
>change the workflow state (and thus change who can view etc., check
>the included workflow.zcml file). 'manage' means you can share an
>item, e.g. give another user the 'editor' role.
>I'd be interested to hear what you think is wrong here specifically,
>or what could be improved about the defaults. The lack of
>documentation here is certainly a bit embarrassing, and there is a
>chance that we can make the default permissions more useful.
>Note that in Kotti, roles are often given in a local context only,T
>through the "Share" tab. E.g. I get the Editor role in "/news" only,
>or I have the Viewer role only in my own department's folder.
>
Thank you for explanation. Local roles is good and I like it. I experimented
a little and found all works well from Kotti UI. Then I started my project
and forced to look under the hood. Several things was a bit confusing:
at first sight ownership described by item's 'owner' field. But in reality it
never used by authorization subsystem, it never changed and should be treated
as 'creator'. Effective ownership is defined by 'local_groups' table. I can
live with this if it were documented somewhere. But thats not all.
Let me briefly explain my case. I plan to create site with normal public
pages and private area for registered users. There will be profile info,
some services and various client's staff. I plan to use Content descendant
for profile page and Node descendants for client items.
User registration function emits UserRegistered event, my addon listen on
it, receive notification and has chance to create custom user Content page.
All looks good and I write the code:
class User(Content):
id = Column(Integer, ForeignKey('
contents.id'), primary_key=True)
type_info = Content.type_info.copy(
name=u'User',
title=_(u'User Profile'),
)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
self.in_navigation = False
self.parent = Profile.get()
self._acl = [
(Allow, 'role:owner', ALL_PERMISSIONS),
DENY_ALL,
]
def create_user_profile(event):
principal = event.object
user = User(name=
principal.name, owner=
principal.name, title=principal.title)
DBSession.add(user)
After test run I see owner can't access his page. I consult 'local_groups' table
and don't see corresponding row for owner. So event subsystem don't fulfill their
promises. After flying around events I land to kotti.events.set_owner:
def set_owner(event):
obj, request = event.object, event.request
if request is not None and isinstance(obj, Node) and obj.owner is None:
userid = authenticated_userid(request)
if userid is not None:
userid = unicode(userid)
# Set owner metadata:
obj.owner = userid
# Add owner role for userid if it's not inherited already:
if u'role:owner' not in list_groups(userid, obj):
groups = list_groups_raw(userid, obj) | set([u'role:owner'])
set_groups(userid, obj, groups)
Oops, third line contains two bugs: implementation - Node has no owner field, and
second more important - design bug. Owner field of newly created object is
ignored, or even worse if it set no local_groups processing performed at all!
Next line somewhat explains that weird behavior - it takes into account only
authenticated user. But in my case there is no authentication user, and even worse:
I can imagine scenario, when some function will create page for user under the
another user account. Maybe this is corner case, but how many such cases can arise
in future especially in addons development.
>Mappings of roles to permissions change depending on the workflow
>state. This might be a little confusing at first, but it's in fact
>much more powerful than what most CMS can do.
>> I implemented such scheme and sent pull request. I didn't write tests
>> nor change existing tests to reflect changes.
>> And I am not sure there is no some glitches somewhere in UI. First I
>> want to see reactions from community.
>>
>> Thanks.
>>
>> PS. To respect owner attribute I had to create new authorization policy.
>> Actually this is ACLAuthorizationPolicy
>> from pyramid with small tweaks. Look at diff in attach.
OK, let me describe in more details my proposition to tweak Kotti security.
1. Local groups stays as is.
2. Owner processing decouples from local groups and bases on 'owner' field
only.
3. To accomplish 2) introduced new authorization policy.
Authorization policy is actually standard one with 15 lines of additional code.
Algorithm is as follows:
1. Determine node owner. If owner has __owner__ field - use it, if not - traverse
over parents of node until found node (Content or descendant) with __owner__
field. So nodes without owner information considered owned by owner of it parent
node.
2. While processing acl if principal is 'role:owner' replace it by node owner
name and continue to run normal algorithm.
For example, node has acl (Allow, 'role:owner', ALL_PERMISSIONS) and
owner is 'jone', system checks user 'jone' rights for this node. So according to 2)
'role:owner' replaced by 'jone' and acl became (Allow, 'jone', ALL_PERMISSIONS)
then legacy algorithm continue to run as usual and grant access to 'jone' for
that node.
If user 'bob' tries to authorize he will be checked again over
(Allow, 'jone', ALL_PERMISSIONS) and access will not be granted.
Very simple isn't it?
The only drawback I see over current implementation is limitation to have only
one owner per resource.
But is it real drawback? First - simple things should be simple. Lets overview some
scenarios.
1. Consider you need all documents of particular owner. In my scheme you simply filter
documents by owner field and you are done. Compare current: you have to construct join
query documents with local_groups and filter by group_name='role:owner'.
2. Consider you want to add owner information to Navigate page. In my case you simply
add 'owner' field to template and you are done. Compare to current scheme: you have to
construct nontrivial join query using node_id and principal_name as join keys and
filter by group_name='role:owner', then you have to made decision how to place several
owners on page, write loop over owners etc. Programmer productivity and system
performance loss is obvious.
3. Consider you need to delete all documents owned by some user, on user delete or
similar scenario. In my case you filter by owner and delete. Compare with current:
you again construct join documents with local groups, filter by 'role:owner',
and wait, you have to check whether node owned by another owner, you shouldn't delete
such node. So you make join query per every document. You and up with complicated
query with sub-queries or will issue query per document. Again, programmer productivity
and system performance loss is obvious.