Commit d885233c authored by Valentin Samir's avatar Valentin Samir
Browse files

[wiki/auth/cas] Sigle Sign Out

parent 90875b1f
......@@ -9,9 +9,12 @@
import sys
import os
import time, re
import urlparse
import urllib, urllib2
from lxml import etree
from lxml.etree import XMLSyntaxError
from MoinMoin import log
logging = log.getLogger(__name__)
......@@ -19,7 +22,6 @@ 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."""
......@@ -53,6 +55,14 @@ class PyCAS(object):
url += "&renew=true"
return url
def singlesignout(self, callback, body):
nodes = etree.fromstring(body).xpath("/samlp:LogoutRequest/samlp:SessionIndex", namespaces={'samlp' : 'urn:oasis:names:tc:SAML:2.0:protocol'})
for node in nodes:
except XMLSyntaxError:
def validate_ticket(self, service, ticket):
"""Validate the given ticket against the given service."""
f = urllib2.urlopen(self.validate_url(service, ticket))
......@@ -68,13 +78,14 @@ class CASAuth(BaseAuth):
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):
def __init__(self, auth_server, login_path="/login", logout_path="/logout", validate_path="/validate", action="login_cas", create_user=False, fallback_url=None, ticket_path=None):
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
self.ticket_path = ticket_path
def request(self, request, user_obj, **kw):
ticket = request.args.get("ticket", "")
......@@ -84,10 +95,46 @@ class CASAuth(BaseAuth):
p = urlparse.urlparse(request.url)
url = urlparse.urlunparse(('https', p.netloc, p.path, "", "", ""))
def store_ticket(ticket, username):
with open(self.ticket_path + ticket, 'w') as f:
def username_of_ticket(ticket):
with open(self.ticket_path + ticket) as f:
username =
os.remove(self.ticket_path + ticket)
return username
except IOError:
return None
def logout_user(ticket):
username = username_of_ticket(ticket)
if username:
u = user.User(request, None, username)
checks = []
if u.exists():
def user_matches(session):
return session[''] ==
except KeyError:
return False
session_service = request.cfg.session_service
for sid in session_service.get_all_session_ids(request):
session = session_service.get_session(request, sid)
if user_matches(session):
session_service.destroy_session(request, session)
# authenticated user
if not force and user_obj and user_obj.valid:
return user_obj, True
if self.ticket_path and request.method == 'POST':
logoutRequest=request.form.get('logoutRequest', None)
if logoutRequest is not None:
self.cas.singlesignout(logout_user, logoutRequest)
# anonymous
if not ticket and not self.action == action:
return user_obj, True
......@@ -105,6 +152,8 @@ class CASAuth(BaseAuth):
u.valid = u.exists()
if self.fallback_url and not u.valid:
request.http_redirect("%s?action=%s&wiki_url=%s" % (self.fallback_url, self.action, url))
if u.valid:
store_ticket(ticket, username)
return u, True
# login
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment