Wow, that's great. I'm just reaching the stage of adding login/
authorization to my project, and your approach looks just like what I
had in mind, but with all the unknowns filled in. Thanks for sharing.
On Mar 27, 9:42 am, Wolverine <[EMAIL PROTECTED]> wrote:
> Yannick Gingras pisze:> Greetings Pyloneers,
>
> > It's be a long time since I hacked something with Pylons but things
> > are moving favorably now. After a flash demo of our great tools, I
> > was able to convince out lead architect that Pylons was the right
> > choice for our next web app.
>
> Hello!
> I'm new to this group, never posted anything here before, but I think
> I've got something just right for you. I have done implementation of
> HTTP-Auth Basic (Digest is no problem also, but you'll have to change
> the controller a bit) and also web based user authentication.
>
> So. Here is my solution for http-auth-basic. Mind you it's not very
> fancy, because we are not using http-auth anymore. Also we are using
> Elixir as our database model system on top of SQLAlchemy. Since this is
> obsolete piece of code it may be not usable, but you can take something
> from this and do your own http-auth login controller. It's not
> guaranteed it will work.
>
> --- cut ---
>
> from YOURPROJECTNAME.lib.base import *
> import base64
>
> class LoginController(BaseController):
> """"""
>
> def index(self):
> """"""
> c.error = session.get('error')
> return render('/login/login.mako')
>
> def login(self):
> """"""
> if not request.headers.has_key('Authorization'):
> response.status_code = 401
> response.headers['WWW-Authenticate'] = "Basic realm=\"REALM\""
> return "Not authenticated"
>
> auth = request.headers['Authorization']
> auth_list = auth.split(' ')
> auth_type = auth_list[0]
> if auth_type == 'Basic':
> auth_login, auth_pass =
> base64.b64decode(auth_list[1]).split(':')
> elif auth_type == 'Digest':
> return 'Digest authentication is not yet implemented'
>
> # FIXME: Get account object from database
> account_obj = model.Account.query().get_by(email = auth_login)
> if account_obj is None:
> # FIXME: Show error
> abort(404)
>
> # Check if account is active
> if account_obj.status == 0:
> # FIXME:
> session['error'] = 'Account is not active! Cannot login.'
> session.save()
> redirect_to(action = 'index')
>
> # If passwords do not match
> if account_obj.password != auth_pass:
> session['error'] = 'Error: Passwords do not match!'
> session.save()
> redirect_to(action = 'index')
>
> # User authentication succeeded, save logged_user_id in session
> session['logged_user_id'] = account_obj.id
> session.save()
> return redirect_to('login/loggedin.mako')
>
> --- cut ---
>
> As for authenticating website users through website form we have devised
> our own system based on Challenge-Response Protocol. Basically the idea
> is to create a login controller like this:
>
> controllers/login.py
> --- cut ---
>
> class LoginController(BaseController): #TODO: docstring
> """
> Login controller class
> """
> hash_func = config.get('passwd_hash_func')
>
> def index(self):
> """
> Shows login form
> """
> c.error = session['error'] if session.has_key('error') else None
>
> # Generate hashed random seed
> rand_str = str(datetime.now()) + str(random.randint(100,1000000))
> rseed = self.hash_func(rand_str).hexdigest()
>
> # Save this random seed into session
> session['login_rseed'] = rseed
> session.save()
>
> # Setup form
> c.form = login_form(action = h.url_for(controller = 'login',
> action = 'login'),
> attrs = {'onsubmit' : 'javascript:return
> validate_login_form();'},
> value = {'rseed' : rseed}
> )
> c.heading = u"Logowanie"
>
> return render('/login/login.mako')
>
> @validate(form = login_form, error_handler = 'index')
> def login(self): #TODO: docstring
> """
> Performs login checks
> """
> # Check if user is logged
> if session.get('logged_user'):
> session['error'] = 'User already logged in!'
> session.save()
> return render('/login/loggedin.mako')
>
> # Get values passed from login form
> email = str(request.POST.get('email'))
> password = str(request.POST.get('password'))
> secure = str(request.POST.get('secure'))
>
> # Remove previous errors
> if session.get('error'):
> del(session['error'])
> session.save()
>
> # Get account from database
> account_obj = model.Account.query().get_by(email = email)
> if account_obj is None:
> session['error'] = 'Error: User does not exist!'
> session.save()
> redirect_to(action = 'index')
>
> # Generate hash for comparison
> apasswd = account_obj.password
>
> # Check if password was sent in secure manner
> if secure == 'yes':
> # Check if random seed has been passed in session
> rseed = session.get('login_rseed')
> if not rseed:
> session['error'] = 'Error: Random seed doesn\'t exist!'
> session.save()
> redirect_to(action = 'index')
>
> # Generate hash from seed and password
> seedpass = self.hash_func(rseed + apasswd).hexdigest()
> else:
> # Password was cleartext so we have to hash it
> seedpass = apasswd
> password = self.hash_func(password).hexdigest()
>
> # Check Challenge Response hashes
> if seedpass != password:
> session['error'] = 'Error: Bad email or password!'
> session.save()
> redirect_to(action = 'index')
>
> # If hashes match save user as logged in
> session['logged_user'] = email
> session['logged_user_id'] = account_obj.id
> session.save()
>
> # Send user back to the page he originally wanted to get to
> if session.get('path_before_login'):
> # Get path before login
> redir_url = session['path_before_login']
> # Remove path before login from session
> del(session['path_before_login'])
> session.save()
> # Redirect to url
> redirect_to(redir_url)
> else:
> return render('/login/loggedin.mako')
>
> def logout(self): #TODO: docstring
> """
> Performs user logout
> """
> # Check if user is logged
> if not session.get('logged_user'):
> session['error'] = 'User is not logged in!'
> session.save()
> return redirect_to(action = 'index')
>
> del(session['logged_user'])
> del(session['logged_user_id'])
> session.save()
> return render('login/logout.mako')
>
> --- cut ---
>
> And here is the login template:
>
> templates/login/login.mako
> --- cut ---
>
> # -*- coding: utf-8 -*-
> <%inherit file="/main.mako" />
>
> % if c.error:
> <div id="errorbox">
> ${ c.error }
> </div>
> % endif
>
> <noscript>
> <div id="errorbox">
> <h2>Warning!</h2>
> You don't have JavaScript enabled. Your password will be unprotected! If
> you want to login securely enable Javascript in your browser settings.
> </div>
> </noscript>
>
> ${c.form}
>
> <%def name="metatags()">
> ${ h.javascript_include_tag('prototypeUtils', 'md5', 'helpers', builtins
> = True) }
> </%def>
>
> --- cut ---
>
> We are also using ToscaWidgets for creating forms so we have something
> like this for the login form:
>
> widgets/forms/login/login.py
> --- cut ---
>
> from toscawidgets.widgets import forms
> from toscawidgets.api import WidgetsList
> from toscawidgets.widgets.forms.validators import Email, UnicodeString,
> NotEmpty
>
> forms.FormField.engine_name = "mako"
>
> class LoginForm(forms.Form):
> """"""
> template = "mako:mibu.templates.forms.default"
> submit_text = u"Login"
>
> class fields(WidgetsList):
> email = forms.TextField(
> validator = Email(not_empty = True),
> label_text = u"E-mail:"
> )
> password = forms.PasswordField(
> validator = UnicodeString(not_empty = True),
> label_text = u"Password:"
> )
> rseed = forms.HiddenField(default = '')
> secure = forms.HiddenField(default = '')
>
> login_form = LoginForm("login_form")
>
> --- cut ---
>
> The last thing to do is to correct BaseController. We are specifying
> requires_auth variable that you can further use in your own controllers
> so unauthenticated users are automatically redirected to the login form
> and after successful login they are brought back to the page they
> requested.
>
> requires_auth is either a list of controller methods or boolean value.
> If it's bool and True every action in the controller requires
> authentication.
>
> lib/base.py
> --- cut ---
>
> class BaseController(WSGIController):
> requires_auth = []
>
> def __before__(self, action):
> # Check if controller needs authorization
> if type(self.requires_auth) == types.BooleanType:
> if self.requires_auth:
> if 'logged_user' not in session:
> session['path_before_login'] = request.path_info
> session.save()
> return redirect_to(h.url_for(controller = 'login'))
> # If requires authorization is list
> else:
> # Check if action needs authorization
> if action in self.requires_auth:
> if 'logged_user' not in session:
> session['path_before_login'] = request.path_info
> session.save()
> return redirect_to(h.url_for(controller = 'login'))
>
> def __call__(self, environ, start_response):
> """Invoke the Controller"""
> # WSGIController.__call__ dispatches to the Controller method
> # the request is routed
> ...
>
> read more ยป
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"pylons-discuss" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en
-~----------~----~----~----~------~----~------~--~---