Back to index

moin  1.9.0~rc2
cas.py
Go to the documentation of this file.
00001 # -*- coding: iso-8859-1 -*-
00002 """
00003     MoinMoin - CAS authentication
00004 
00005     Jasig CAS (see http://www.jasig.org/cas) authentication module.
00006 
00007     @copyright: 2009 MoinMoin:RichardLiao
00008     @license: GNU GPL, see COPYING for details.
00009 """
00010 
00011 import time, re
00012 import urlparse
00013 import urllib, urllib2
00014 
00015 from MoinMoin import log
00016 logging = log.getLogger(__name__)
00017 
00018 from MoinMoin.auth import BaseAuth
00019 from MoinMoin import user, wikiutil
00020 
00021 
00022 class PyCAS(object):
00023     """A class for working with a CAS server."""
00024 
00025     def __init__(self, server_url, renew=False, login_path='/login', logout_path='/logout',
00026                  validate_path='/validate', coding='utf-8'):
00027         self.server_url = server_url
00028         self.renew = renew
00029         self.login_path = login_path
00030         self.logout_path = logout_path
00031         self.validate_path = validate_path
00032         self.coding = coding
00033 
00034     def login_url(self, service):
00035         """Return the login URL for the given service."""
00036         url = self.server_url + self.login_path + '?service=' + urllib.quote_plus(service)
00037         if self.renew:
00038             url += "&renew=true"
00039         return url
00040 
00041     def logout_url(self, redirect_url=None):
00042         """Return the logout URL."""
00043         url = self.server_url + self.logout_path
00044         if redirect_url:
00045             url += '?url=' + urllib.quote_plus(redirect_url)
00046         return url
00047 
00048     def validate_url(self, service, ticket):
00049         """Return the validation URL for the given service. (For CAS 1.0)"""
00050         url = self.server_url + self.validate_path + '?service=' + urllib.quote_plus(service) + '&ticket=' + urllib.quote_plus(ticket)
00051         if self.renew:
00052             url += "&renew=true"
00053         return url
00054 
00055     def validate_ticket(self, service, ticket):
00056         """Validate the given ticket against the given service."""
00057         f = urllib2.urlopen(self.validate_url(service, ticket))
00058         valid = f.readline()
00059         valid = valid.strip() == 'yes'
00060         user = f.readline().strip()
00061         user = user.decode(self.coding)
00062         return valid, user
00063 
00064 
00065 class CASAuth(BaseAuth):
00066     """ handle login from CAS """
00067     name = 'CAS'
00068     login_inputs = ['username', 'password']
00069     logout_possible = True
00070 
00071     def __init__(self, auth_server, login_path="/login", logout_path="/logout", validate_path="/validate"):
00072         BaseAuth.__init__(self)
00073         self.cas = PyCAS(auth_server, login_path=login_path,
00074                          validate_path=validate_path, logout_path=logout_path)
00075 
00076     def request(self, request, user_obj, **kw):
00077         ticket = request.args.get('ticket')
00078         action = request.args.get("action", [])
00079         logoutRequest = request.args.get('logoutRequest', [])
00080         url = request.getBaseURL() + urllib.quote_plus(request.getPathinfo().encode('utf-8'))
00081 
00082         # # handle logout request from CAS
00083         # if logoutRequest:
00084             # logoutRequestMatch = re.search("<samlp:SessionIndex>(.*)</samlp:SessionIndex>", logoutRequest[0])
00085             # service_ticket = logoutRequestMatch.group(1)
00086             # if service_ticket:
00087                 # # TODO: logout
00088                 # return self.logout(request, user_obj)
00089 
00090         # authenticated user
00091         if user_obj and user_obj.valid:
00092             return user_obj, True
00093 
00094         # anonymous
00095         if not ticket and not "login" in action:
00096             return user_obj, True
00097 
00098         # valid ticket on CAS
00099         if ticket:
00100             valid, username = self.cas.validate_ticket(url, ticket[0])
00101             if valid:
00102                 u = user.User(request, auth_username=username, auth_method=self.name)
00103                 u.valid = valid
00104                 # auto create user
00105                 u.create_or_update(True)
00106                 return u, True
00107 
00108         # login
00109         request.http_redirect(self.cas.login_url(url))
00110 
00111         return user_obj, True
00112 
00113     def logout(self, request, user_obj, **kw):
00114         if self.name and user_obj and user_obj.auth_method == self.name:
00115             url = request.getBaseURL() + urllib.quote_plus(request.getPathinfo().encode('utf-8'))
00116             request.http_redirect(self.cas.logout_url(url))
00117 
00118             user_obj.valid = False
00119 
00120         return user_obj, True
00121