From 19eb6c8e7bf6c5608886184e61dbb7a0b5e4bb6f Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Tue, 21 May 2013 15:06:26 +0200 Subject: [PATCH] [wiki] Ajout d'un module d'authentification via le CAS --- wiki/auth/__init__.py | 0 wiki/auth/cas.py | 123 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 wiki/auth/__init__.py create mode 100644 wiki/auth/cas.py diff --git a/wiki/auth/__init__.py b/wiki/auth/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/wiki/auth/cas.py b/wiki/auth/cas.py new file mode 100644 index 00000000..0e331b0b --- /dev/null +++ b/wiki/auth/cas.py @@ -0,0 +1,123 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - CAS authentication + + Jasig CAS (see http://www.jasig.org/cas) authentication module. + + @copyright: 2012 MoinMoin:RichardLiao + @license: GNU GPL, see COPYING for details. +""" + +import sys +import time, re +import urlparse +import urllib, urllib2 + +from MoinMoin import log +logging = log.getLogger(__name__) + +from MoinMoin.auth import BaseAuth +from MoinMoin import user, wikiutil + + +class PyCAS(object): + """A class for working with a CAS server.""" + + def __init__(self, server_url, renew=False, login_path='/login', logout_path='/logout', + validate_path='/validate', coding='utf-8'): + self.server_url = server_url + self.renew = renew + self.login_path = login_path + self.logout_path = logout_path + self.validate_path = validate_path + self.coding = coding + + def login_url(self, service): + """Return the login URL for the given service.""" + url = self.server_url + self.login_path + '?service=' + urllib.quote_plus(service) + if self.renew: + url += "&renew=true" + return url + def logout_url(self, redirect_url=None): + """Return the logout URL.""" + url = self.server_url + self.logout_path + if redirect_url: + url += '?url=' + urllib.quote_plus(redirect_url) + return url + + def validate_url(self, service, ticket): + """Return the validation URL for the given service. (For CAS 1.0)""" + url = self.server_url + self.validate_path + '?service=' + urllib.quote_plus(service) + '&ticket=' + urllib.quote_plus(ticket) + if self.renew: + url += "&renew=true" + return url + + def validate_ticket(self, service, ticket): + """Validate the given ticket against the given service.""" + f = urllib2.urlopen(self.validate_url(service, ticket)) + valid = f.readline() + valid = valid.strip() == 'yes' + user = f.readline().strip() + user = user.decode(self.coding) + return valid, user + +class CASAuth(BaseAuth): + """ handle login from CAS """ + name = 'CAS' + login_inputs = ['username', 'password'] + logout_possible = True + + def __init__(self, auth_server, login_path="/login", logout_path="/logout", validate_path="/validate", action="login_cas", create_user=False, fallback_url=None): + BaseAuth.__init__(self) + self.cas = PyCAS(auth_server, login_path=login_path, + validate_path=validate_path, logout_path=logout_path) + self.action = action + self.create_user = create_user + self.fallback_url = fallback_url + + def request(self, request, user_obj, **kw): + ticket = request.args.get("ticket", "") + action = request.args.get("action", "") + logoutRequest = request.args.get("logoutRequest", []) + p = urlparse.urlparse(request.url) + url = urlparse.urlunparse(('https', p.netloc, p.path, "", "", "")) + + # authenticated user + if user_obj and user_obj.valid: + return user_obj, True + + # anonymous + if not ticket and not self.action == action: + return user_obj, True + + # valid ticket on CAS + if ticket: + valid, username = self.cas.validate_ticket(url, ticket) + if valid: + u = user.User(request, auth_username=username, auth_method=self.name) + # auto create user ? + if self.create_user: + u.valid = valid + u.create_or_update(True) + else: + u.valid = u.exists() + if self.fallback_url and not u.valid: + request.http_redirect(self.fallback_url) + return u, True + + # login + request.http_redirect(self.cas.login_url(url)) + + return user_obj, True + + def logout(self, request, user_obj, **kw): + if self.name and user_obj and user_obj.auth_method == self.name: + user_obj.valid = False + request.cfg.session_service.destroy_session(request, request.session) + + p = urlparse.urlparse(request.url) + url = urlparse.urlunparse((p.scheme, p.netloc, p.path, "", "", "")) + request.http_redirect(self.cas.logout_url(url)) + return user_obj, False + +