Changeset 174
- Timestamp:
- 07/25/12 01:41:34 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
etherws/trunk/etherws.py
r173 r174 236 236 except: 237 237 traceback.print_exc() 238 tornado.ioloop.IOLoop.instance().stop() 238 tornado.ioloop.IOLoop.instance().stop() # XXX: should unregister fd 239 239 240 240 def _read(self): … … 268 268 269 269 class EtherWebSocketClient(DebugMixIn): 270 def __init__(self, switch, url, user=None, passwd=None, debug=False):270 def __init__(self, switch, url, cred=None, debug=False): 271 271 self._switch = switch 272 272 self._url = url … … 275 275 self._options = {} 276 276 277 if user and passwd:278 token = base64.b64encode('%s:%s' % ( user, passwd))277 if isinstance(cred, dict) and cred['user'] and cred['passwd']: 278 token = base64.b64encode('%s:%s' % (cred['user'], cred['passwd'])) 279 279 auth = ['Authorization: Basic %s' % token] 280 280 self._options['header'] = auth … … 322 322 except: 323 323 traceback.print_exc() 324 tornado.ioloop.IOLoop.instance().stop() 324 tornado.ioloop.IOLoop.instance().stop() # XXX: should unregister fd 325 326 327 class Htpasswd(object): 328 def __init__(self, path): 329 self._path = path 330 self._stat = None 331 self._data = {} 332 333 def auth(self, name, passwd): 334 passwd = base64.b64encode(hashlib.sha1(passwd).digest()) 335 return self._data.get(name) == passwd 336 337 def load(self): 338 old_stat = self._stat 339 340 with open(self._path) as fp: 341 self._stat = os.fstat(fp.fileno()) 342 343 unchanged = old_stat and \ 344 old_stat.st_ino == self._stat.st_ino and \ 345 old_stat.st_dev == self._stat.st_dev and \ 346 old_stat.st_mtime == self._stat.st_mtime 347 348 if not unchanged: 349 self._data = self._parse(fp) 350 351 def _parse(self, fp): 352 data = {} 353 for line in fp: 354 line = line.strip() 355 if 0 <= line.find(':'): 356 name, passwd = line.split(':', 1) 357 if passwd.startswith('{SHA}'): 358 data[name] = passwd[5:] 359 return data 360 361 362 def wrap_basic_auth(handler_class, htpasswd_path): 363 if not htpasswd_path: 364 return handler_class 365 366 old_execute = handler_class._execute 367 htpasswd = Htpasswd(htpasswd_path) 368 369 def execute(self, transforms, *args, **kwargs): 370 def auth_required(): 371 self.stream.write(tornado.escape.utf8( 372 'HTTP/1.1 401 Authorization Required\r\n' 373 'WWW-Authenticate: Basic realm=etherws\r\n\r\n' 374 )) 375 self.stream.close() 376 377 creds = self.request.headers.get('Authorization') 378 379 if not creds or not creds.startswith('Basic '): 380 return auth_required() 381 382 try: 383 name, passwd = base64.b64decode(creds[6:]).split(':', 1) 384 htpasswd.load() 385 386 if not htpasswd.auth(name, passwd): 387 return auth_required() 388 389 return old_execute(self, transforms, *args, **kwargs) 390 391 except: 392 return auth_required() 393 394 handler_class._execute = execute 395 return handler_class 325 396 326 397 … … 361 432 362 433 def server_main(args): 363 def wrap_basic_auth(cls, users):364 o_exec = cls._execute365 366 if not users:367 return cls368 369 def execute(self, transforms, *args, **kwargs):370 def auth_required():371 self.stream.write(tornado.escape.utf8(372 'HTTP/1.1 401 Authorization Required\r\n'373 'WWW-Authenticate: Basic realm=etherws\r\n\r\n'374 ))375 self.stream.close()376 377 creds = self.request.headers.get('Authorization')378 379 if not creds or not creds.startswith('Basic '):380 return auth_required()381 382 try:383 name, passwd = base64.b64decode(creds[6:]).split(':', 1)384 passwd = base64.b64encode(hashlib.sha1(passwd).digest())385 386 if name not in users or users[name] != passwd:387 return auth_required()388 389 return o_exec(self, transforms, *args, **kwargs)390 391 except:392 return auth_required()393 394 cls._execute = execute395 return cls396 397 def load_htpasswd(path):398 users = {}399 try:400 with open(path) as fp:401 for line in fp:402 line = line.strip()403 if 0 <= line.find(':'):404 name, passwd = line.split(':', 1)405 if passwd.startswith('{SHA}'):406 users[name] = passwd[5:]407 if not users:408 raise ValueError('no valid users found')409 except TypeError:410 pass411 return users412 413 434 realpath(args, 'keyfile', 'certfile', 'htpasswd') 414 435 … … 434 455 fdb = FDB(ageout=args.ageout, debug=args.debug) 435 456 switch = SwitchingHub(fdb, debug=args.debug) 436 taps = [TapHandler(switch, dev, debug=args.debug) for dev in args.device] 437 438 handler = wrap_basic_auth(EtherWebSocketHandler, 439 load_htpasswd(args.htpasswd)) 440 app = tornado.web.Application([ 441 (args.path, handler, {'switch': switch, 'debug': args.debug}), 442 ]) 457 458 handler = wrap_basic_auth(EtherWebSocketHandler, args.htpasswd) 459 srv = (args.path, handler, {'switch': switch, 'debug': args.debug}) 460 app = tornado.web.Application([srv]) 443 461 server = tornado.httpserver.HTTPServer(app, ssl_options=ssl_options) 444 462 server.listen(args.port, address=args.address) 445 463 446 for tap in taps: 464 for dev in args.device: 465 tap = TapHandler(switch, dev, debug=args.debug) 447 466 tap.open() 448 467 ioloop.add_handler(tap.fileno(), tap, ioloop.READ) … … 460 479 websocket.enableTrace(True) 461 480 462 if not args.insecure: 481 if args.insecure: 482 websocket._SSLSocketWrapper = \ 483 lambda s: ssl.wrap_socket(s) 484 else: 463 485 websocket._SSLSocketWrapper = \ 464 486 lambda s: ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, 465 487 ca_certs=args.cacerts) 466 else: 467 websocket._SSLSocketWrapper = \468 lambda s: ssl.wrap_socket(s)488 489 if args.ageout <= 0: 490 raise ValueError('invalid ageout: %s' % args.ageout) 469 491 470 492 if args.user and args.passwd is None: 471 493 args.passwd = getpass.getpass() 472 494 473 if args.ageout <= 0: 474 raise ValueError('invalid ageout: %s' % args.ageout) 475 495 cred = {'user': args.user, 'passwd': args.passwd} 476 496 ioloop = tornado.ioloop.IOLoop.instance() 477 497 fdb = FDB(ageout=args.ageout, debug=args.debug) 478 498 switch = SwitchingHub(fdb, debug=args.debug) 479 taps = [TapHandler(switch, dev, debug=args.debug) for dev in args.device] 480 481 clients = [EtherWebSocketClient(switch, uri, 482 args.user, args.passwd, args.debug) 483 for uri in args.uri] 484 485 for client in clients: 499 500 for uri in args.uri: 501 client = EtherWebSocketClient(switch, uri, cred, args.debug) 486 502 client.open() 487 503 ioloop.add_handler(client.fileno(), client, ioloop.READ) 488 504 489 for tap in taps: 505 for dev in args.device: 506 tap = TapHandler(switch, dev, debug=args.debug) 490 507 tap.open() 491 508 ioloop.add_handler(tap.fileno(), tap, ioloop.READ)
Note: See TracChangeset
for help on using the changeset viewer.