File: api.py

package info (click to toggle)
python-authkit 0.4.1~r143-1
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 740 kB
  • ctags: 703
  • sloc: python: 4,643; makefile: 39; sh: 33
file content (119 lines) | stat: -rw-r--r-- 4,438 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""SSO API's

This module supplies the common abstract redirection-based SSO system used by
a variety of University SSO systems.

Generally the SSO system will throw a redirect for the authentication to be
performed elsewhere. Upon the user being redirected back, a verification 
process will be done to ensure they actually logged on.

It's also possible for some SSO systems to have more full fledged sign-on 
systems that operate as middleware in addition to purely processing a sign-on
request.
"""
import logging

from elementtree import ElementTree
from paste.request import construct_url
from paste.util.converters import asbool
from paste.httpexceptions import HTTPNotFound, HTTPSeeOther, HTTPForbidden
from paste.wsgiwrappers import WSGIRequest

from authkit.authenticate.multi import MultiHandler, status_checker
from authkit.authenticate import AuthKitConfigError
from authkit.authorize import NotAuthenticatedError

log = logging.getLogger(__name__)

class LoginFailure(HTTPForbidden):
    """ The exception raised if the verification fails """


class RedirectingAuthHandler(object):
    """Handles generating redirect to SSO system
    
    This application should implement a ``redirect_url`` method that will
    generate a redirect URL to the
    """
    def __call__(self, environ, start_response):
        request = WSGIRequest(environ)
        url = self.redirect_url(environ)
        log.debug("Sending redirect to %s", url)
        return HTTPSeeOther(url).wsgi_application(environ, start_response)


class RedirectingAuthMiddleware(object):
    def __init__(self, app, **kwargs):
        """Subclass should save several basic variables
        
        The application object should be saved to self.app, and the path
        handling for URL dispatch should be in a dict saved to self.dispatch
        like so:
        
        .. code-block :: Python
            
            class MyRedirectMiddleware(RedirectingAuthMiddleware):
                def __init__(self, app, path, use_options=False):
                    self.app = app
                    self.protect = []
                    self.dispatch = {
                        '/verify':'verify',
                        '/process':'handle_process'
                    }
                    self.path = '/cas2'
                
                def verify(self, environ, start_response):
                    # called for /cas2/verify
                    pass
                
                def handle_process(self, environ, start_response):
                    # called for /cas2/process
                    pass
        """
        raise NotImplemented()
    
    def __call__(self, environ, start_response):
        path = environ['PATH_INFO']
        
        if path in self.dispatch:
            log.debug("Found %s in dispatch path, calling method %s", 
                      path, self.dispath[path])
            return getattr(self, self.path + 
                           self.dispatch[path])(environ, start_response)
        
        for route in self.protect:
            if path.startswith(route) and 'REMOTE_USER' not in environ \
               and 'type=' + self.type in environ['QUERY_STRING']:
                log.debug("Found %s in protection paths. No REMOTE_USER set,"
                          " running auth verify.", path)
                return self.verify(environ, start_response)
            elif path.startswith(route):
                return NotAuthenticatedError()(environ, start_response)
        
        log.debug("Path: %s not in protect list %s.", path, self.protect)
        return self.app(environ, start_response)
    
    def verify(self):
        """Perform verification of redirection"""
        raise NotImplemented()
    
    def redirect_url(self):
        """Construct the redirect URL"""
        raise NotImplemented()


def find_multi_app(app):
    """Walks an app assuming it is a middleware stack with apps glued on at 
    either self.app or self.application
    
    Returns a tuple of the MultiHandler app ref and the possibly new app 
    stack. If a multihandler app wasn't found, then it will be at the top of 
    the returned app.
    """
    tempref = app
    while not isinstance(tempref, MultiHandler):
        tempref = getattr(tempref, 'app', getattr(tempref, 'application', None))
        if tempref is None:
            app = MultiHandler(app)
            tempref = app
    return tempref, app