|
from wsgiref.simple_server import make_server |
|
|
|
from pyramid.config import Configurator |
|
from pyramid.decorator import reify |
|
from pyramid.authorization import ACLAuthorizationPolicy |
|
from pyramid.authentication import CallbackAuthenticationPolicy |
|
from pyramid.view import view_config, view_defaults |
|
from pyramid.security import ( |
|
ALL_PERMISSIONS, |
|
Allow, |
|
unauthenticated_userid, |
|
Everyone, |
|
) |
|
from pyramid.traversal import find_interface |
|
|
|
|
|
def main(global_config, **settings): |
|
config = Configurator(settings=settings) |
|
config.include(__name__) |
|
return config.make_wsgi_app() |
|
|
|
|
|
def includeme(config): |
|
config.set_root_factory(Root) |
|
config.set_authentication_policy(AuthenticationPolicy()) |
|
config.set_authorization_policy(ACLAuthorizationPolicy()) |
|
config.scan() |
|
|
|
|
|
class AuthenticationPolicy(CallbackAuthenticationPolicy): |
|
|
|
def __init__(self): |
|
super(CallbackAuthenticationPolicy, self).__init__() |
|
|
|
def unauthenticated_userid(self, request): |
|
userid = None |
|
if 'X-DUMMY-AUTH-USERID' in request.headers: |
|
userid = request.headers.get('X-DUMMY-AUTH-USERID') |
|
return userid |
|
|
|
def callback(self, userid, request): |
|
principals = [] |
|
context = request.context |
|
|
|
if hasattr(context, 'group_finder'): |
|
principals.extend(context.group_finder(request)) |
|
|
|
return principals |
|
|
|
|
|
# / |
|
class Root(object): |
|
|
|
def __init__(self, request): |
|
self.request = request |
|
self.__name__ = '' |
|
self.__parent__ = None |
|
|
|
def __getitem__(self, key): |
|
return UsersCollection(key, self) |
|
|
|
|
|
# /users |
|
class UsersCollection(object): |
|
|
|
def __init__(self, name, parent): |
|
self.__name__ = name |
|
self.__parent__ = parent |
|
|
|
def __getitem__(self, key): |
|
return User(key, self) |
|
|
|
|
|
# /users/bob_marley/ |
|
class User(object): |
|
|
|
def __init__(self, name, parent): |
|
self.__name__ = name |
|
self.__parent__ = parent |
|
|
|
def __getitem__(self, key): |
|
return NotesCollection(key, self) |
|
|
|
|
|
# /users/bob_marley/notes/ |
|
class NotesCollection(object): |
|
|
|
__acl__ = [ |
|
(Allow, Everyone, 'show'), |
|
(Allow, 'group:owner', ALL_PERMISSIONS), |
|
] |
|
|
|
def __init__(self, name, parent): |
|
self.__name__ = name |
|
self.__parent__ = parent |
|
|
|
def __getitem__(self, key): |
|
return Note(key, self) |
|
|
|
|
|
# /users/bob_marley/notes/456 |
|
class Note(object): |
|
|
|
def __init__(self, name, parent): |
|
self.__name__ = name |
|
self.__parent__ = parent |
|
|
|
@reify |
|
def user(self): |
|
return find_interface(self, User) |
|
|
|
@property |
|
def userid(self): |
|
# /users/123/notes/456 will return 123 |
|
return self.user.__name__ |
|
|
|
def group_finder(self, request): |
|
principals = [] |
|
if unauthenticated_userid(request) == self.user.__name__: |
|
principals.append('group:owner') |
|
return principals |
|
|
|
def replace(self, params): |
|
"save in db... Only owners can" |
|
return {'status': '200'} |
|
|
|
def show(self): |
|
"get from db" |
|
return { |
|
'id': self.__name__, |
|
'content': 'A dummy note', |
|
} |
|
|
|
|
|
@view_defaults(context=Note) |
|
class View(object): |
|
|
|
def __init__(self, context, request): |
|
self.request = request |
|
self.context = context |
|
|
|
@view_config(request_method='GET', permission='show', renderer='json') |
|
def show(self): |
|
return self.context.show() |
|
|
|
@view_config(request_method='PUT', permission='replace', renderer='json') |
|
def replace(self): |
|
return self.context.replace(self.request.POST) |
|
|
|
|
|
if __name__ == '__main__': |
|
server = make_server('0.0.0.0', 8080, main({})) |
|
server.serve_forever() |
@wolever you could define a role 'group:friends' and the resource group_finder method would append 'group:friends' to principals if the authenticated user is a friend of the resource's owner.
Does it make sense?