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
...
read more »