165 lines
6.9 KiB
Python
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'))
|
|
|