Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
217 views
in Technique[技术] by (71.8m points)

python - Pyramid authorization for stored items

I'm trying to create an authorization policy that takes "item" ownership into account. For example some user X "owns" items A, B, C. Those are accessed via URLs like /item/{item}/some_options.

How can I get the information about {item} to the authorization policy object (permits() call)? Is putting additional information into context a good idea (I'm doing routes-based routing only). How would I do that?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can do this using the ACLAuthorizationPolicy combined with URL Dispatch by using a custom resource tree designed for this purpose.

For example, you have permissions for Foo objects, and permissions for Bar objects. These ACLs can be found by traversing the resource tree using the urls:

/foos/{obj}
/bars/{obj}

Your resource tree then becomes a hierarchy of permissions, where at any point in the tree you can place an __acl__ on the resource object:

root                       (Root)
|- foos                    (FooContainer)
|  `- {obj}                (Foo)
`- bars                    (BarContainer)
   `- {obj}                (Bar)

You can represent this hierarchy in a resource tree:

class Root(dict):
    # this is the root factory, you can set an __acl__ here for all resources
    __acl__ = [
        (Allow, 'admin', ALL_PERMISSIONS),
    ]
    def __init__(self, request):
        self.request = request
        self['foos'] = FooContainer(self, 'foos')
        self['bars'] = BarContainer(self, 'bars')

class FooContainer(object):
    # set ACL here for *all* objects of type Foo
    __acl__ = [
    ]

    def __init__(self, parent, name):
        self.__parent__ = parent
        self.__name__ = name

    def __getitem__(self, key):
        # get a database connection
        s = DBSession()
        obj = s.query(Foo).filter_by(id=key).scalar()
        if obj is None:
            raise KeyError
        obj.__parent__ = self
        obj.__name__ = key
        return obj

class Foo(object):
    # this __acl__ is computed dynamically based on the specific object
    @property
    def __acl__(self):
        acls = [(Allow, 'u:%d' % o.id, 'view') for o in self.owners]
        return acls

    owners = relation('FooOwner')

class Bar(object):
    # allow any authenticated user to view Bar objects
    __acl__ = [
        (Allow, Authenticated, 'view')
    ]

With a setup like this, you can then map route patterns to your resource tree:

config = Configurator()
config.add_route('item_options', '/item/{item}/some_options',
                 # tell pyramid where in the resource tree to go for this url
                 traverse='/foos/{item}')

You will also need to map your route to a specific view:

config.add_view(route_name='item_options', view='.views.options_view',
                permission='view', renderer='item_options.mako')

Great, now we can define our view and use the loaded context object, knowing that if the view is executed, the user has the appropriate permissions!

def options_view(request):
    foo = request.context
    return {
        'foo': foo,
    }

Using this setup, you are using the default ACLAuthorizationPolicy, and you are providing row-level permissions for your objects with URL Dispatch. Note also, that because the objects set the __parent__ property on the children, the policy will bubble up the lineage, inheriting permissions from the parents. This can be avoided by simply putting a DENY_ALL ACE in your ACL, or by writing a custom policy that does not use the context's lineage.

* Update * I've turned this post into an actual demo on Github. Hopefully it helps someone. https://github.com/mmerickel/pyramid_auth_demo

* Update * I've written a full tutorial around pyramid's authentication and authorization system here: http://michael.merickel.org/projects/pyramid_auth_demo/


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...