#!/usr/local/bin/python import re import string import logging from M2Crypto import SSL from fedid import fedid class fedd_ssl_context(SSL.Context): """ Simple wrapper around an M2Crypto.SSL.Context to initialize it for fedd. """ def __init__(self, my_cert, trusted_certs=None, password=None): """ construct a fedd_ssl_context @param my_cert: PEM file with my certificate in it @param trusted_certs: PEM file with trusted certs in it (optional) """ SSL.Context.__init__(self) # load_cert takes a callback to get a password, not a password, so if # the caller provided a password, this creates a nonce callback using a # lambda form. if password != None and not callable(password): # This is cute. password = lambda *args: password produces a # function object that returns itself rather than one that returns # the object itself. This is because password is an object # reference and after the assignment it's a lambda. So we assign # to a temp. pwd = password password =lambda *args: pwd if password != None: self.load_cert(my_cert, callback=password) else: self.load_cert(my_cert) # If no trusted certificates are specified, allow unknown CAs. if trusted_certs: self.load_verify_locations(trusted_certs) self.set_verify(SSL.verify_peer, 10) else: self.set_verify(SSL.verify_peer, 10, callback=SSL.cb.ssl_verify_callback_allow_unknown_ca) def read_simple_accessdb(fn, auth, mask=[]): """ Read a simple access database. Each line is a fedid (of the form fedid:hexstring) and a comma separated list of atributes to be assigned to it. This parses out the fedids and adds the attributes to the authorizer. comments (preceded with a #) and blank lines are ignored. Exceptions (e.g. file exceptions and ValueErrors from badly parsed lines) are propagated. """ rv = [ ] lineno = 0 fedid_line = re.compile("fedid:([" + string.hexdigits + "]+)\s+" +\ "(\w+\s*(,\s*\w+)*)") # If a single string came in, make it a list if isinstance(mask, basestring): mask = [ mask ] f = open(fn, 'r') for line in f: lineno += 1 line = line.strip() if line.startswith('#') or len(line) == 0: continue m = fedid_line.match(line) if m : fid = fedid(hexstr=m.group(1)) for a in [ a.strip() for a in m.group(2).split(",") \ if not mask or a.strip() in mask ]: auth.set_attribute(fid, a.strip()) else: raise ValueError("Badly formatted line in accessdb: %s line %d" %\ (nf, lineno)) f.close() return rv def pack_id(id): """ Return a dictionary with the field name set by the id type. Handy for creating dictionaries to be converted to messages. """ if isinstance(id, fedid): return { 'fedid': id } elif id.startswith("http:") or id.startswith("https:"): return { 'uri': id } else: return { 'localname': id} def unpack_id(id): """return id as a type determined by the key""" for k in ("localname", "fedid", "uri", "kerberosUsername"): if id.has_key(k): return id[k] return None def set_log_level(config, sect, log): """ Set the logging level to the value passed in sect of config.""" # The getattr sleight of hand finds the logging level constant # corrersponding to the string. We're a little paranoid to avoid user # mayhem. if config.has_option(sect, "log_level"): level_str = config.get(sect, "log_level") try: level = int(getattr(logging, level_str.upper(), -1)) if logging.DEBUG <= level <= logging.CRITICAL: log.setLevel(level) else: log.error("Bad experiment_log value: %s" % level_str) except ValueError: log.error("Bad experiment_log value: %s" % level_str)