Created
April 28, 2015 23:06
-
-
Save mcdonc/7dc2e06045f3df71d12d to your computer and use it in GitHub Desktop.
example of permissions and interface-based view configuration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from wsgiref.simple_server import make_server | |
from zope.interface import ( | |
Interface, | |
alsoProvides, | |
) | |
from pyramid.config import Configurator | |
from pyramid.httpexceptions import HTTPFound | |
from pyramid.response import Response | |
from pyramid.security import Allow, remember, forget | |
from pyramid.authorization import ACLAuthorizationPolicy | |
from pyramid.authentication import AuthTktAuthenticationPolicy | |
from pyramid.view import ( | |
view_config, | |
forbidden_view_config, | |
) | |
class ICase(Interface): pass | |
class IFooCase(ICase): pass | |
class IBarCase(ICase): pass | |
cases = { | |
'1':{'name':'Fred', 'type':'foo'}, | |
'2':{'name':'Jane', 'type':'bar'}, | |
} | |
type_to_interface = { | |
'foo':IFooCase, | |
'bar':IBarCase, | |
} | |
users = { | |
'allcases':{ | |
'name':'All Cases', | |
'groups':('g:foocase_viewer', 'g:barcase_viewer'), | |
}, | |
'foocases':{ | |
'name':'Foo Cases', | |
'groups':('g:foocase_viewer', ), | |
} | |
} | |
def groupfinder(userid, request): | |
user = users.get(userid) | |
if user is not None: | |
return user['groups'] | |
class CaseContext(object): | |
def __init__(self, request): | |
case_id = request.matchdict['id'] | |
self.case = cases[case_id] | |
self.case_type = self.case['type'] | |
iface = type_to_interface[self.case_type] | |
alsoProvides(self, iface) # either IFooCase or IBarCase | |
def __acl__(self): | |
return [ | |
(Allow, 'g:%scase_viewer' % self.case_type, 'view') | |
] | |
@view_config( | |
route_name='root', | |
) | |
def root(request): | |
body = ''' | |
<html> | |
<head> | |
</head> | |
<body> | |
<p> Logged in as: %s </p> | |
<p> Intent: | |
<ul> | |
<li>A user who is not logged in will be shown the forbidden page for both /cases/1 and /cases/2 </li> | |
<li>Someone logged in as 'foocases' will be be shown the show_foo_case view when they visit /cases/1 (a Foo case), but will be shown the forbidden_case view when they visit /cases/2 (a Bar case) </li> | |
<li>Someone logged in as 'allcases' will be be shown the show_foo_case view when they visit /cases/1 (a Foo case), they will be shown the show_bar_case view when they visit the /cases/2 (a Bar case) </li> | |
</ul> | |
</p> | |
<ul> | |
<li> <a href="/login?userid=foocases">Log In As foocases</a> </li> | |
<li> <a href="/login?userid=allcases">Log In As allcases</a> </li> | |
<li> <a href="/logout">Log Out</a> </li> | |
</ul> | |
<ul> | |
<li> <a href="/cases/1">/cases/1 (a Foo case)</a> </li> | |
<li> <a href="/cases/2">/cases/2 (a Bar case)</a> </li> | |
</ul> | |
</body> | |
</html>''' % request.authenticated_userid | |
return Response( | |
content_type='text/html', | |
body = body, | |
) | |
@view_config( | |
route_name='show_case', | |
context=IFooCase, | |
permission='view', | |
renderer='string' | |
) | |
def show_foo_case(context, request): | |
return 'show_foo_case: This foo case is named %(name)s' % context.case | |
@view_config( | |
route_name='show_case', | |
context=IBarCase, | |
permission='view', | |
renderer='string' | |
) | |
def show_bar_case(context, request): | |
return 'show_bar_case: This bar case is named %(name)s' % context.case | |
@forbidden_view_config( | |
renderer='string', | |
route_name='show_case', | |
) | |
def forbidden_case(request): | |
# cant use ``context=`` in the view configuration here, as the context | |
# will be an HTTPForbidden exception object when we get here. However, | |
# request.context will be the original CaseContext instance, so we | |
# can perform some sort of dispatch on that as necessary. | |
return ('forbidden_case: You are forbidden to see the case of ' | |
'type %(type)s named %(name)s' % request.context.case) | |
@view_config( | |
route_name='login', | |
) | |
def login_view(request): | |
userid = request.GET.get('userid') | |
user = users.get(userid) | |
if user is not None: | |
headers = remember(request, userid) | |
return HTTPFound( | |
location=request.route_url('root'), | |
headers=headers | |
) | |
return HTTPFound(location=request.route_url('login')) | |
@view_config( | |
route_name='logout', | |
) | |
def logout_view(request): | |
headers = forget(request) | |
return HTTPFound(location=request.route_url('root'), headers=headers) | |
if __name__ == '__main__': | |
authz_policy = ACLAuthorizationPolicy() | |
authn_policy = AuthTktAuthenticationPolicy( | |
'sosecret', | |
callback=groupfinder | |
) | |
config = Configurator( | |
authentication_policy=authn_policy, | |
authorization_policy=authz_policy, | |
) | |
config.add_route('root', '/') | |
config.add_route('login', '/login') | |
config.add_route('logout', '/logout') | |
config.add_route('show_case', '/cases/{id}', factory=CaseContext) | |
config.scan() | |
app = config.make_wsgi_app() | |
server = make_server('0.0.0.0', 8080, app) | |
server.serve_forever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment