This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
mandaye/mandaye/auth/authform.py

165 lines
6.9 KiB
Python

"""
Dispatcher for basic auth form authentifications
"""
import Cookie
import urllib
from cookielib import CookieJar
from urlparse import parse_qs
from BeautifulSoup import BeautifulSoup
import mandaye
from mandaye.models import Site, ExtUser, LocalUser
from mandaye.http import HTTPResponse, HTTPHeader, HTTPRequest
from mandaye.response import _500, _302, _401
from mandaye.response import template_response
from mandaye.server import get_response
class AuthForm(object):
def __init__(self, local_auth, form_values):
""" local_auth: instance of your local authentification system
form_values: dict example :
{
'form_action': '/myform',
'form_url': '/myform',
'form_attrs': { 'name': 'form40', },
'username_field': 'user',
'password_field': 'pwd'
}
"""
self.local_auth = local_auth
if not form_values.has_key('form_headers'):
form_values['form_headers'] = {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 Mandaye/0.0'
}
if not form_values.has_key('form_url') or \
not form_values.has_key('form_attrs') or \
not form_values.has_key('username_field') or \
not form_values.has_key('password_field'):
logging.critical("Bad configuration: AuthForm form_values dict must have \
this keys: form_url, form_attrs, username_field and password_field")
# TODO: manage Mandaye exceptions
raise BaseException, 'AuthForm bad configuration'
self.form_url = form_values['form_url']
self.form_values = form_values
def replay(self, env, username, password, extra_values={}):
""" replay the login / password
env: WSGI env with beaker session and the target
extra_values: dict with the field name (key) and the field value (value)
"""
if not "://" in self.form_url:
self.form_url = env['target'].geturl() + '/' + self.form_url
cj = CookieJar()
request = HTTPRequest()
login = get_response(env, request, self.form_url, cj)
if login.code == 502:
return login
soup = BeautifulSoup(login.msg)
form = soup.find('form', self.form_values['form_attrs'])
if not self.form_values.has_key('from_action'):
action = form['action']
else:
action = self.form_values['form_action']
if not "://" in action:
action = env['target'].geturl() + '/' + action
if not form:
logging.warning("%s %s: can't find login form on %s" %
(self.env['HTTP_HOST'], self.env['PATH_INFO'], self.form_url))
return HTTPResponse()
cookies = login.cookies
headers = HTTPHeader()
headers.load_from_dict(self.form_values['form_headers'])
params = {}
for input in form.findAll('input'):
if input.has_key('name'):
if input.has_key('value'):
params[input['name']] = input['value']
else:
params[input['name']] = ''
params[self.form_values['username_field']] = username
params[self.form_values['password_field']] = password
for key, value in extra_values.iteritems():
params[key] = value
params = urllib.urlencode(params)
request = HTTPRequest(cookies, headers, "POST", params)
return get_response(env, request, action, cj)
def associate_submit(self, env, values, condition, request, response):
""" Associate your login / password with Mandaye
"""
pseudo = env['beaker.session'].get('pseudo')
if request.msg:
post = parse_qs(request.msg.read(), request)
if not post.has_key('username') or not post.has_key('password'):
return get_response(env, HTTPRequest(), values.get('failed_url'))
# TODO: generized this part (use a generic key / value table)
extra_values = {}
if post.has_key('birthdate'):
birthdate_field = self.form_values['birthdate_field']
extra_values = {birthdate_field: post['birthdate'][0]}
response = self.replay(env, post['username'][0], post['password'][0], extra_values)
if eval(condition):
if not pseudo:
return _302(values.get('connection_url'))
else:
site = mandaye.sql_session.query(Site).\
filter_by(name=values.get('site_name')).first()
if not site:
site = Site(values.get('site_name'))
mandaye.sql_session.add(site)
local_user = mandaye.sql_session.query(LocalUser).\
filter_by(login=pseudo).first()
if not local_user:
local_user = LocalUser(login=pseudo)
mandaye.sql_session.add(local_user)
ext_user = mandaye.sql_session.query(ExtUser).join(LocalUser).\
filter(LocalUser.login==pseudo).first()
if not ext_user:
ext_user = ExtUser()
mandaye.sql_session.add(ext_user)
ext_user.login = post['username'][0]
ext_user.password = post['password'][0]
ext_user.local_user = local_user
# TODO: generalize this
if post.has_key('birthdate'):
ext_user.birthdate = post['birthdate'][0]
mandaye.sql_session.commit()
return _302(values.get('connection_url'))
return get_response(env, HTTPRequest(), values.get('failed_url'))
def login(self, env, values, condition, request, response):
""" Automatic login on a site with a form
"""
login = self.local_auth.get_current_login(env)
if not login:
return _401('Access denied: invalid token')
ext_user = mandaye.sql_session.query(ExtUser).\
join(LocalUser).\
filter(LocalUser.login==login).\
first()
if not ext_user:
return _302(values.get('associate_url'))
if not ext_user.login or not ext_user.password:
return _500(env['PATH_INFO'],
'Invalid values for AuthFormDispatcher.login')
# TODO: generized this condition
extra_values = {}
if ext_user.birthdate:
extra_values = { self.form_values['birthdate_field']: ext_user.birthdate }
response = self.replay(env, ext_user.login, ext_user.password, extra_values)
if condition and eval(condition):
return response
else:
# TODO; find a better solution
return _302(values.get('associate_url'))