Step 01: Hello World for ACLs

Pyramid resources are protected with security statements called access control lists (or ACLs.) This is a familiar security concept, in which you state:

[(Action, Principal, Permission),]

...where action is either Allow or Deny.

Goals

  • Associate a security statement with a resource

Objectives

  • Put an ACL on the class for the SiteFolder
  • Place a permission in the @view_config for a view

Steps

  1. $ cd ../../security; mkdir step01; cd step01

  2. (Unchanged) Copy the following into step01/application.py:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    from wsgiref.simple_server import make_server
    
    from pyramid.config import Configurator
    from pyramid.authentication import AuthTktAuthenticationPolicy
    
    from resources import bootstrap
    
    
    def main():
        config = Configurator(
            root_factory=bootstrap,
            authentication_policy=AuthTktAuthenticationPolicy('seekr1t'),
        )
    
        config.scan("views")
        app = config.make_wsgi_app()
        return app
    
    
    if __name__ == '__main__':
        app = main()
        server = make_server(host='0.0.0.0', port=8080, app=app)
        server.serve_forever()
    
  3. Copy the following into step01/views.py:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    from pyramid.view import view_config
    
    class ProjectorViews(object):
        def __init__(self, context, request):
            self.context = context
            self.request = request
    
        @view_config(renderer="templates/default_view.pt",
                     permission='view')
        def default_view(self):
            return dict(page_title="View Site")
    
        @view_config(renderer="templates/default_view.pt",
                     permission='edit',
                     name="edit")
        def edit_view(self):
            return dict(page_title="Edit Site")
    
  4. Copy the following into step01/resources.py:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    from pyramid.security import Allow
    from pyramid.security import Everyone
    
    class Folder(dict):
        def __init__(self, name, parent, title):
            self.__name__ = name
            self.__parent__ = parent
            self.title = title
    
    
    class SiteFolder(Folder):
        __acl__ = [(Allow, Everyone, 'view')]
    
    class Document(object):
        def __init__(self, name, parent, title):
            self.__name__ = name
            self.__parent__ = parent
            self.title = title
    
    root = SiteFolder('', None, 'Projector Site')
    
    def bootstrap(request):
        # Let's make:
        # /
        #   doc1
        #   doc2
        #   folder1/
        #      doc1
        doc1 = Document('doc1', root, 'Document 01')
        root['doc1'] = doc1
        doc2 = Document('doc2', root, 'Document 02')
        root['doc2'] = doc2
        folder1 = Folder('folder1', root, 'Folder 01')
        root['folder1'] = folder1
    
        return root
    
  5. Copy the following into step01/templates/default_view.pt:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
            "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:tal="http://xml.zope.org/namespaces/tal">
    <head>
        <title>${page_title}</title>
    </head>
    <body>
    <h1>${page_title}</h1>
    
    <p>This is the home page, only visible to <code>group:editors</code></p>
    
    <p><a href="/">Site Root</a> | <a href="/edit">Edit</a></p>
    </body>
    </html>
    
  6. $ python application.py

  7. Open http://127.0.0.1:8080/ in your browser. Visit the Edit link.

Extra Credit

  1. What if you put no ACL on SiteFolder? What would be the effect?
  2. Do you have to use the imported constants for Allow and Deny or can you just use a string?
  3. Do we have to use ACLs? Is there some other way to protect resources?
  4. We have a subfolder at /folder1/. Do security statements apply to it? (Give it a try in your browser.)
  5. But wait...we put the ACL on SiteFolder not Folder. What’s going on?

Analysis

The application.py grew an authentication_policy keyword argument in the configuration. That is the place where you decide what kind of authentication system to use.

Of course we aren’t using this too much until we actually do logins in the next step.

We are using the default authorization policy, which is the ACL authorization policy.

Once you turn on security, you get an implicit ``Deny``.

Discussion

  • How are ACL statements stacked with allow and deny?
  • Does Pyramid support hierarchical security, like Zope?

Table Of Contents