I've started to use web2py for a new project and I've found a couple of small bugs on the gluon/contrib/login_methods/cas_auth.py file:
1. I'm serving the aplication using HTTPS, but the __init__ function hardcodes 'http' as scheme; to fix it I've changed the following: @@ -57,7 +57,11 @@ self.casusername = casusername http_host=current.request.env.http_x_forwarded_for if not http_host: http_host=current.request.env.http_host - self.cas_my_url='http://%s%s'%( http_host, current.request.env.path_info ) + if current.request.env.wsgi_url_scheme in [ 'https', 'HTTPS' ]: + scheme = 'https' + else: + scheme = 'http' + self.cas_my_url='%s://%s%s'%( scheme, http_host, current.request.env.path_info ) def login_url( self, next = "/" ): current.session.token=self._CAS_login() return next 2. I've developed a new login form (multi_cas_login_form) that allows the users to authenticate using the standard web2py authentication or use a remote CAS server from a list of configured servers; it works OK now, but while developing it I tested a chained authentication by mistake (a test application used the application configured to use the multi_cas_login_form as its CAS provider while I was logged using a remote CAS server, and the login failed). One of the problems was related to a simple typo: the _CAS_login function uses the ExpatError exception without importing it, to fix it I just moved the imports and qualified the exception: @@ -95,9 +99,9 @@ a,b,c = data[1].split( ':' )+[None,None] return dict(user=a,email=b,username=c) return None + import xml.dom.minidom as dom + import xml.parsers.expat as expat try: - import xml.dom.minidom as dom - import xml.parsers.expat as expat dxml=dom.parseString(data) envelop = dxml.getElementsByTagName("cas:authenticationSuccess") if len(envelop)>0: @@ -113,7 +117,7 @@ res[key]=[res[key]] res[key].append(value) return res - except ExpatError: pass + except expat.ExpatError: pass return None # fallback Once the typo was fixed I found a real problem related to the XML processing: if there is a field without a value on the recived file, the line: value = x.childNodes[0].nodeValue.encode('utf8') fails because there are no elements on childNodes. My fix was also simple: @@ -103,7 +107,7 @@ if len(envelop)>0: res = dict() for x in envelop[0].childNodes: - if x.nodeName.startswith('cas:'): + if x.nodeName.startswith('cas:') and len(x.childNodes): key = x.nodeName[4:].encode('utf8') value = x.childNodes[0].nodeValue.encode('utf8') if not key in res: The problem was related to the standard way of generating a local user with CASAuth; the default mapping does not include the 'first_name' and 'last_name' sent by the _CAS_login and that leaves the 'last_name' empty on the database (the 'first_name' is filled by the program using the 'username' or the 'email') and when I called the nested authentication the _CAS_login received the XML 'last_name' with an empty value. For that bug I fixed my application by adding a full mapping to the CASAuth objects (I set the 'username' and copy the 'email', 'first_name' and 'last_name' from the remote CAS server), but I believe that the fix is still valid anyway. I'm attaching a full patch to this message with the described changes. Greetings, Sergio. -- Sergio Talens-Oliag <s...@iti.upv.es> <http://www.iti.upv.es/> Key fingerprint = FF77 A16B 9D09 FC7B 6656 CFAD 261D E19A 578A 36F2
--- web2py.orig/gluon/contrib/login_methods/cas_auth.py 2011-06-07 22:07:48.000000000 +0200 +++ web2py/gluon/contrib/login_methods/cas_auth.py 2011-06-21 19:09:12.549477656 +0200 @@ -57,7 +57,11 @@ self.casusername = casusername http_host=current.request.env.http_x_forwarded_for if not http_host: http_host=current.request.env.http_host - self.cas_my_url='http://%s%s'%( http_host, current.request.env.path_info ) + if current.request.env.wsgi_url_scheme in [ 'https', 'HTTPS' ]: + scheme = 'https' + else: + scheme = 'http' + self.cas_my_url='%s://%s%s'%( scheme, http_host, current.request.env.path_info ) def login_url( self, next = "/" ): current.session.token=self._CAS_login() return next @@ -95,15 +99,15 @@ a,b,c = data[1].split( ':' )+[None,None] return dict(user=a,email=b,username=c) return None + import xml.dom.minidom as dom + import xml.parsers.expat as expat try: - import xml.dom.minidom as dom - import xml.parsers.expat as expat dxml=dom.parseString(data) envelop = dxml.getElementsByTagName("cas:authenticationSuccess") if len(envelop)>0: res = dict() for x in envelop[0].childNodes: - if x.nodeName.startswith('cas:'): + if x.nodeName.startswith('cas:') and len(x.childNodes): key = x.nodeName[4:].encode('utf8') value = x.childNodes[0].nodeValue.encode('utf8') if not key in res: @@ -113,7 +117,7 @@ res[key]=[res[key]] res[key].append(value) return res - except ExpatError: pass + except expat.ExpatError: pass return None # fallback