Improve README and finish duonet support

* mandaye/auth/authform.py: update to support duonet replay
 * README.rst: improve the quick launch text
 * mandaye/filters/vincennes.py: filters for Duonet
 * mandaye/models.py: add birthdate for duonet
 * mandayectl: improve the cmd line management
This commit is contained in:
Jérôme Schneider 2011-09-23 08:49:32 +02:00
parent b316506ed2
commit 85141684d0
6 changed files with 79 additions and 48 deletions

View File

@ -68,11 +68,15 @@ or easy_install::
Quick Start
-----------
Configure mandaye/config.py
Then launch the following commands::
TODO
./mandayectl --createdb
./mandayectl --start
You should see the following output::
TODO
Database created
Starting Mandaye x.x.x.x:xx ...

View File

@ -49,24 +49,26 @@ this keys: form_url, form_attrs, username_field and password_field")
self.form_url = form_values['form_url']
self.form_values = form_values
def replay(self, env, username, password, **kwargs):
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
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'])
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
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))
@ -77,32 +79,33 @@ this keys: form_url, form_attrs, username_field and password_field")
headers.load_from_dict(self.form_values['form_headers'])
params = {}
for input in form.findAll('input'):
if input['type'] != "submit" and input['type'] != 'button' \
and input.has_key('name'):
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 kwargs:
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(self, env, values, request):
""" Render the associate page
"""
return template_response(values['template'], values)
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)
response = self.replay(env, post['username'][0], post['password'][0])
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'))
@ -125,6 +128,9 @@ this keys: form_url, form_attrs, username_field and password_field")
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'))
@ -145,7 +151,11 @@ this keys: form_url, form_attrs, username_field and password_field")
if not ext_user.login or not ext_user.password:
return _500(env['PATH_INFO'],
'Invalid values for AuthFormDispatcher.login')
response = self.replay(env, ext_user.login, ext_user.password)
# 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:

View File

@ -11,12 +11,13 @@ filters = Duonet()
form_values = {
'form_url': 'Connect.aspx?key=CV4j27Em0dM%3d',
'form_attrs': { 'name': 'form1', },
'form_attrs': { 'name': 'form1' },
'username_field': 'txtNomFoyer',
'birthdate_field': 'txtDateNaissance',
'password_field': 'txtCode',
}
authform = AuthForm(auth_vincennes, form_values)
@ -26,7 +27,7 @@ duonet_mapping = [
'method': 'GET',
'response': [{
'filter': authform.login,
'values': { 'associate_url': '/vincennes/associate' },
'values': { 'associate_url': '/associate' },
'condition': 'response.code==302',
},]
},
@ -42,29 +43,29 @@ duonet_mapping = [
},
}]
},
# {
# 'path': r'/vincennes/associate$',
# 'method': 'POST',
# 'response': [
# {
# 'filter': authform.associate_submit,
# 'values': {
# 'site_name': 'espace_famille',
# 'connection_url': '/vincennes/connection',
# 'failed_url': 'https://vincennes.espace-famille.net/vincennes/index.do'
# },
# 'condition': "response.code==302"
# },
# {
# 'filter': filters.resp_associate,
# 'values': {
# 'action': '/vincennes/associate',
# 'template': 'famille_associate.html',
# 'error_msg': "Code famille et/ou mot de passe incorrects",
# },
# },
# ]
# },
{
'path': r'/associate$',
'method': 'POST',
'response': [
{
'filter': authform.associate_submit,
'values': {
'site_name': 'conservatoire',
'connection_url': '/vincennes/connection',
'failed_url': 'https://extranet.duonet.fr/Connect.aspx?key=CV4j27Em0dM%3d'
},
'condition': "response.code==302"
},
{
'filter': filters.resp_associate,
'values': {
'action': '/associate',
'template': 'duonet_associate.html',
'error_msg': "Identifiants incorrects",
},
},
]
},
{
'path': r'/vincennes/connection$',
'method': 'GET',
@ -84,6 +85,14 @@ duonet_mapping = [
'filter': filters.resp_login_page,
'values': {'connection_url': '/vincennes/connection'}}]
},
{
'path': r'/$',
'method': 'GET',
'target': 'https://extranet.duonet.fr/Connect.aspx?key=CV4j27Em0dM%3d',
'on_response': [{
'filter': filters.resp_login_page,
'values': {'connection_url': '/vincennes/connection'}}]
},
]

View File

@ -1,10 +1,15 @@
import ipdb
import mandaye
import re
from urlparse import parse_qs
from BeautifulSoup import BeautifulSoup
from mandaye.models import Site, ExtUser, LocalUser
from mandaye.server import get_response
from mandaye.response import serve_template
from mandaye.http import HTTPRequest
from mandaye.response import _500, _302, _401
def biblio_html_login_page(env, values, request, response):
""" msg: response message body
@ -83,5 +88,3 @@ class Duonet:
response.msg = str(soup)
return response
def associate_submit(self, env, values, request, response):
pass

View File

@ -26,7 +26,7 @@ class LocalUser(Base):
id = Column(Integer, primary_key=True)
login = Column(String(150), nullable=True, unique=True)
password = Column(String, nullable=True)
password = Column(String(25), nullable=True)
fullname = Column(String(150), nullable=True)
def __init__(self, login=None, password=None, fullname=None):
@ -48,7 +48,8 @@ class ExtUser(Base):
id = Column(Integer, primary_key=True)
login = Column(String(80), nullable=True)
password = Column(String, nullable=True)
password = Column(String(25), nullable=True)
birthdate = Column(String(15), nullable=True)
local_user_id = Column(Integer, ForeignKey('local_users.id'))
site_id = Column(Integer, ForeignKey('sites.id'))

View File

@ -12,7 +12,8 @@ from mandaye import config
from mandaye import server
def get_cmd_options():
parser = OptionParser()
usage = "usage: %prog [-d, --daemon] start|stop|createdb"
parser = OptionParser(usage=usage)
parser.add_option("--start",
dest="start",
default=False,
@ -42,6 +43,8 @@ def get_cmd_options():
parser.error("you can't use options start and stop at the same time")
if options.daemon and not options.start and not options.stop:
parser.error("You must use option start or stop")
if not options.start and not options.stop and not options.createdb:
parser.error("You must use option start | stop | createdb")
return options
def main():
@ -53,9 +56,10 @@ def main():
from sqlalchemy import create_engine
engine = create_engine(config.db_url)
Base.metadata.create_all(engine)
print "Database created"
if options.start:
logging.info("Starting Mandaye %s:%d .." % (config.host, config.port))
print "Starting Mandaye %s:%d .." % (config.host, config.port)
server.serve()
if __name__ == "__main__":