diff --git a/README.rst b/README.rst index 3597ed4..bd1ce50 100644 --- a/README.rst +++ b/README.rst @@ -98,7 +98,7 @@ Launch mandaye server::: mandaye_server.py use gunicorn and gunicorn options (please read http://gunicorn.org/configure.html) -You could alse use gunicorn.conf.py-sample (in the mandaye files):: +You could also use gunicorn.conf.py-sample (in the mandaye files):: $ mandaye_server.py -c PATH_TO_THE_FILE/gunicorn.conf.py diff --git a/mandaye/__init__.py b/mandaye/__init__.py index d17ccaa..930c224 100644 --- a/mandaye/__init__.py +++ b/mandaye/__init__.py @@ -1,28 +1 @@ VERSION=0.2 - -import logging -from logging import FileHandler -from logging.handlers import SysLogHandler -from mandaye.config import log_level, syslog, log_file - -logger = logging.getLogger() -logger.setLevel(log_level) - -# Stream logging -sh = logging.StreamHandler() -sh.setFormatter(logging.Formatter('%(levelname)s %(message)s')) -logger.addHandler(sh) - -# Syslog logging -if syslog: - syslog_handler = SysLogHandler(address='/dev/log') - syslog_handler.setFormatter(logging.Formatter('mandaye: %(levelname)s %(message)s')) - logger.addHandler(syslog_handler) - -# File logging -if log_file: - filehandler = FileHandler(log_file) - filehandler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s', - datefmt='%Y-%m-%d %H:%M:%S')) - logger.addHandler(filehandler) - diff --git a/mandaye/auth/authform.py b/mandaye/auth/authform.py index f353633..521deb3 100644 --- a/mandaye/auth/authform.py +++ b/mandaye/auth/authform.py @@ -3,7 +3,6 @@ Dispatcher for basic auth form authentifications """ import Cookie import base64 -import logging import re import traceback import urllib @@ -11,7 +10,6 @@ import urllib import mandaye from cookielib import CookieJar -from Crypto.Cipher import AES from datetime import datetime from lxml.html import fromstring from urlparse import parse_qs @@ -19,11 +17,16 @@ from urlparse import parse_qs from mandaye import config from mandaye.db import sql_session from mandaye.models import Site, ExtUser, LocalUser +from mandaye.log import logger 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 +try: + from Crypto.Cipher import AES +except ImportError: + config.encrypt_ext_password = False class AuthForm(object): @@ -49,7 +52,7 @@ class AuthForm(object): 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 \ + logger.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' @@ -65,7 +68,7 @@ this keys: form_url, form_attrs, username_field and password_field") pwd: the password you want to encrypt return None if encryption failed """ - logging.debug("Encrypt password") + logger.debug("Encrypt password") enc_pwd = pwd if config.encrypt_secret: try: @@ -75,9 +78,9 @@ this keys: form_url, form_attrs, username_field and password_field") except Exception, e: if config.debug: traceback.print_exc() - logging.warning('Password encrypting failed %s' % e) + logger.warning('Password encrypting failed %s' % e) else: - logging.warning("You must set a secret to use pwd encryption") + logger.warning("You must set a secret to use pwd encryption") return enc_pwd def _decrypt_pwd(self, enc_pwd): @@ -88,7 +91,7 @@ this keys: form_url, form_attrs, username_field and password_field") enc_pwd: your encoded password return None if encryption failed """ - logging.debug("Decrypt password") + logger.debug("Decrypt password") pwd = enc_pwd if config.encrypt_secret: try: @@ -98,9 +101,9 @@ this keys: form_url, form_attrs, username_field and password_field") except Exception, e: if config.debug: traceback.print_exc() - logging.warning('Decrypting password failed: %s' % e) + logger.warning('Decrypting password failed: %s' % e) else: - logging.warning("You must set a secret to use pwd decryption") + logger.warning("You must set a secret to use pwd decryption") return pwd def replay(self, env, username, password, extra_values={}): @@ -127,13 +130,13 @@ this keys: form_url, form_attrs, username_field and password_field") break if auth_form == None: - logging.critical("%s %s: can't find login form on %s" % + logger.critical("%s %s: can't find login form on %s" % (env['HTTP_HOST'], env['PATH_INFO'], self.form_url)) return _500(env['PATH_INFO'], "Replay: Can't find login form") if not self.form_values.has_key('from_action'): if not auth_form.action: - logging.critical("%s %s: don't find form action on %s" % + logger.critical("%s %s: don't find form action on %s" % (env['HTTP_HOST'], env['PATH_INFO'], self.form_url)) return _500(env['PATH_INFO'], 'Replay: form action not found') action = auth_form.action @@ -171,13 +174,13 @@ this keys: form_url, form_attrs, username_field and password_field") site = sql_session().query(Site).\ filter_by(name=self.site_name).first() if not site: - logging.info('Add %s site in the database' % self.site_name) + logger.info('Add %s site in the database' % self.site_name) site = Site(self.site_name) sql_session().add(site) local_user = sql_session().query(LocalUser).\ filter_by(login=local_login).first() if not local_user: - logging.debug('Add user %s in the database' % local_login) + logger.debug('Add user %s in the database' % local_login) local_user = LocalUser(login=local_login) sql_session().add(local_user) ext_user = sql_session().query(ExtUser).\ @@ -188,7 +191,7 @@ this keys: form_url, form_attrs, username_field and password_field") if not ext_user: ext_user = ExtUser() sql_session().add(ext_user) - logging.info('New association: %s with %s on site %s' % \ + logger.info('New association: %s with %s on site %s' % \ (ext_username, local_login, self.site_name)) ext_user.login = ext_username if config.encrypt_ext_password: @@ -208,18 +211,18 @@ this keys: form_url, form_attrs, username_field and password_field") def associate_submit(self, env, values, condition, request, response): """ Associate your login / password into your database """ - logging.debug("Trying to associate a user") + logger.debug("Trying to associate a user") login = env['beaker.session'].get('login') if request.msg: if not login: - logging.warning("Association failed: user isn't login on Mandaye") + logger.warning("Association failed: user isn't login on Mandaye") return _302(values.get('connection_url')) post = parse_qs(request.msg.read(), request) qs = parse_qs(env['QUERY_STRING']) for key, value in qs.iteritems(): qs[key] = value[0] if not post.has_key('username') or not post.has_key('password'): - logging.info('Association auth failed: form not correctly filled') + logger.info('Association auth failed: form not correctly filled') qs['type'] = 'badlogin' return _302(values.get('associate_url') + "?%s" % urllib.urlencode(qs)) username = post['username'][0] @@ -234,12 +237,12 @@ this keys: form_url, form_attrs, username_field and password_field") response = self.replay(env, username, post['password'][0], extra_values) if eval(condition): - logging.debug("Replay works: save the association") + logger.debug("Replay works: save the association") self._save_association(env, login, username, post['password'][0], birthdate) if qs.has_key('next_url'): return _302(qs['next_url'], response.cookies) return response - logging.info('Auth failed: Bad password or login for %s on %s' % \ + logger.info('Auth failed: Bad password or login for %s on %s' % \ (post['username'][0], self.site_name)) qs['type'] = 'badlogin' return _302(values.get('associate_url') + "?%s" % urllib.urlencode(qs)) @@ -272,7 +275,7 @@ this keys: form_url, form_attrs, username_field and password_field") def login(self, env, values, condition, request, response): """ Automatic login on a site with a form """ - logging.debug('Trying to login on Mandaye') + logger.debug('Trying to login on Mandaye') login = self.get_current_login(env) if not login: return _401('Access denied: invalid token') @@ -283,7 +286,7 @@ this keys: form_url, form_attrs, username_field and password_field") env['beaker.session']['login'] = login env['beaker.session'].save() - logging.debug('User %s successfully login' % env['beaker.session']['login']) + logger.debug('User %s successfully login' % env['beaker.session']['login']) ext_user = sql_session().query(ExtUser).\ join(LocalUser).\ @@ -293,14 +296,14 @@ this keys: form_url, form_attrs, username_field and password_field") order_by(ExtUser.last_connection.desc()).\ first() if not ext_user: - logging.debug('User %s is not associate' % env['beaker.session']['login']) + logger.debug('User %s is not associate' % env['beaker.session']['login']) return _302(values.get('associate_url') + "?type=first") return self._login_ext_user(ext_user, env, condition, values) def logout(self, env, values, request, response): """ Destroy the Beaker session """ - logging.debug('Logout from Mandaye') + logger.debug('Logout from Mandaye') env['beaker.session'].delete() return response @@ -345,7 +348,7 @@ this keys: form_url, form_attrs, username_field and password_field") filter(ExtUser.id==id).\ first() if ext_user: - logging.debug('Disassociate account %s' % ext_user.login) + logger.debug('Disassociate account %s' % ext_user.login) sql_session().delete(ext_user) sql_session().commit() if qs.has_key('logout'): diff --git a/mandaye/auth/vincennes.py b/mandaye/auth/vincennes.py index 76c77b9..4595e14 100644 --- a/mandaye/auth/vincennes.py +++ b/mandaye/auth/vincennes.py @@ -1,7 +1,6 @@ """ Vincennes authentifications """ import base64 -import logging import traceback from Crypto.Cipher import AES @@ -9,6 +8,7 @@ from datetime import datetime, timedelta from urlparse import parse_qs from mandaye.auth.authform import AuthForm +from mandaye.log import logger from mandaye.models import Site, ExtUser, LocalUser from mandaye.db import sql_session from mandaye.response import _502, _302 @@ -54,7 +54,7 @@ class VincennesAuth(AuthForm): except Exception, e: if config.debug: traceback.print_exc() - logging.info("Invalid token %s" % e) + logger.info("Invalid token %s" % e) return None else: info = eval(decode[16:]) @@ -64,7 +64,7 @@ class VincennesAuth(AuthForm): delta = datetime.utcnow() - token_date timeout = timedelta(seconds=config.token_timeout) if abs(delta) > timeout: - logging.warning('Vincennes token timeout (delta of %s seconds)' \ + logger.warning('Vincennes token timeout (delta of %s seconds)' \ % abs(delta)) return None return info['pseudo'] @@ -82,15 +82,15 @@ class VincennesAuth(AuthForm): def auto_login(self, env, values, condition, request, response): """ Try to auto login the user if he is already login on www.vincennes.fr """ - logging.debug('Trying to auto log user on %s' % self.site_name) + logger.debug('Trying to auto log user on %s' % self.site_name) login = self.get_current_login(env) if env['beaker.session'].has_key('next_url'): path = env['beaker.session']['next_url'] else: - logging.warning('Auto login without mandaye_next_url automatically redirect to /') + logger.warning('Auto login without mandaye_next_url automatically redirect to /') path = '/' if not login: - logging.debug('Auto login failed because the user is not connected on vincennes.fr') + logger.debug('Auto login failed because the user is not connected on vincennes.fr') return _302(path, request.cookies) env['beaker.session']['login'] = login env['beaker.session'].save() @@ -102,12 +102,12 @@ class VincennesAuth(AuthForm): order_by(ExtUser.last_connection.desc()).\ first() if not ext_user: - logging.debug("No association found redirect to the association page %s" % values.get('associate_url')) + logger.debug("No association found redirect to the association page %s" % values.get('associate_url')) # TODO: urllencode path return _302(values.get('associate_url') + "?type=first&next_url=%s" % path) else: response = self._login_ext_user(ext_user, env, condition, values) - logging.info("User %s has been successfully auto login on %s" % (login, self.site_name)) + logger.info("User %s has been successfully auto login on %s" % (login, self.site_name)) return _302(path, response.cookies) def auto_connection(self, env, values, request, response): @@ -129,10 +129,10 @@ class VincennesAuth(AuthForm): else: env['beaker.session']['next_url'] = env['PATH_INFO'] env['beaker.session'].save() - logging.debug('Auto connection call %s' % target) + logger.debug('Auto connection call %s' % target) return _302(target) if env['beaker.session'].get('next_url'): - logging.debug('Disable next_url in the session') + logger.debug('Disable next_url in the session') env['beaker.session']['next_url'] = None env['beaker.session'].save() return response diff --git a/mandaye/config.py b/mandaye/config.py index 5ea38f0..2aad8a8 100644 --- a/mandaye/config.py +++ b/mandaye/config.py @@ -29,6 +29,7 @@ email_from = 'traceback@entrouvert.com' email_to = ['admin@localhost'] # Encrypt external passwords with a secret +# You should install pycypto to use this feature encrypt_ext_password = False # Must be a 16, 24, or 32 bytes long encrypt_secret = '' diff --git a/mandaye/dispatcher.py b/mandaye/dispatcher.py index 6237846..663a65f 100644 --- a/mandaye/dispatcher.py +++ b/mandaye/dispatcher.py @@ -1,9 +1,9 @@ -import logging import re from urlparse import urlparse from importlib import import_module +from mandaye.log import logger from mandaye.filters.default import MandayeFilter from mandaye.response import _500, _302 from mandaye.exceptions import ImproperlyConfigured @@ -83,7 +83,7 @@ class Dispatcher(object): if re.match(path, self.env['PATH_INFO']): req_mapping = self.__get_mappings_hooks(mapper, req_mapping) else: - logging.warning('Config error: you need to specify paths in your mapping') + logger.warning('Config error: you need to specify paths in your mapping') return req_mapping def _call_hook(self, hook, *args): @@ -96,7 +96,7 @@ class Dispatcher(object): else: return hook['filter'](self.env, values, *args) else: - logging.warning("%s hook failed (no filter option)" % self.env['PATH_INFO']) + logger.warning("%s hook failed (no filter option)" % self.env['PATH_INFO']) return None def get_target_url(self): @@ -126,12 +126,13 @@ class Dispatcher(object): if self.req_mapping['redirect']: return _302(self.req_mapping['redirect']) response = None + logger.debug("Loading response hook(s)") for hook in self.req_mapping['response']: new_response = self._call_hook(hook, request, response) if new_response: response = new_response else: - logging.warning("%s Response hook %s failed" % (self.env['PATH_INFO'], + logger.warning("%s Response hook %s failed" % (self.env['PATH_INFO'], self.req_mapping['response']['filter'])) if not response: return _500(self.env["PATH_INFO"], "The response hook failed") @@ -152,7 +153,7 @@ class Dispatcher(object): if new_request: request = new_request else: - logging.warning("%s On_request hook %s failed (empty request)" % \ + logger.warning("%s On_request hook %s failed (empty request)" % \ (self.env['PATH_INFO'], hook['filter'])) return request @@ -171,7 +172,7 @@ class Dispatcher(object): if new_response: response = new_response else: - logging.warning("%s On_response hook %s failed (empty answer)" % \ + logger.warning("%s On_response hook %s failed (empty answer)" % \ (self.env['PATH_INFO'], hook['filter'])) return response diff --git a/mandaye/emails.py b/mandaye/emails.py index b5277dd..f646fca 100644 --- a/mandaye/emails.py +++ b/mandaye/emails.py @@ -1,9 +1,9 @@ -import logging import smtplib from email.mime.text import MIMEText from mandaye import config +from mandaye.log import logger class Email: @@ -13,7 +13,7 @@ class Email: self.config_ok = True if not config.smtp_host or not config.smtp_port or \ not config.email_from or not config.email_to: - logging.warning('[Config] Bad email notification configuration') + logger.warning('[Config] Bad email notification configuration') self.config_ok = False def sent(self, subject, msg, type='plain'): @@ -22,7 +22,7 @@ class Email: subject; email subject """ if not self.config_ok: - logging.warning('[Config] Send email %s failed: bad configuration' % msg) + logger.warning('[Config] Send email %s failed: bad configuration' % msg) # build email msg = MIMEText(msg, type) msg['Subject'] = subject diff --git a/mandaye/filters/vincennes.py b/mandaye/filters/vincennes.py index e56d646..67bd967 100644 --- a/mandaye/filters/vincennes.py +++ b/mandaye/filters/vincennes.py @@ -1,5 +1,4 @@ import Cookie -import logging import mandaye import re @@ -8,6 +7,7 @@ from BeautifulSoup import BeautifulSoup import lxml.html from mandaye.db import sql_session +from mandaye.log import logger from mandaye.models import Site, ExtUser, LocalUser from mandaye.response import serve_template from mandaye.response import _302, _401 @@ -81,7 +81,7 @@ class Biblio: response.msg) response.msg = sub[0] if sub[1] != 1: - logging.warning('Filter Biblio.resp_html_login_page failed !') + logger.warning('Filter Biblio.resp_html_login_page failed !') return response def resp_html(self, env, values, request, response): @@ -110,7 +110,7 @@ class Biblio: sub = re.subn(r, form, response.msg) response.msg = sub[0] if sub[1] != 1: - logging.warning('Filter Biblio.resp_associate failed !') + logger.warning('Filter Biblio.resp_associate failed !') return response def resp_multicompte_html(self, env, values, request, response): @@ -128,7 +128,7 @@ class Biblio: response.msg) response.msg = sub[0] if sub[1] != 1: - logging.warning('Filter Biblio.resp_multicompte_html: add card number in account information failed') + logger.warning('Filter Biblio.resp_multicompte_html: add card number in account information failed') desassociate = serve_template('biblio/disassociate.html', account=current_account, **values) sub = re.subn(r'