Skip to content

Instantly share code, notes, and snippets.

@mcdonc
Created April 28, 2015 23:06
Show Gist options
  • Save mcdonc/7dc2e06045f3df71d12d to your computer and use it in GitHub Desktop.
Save mcdonc/7dc2e06045f3df71d12d to your computer and use it in GitHub Desktop.
example of permissions and interface-based view configuration
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