better cas compliance

This commit is contained in:
Massimo DiPierro
2011-12-02 23:27:42 -06:00
parent 789bbb4e59
commit bd542c3d36
3 changed files with 69 additions and 35 deletions
+1 -1
View File
@@ -1 +1 @@
Version 1.99.3 (2011-12-02 17:48:23) dev Version 1.99.3 (2011-12-02 23:27:41) dev
+2 -2
View File
@@ -41,7 +41,7 @@ class CasAuth( object ):
""" """
def __init__(self, g=None, ### g for backward compatibility ### def __init__(self, g=None, ### g for backward compatibility ###
urlbase = "https://web2py.com/cas/cas", urlbase = "https://web2py.com/cas/cas",
actions=['login','check','logout'], actions=['login','validate','logout'],
maps=dict(username=lambda v:v.get('username',v['user']), maps=dict(username=lambda v:v.get('username',v['user']),
email=lambda v:v.get('email',None), email=lambda v:v.get('email',None),
user_id=lambda v:v['user']), user_id=lambda v:v['user']),
@@ -97,7 +97,7 @@ class CasAuth( object ):
if data.startswith('yes') or data.startswith('no'): if data.startswith('yes') or data.startswith('no'):
data = data.split('\n') data = data.split('\n')
if data[0]=='yes': if data[0]=='yes':
a,b,c = data[1].split( ':' )+[None,None] a=b=c = data[1]
return dict(user=a,email=b,username=c) return dict(user=a,email=b,username=c)
return None return None
import xml.dom.minidom as dom import xml.dom.minidom as dom
+66 -32
View File
@@ -880,6 +880,8 @@ class Auth(object):
settings.cas_provider = cas_provider settings.cas_provider = cas_provider
settings.cas_actions = {'login':'login', settings.cas_actions = {'login':'login',
'validate':'validate', 'validate':'validate',
'servicevalidate':'serviceValidate',
'proxyvalidate':'proxyValidate',
'logout':'logout'} 'logout':'logout'}
settings.cas_maps = None settings.cas_maps = None
settings.extra_fields = {} settings.extra_fields = {}
@@ -1141,7 +1143,11 @@ class Auth(object):
if args(1) == self.settings.cas_actions['login']: if args(1) == self.settings.cas_actions['login']:
return self.cas_login(version=2) return self.cas_login(version=2)
elif args(1) == self.settings.cas_actions['validate']: elif args(1) == self.settings.cas_actions['validate']:
return self.cas_validate(version=2) return self.cas_validate(version=1)
elif args(1) == self.settings.cas_actions['servicevalidate']:
return self.cas_validate(version=2, proxy=False)
elif args(1) == self.settings.cas_actions['proxyvalidate']:
return self.cas_validate(version=2, proxy=True)
elif args(1) == self.settings.cas_actions['logout']: elif args(1) == self.settings.cas_actions['logout']:
return self.logout(next=request.vars.service or DEFAULT) return self.logout(next=request.vars.service or DEFAULT)
else: else:
@@ -1381,8 +1387,9 @@ class Auth(object):
Field('user_id', settings.table_user, default=None, Field('user_id', settings.table_user, default=None,
label=self.messages.label_user_id), label=self.messages.label_user_id),
Field('created_on','datetime',default=now), Field('created_on','datetime',default=now),
Field('url',requires=IS_URL()), Field('service',requires=IS_URL()),
Field('uuid'), Field('ticket'),
Field('renew', 'boolean', default=False),
*settings.extra_fields.get(settings.table_cas_name,[]), *settings.extra_fields.get(settings.table_cas_name,[]),
**dict( **dict(
migrate=self.__get_migrate( migrate=self.__get_migrate(
@@ -1509,52 +1516,79 @@ class Auth(object):
log=DEFAULT, log=DEFAULT,
version=2, version=2,
): ):
request, session = current.request, current.session request = current.request
response = current.response
session = current.session
db, table = self.db, self.settings.table_cas db, table = self.db, self.settings.table_cas
session._cas_service = request.vars.service or session._cas_service session._cas_service = request.vars.service or session._cas_service
if not request.env.http_host in self.settings.cas_domains or \ if not request.env.http_host in self.settings.cas_domains or \
not session._cas_service: not session._cas_service:
raise HTTP(403,'not authorized') raise HTTP(403,'not authorized')
def allow_access(): def allow_access(interactivelogin=False):
row = table(url=session._cas_service,user_id=self.user.id) row = table(service=session._cas_service,user_id=self.user.id)
if row: if row:
row.update_record(created_on=request.now) row.update_record(created_on=request.now)
uuid = 'LT-'+row.uuid ticket = row.ticket
else: else:
uuid = 'LT-'+web2py_uuid() ticket = 'ST-'+web2py_uuid()
table.insert(url=session._cas_service, user_id=self.user.id, table.insert(service=session._cas_service, user_id=self.user.id,
uuid=uuid, created_on=request.now) ticket=ticket, created_on=request.now, renew=interactivelogin)
url = session._cas_service service = session._cas_service
del session._cas_service del session._cas_service
redirect(url+"?ticket="+uuid) if request.vars.has_key('warn'):
if self.is_logged_in(): response.headers['refresh'] = "5;URL=%s"%service+"?ticket="+ticket
allow_access() return A("Continue to %s"%service,
_href=service+"?ticket="+ticket)
else:
redirect(service+"?ticket="+ticket)
if self.is_logged_in() and not request.vars.has_key('renew'):
return allow_access()
elif not self.is_logged_in() and request.vars.has_key('gateway'):
redirect(service)
def cas_onaccept(form, onaccept=onaccept): def cas_onaccept(form, onaccept=onaccept):
if not onaccept is DEFAULT: onaccept(form) if not onaccept is DEFAULT: onaccept(form)
allow_access() return allow_access(interactivelogin=True)
return self.login(next,onvalidation,cas_onaccept,log) return self.login(next,onvalidation,cas_onaccept,log)
def cas_validate(self, version=2): def cas_validate(self, version=2, proxy=False):
request = current.request request = current.request
db, table = self.db, self.settings.table_cas db, table = self.db, self.settings.table_cas
current.response.headers['Content-Type']='text' current.response.headers['Content-Type']='text'
ticket = table(uuid=request.vars.ticket) ticket = request.vars.ticket
if ticket: # and ticket.created_on>request.now-datetime.timedelta(60): renew = True if request.vars.has_key('renew') else False
user = self.settings.table_user(ticket.user_id) row = table(ticket=ticket)
fullname = user.first_name+' '+user.last_name if row:
if version == 1: if self.settings.login_userfield:
raise HTTP(200,'yes\n%s:%s:%s'%(user.id,user.email,fullname)) userfield = self.settings.login_userfield
# assume version 2 elif 'username' in table.fields:
username = user.get('username',user.email) userfield = 'username'
raise HTTP(200,'<?xml version="1.0" encoding="UTF-8"?>\n'+\ else:
TAG['cas:serviceResponse']( userfield = 'email'
TAG['cas:authenticationSuccess']( # If ticket is a service Ticket and RENEW flag respected
TAG['cas:user'](username), if ticket[0:3] == 'ST-' and not ((row.renew and renew) ^ renew):
*[TAG['cas:'+field.name](user[field.name]) \ user = self.settings.table_user(row.user_id)
for field in self.settings.table_user \ row.delete_record()
if field.readable]), if version == 1:
**{'_xmlns:cas':'http://www.yale.edu/tp/cas'}).xml()) raise HTTP(200,'yes\n%s'%(user[userfield]))
# assume version 2
username = user.get('username',user[userfield])
raise HTTP(200,'<?xml version="1.0" encoding="UTF-8"?>\n'+\
TAG['cas:serviceResponse'](
TAG['cas:authenticationSuccess'](
TAG['cas:user'](username),
*[TAG['cas:'+field.name](user[field.name]) \
for field in self.settings.table_user \
if field.readable]),
**{'_xmlns:cas':'http://www.yale.edu/tp/cas'}).xml())
else:
raise HTTP(200,'<?xml version="1.0" encoding="UTF-8"?>\n'+\
TAG['cas:serviceResponse'](
TAG['cas:authenticationFailure'](),
**{'_xmlns:cas':'http://www.yale.edu/tp/cas'}).xml())
# Delete ticket if not already done
row.delete_record()
if version == 1: if version == 1:
raise HTTP(200,'no\n') raise HTTP(200,'no\n')
# assume version 2 # assume version 2