55# For license terms see the file COPYING.txt.
66#
77
8- import getopt , os , sys , socket
9- from roundup .xmlrpc import RoundupServer , RoundupRequestHandler
8+ import base64 , getopt , os , sys , socket , urllib
9+ from roundup .xmlrpc import translate
10+ from roundup .xmlrpc import RoundupInstance
11+ import roundup .instance
1012from roundup .instance import TrackerError
13+ from roundup .cgi .exceptions import Unauthorised
1114from SimpleXMLRPCServer import SimpleXMLRPCServer
15+ from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
16+
17+
18+ class RequestHandler (SimpleXMLRPCRequestHandler ):
19+ """A SimpleXMLRPCRequestHandler with support for basic
20+ HTTP Authentication."""
21+
22+ TRACKER_HOMES = {}
23+ TRACKERS = {}
24+
25+ def is_rpc_path_valid (self ):
26+ path = self .path .split ('/' )
27+ name = urllib .unquote (path [1 ]).lower ()
28+ return name in self .TRACKER_HOMES
29+
30+ def get_tracker (self , name ):
31+ """Return a tracker instance for given tracker name."""
32+
33+ if name in self .TRACKERS :
34+ return self .TRACKERS [name ]
35+
36+ if name not in self .TRACKER_HOMES :
37+ raise Exception ('No such tracker "%s"' % name )
38+ tracker_home = self .TRACKER_HOMES [name ]
39+ tracker = roundup .instance .open (tracker_home )
40+ self .TRACKERS [name ] = tracker
41+ return tracker
42+
43+
44+ def authenticate (self , tracker ):
45+
46+
47+ # Try to extract username and password from HTTP Authentication.
48+ username , password = None , None
49+ authorization = self .headers .get ('authorization' , ' ' )
50+ scheme , challenge = authorization .split (' ' , 1 )
51+
52+ if scheme .lower () == 'basic' :
53+ decoded = base64 .decodestring (challenge )
54+ username , password = decoded .split (':' )
55+ if not username :
56+ username = 'anonymous'
57+ db = tracker .open ('admin' )
58+ try :
59+ userid = db .user .lookup (username )
60+ except KeyError : # No such user
61+ db .close ()
62+ raise Unauthorised , 'Invalid user'
63+ stored = db .user .get (userid , 'password' )
64+ if stored != password :
65+ # Wrong password
66+ db .close ()
67+ raise Unauthorised , 'Invalid user'
68+ db .setCurrentUser (username )
69+ return db
70+
71+
72+ def do_POST (self ):
73+ """Extract username and password from authorization header."""
74+
75+ db = None
76+ try :
77+ path = self .path .split ('/' )
78+ tracker_name = urllib .unquote (path [1 ]).lower ()
79+ tracker = self .get_tracker (tracker_name )
80+ db = self .authenticate (tracker )
81+
82+ instance = RoundupInstance (db , None )
83+ self .server .register_instance (instance )
84+ SimpleXMLRPCRequestHandler .do_POST (self )
85+ except Unauthorised , message :
86+ self .send_error (403 , '%s (%s)' % (self .path , message ))
87+ except :
88+ if db :
89+ db .close ()
90+ exc , val , tb = sys .exc_info ()
91+ print exc , val , tb
92+ raise
93+ if db :
94+ db .close ()
95+
96+
97+ class Server (SimpleXMLRPCServer ):
98+
99+ def _dispatch (self , method , params ):
100+
101+ retn = SimpleXMLRPCServer ._dispatch (self , method , params )
102+ retn = translate (retn )
103+ return retn
104+
12105
13106def usage ():
14- print """
107+ print """Usage: %s: [options] [name=tracker home]+
15108
16109Options:
17110 -i instance home -- specify the issue tracker "home directory" to administer
18111 -V -- be verbose when importing
19112 -p, --port <port> -- port to listen on
20113
21- """
114+ """ % sys . argv [ 0 ]
22115
23116def run ():
24117
@@ -30,38 +123,42 @@ def run():
30123 return 1
31124
32125 verbose = False
33- tracker = ''
34126 port = 8000
35127 encoding = None
36128
37129 for opt , arg in opts :
38130 if opt == '-V' :
39131 verbose = True
40- elif opt == '-i' :
41- tracker = arg
42132 elif opt in ['-p' , '--port' ]:
43133 port = int (arg )
44134 elif opt in ['-e' , '--encoding' ]:
45135 encoding = encoding
46136
47- if sys . version_info [ 0 : 2 ] < ( 2 , 5 ):
48- if encoding :
49- print 'encodings not supported with python < 2.5'
50- sys . exit ( - 1 )
51- server = SimpleXMLRPCServer (( '' , port ), RoundupRequestHandler )
52- else :
53- server = SimpleXMLRPCServer (( '' , port ), RoundupRequestHandler ,
54- allow_none = True , encoding = encoding )
55- if not os . path . exists ( tracker ):
56- print 'Instance home does not exist.'
57- sys . exit ( - 1 )
58- try :
59- object = RoundupServer ( tracker , verbose )
60- except TrackerError :
61- print 'Instance home does not exist.'
62- sys . exit ( - 1 )
137+ tracker_homes = {}
138+ for arg in args :
139+ try :
140+ name , home = arg . split ( '=' , 1 )
141+ # Validate the argument
142+ tracker = roundup . instance . open ( home )
143+ except ValueError :
144+ print 'Instances must be name=home'
145+ sys . exit ( - 1 )
146+ except TrackerError :
147+ print 'Tracker home does not exist.'
148+ sys . exit ( - 1 )
149+
150+ tracker_homes [ name ] = home
151+
152+ RequestHandler . TRACKER_HOMES = tracker_homes
63153
64- server .register_instance (object )
154+ if sys .version_info [0 :2 ] < (2 ,5 ):
155+ if encoding :
156+ print 'encodings not supported with python < 2.5'
157+ sys .exit (- 1 )
158+ server = Server (('' , port ), RequestHandler )
159+ else :
160+ server = Server (('' , port ), RequestHandler ,
161+ allow_none = True , encoding = encoding )
65162
66163 # Go into the main listener loop
67164 print 'Roundup XMLRPC server started on %s:%d' \
0 commit comments