WebStack

Annotated examples/Common/Login/__init__.py

149:ef8ed7f6e97a
2004-05-30 paulb [project @ 2004-05-30 15:58:16 by paulb] Moved anonymous user handling back into LoginRedirect which sets the anonymous user cookie.
paulb@126 1
#!/usr/bin/env python
paulb@126 2
paulb@126 3
"An example login screen."
paulb@126 4
paulb@126 5
import WebStack.Generic
paulb@143 6
from WebStack.Helpers.Auth import get_token
paulb@126 7
paulb@126 8
class LoginResource:
paulb@126 9
paulb@126 10
    "A resource providing a login screen."
paulb@126 11
paulb@149 12
    def __init__(self, authenticator, use_redirect=1):
paulb@126 13
paulb@138 14
        """
paulb@145 15
        Initialise the resource with an 'authenticator'.
paulb@145 16
paulb@145 17
        If the optional 'use_redirect' flag is set to 0, a confirmation screen is given
paulb@145 18
        instead of redirecting the user back to the original application.
paulb@138 19
        """
paulb@126 20
paulb@126 21
        self.authenticator = authenticator
paulb@138 22
        self.use_redirect = use_redirect
paulb@126 23
paulb@126 24
    def respond(self, trans):
paulb@126 25
paulb@145 26
        fields_path = trans.get_fields_from_path()
paulb@145 27
        fields_body = trans.get_fields_from_body()
paulb@145 28
paulb@145 29
        # NOTE: Handle missing redirects better.
paulb@145 30
paulb@145 31
        if fields_body.has_key("redirect"):
paulb@145 32
            redirects = fields_body["redirect"]
paulb@145 33
            redirect = redirects[0]
paulb@145 34
        elif fields_path.has_key("redirect"):
paulb@145 35
            redirects = fields_path["redirect"]
paulb@145 36
            redirect = redirects[0]
paulb@145 37
        else:
paulb@145 38
            redirect = ""
paulb@126 39
paulb@149 40
        # Check for a submitted login form.
paulb@145 41
paulb@149 42
        if fields_body.has_key("login"):
paulb@126 43
            if self.authenticator.authenticate(trans):
paulb@145 44
                self._redirect(trans, redirect)
paulb@145 45
paulb@145 46
        # Otherwise, show the login form.
paulb@126 47
paulb@138 48
        self._show_login(trans, redirect)
paulb@138 49
paulb@145 50
    def _redirect(self, trans, redirect):
paulb@145 51
paulb@145 52
        "Redirect the client using 'trans' and the given 'redirect' URL."
paulb@145 53
paulb@145 54
        if self.use_redirect:
paulb@145 55
            trans.set_header_value("Location", redirect)
paulb@145 56
            trans.set_response_code(307)
paulb@145 57
paulb@145 58
        # Show the success page anyway.
paulb@145 59
paulb@145 60
        self._show_success(trans, redirect)
paulb@145 61
paulb@138 62
    def _show_login(self, trans, redirect):
paulb@138 63
paulb@126 64
        # When authentication fails or is yet to take place, show the login
paulb@126 65
        # screen.
paulb@126 66
paulb@135 67
        trans.set_content_type(WebStack.Generic.ContentType("text/html"))
paulb@126 68
        out = trans.get_response_stream()
paulb@126 69
        out.write("""
paulb@126 70
<html>
paulb@126 71
  <head>
paulb@126 72
    <title>Login Example</title>
paulb@126 73
  </head>
paulb@126 74
  <body>
paulb@126 75
    <h1>Login</h1>
paulb@126 76
    <form method="POST">
paulb@126 77
      <p>Username: <input name="username" type="text" size="12"/></p>
paulb@126 78
      <p>Password: <input name="password" type="text" size="12"/></p>
paulb@126 79
      <p><input name="login" type="submit" value="Login"/></p>
paulb@126 80
      <input name="redirect" type="hidden" value="%s"/>
paulb@126 81
    </form>
paulb@126 82
  </body>
paulb@126 83
</html>
paulb@126 84
""" % redirect)
paulb@126 85
paulb@138 86
    def _show_success(self, trans, redirect):
paulb@138 87
paulb@138 88
        # When authentication fails or is yet to take place, show the login
paulb@138 89
        # screen.
paulb@138 90
paulb@138 91
        trans.set_content_type(WebStack.Generic.ContentType("text/html"))
paulb@138 92
        out = trans.get_response_stream()
paulb@138 93
        out.write("""
paulb@138 94
<html>
paulb@138 95
  <head>
paulb@138 96
    <title>Login Example</title>
paulb@138 97
  </head>
paulb@138 98
  <body>
paulb@138 99
    <h1>Login Successful</h1>
paulb@138 100
    <p>Please proceed <a href="%s">to the application</a>.</p>
paulb@138 101
  </body>
paulb@138 102
</html>
paulb@138 103
""" % redirect)
paulb@138 104
paulb@135 105
    def _decode(self, url):
paulb@135 106
paulb@135 107
        "Decode the given 'url' for redirection purposes."
paulb@135 108
paulb@135 109
        return url.replace("%3f", "?").replace("%26", "&")
paulb@135 110
paulb@126 111
class LoginAuthenticator:
paulb@126 112
paulb@130 113
    def __init__(self, secret_key, credentials, cookie_name=None):
paulb@126 114
paulb@130 115
        """
paulb@130 116
        Initialise the authenticator with a 'secret_key', the authenticator's registry of
paulb@130 117
        'credentials' and an optional 'cookie_name'.
paulb@126 118
paulb@130 119
        The 'credentials' must be an object which supports tests of the form
paulb@130 120
        '(username, password) in credentials'.
paulb@130 121
        """
paulb@126 122
paulb@126 123
        self.secret_key = secret_key
paulb@130 124
        self.credentials = credentials
paulb@130 125
        self.cookie_name = cookie_name or "LoginAuthenticator"
paulb@126 126
paulb@126 127
    def authenticate(self, trans):
paulb@126 128
paulb@126 129
        # Process any supplied parameters.
paulb@126 130
paulb@126 131
        fields = trans.get_fields_from_body()
paulb@126 132
paulb@126 133
        if fields.has_key("username") and fields.has_key("password"):
paulb@126 134
            usernames, passwords = fields["username"], fields["password"]
paulb@126 135
paulb@126 136
            # Insist on only one username and password.
paulb@126 137
paulb@126 138
            if len(usernames) == 1 and len(passwords) == 1:
paulb@126 139
                username, password = usernames[0], passwords[0]
paulb@126 140
paulb@126 141
                # Check against the class's credentials.
paulb@126 142
paulb@126 143
                if (username, password) in self.credentials:
paulb@126 144
paulb@126 145
                    # Make a special cookie token.
paulb@126 146
paulb@145 147
                    self.set_token(trans, username)
paulb@126 148
                    return 1
paulb@126 149
paulb@126 150
        return 0
paulb@126 151
paulb@145 152
    def set_token(self, trans, username):
paulb@145 153
paulb@145 154
        "Set an authentication in the 'trans' with the given 'username'."
paulb@145 155
paulb@145 156
        trans.set_cookie_value(
paulb@145 157
            self.cookie_name,
paulb@145 158
            get_token(username, self.secret_key)
paulb@145 159
        )
paulb@145 160
paulb@126 161
# vim: tabstop=4 expandtab shiftwidth=4