1 __all__ = []
2
4 """
5 Internal Exception class that is thrown inside L{AuthenticationMiddleware},
6 but not visible to other code.
7 """
8
11
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
22 """
23 @param app: is a WSGI application.
24 """
25 assert self.authorization_method is not None
26 self.app = app
27
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
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
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