Changeset 88
- Timestamp:
- 06/13/07 20:58:55
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
AuthKit/branches/0.4/authkit/authenticate/sso/__init__.py
r78 r88 25 25 SSO schemes like LID may also be supported. 26 26 27 27 These systems sub-class the ``RedirectingAuthMiddleware`` from the api package 28 as they all utilize a similar scheme of authentcation via redirection with 29 back-end verification. 28 30 29 31 .. note:: AuthKit/branches/0.4/authkit/authenticate/sso/api.py
r84 r88 20 20 21 21 from authkit.authenticate.multi import MultiHandler, status_checker 22 from authkit.authenticate import AuthKitConfigError 22 23 23 24 class LoginFailure(HTTPForbidden): … … 32 33 def __call__(self, environ, start_response): 33 34 request = WSGIRequest(environ) 34 url = self.redirect_url( self,environ)35 return HTTPSeeOther( ).wsgi_application(environ, start_response)35 url = self.redirect_url(environ) 36 return HTTPSeeOther(url).wsgi_application(environ, start_response) 36 37 37 38 class RedirectingAuthMiddleware(object): … … 90 91 tempref = app 91 92 while not isinstance(tempref, MultiHandler): 92 tempref = getattr( cur_app, 'app', getattr(cur_app, 'application', None))93 tempref = getattr(tempref, 'app', getattr(tempref, 'application', None)) 93 94 if tempref is None: 94 95 app = MultiHandler(app) AuthKit/branches/0.4/authkit/authenticate/sso/cas.py
r78 r88 5 5 service tickets. 6 6 7 Note that this does not implement proxy granting ticket requests, merely 8 CAS 2.0 service validation (which can take proxy tickets). 7 9 8 10 `Protocol Reference <http://www.ja-sig.org/products/cas/overview/protocol/index.html>`_ 9 11 """ 12 import logging 10 13 import urllib 11 from elementtree import ElementTree12 14 13 from paste.request import construct_url 14 from paste.util.converters import asbool 15 from authkit.authenticate.sso.api import * 15 16 16 from authkit.authenticate.sso.api import RedirectingAuthMiddleware 17 from authkit.authenticate.multi import MultiHandler, status_checker 17 log = logging.getLogger('authkit.authenticate.sso.cas') 18 18 19 class AuthCASHandler(RedirectingAuthMiddleware): 19 class AuthCASHandler(RedirectingAuthHandler): 20 """CAS 1.0 and 2.0 Redirect Handler 21 22 This small middleware piece handles generating the redirect URL for the 23 CAS 24 """ 25 def __init__(self, app, authority, path='casauth', use_cas2=False): 26 self.app = app 27 self.authority = authority 28 self.path = path 29 self._cas2 = use_cas2 30 31 def redirect_url(self, environ): 32 kwargs = {'service': construct_url(environ, script_name='', 33 path_info=self.path + '/verify')} 34 35 # XXX TODO: Store this for the middleware below, also look for a proxy 36 # granting ticket option to store that its desired 37 if 'authkit.cas.renew' in environ: 38 kwargs['renew'] = 'true' 39 if 'authkit.cas.gateway' in environ: 40 kwargs['gateway'] = 'true' 41 42 # renew and gateway should not both be set at once according to 43 # CAS protocol 44 assert 'renew' not in kwargs 45 46 args = urllib.urlencode(kwargs) 47 return self.authority + "login?" + args 48 49 class AuthCASMiddleware(RedirectingAuthMiddleware): 20 50 """CAS 1.0 and 2.0 Capable Authentication Handler""" 21 51 def __init__(self, app, authority, use_cas2=False): … … 27 57 else: 28 58 self._authtype = 'CAS 1.0' 29 30 def do_verify(self, req): 31 return req.GET.get('ticket') 32 33 def verify(self, req): 59 self.dispatch = {'/verify':'verify'} 60 61 def verify(self, environ, start_response): 62 req = WSGIRequest(environ) 63 if 'ticket' not in req.GET: 64 return HTTPNotFound().wsgi_application(environ, start_response) 65 34 66 ticket = req.GET['ticket'] 67 35 68 service = construct_url(environ) 36 kwargs = {'service': service, 'ticket':ticket}69 kwargs = {'service': service, 'ticket':ticket} 37 70 if req.environ.get('authkit.sso.cas.renew'): 38 71 kwargs['renew'] = 'true' 39 72 args = urllib.urlencode(kwargs) 73 74 # XXX TODO: Store whether renew was used for this request to ensure 75 # that the validation asks for it as well 76 # Also store whether a proxy ticket was requested and ask for 77 # it during validation 40 78 if self._cas2: 41 requrl = self.authority + "serviceValidate?" + args 79 # We use proxyValidate for CAS 2.0 because it will handle both 80 # service and proxy ticket validation 81 requrl = self.authority + "proxyValidate?" + args 42 82 response = urllib.urlopen(requrl).read() 43 83 tree = ElementTree.fromstring(response) … … 46 86 if success: 47 87 results['user'] = tree[0][0].text 88 results['extra_environ'] = {} 89 90 # Did we get a proxy ticket? 91 if len(tree[0]) > 1 and tree[0][1].tag.endswith('proxyGrantingTicket'): 92 results['authkit.cas.proxyTicket'] = tree[0][1].text.strip() 93 94 # Any proxies returned as well? 95 if len(tree[0] > 2): 96 proxies = [x.text.strip() for x in tree[0][2]] 97 results['authkit.cas.proxies'] = proxies 98 else: 99 log.info('Authentication failed for auth: %s, ticket %s, ' 100 'response: %s', self._authtype, ticket, 101 tree[0].attrib['code']) 48 102 else: 49 103 requrl = self.authority + "validate?" + args … … 53 107 if valid: 54 108 results['user'] = result[1] 55 return valid, results 56 57 def redirect_url(self, req): 58 args = urllib.urlencode({'service': construct_url(environ)}) 59 return self.authority + "login?" + args 109 else: 110 log.info('Authentication failed for auth: %s, ticket %s, ' 111 'response: %s', self._authtype, ticket, result[0]) 112 113 if not valid: 114 return LoginFailure().wsgi_application(environ, start_response) 115 environ['AUTH_TYPE'] = self._authtype 116 environ['REMOTE_USER'] = results['user'] 117 118 # Add in optional environ data from the auth system 119 if 'extra_environ' in results: 120 environ.update(results['extra_environ']) 121 122 return self.app(environ, start_response) 60 123 61 124 def make_cas_handler(app, auth_conf, app_conf=None, global_conf=None, 62 125 prefix='authkit.sso.cas'): 63 if not auth_conf.has_key('internalpath'): 64 raise AuthKitConfigError("No %sinternalpath key specified"%prefix) 65 app = MultiHandler(app) 66 cas2 = asbool(auth_conf.get('use_cas2', False)) 67 app.add_method('cas', AuthCASHandler, auth_conf['authority'], cas2) 68 app.add_checker('cas', status_checker) 126 if 'authority' not in auth_conf: 127 raise AuthKitConfigError("No %sauthority key specified" % prefix) 128 kwargs = dict(authority=auth_conf['authority']) 129 if 'use_cas2' in auth_conf: 130 kwargs['use_cas2'] = True 131 if 'path' in auth_conf: 132 kwargs['path'] = auth_conf['path'] 133 134 multi_app, app = find_multi_app(app) 135 multi_app.add_method('cas', AuthCASHandler, **kwargs) 136 multi_app.add_checker('cas', status_checker) 137 138 app = AuthCASMiddleware(app, **kwargs) 69 139 return app
