Sunday, June 3, 2012

Quick start pylons authentication.

Authentication is vital function in Today's some web applications.
Pylons framework that my powerful tool have useful authenticate function using authkit.
Today, I tried to make simple portal using authkit.
$ cd ~/
$ easy_install "AuthKit>=0.4.3,<=0.4.99"
$ mkdir webapplications
$ cd webapplications
$ paster create -t pylons auth1
$ emacs -nw ./auth1/auth1/config/middleware.py
  from pylons.wsgiapp import PylonsApp
  from routes.middleware import RoutesMiddleware

+ from auth1.config.environment import load_environment

  def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
      """Create a Pylons WSGI application and return it

  from pylons.wsgiapp import PylonsApp
  from routes.middleware import RoutesMiddleware

  def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
      """Create a Pylons WSGI application and return it
      app = CacheMiddleware(app, config)

      # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
+     import authkit.authenticate

      if asbool(full_stack):
          # Handle Python exceptions
          app = ErrorHandler(app, global_conf, **config['pylons.errorware'])

+         app = authkit.authenticate.middleware(app, app_conf)

 # Display error documents for 401, 403, 404 status codes (and
          # 500 when debug is disabled)
          if asbool(config['debug']):
$ emacs -nw ./auth1/development.ini
cache_dir = %(here)s/data
beaker.session.key = auth1
beaker.session.secret = somesecret

# setup authkit
authkit.setup.enable = true
authkit.setup.method = form, cookie
authkit.form.authenticate.user.type = authkit.users.sqlalchemy_driver:UsersFromDatabase
authkit.form.authenticate.user.data = auth1.model
authkit.cookie.secret = secret string
authkit.cookie.signoutpath = /signout

# If you'd like to fine-tune the individual locations of the cache data dirs
# for the Cache data, or the Session saves, un-comment the desired settings
# here:
#beaker.cache.data_dir = %(here)s/data/cache
#beaker.session.data_dir = %(here)s/data/sessions

# SQLAlchemy database URL
#sqlalchemy.url = sqlite:///%(here)s/development.db
sqlalchemy.url = mysql://[user]:[passuword]@localhost:3306/auth1
$ mysql -u root -p
mysql> create database auth1;
$ emacs -nw ./auth1/auth1/websetup.py
  """Setup the hello application"""
  import logging

+ from hello.config.environment import load_environment

  log = logging.getLogger(__name__)

  def setup_app(command, conf, vars):
      """Place any commands to setup hello here"""
      load_environment(conf.global_conf, conf.local_conf)
      """Setup the auth1 application"""
      import logging

+ from auth1.config.environment import load_environment
+ from auth1 import model
+ from auth1.model import meta

  log = logging.getLogger(__name__)

  def setup_app(command, conf, vars):
      """Place any commands to setup auth1 here"""
      load_environment(conf.global_conf, conf.local_conf)
+
+     # Create the tables if they don't already exist
+     meta.metadata.create_all(bind=meta.engine)
+
+     from authkit.users.sqlalchemy_driver import UsersFromDatabase
+     meta.metadata.bind = meta.engine
+
+     log.info("Adding the AuthKit model...")
+     users = UsersFromDatabase(model)
+     meta.metadata.create_all(checkfirst=True)
+
+     log.info("Adding roles and users...")
+     users.role_create("delete")
+     users.user_create("foo", password="bar")
+     users.user_create("admin", password="opensesame")
+     users.user_add_role("admin", role="delete")
+  
+     meta.Session.commit()
$ paster setup-app development.ini
$ mysql -u root -p
mysql> connect auth1;
mysql> show tables;
$ emacs -nw ./auth1/auth1/lib/auth.py
from authkit.permissions import ValidAuthKitUser
from authkit.permissions import HasAuthKitRole
from authkit.authorize.pylons_adaptors import authorized

is_valid_user = ValidAuthKitUser()
$ emacs -nw ./auth1/auth1/lib/helper.py
  # Import helpers as desired, or define your own, ie:
  #from webhelpers.html.tags import checkbox, password

+ from auth1.lib import auth
  from routes import url_for
$ paster controller account
  import logging

  from pylons import request, response, session, tmpl_context as c
  from pylons.controllers.util import abort, redirect_to

+ from auth1.lib.base import BaseController, render

  log = logging.getLogger(__name__)

  class AccountController(BaseController):

+     def signin(self):
+         if not request.environ.get('REMOTE_USER'):
+             abort(401)
+         else:
+             return render('/derived/account/signedin.mako')

+     def signout(self):
+         return render('/derived/account/signedout.mako')
$ paster controller portal
  import logging

  from pylons import request, response, session, tmpl_context as c
  from pylons.controllers.util import abort, redirect_to

+ from auth1.lib.base import BaseController, render

+ from authkit.permissions import ValidAuthKitUser
+ from authkit.authorize.pylons_adaptors import authorize

+ from auth1.lib import auth

  log = logging.getLogger(__name__)

  class PortalController(BaseController):
   
+     @authorize(ValidAuthKitUser())
      def index(self):
!         return render('portal.mako')
$ emacs -nw ./auth1/auth1/templates/portal.mako
<html>
  <head>
<title>Portal</title>
  </head>
  <body>
<h1>Portal</h1>
  </body>
</html>
$ mkdir ./auth1/auth1/templates/derived
$ mkdir ./auth1/auth1/templates/derived/account
$ emacs -nw ./auth1/auth1/templates/derived/account/signedin.mako
<%inherit file="/base/index.mako"/>

<%def name="title()">Signed In</%def>
<%def name="heading()"><h1>Signed In</h1></%def>

<p>You are signed in as ${request.environ['REMOTE_USER']}.
<a href="${h.url_for(controller='account', action='signout')}">Sign out</a></p>
$ emacs -nw ./auth1/auth1/templates/derived/account/signedout.mako
<%inherit file="/base/index.mako"/>

<%def name="title()">Signed Out</%def>
<%def name="heading()"><h1>Signed Out</h1></%def>

<p>You have been signed out.</p>
$ mkdir ./auth1/auth1/templates/base
$ emacs -nw ./auth1/auth1/templates/base/index.mako
<div id="hd">
  <div class="yui-gc">
<div class="yui-u first">
 ${self.heading()}
</div>
<div class="yui-u">
      %if h.auth.authorized(h.auth.is_valid_user) and not (request.urlvars['controller'] == 'account' and request.urlvars['action'] == 'signout'):
 <p>Signed in as ${request.environ['REMOTE_USER']},
<a href="${h.url_for('signout')}">Sign out</a></p>
 %else:
 <p>
<a href="${h.url_for('signin')}">Sign in</a></p>
 %endif
</div>
  </div>
</div>
$ emacs -nw ./auth1/auth1/config/routing.py
def make_map():
    """Create, configure and return the routes Mapper"""
    map = Mapper(directory=config['pylons.paths']['controllers'],
                 always_scan=config['debug'])
    map.minimization = False

    # The ErrorController route (handles 404/500 error pages); it should
    # likely stay at the top, ensuring it can always be resolved
    map.connect('/error/{action}', controller='error')
    map.connect('/error/{action}/{id}', controller='error')

    # CUSTOM ROUTES HERE

    map.connect('/{controller}/{action}')
    map.connect('/{controller}/{action}/{id}')

+   map.connect('signout', '/signout', controller='account', action='signout')
+   map.connect('signin', '/signin', controller='account', action='signin')

    return map
$ mkdir ./auth1/auth1/public/css
$ emacs -nw ./auth1/auth1/public/css/main.css
#hd p {
text-align: right;
padding-right: 20px;
padding-top: 5px;
}