Package wsgitools :: Module authentication
[hide private]
[frames] | no frames]

Source Code for Module wsgitools.authentication

  1  __all__ = [] 
  2   
3 -class AuthenticationRequired(Exception):
4 """ 5 Internal Exception class that is thrown inside L{AuthenticationMiddleware}, 6 but not visible to other code. 7 """
8
9 -class ProtocolViolation(AuthenticationRequired):
10 pass
11
12 -class AuthenticationMiddleware(object):
13 """Base class for HTTP authorization schemes. 14 15 @cvar authorization_method: the implemented Authorization method. It will 16 be verified against Authorization headers. Subclasses must define this 17 attribute. 18 @type authorization_method: str 19 """ 20 authorization_method = None
21 - def __init__(self, app):
22 """ 23 @param app: is a WSGI application. 24 """ 25 assert self.authorization_method is not None 26 self.app = app
27
28 - def authenticate(self, auth, environ):
29 """Try to authenticate a request. The Authorization header is examined 30 and checked agains the L{authorization_method} before being passed to 31 this method. This method must either raise an AuthenticationRequired 32 instance or return a dictionary explaining what was successfully 33 authenticated. 34 35 @type auth: str 36 @param auth: is the part of the Authorization header after the method 37 @type environ: {str: object} 38 @param environ: is the environment passed with a WSGI request 39 @rtype: {str: object} 40 @returns: a dictionary that provides a key "user" listing the 41 authenticated username as a string. It may also provide the key 42 "outheaders" with a [(str, str)] value to extend the response 43 headers. 44 @raises AuthenticationRequired: if the authentication was unsuccessful 45 """ 46 raise NotImplementedError
47
48 - def __call__(self, environ, start_response):
49 """wsgi interface 50 51 @type environ: {str: object} 52 """ 53 assert isinstance(environ, dict) 54 try: 55 try: 56 auth = environ["HTTP_AUTHORIZATION"] 57 except KeyError: 58 raise AuthenticationRequired("no Authorization header found") 59 try: 60 method, rest = auth.split(' ', 1) 61 except ValueError: 62 method, rest = auth, "" 63 if method.lower() != self.authorization_method: 64 raise AuthenticationRequired( 65 "authorization method not implemented: %r" % method) 66 result = self.authenticate(rest, environ) 67 except AuthenticationRequired as exc: 68 return self.authorization_required(environ, start_response, exc) 69 assert isinstance(result, dict) 70 assert "user" in result 71 environ["REMOTE_USER"] = result["user"] 72 if "outheaders" in result: 73 def modified_start_response(status, headers, exc_info=None): 74 assert isinstance(headers, list) 75 headers.extend(result["outheaders"]) 76 return start_response(status, headers, exc_info)
77 else: 78 modified_start_response = start_response 79 return self.app(environ, modified_start_response)
80
81 - def www_authenticate(self, exception):
82 """Generates a WWW-Authenticate header. Subclasses must implement this 83 method. 84 85 @type exception: L{AuthenticationRequired} 86 @param exception: reason for generating the header 87 @rtype: (str, str) 88 @returns: the header as (part_before_colon, part_after_colon) 89 """ 90 raise NotImplementedError
91
92 - def authorization_required(self, environ, start_response, exception):
93 """Generate an error page after failed authentication. Apart from the 94 exception parameter, this method behaves like a WSGI application. 95 96 @type exception: L{AuthenticationRequired} 97 @param exception: reason for the authentication failure 98 """ 99 status = "401 Authorization required" 100 html = b"<html><head><title>401 Authorization required</title></head>" \ 101 b"<body><h1>401 Authorization required</h1></body></html>" 102 headers = [("Content-Type", "text/html"), 103 self.www_authenticate(exception), 104 ("Content-Length", str(len(html)))] 105 start_response(status, headers) 106 if environ["REQUEST_METHOD"].upper() == "HEAD": 107 return [] 108 return [html]
109