[wiki/auth/cas] Sigle Sign Out
This commit is contained in:
parent
90875b1faf
commit
d885233c75
1 changed files with 51 additions and 2 deletions
|
@ -9,9 +9,12 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
import time, re
|
import time, re
|
||||||
import urlparse
|
import urlparse
|
||||||
import urllib, urllib2
|
import urllib, urllib2
|
||||||
|
from lxml import etree
|
||||||
|
from lxml.etree import XMLSyntaxError
|
||||||
|
|
||||||
from MoinMoin import log
|
from MoinMoin import log
|
||||||
logging = log.getLogger(__name__)
|
logging = log.getLogger(__name__)
|
||||||
|
@ -19,7 +22,6 @@ logging = log.getLogger(__name__)
|
||||||
from MoinMoin.auth import BaseAuth
|
from MoinMoin.auth import BaseAuth
|
||||||
from MoinMoin import user, wikiutil
|
from MoinMoin import user, wikiutil
|
||||||
|
|
||||||
|
|
||||||
class PyCAS(object):
|
class PyCAS(object):
|
||||||
"""A class for working with a CAS server."""
|
"""A class for working with a CAS server."""
|
||||||
|
|
||||||
|
@ -53,6 +55,14 @@ class PyCAS(object):
|
||||||
url += "&renew=true"
|
url += "&renew=true"
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
def singlesignout(self, callback, body):
|
||||||
|
try:
|
||||||
|
nodes = etree.fromstring(body).xpath("/samlp:LogoutRequest/samlp:SessionIndex", namespaces={'samlp' : 'urn:oasis:names:tc:SAML:2.0:protocol'})
|
||||||
|
for node in nodes:
|
||||||
|
callback(node.text)
|
||||||
|
except XMLSyntaxError:
|
||||||
|
pass
|
||||||
|
|
||||||
def validate_ticket(self, service, ticket):
|
def validate_ticket(self, service, ticket):
|
||||||
"""Validate the given ticket against the given service."""
|
"""Validate the given ticket against the given service."""
|
||||||
f = urllib2.urlopen(self.validate_url(service, ticket))
|
f = urllib2.urlopen(self.validate_url(service, ticket))
|
||||||
|
@ -68,13 +78,14 @@ class CASAuth(BaseAuth):
|
||||||
login_inputs = ['username', 'password']
|
login_inputs = ['username', 'password']
|
||||||
logout_possible = True
|
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):
|
||||||
BaseAuth.__init__(self)
|
BaseAuth.__init__(self)
|
||||||
self.cas = PyCAS(auth_server, login_path=login_path,
|
self.cas = PyCAS(auth_server, login_path=login_path,
|
||||||
validate_path=validate_path, logout_path=logout_path)
|
validate_path=validate_path, logout_path=logout_path)
|
||||||
self.action = action
|
self.action = action
|
||||||
self.create_user = create_user
|
self.create_user = create_user
|
||||||
self.fallback_url = fallback_url
|
self.fallback_url = fallback_url
|
||||||
|
self.ticket_path = ticket_path
|
||||||
|
|
||||||
def request(self, request, user_obj, **kw):
|
def request(self, request, user_obj, **kw):
|
||||||
ticket = request.args.get("ticket", "")
|
ticket = request.args.get("ticket", "")
|
||||||
|
@ -84,10 +95,46 @@ class CASAuth(BaseAuth):
|
||||||
p = urlparse.urlparse(request.url)
|
p = urlparse.urlparse(request.url)
|
||||||
url = urlparse.urlunparse(('https', p.netloc, p.path, "", "", ""))
|
url = urlparse.urlunparse(('https', p.netloc, p.path, "", "", ""))
|
||||||
|
|
||||||
|
def store_ticket(ticket, username):
|
||||||
|
with open(self.ticket_path + ticket, 'w') as f:
|
||||||
|
f.write(username)
|
||||||
|
|
||||||
|
def username_of_ticket(ticket):
|
||||||
|
try:
|
||||||
|
with open(self.ticket_path + ticket) as f:
|
||||||
|
username = f.read()
|
||||||
|
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):
|
||||||
|
try:
|
||||||
|
return session['user.id'] == u.id
|
||||||
|
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
|
# authenticated user
|
||||||
if not force and user_obj and user_obj.valid:
|
if not force and user_obj and user_obj.valid:
|
||||||
return user_obj, True
|
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
|
# anonymous
|
||||||
if not ticket and not self.action == action:
|
if not ticket and not self.action == action:
|
||||||
return user_obj, True
|
return user_obj, True
|
||||||
|
@ -105,6 +152,8 @@ class CASAuth(BaseAuth):
|
||||||
u.valid = u.exists()
|
u.valid = u.exists()
|
||||||
if self.fallback_url and not u.valid:
|
if self.fallback_url and not u.valid:
|
||||||
request.http_redirect("%s?action=%s&wiki_url=%s" % (self.fallback_url, self.action, url))
|
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
|
return u, True
|
||||||
|
|
||||||
# login
|
# login
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue