~openerp-commiter/openobject-addons/trunk-extra-addons

« back to all changes in this revision

Viewing changes to document/webdav/DAV/AuthServer.py

  • Committer: nel
  • Date: 2007-10-01 05:36:04 UTC
  • Revision ID: nel-96aa6366eff3c935db4b610739abba94e5d985f0
ref taken off

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
"""
 
4
    Authenticating HTTP Server
 
5
 
 
6
    This module builds on BaseHTTPServer and implements 
 
7
    basic authentication
 
8
 
 
9
"""
 
10
 
 
11
from utils import VERSION, AUTHOR
 
12
__version__ = VERSION
 
13
__author__  = AUTHOR
 
14
 
 
15
import os
 
16
import sys
 
17
import time
 
18
import socket
 
19
import string
 
20
import posixpath
 
21
import SocketServer
 
22
import BufferingHTTPServer
 
23
import BaseHTTPServer
 
24
import base64
 
25
 
 
26
from string import atoi,split
 
27
 
 
28
AUTH_ERROR_MSG="""<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
 
29
<HTML><HEAD>
 
30
<TITLE>401 Authorization Required</TITLE>
 
31
</HEAD><BODY>
 
32
<H1>Authorization Required</H1>
 
33
This server could not verify that you
 
34
are authorized to access the document
 
35
requested.  Either you supplied the wrong
 
36
credentials (e.g., bad password), or your
 
37
browser doesn't understand how to supply
 
38
the credentials required.<P>
 
39
</BODY></HTML>"""
 
40
 
 
41
class AuthRequestHandler:
 
42
    """
 
43
    Simple handler that use buffering and can check for auth headers 
 
44
 
 
45
    In order to use it create a subclass of BufferedAuthRequestHandler
 
46
    or BasicAuthRequestHandler depending on if you want to send
 
47
    responses as block or as stream.
 
48
 
 
49
    In your subclass you have to define the method get_userinfo(user,pw)
 
50
    which should return 1 or None depending on whether the password was
 
51
    ok or not. None means that the user is not authorized.
 
52
    """
 
53
 
 
54
    # False means no authentiation 
 
55
    DO_AUTH=1
 
56
 
 
57
    AUTH_ERROR_MSG="""<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
 
58
    <HTML><HEAD>
 
59
    <TITLE>401 Authorization Required</TITLE>
 
60
    </HEAD><BODY>
 
61
    <H1>Authorization Required</H1>
 
62
    This server could not verify that you
 
63
    are authorized to access the document
 
64
    requested.  Either you supplied the wrong
 
65
    credentials (e.g., bad password), or your
 
66
    browser doesn't understand how to supply
 
67
    the credentials required.<P>
 
68
    </BODY></HTML>"""
 
69
 
 
70
    server_version = "AuthHTTP/" + __version__
 
71
 
 
72
    def _log(self, message):
 
73
        pass
 
74
 
 
75
    def handle(self):
 
76
        """
 
77
        Special handle method with buffering and authentication
 
78
        """
 
79
        
 
80
        self.infp=open("/tmp/in.%s" %self.__class__, "a+")
 
81
 
 
82
        self.infp.write("------------------------------------------------------------------------------\n")
 
83
        self.raw_requestline = self.rfile.readline()
 
84
        self.infp.write(self.raw_requestline)
 
85
        self.request_version = version = "HTTP/0.9" # Default
 
86
        requestline = self.raw_requestline
 
87
 
 
88
        # needed by send_error
 
89
        self.command = requestline
 
90
 
 
91
        if requestline[-2:] == '\r\n':
 
92
            requestline = requestline[:-2]
 
93
        elif requestline[-1:] == '\n':
 
94
            requestline = requestline[:-1]
 
95
 
 
96
        self.requestline = requestline
 
97
        words = string.split(requestline)
 
98
        if len(words) == 3:
 
99
            [command, path, version] = words
 
100
            if version[:5] != 'HTTP/':
 
101
                self.send_error(400, "Bad request version (%s)" % `version`)
 
102
                return
 
103
        elif len(words) == 2:
 
104
            [command, path] = words
 
105
            if command != 'GET':
 
106
                self.send_error(400,
 
107
                                "Bad HTTP/0.9 request type (%s)" % `command`)
 
108
                return
 
109
        else:
 
110
            self.send_error(400, "Bad request syntax (%s)" % `requestline`)
 
111
            return
 
112
        
 
113
        self.command, self.path, self.request_version = command, path, version
 
114
        self.headers = self.MessageClass(self.rfile, 0)
 
115
        self.infp.write(str(self.headers))
 
116
 
 
117
        # test authentification
 
118
        if self.DO_AUTH:
 
119
            try:
 
120
                a=self.headers["Authorization"]
 
121
                m,up=string.split(a)
 
122
                up2=base64.decodestring(up)
 
123
                user,pw=string.split(up2,":")
 
124
                if not self.get_userinfo(user,pw):
 
125
                    self.send_autherror(401,"Authorization Required"); return
 
126
            except:
 
127
                self.send_autherror(401,"Authorization Required")
 
128
                return
 
129
 
 
130
        # check for methods starting with do_
 
131
        mname = 'do_' + command
 
132
        if not hasattr(self, mname):
 
133
            self.send_error(501, "Unsupported method (%s)" % `command`)
 
134
            return
 
135
 
 
136
        method = getattr(self, mname)
 
137
        method()
 
138
 
 
139
        self.infp.flush()
 
140
        self.infp.close()
 
141
        self._flush()
 
142
 
 
143
    def write_infp(self,s):
 
144
        self.infp.write(str(s))
 
145
        self.infp.flush()
 
146
 
 
147
    def send_response(self,code, message=None):
 
148
        """Override send_response to use the correct http version
 
149
           in the response."""
 
150
 
 
151
        self.log_request(code)
 
152
        if message is None:
 
153
            if self.responses.has_key(code):
 
154
                message = self.responses[code][0]
 
155
            else:
 
156
                message = ''
 
157
 
 
158
        if self.request_version != 'HTTP/0.9':
 
159
            self._append("%s %s %s\r\n" %
 
160
                             (self.request_version, str(code), message))
 
161
 
 
162
        self.send_header('Server', self.version_string())
 
163
        self.send_header('Date', self.date_time_string())
 
164
        self.send_header('Connection', 'close')
 
165
 
 
166
    def send_head(self):
 
167
        """Common code for GET and HEAD commands.
 
168
 
 
169
        This sends the response code and MIME headers.
 
170
 
 
171
        Return value is either a file object (which has to be copied
 
172
        to the outputfile by the caller unless the command was HEAD,
 
173
        and must be closed by the caller under all circumstances), or
 
174
        None, in which case the caller has nothing further to do.
 
175
 
 
176
        """
 
177
        path = self.translate_path(self.path)
 
178
        if os.path.isdir(path):
 
179
            self.send_error(403, "Directory listing not supported")
 
180
            return None
 
181
        try:
 
182
            f = open(path, 'rb')
 
183
        except IOError:
 
184
            self.send_error(404, "File not found")
 
185
            return None
 
186
 
 
187
        self.send_response(200)
 
188
        self.send_header("Content-type", self.guess_type(path))
 
189
        self.end_headers()
 
190
        return f
 
191
 
 
192
    def send_autherror(self,code,message=None):
 
193
        try:
 
194
            short, long = self.responses[code]
 
195
        except KeyError:
 
196
            short, long = '???', '???'
 
197
        if not message:
 
198
            message = short
 
199
        explain = long
 
200
 
 
201
        emsg=self.AUTH_ERROR_MSG
 
202
        self.log_error("code %d, message %s", code, message)
 
203
        self.send_response(code, message)
 
204
        self.send_header("WWW-Authenticate","Basic realm=\"PyWebDAV\"")
 
205
        self.send_header("Content-Type", 'text/html')
 
206
        self.end_headers()
 
207
        
 
208
        lines=split(emsg,"\n")
 
209
        for l in lines:
 
210
            self._append("%s\r\n" %l)
 
211
 
 
212
    def get_userinfo(self,user):
 
213
        """ return the password of the user 
 
214
        Override this class to return the right password 
 
215
        """
 
216
        
 
217
        # Always reject
 
218
        return None
 
219
 
 
220
class BufferedAuthRequestHandler(BufferingHTTPServer.BufferedHTTPRequestHandler,AuthRequestHandler):
 
221
 
 
222
    def handle(self):
 
223
        self._init_buffer()
 
224
        AuthRequestHandler.handle(self)
 
225
        self._flush()
 
226
 
 
227
class BasicAuthRequestHandler(BufferingHTTPServer.BufferedHTTPRequestHandler,AuthRequestHandler):
 
228
 
 
229
    def _append(self,s):
 
230
        """ write the string to wfile """
 
231
        self.wfile.write(s)
 
232