File: form.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 (153 lines) | stat: -rw-r--r-- 5,245 bytes parent folder | download
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""Form and cookie based authentication middleware

As with all the other AuthKit middleware, this middleware is described in
detail in the AuthKit manual and should be used via the
``authkit.authenticate.middleware`` function.

The option form.status can be set to "200 OK" if the Pylons error document
middleware is intercepting the 401 response and just showing the standard 401
error document. This will not happen in recent versions of Pylons (0.9.6)
because this middleware sets the environ['pylons.error_call'] key so that the
error documents middleware doesn't intercept the response.

From AuthKit 0.4.1 using 200 OK when the form is shown is now the default. 
This is so that Safari 3 Beta displays the page rather than trying to 
handle the response itself as a basic or digest authentication.

The username and password are username2, password2 and الإعلاني, password1
respectively.
"""

from paste.auth.form import AuthFormHandler
from paste.request import construct_url, parse_formvars
from authkit.authenticate import get_template, valid_password, \
   get_authenticate_function, strip_base, RequireEnvironKey, \
   AuthKitAuthHandler
from authkit.authenticate.multi import MultiHandler, status_checker

import logging
log = logging.getLogger('authkit.authenticate.form')

def template():
    return """\
<html>
  <head><title>Please Sign In</title></head>
  <body>
    <h1>Please Sign In</h1>
    <form action="%s" method="post">
      <dl>
        <dt>Username:</dt>
        <dd><input type="text" name="username"></dd>
        <dt>Password:</dt>
        <dd><input type="password" name="password"></dd>
      </dl>
      <input type="submit" name="authform" value="Sign In" />
    </form>
  </body>
</html>
"""

class FormAuthHandler(AuthKitAuthHandler, AuthFormHandler):
    def __init__(
        self, 
        app,
        charset=None,
        status="200 OK",
        **p
    ):
        AuthFormHandler.__init__(self, app, **p)
        self.status = status
        if charset is None:
            self.charset = ''
        else:
            self.charset = '; charset='+charset
    
    def on_authorized(self, environ, start_response):
        environ['paste.auth_tkt.set_user'](userid=environ['REMOTE_USER'])
        return self.application(environ, start_response)
        
    def __call__(self, environ, start_response):
        # Shouldn't ever allow a response if this is called via the 
        # multi handler
        username = environ.get('REMOTE_USER','')
        if 'POST' == environ['REQUEST_METHOD']:
            formvars = parse_formvars(environ, include_get_vars=False)
            username = formvars.get('username')
            password = formvars.get('password')
            if username and password:
                if self.authfunc(environ, username, password):
                    environ['AUTH_TYPE'] = 'form'
                    environ['REMOTE_USER'] = username
                    environ['REQUEST_METHOD'] = 'GET'
                    environ['CONTENT_LENGTH'] = ''
                    environ['CONTENT_TYPE'] = ''
                    del environ['paste.parsed_formvars']
                    return self.on_authorized(environ, start_response)
        action =  construct_url(environ)
        log.debug("Form action is: %s", action)
        content = self.template() % action
        # @@@ Tell Pylons error documents middleware not to intercept the 
        # response
        environ['pylons.error_call'] = 'authkit'
        start_response(self.status,[('Content-Type', 'text/html'+self.charset),
                                 ('Content-Length', str(len(content)))])
        return [content]

def load_form_config(
    app, 
    auth_conf, 
    app_conf=None,
    global_conf=None,
    prefix='authkit.method.form',
):
    app = RequireEnvironKey(
        app,
        'paste.auth_tkt.set_user',
        missing_error=(
            'Missing the key %(key)s from the environ. '
            'Have you added the cookie method after the form method?'
        )
    )
    template_conf = strip_base(auth_conf, 'template.')
    if template_conf:
        template_ = get_template(template_conf, prefix=prefix+'template.')
    else:
        template_ = template
    authenticate_conf = strip_base(auth_conf, 'authenticate.')
    app, authfunc, users = get_authenticate_function(
        app, 
        authenticate_conf, 
        prefix=prefix+'authenticate.', 
        format='basic'
    )
    charset=auth_conf.get('charset')
    return app, {'authfunc':authfunc, 'template':template_, 'charset':charset}, None

def make_form_handler(
    app, 
    auth_conf, 
    app_conf=None,
    global_conf=None,
    prefix='authkit.method.form', 
):
    app, auth_handler_params, user_setter_params = load_form_config(
        app, 
        auth_conf, 
        app_conf=None,
        global_conf=None,
        prefix='authkit.method.form',
    )
    app = MultiHandler(app)
    app.add_method(
        'form', 
        FormAuthHandler, 
        authfunc=auth_handler_params['authfunc'], 
        template=auth_handler_params['template'], 
        charset=auth_handler_params['charset']
    )
    app.add_checker('form', status_checker)
    return app

# Backwards compatbility
Form = FormAuthHandler