1.1 --- a/WebStack/Resources/LoginRedirect.py Sun Aug 24 20:51:10 2008 +0200
1.2 +++ b/WebStack/Resources/LoginRedirect.py Sat Nov 15 02:33:06 2008 +0100
1.3 @@ -26,12 +26,42 @@
1.4
1.5 class LoginRedirectResource:
1.6
1.7 - "A resource redirecting to a login URL."
1.8 + """
1.9 + A resource redirecting to a login URL. A number of class attributes can be
1.10 + set or overridden by instance attributes:
1.11 +
1.12 + * anonymous_parameter_name - if set to a value other than None, clients
1.13 + providing a parameter of that name in the
1.14 + URL will not be authenticated, but then
1.15 + such clients will get a predefined user
1.16 + identity associated with them, configurable
1.17 + using 'anonymous_username'
1.18 +
1.19 + * logout_parameter_name - if set to a value other than None, clients
1.20 + providing a parameter of that name in the URL
1.21 + will become logged out; after logging out,
1.22 + clients are redirected to a location which can
1.23 + be configured by 'logout_url'
1.24
1.25 - def __init__(self, resource, authenticator, login_url=None, app_url=None,
1.26 - anonymous_parameter_name=None, anonymous_username="anonymous",
1.27 - logout_parameter_name=None, logout_url="/", use_logout_redirect=1,
1.28 - urlencoding=None, path_encoding=None):
1.29 + * use_logout_redirect - if set to 0, a confirmation screen is given
1.30 + instead of redirecting the user to 'logout_url'
1.31 +
1.32 + * path_encoding' (previously 'urlencoding') allows a special encoding to
1.33 + be used in producing the redirection path
1.34 +
1.35 + To change the page used by this resource, either redefine the
1.36 + 'logout_page' attribute in instances of this class or a subclass, or
1.37 + override the 'show_logout' method.
1.38 + """
1.39 +
1.40 + anonymous_parameter_name = None
1.41 + anonymous_username = "anonymous"
1.42 + logout_parameter_name = None
1.43 + logout_url = "/"
1.44 + use_logout_redirect = 1
1.45 + path_encoding = None
1.46 +
1.47 + def __init__(self, resource, authenticator, login_url=None, app_url=None):
1.48
1.49 """
1.50 Initialise the resource with a 'resource' for the application being
1.51 @@ -45,39 +75,12 @@
1.52
1.53 The 'app_url' should be the "bare" reference using a protocol, host
1.54 and port, not including any path information.
1.55 -
1.56 - If the optional 'anonymous_parameter_name' is set, clients providing a
1.57 - parameter of that name in the URL will not be authenticated, but then
1.58 - such clients will get a predefined user identity associated with them,
1.59 - configurable using the optional 'anonymous_username'.
1.60 -
1.61 - If the optional 'logout_parameter_name' is set, clients providing a
1.62 - parameter of that name in the URL will become logged out. After logging
1.63 - out, clients are redirected to a location which can be configured by the
1.64 - optional 'logout_url'.
1.65 -
1.66 - If the optional 'use_logout_redirect' flag is set to 0, a confirmation
1.67 - screen is given instead of redirecting the user to the 'logout_url'.
1.68 -
1.69 - The optional 'path_encoding' parameter (previously 'urlencoding', which
1.70 - is still supported) allows a special encoding to be used in producing
1.71 - the redirection path.
1.72 -
1.73 - To change the page used by this resource, either redefine the
1.74 - 'logout_page' attribute in instances of this class or a subclass, or
1.75 - override the 'show_logout' method.
1.76 """
1.77
1.78 self.login_url = login_url
1.79 self.app_url = app_url
1.80 self.resource = resource
1.81 self.authenticator = authenticator
1.82 - self.anonymous_parameter_name = anonymous_parameter_name
1.83 - self.anonymous_username = anonymous_username
1.84 - self.logout_parameter_name = logout_parameter_name
1.85 - self.logout_url = logout_url
1.86 - self.use_logout_redirect = use_logout_redirect
1.87 - self.path_encoding = path_encoding or urlencoding
1.88
1.89 def respond(self, trans):
1.90
1.91 @@ -179,6 +182,28 @@
1.92 </html>
1.93 """
1.94
1.95 +class SiteLoginRedirectResource(LoginRedirectResource):
1.96 +
1.97 + "Login redirection within a site."
1.98 +
1.99 + site_attribute_name = "root"
1.100 +
1.101 + def _get_url(self, trans, site_relative_url):
1.102 +
1.103 + "Return the URL, using 'trans', for the given 'site_relative_url'."
1.104 +
1.105 + return trans.get_attributes()[self.site_attribute_name] + site_relative_url
1.106 +
1.107 + def get_login_url(self, trans):
1.108 +
1.109 + """
1.110 + Return the login URL, using 'trans' if necessary, in order to
1.111 + provide a complete URL to redirect an authenticated user to their
1.112 + originally requested page.
1.113 + """
1.114 +
1.115 + return self._get_url(trans, LoginRedirectResource.get_login_url(self, trans))
1.116 +
1.117 class LoginRedirectAuthenticator(Verifier):
1.118
1.119 """
2.1 --- a/WebStack/Resources/Selectors.py Sun Aug 24 20:51:10 2008 +0200
2.2 +++ b/WebStack/Resources/Selectors.py Sat Nov 15 02:33:06 2008 +0100
2.3 @@ -4,7 +4,7 @@
2.4 Resources which "select" other resources, sometimes causing desirable
2.5 side-effects.
2.6
2.7 -Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk>
2.8 +Copyright (C) 2007, 2008 Paul Boddie <paul@boddie.org.uk>
2.9
2.10 This library is free software; you can redistribute it and/or
2.11 modify it under the terms of the GNU Lesser General Public
2.12 @@ -138,4 +138,62 @@
2.13 finally:
2.14 self.store.rollback()
2.15
2.16 +class ConditionalAuthSelector:
2.17 +
2.18 + """
2.19 + Test for the presence of authenticated user information, dispatching to the
2.20 + authenticating resource where no such information can be found, dispatching
2.21 + beyond the authenticating resource otherwise.
2.22 + """
2.23 +
2.24 + def __init__(self, resource):
2.25 +
2.26 + """
2.27 + Initialise the selector with the given authenticating 'resource' which
2.28 + would normally conduct an authentication process unconditionally. This
2.29 + 'resource' must itself have an attribute called 'resource' in order to
2.30 + support dispatch beyond the authentication mechanisms where
2.31 + authentication has already taken place.
2.32 + """
2.33 +
2.34 + self.resource = resource
2.35 +
2.36 + def respond(self, trans):
2.37 +
2.38 + """
2.39 + Respond to the transaction 'trans', either dispatching to this object's
2.40 + resource for authentication, or if authentication has already taken
2.41 + place and a user has been set, dispatching to the target of the resource
2.42 + - the resource wrapped by the authenticating resource.
2.43 + """
2.44 +
2.45 + if trans.get_user() is None:
2.46 + self.resource.respond(trans)
2.47 + else:
2.48 + self.resource.resource.respond(trans)
2.49 +
2.50 +class AuthInfoSelector:
2.51 +
2.52 + """
2.53 + A selector which ensures that any information set by authenticators is made
2.54 + available.
2.55 + """
2.56 +
2.57 + def __init__(self, resource, authenticator):
2.58 +
2.59 + "Initialise the selector with the given 'resource' and 'authenticator'."
2.60 +
2.61 + self.resource = resource
2.62 + self.authenticator = authenticator
2.63 +
2.64 + def respond(self, trans):
2.65 +
2.66 + """
2.67 + Respond to 'trans' by performing authentication and forwarding the
2.68 + request.
2.69 + """
2.70 +
2.71 + self.authenticator.authenticate(trans)
2.72 + self.resource.respond(trans)
2.73 +
2.74 # vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/WebStack/Resources/Static.py Sun Aug 24 20:51:10 2008 +0200
3.2 +++ b/WebStack/Resources/Static.py Sat Nov 15 02:33:06 2008 +0100
3.3 @@ -3,7 +3,7 @@
3.4 """
3.5 Resources for serving static content.
3.6
3.7 -Copyright (C) 2004, 2005, 2006 Paul Boddie <paul@boddie.org.uk>
3.8 +Copyright (C) 2004, 2005, 2006, 2007, 2008 Paul Boddie <paul@boddie.org.uk>
3.9
3.10 This library is free software; you can redistribute it and/or
3.11 modify it under the terms of the GNU Lesser General Public
3.12 @@ -22,6 +22,7 @@
3.13
3.14 from WebStack.Generic import ContentType, EndOfResponse
3.15 import os
3.16 +import email.utils
3.17
3.18 class DirectoryResource:
3.19
3.20 @@ -117,7 +118,11 @@
3.21
3.22 # Write the file to the client.
3.23
3.24 - f = open(os.path.join(self.directory, filename), "rb")
3.25 + pathname = os.path.join(self.directory, filename)
3.26 + mtime = email.utils.formatdate(os.path.getmtime(pathname), usegmt=1)
3.27 + trans.set_header_value("Last-Modified", mtime)
3.28 +
3.29 + f = open(pathname, "rb")
3.30 out.write(f.read())
3.31 f.close()
3.32
3.33 @@ -143,7 +148,10 @@
3.34 self.content_type = content_type
3.35
3.36 def respond(self, trans):
3.37 + mtime = email.utils.formatdate(os.path.getmtime(self.filename), usegmt=1)
3.38 +
3.39 trans.set_content_type(self.content_type)
3.40 + trans.set_header_value("Last-Modified", mtime)
3.41 f = open(self.filename, "rb")
3.42 trans.get_response_stream().write(f.read())
3.43 f.close()
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/examples/Common/SimpleWithLogin/__init__.py Sat Nov 15 02:33:06 2008 +0100
4.3 @@ -0,0 +1,41 @@
4.4 +#!/usr/bin/env python
4.5 +
4.6 +from WebStack.Generic import ContentType
4.7 +from WebStack.Resources.LoginRedirect import LoginRedirectResource, LoginRedirectAuthenticator
4.8 +from WebStack.Resources.Login import LoginResource, LoginAuthenticator
4.9 +from WebStack.Resources.ResourceMap import MapResource
4.10 +from Simple import SimpleResource
4.11 +
4.12 +def get_site_map(app_url, login_url, secret_key):
4.13 +
4.14 + """
4.15 + Resource a resource for the site having the given 'app_url' and 'login_url',
4.16 + using the given 'secret_key' for authentication tokens.
4.17 + """
4.18 +
4.19 + simple = LoginRedirectResource(
4.20 + login_url=login_url,
4.21 + app_url=app_url,
4.22 + resource=SimpleResource(),
4.23 + authenticator=LoginRedirectAuthenticator(secret_key=secret_key)
4.24 + )
4.25 +
4.26 + simple.anonymous_parameter_name = "anonymous"
4.27 + simple.logout_parameter_name = "logout"
4.28 +
4.29 + return MapResource({
4.30 + "simple" : simple,
4.31 + "login" :
4.32 + LoginResource(
4.33 + LoginAuthenticator(
4.34 + secret_key=secret_key,
4.35 + credentials=(
4.36 + ("badger", "abc"),
4.37 + ("vole", "xyz"),
4.38 + )
4.39 + )
4.40 + ),
4.41 + "" : simple
4.42 + })
4.43 +
4.44 +# vim: tabstop=4 expandtab shiftwidth=4