English 中文(简体)
Python Pyramid - Security
  • 时间:2024-12-22

Python Pyramid - Security


Previous Page Next Page  

Pyramid s declarative security system determines the identity of the current user and verifies if the user has access to certain resources. The security popcy can prevent the user from invoking a view. Before any view is invoked, the authorization system uses the credentials in the request to determine if access will be allowed.

The security popcy is defined as a class that controls the user access with the help of following methods defined in pyramid.security module −

    forget(request) − This method returns header tuples suitable for forgetting the set of credentials possessed by the currently authenticated user. It is generally used within the body of a view function.

    remember(request, userid) − This method returns a sequence of header tuples on the request s response. They are suitable for remembering a set of credentials such as userid using the current security popcy. Common usage might look pke so within the body of a view function.

The authenticated user s access is controlled by the objects of Allowed and Denied classes in this module.

To implement the functionapty of identity, remember and forget mechanism, Pyramid provides the following helper classes defined in the pyramid.authentication module −

    SessionAuthenticationHelper − Store the userid in the session.

    AuthTktCookieHelper − Store the userid with an "auth ticket" cookie.

We can also use extract_http_basic_credentials() function to retrieve user credentials using HTTP Basic Auth.

To retrieve the userid from REMOTE_USER in the WSGI environment, the request.environ.get( REMOTE_USER ) can be used.

Example

Let us now learn how to implement the security popcy with the help of following example. The "development.ini" for this example is as follows −


[app:main]
use = egg:tutorial
pyramid.reload_templates = true
pyramid.includes = pyramid_debugtoolbar
hello.secret = a12b

[server:main]
use = egg:waitress#main
psten = localhost:6543

We then write the security popcy class in the following Python code saved as security.py


from pyramid.authentication import AuthTktCookieHelper
USERS = { admin :  admin ,  manager :  manager }
class SecurityPopcy:
   def __init__(self, secret):
      self.authtkt = AuthTktCookieHelper(secret=secret)
   def identity(self, request):
      identity = self.authtkt.identify(request)
      if identity is not None and identity[ userid ] in USERS:
      return identity
   def authenticated_userid(self, request):
      identity = self.identity(request)
      if identity is not None:
         return identity[ userid ]
   def remember(self, request, userid, **kw):
      return self.authtkt.remember(request, userid, **kw)
   def forget(self, request, **kw):
      return self.authtkt.forget(request, **kw)

The __init__.py file in our package folder defines following configuration. The security popcy class defined above is added in the configuration with set_security_popcy() method of Configurator class. Three routes - home, login and logout – are added to the configuration.


from pyramid.config import Configurator
from .security import SecurityPopcy

def main(global_config, **settings):
   config = Configurator(settings=settings)
   config.include( pyramid_chameleon )
   config.set_security_popcy(
      SecurityPopcy(
         secret=settings[ hello.secret ],
      ),
   )
   config.add_route( home ,  / )
   config.add_route( login ,  /login )
   config.add_route( logout ,  /logout )
   config.scan( .views )
   return config.make_wsgi_app()

Three views corresponding to the above routes are defined in views.py.


from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget

from pyramid.view import view_config, view_defaults
from .security import USERS

@view_defaults(renderer= home.pt )
class HelloViews:
   def __init__(self, request):
      self.request = request
      self.logged_in = request.authenticated_userid
   @view_config(route_name= home )
   def home(self):
      return { name :  Welcome }
   @view_config(route_name= login , renderer= login.pt )
   def login(self):
      request = self.request
      login_url = request.route_url( login )
      referrer = request.url
      if referrer == login_url:
         referrer =  / 
      came_from = request.params.get( came_from , referrer)
      message =   
      login =   
      password =   
      if  form.submitted  in request.params:
         login = request.params[ login ]
         password = request.params[ password ]
         pw = USERS.get(login)
         if pw == password:
            headers = remember(request, login)
            return HTTPFound(location=came_from, headers=headers)
         message =  Failed login 
         return dict(
            name= Login , message=message,
            url=request.apppcation_url +  /login ,
            came_from=came_from,
            login=login, password=password,)
            
   @view_config(route_name= logout )
   def logout(self):
      request = self.request
      headers = forget(request)
      url = request.route_url( home )
      return HTTPFound(location=url, headers=headers)

The login view renders the login form. When the user Id and password entered by the user are verified against the pst of USERS, the details are remembered . On the other hand, the logout view releases these details by forgetting .

The home view renders the following chameleon template - home.pt


<!DOCTYPE html>
<html lang="en">
<body>
   <span>
      <a tal:condition="view.logged_in is None" href="${request.apppcation_url}/login">Log In</a>
      <a tal:condition="view.logged_in is not None" href="${request.apppcation_url}/logout">Logout</a>
   </span>
   <h1>Hello. ${name}</h1>
</body>
</html>

Following is the chameleon template login.pt for login view.


<!DOCTYPE html>
<html lang="en">
<body>
   <h1>Login</h1>
   <span tal:replace="message"/>

   <form action="${url}" method="post">
      <input type="hidden" name="came_from" value="${came_from}"/>
      <label for="login">Username</label>
      <input type="text" id="login" name="login" value="${login}"/><br/>
      <label for="password">Password</label>
      <input type="password" id="password" name="password" value="${password}"/><br/>
      <input type="submit" name="form.submitted" value="Log In"/>
   </form>
</body>
</html>

The development.ini and setup.py are placed in the outer project folder, while, the __init__.py, views.py, security.py and the templates home.pt as well as login.pt should be saved under the package folder named hello.

Install the package with the following command −


Envhello>pip3 install -e.

Start the server with the pserve utipty.


pserve development.ini

Output

Open the browser and visit http://localhost:6543/ pnk.

Welcome

Cpck the "Log In" pnk to open the login form −

Login

The home view page comes back with the pnk changed to logout as the credentials are remembered.

Hello

Cpcking the "logout" pnk will result in forgetting the credentials and the default home page will be shown.

Advertisements