Пример #1
0
 def RenewSlice(self, slice_urn, expire_str):
     self.logger.info("Called RenewSlice(%s, %s)", slice_urn, expire_str)
     if not self.slices.has_key(slice_urn):
         self.logger.warning('Slice %s was not found', slice_urn)
         return False
     try:
         in_expiration = dateutil.parser.parse(expire_str)
     except:
         self.logger.warning('Unable to parse date "%s"', expire_str)
         return False
     # Is requested expiration valid? It must be in the future,
     # but not too far into the future.
     now = datetime.datetime.utcnow()
     now = now.replace(tzinfo=in_expiration.tzinfo)
     if in_expiration < now:
         self.logger.warning('Expiration "%s" is in the past.', expire_str)
         return False
     duration = in_expiration - now
     max_duration = datetime.timedelta(seconds=SLICE_MAX_LIFE_SECS)
     if duration > max_duration:
         self.logger.warning('Expiration %s is too far in the future.',
                             expire_str)
         return False
     # Everything checks out, so create a new slice cred and tuck it away.
     user_gid = gid.GID(string=self._server.pem_cert)
     slice_cred = self.slices[slice_urn]
     slice_gid = slice_cred.get_gid_object()
     duration_secs = duration.seconds + duration.days * 24 * 3600
     slice_cred = self.create_slice_credential(user_gid, slice_gid,
                                               duration_secs)
     self.logger.info("Slice %s renewed to %s", slice_urn, expire_str)
     return True
Пример #2
0
    def verify_from_strings(self, gid_string, cred_strings, target_urn,
                            privileges):
        '''Create Credential and GID objects from the given strings,
        and then verify the GID has the right privileges according 
        to the given credentials on the given target.'''
        def make_cred(cred_string):
            return cred.Credential(string=cred_string)

        return self.verify(gid.GID(string=gid_string),
                           map(make_cred, cred_strings), target_urn,
                           privileges)
Пример #3
0
 def CreateUserCredential(self, user_gid):
     '''Return string representation of a user credential
     issued by this CH with caller/object this user_gid (string)
     with user privileges'''
     # FIXME: Validate arg - non empty, my user
     user_gid = gid.GID(string=user_gid)
     self.logger.info("Called CreateUserCredential for GID %s" % user_gid.get_hrn())
     expiration = datetime.datetime.utcnow() + datetime.timedelta(seconds=USER_CRED_LIFE)
     try:
         ucred = cred_util.create_credential(user_gid, user_gid, expiration, 'user', self.keyfile, self.certfile, self.trusted_root_files)
     except Exception, exc:
         self.logger.error("Failed to create user credential for %s: %s", user_gid.get_hrn(), traceback.format_exc())
         raise Exception("Failed to create user credential for %s" % user_gid.get_hrn(), exc)
Пример #4
0
def CreateSlice(user_cert, urn_req=None):
    
    # Is this user allowed to create a slice?
    # first get the user with this cert
    username = get_username_from_cert(user_cert)
    try:
        User.objects.get(username=username)
    except User.DoesNotExist:
        raise Exception("Unknown user %s." % username)
    
    if urn_req:
        # check the requested URN
        urn = URN(urn=urn_req)
        
        # make sure that we would generate the same urn if using the
        # same name (i.e. authority is the same...)
        urn_gen = get_slice_urn(urn.getName())
        
        if urn_gen != urn_req:
            raise BadURNException(
                "The requested URN is not one that would be generated"
                " by this clearinghouse. Requested was %s, but generated"
                " is %s" % (urn_req, urn_gen)
            )
            
    else:
        # Generate a unique URN for the slice
        urn_req = create_slice_urn()
        
    try:
        slice_gid = create_x509_cert(urn_req)[0]
    except Exception as exc:
        logger.error("Could not create slice. Error\n %s"
                     % traceback.format_exc())
        raise Exception("Failed to create slice %s." % urn_req)

    # Now get the user GID which will have permissions on this slice.
    # It doesnt have the chain but should be signed
    # by this CHs cert, which should also be a trusted
    # root at any federated AM. So everyone can verify it as is.
    # Note that if a user from a different CH (installed
    # as trusted by this CH for some reason) called this method,
    # that user would be used here - and can still get a valid slice
    try:
        user_gid = gid.GID(string=user_cert)
    except Exception, exc:
        logger.error("CreateSlice failed to create user_gid from SSL client cert: %s", traceback.format_exc())
        raise Exception("Failed to create slice %s. Cant get user GID from SSL client certificate." % urn_req, exc)
Пример #5
0
def CreateUserCredential(user_gid):
    '''Return string representation of a user credential
    issued by this CH with caller/object this user_gid (string)
    with user privileges'''

    username = get_username_from_cert(user_gid)
    try:
        User.objects.get(username=username)
    except User.DoesNotExist:
        raise Exception("Unknown user %s." % username)

    user_gid = gid.GID(string=user_gid)
    logger.info("Called CreateUserCredential for GID %s" % user_gid.get_hrn())
    try:
        ucred = create_user_credential(user_gid)
    except Exception, exc:
        logger.error("Failed to create user credential for %s: %s", user_gid.get_hrn(), traceback.format_exc())
        raise Exception("Failed to create user credential for %s" % user_gid.get_hrn(), exc)
Пример #6
0
 def RenewSlice(self, slice_urn, expire_str):
     self.logger.info("Called RenewSlice(%s, %s)", slice_urn, expire_str)
     if not self.slices.has_key(slice_urn):
         self.logger.warning('Slice %s was not found', slice_urn)
         return False
     try:
         in_expiration = dateutil.parser.parse(expire_str)
         in_expiration = cred_util.naiveUTC(in_expiration)
     except:
         self.logger.warning('Unable to parse date "%s"', expire_str)
         return False
     # Is requested expiration valid? It must be in the future,
     # but not too far into the future.
     now = datetime.datetime.utcnow()
     if in_expiration < now:
         self.logger.warning('Expiration "%s" is in the past.', expire_str)
         return False
     duration = in_expiration - now
     max_duration = datetime.timedelta(seconds=SLICE_MAX_LIFE_SECS)
     if duration > max_duration:
         self.logger.warning('Expiration %s is too far in the future.',
                             expire_str)
         return False
     # Everything checks out, so create a new slice cred and tuck it away.
     user_gid = gid.GID(string=self._server.pem_cert)
     slice_cred = self.slices[slice_urn]
     slice_gid = slice_cred.get_gid_object()
     # if original slice' privileges were all delegatable,
     # make all the privs here delegatable
     # Of course, the correct thing would be to do it priv by priv...
     dgatable = False
     if slice_cred.get_privileges().get_all_delegate():
         dgatable = True
     slice_cred = self.create_slice_credential(user_gid,
                                               slice_gid,
                                               in_expiration,
                                               delegatable=dgatable)
     self.logger.info("Slice %s renewed to %s", slice_urn, expire_str)
     self.slices[slice_urn] = slice_cred
     return True
Пример #7
0
def create_credential(caller_gid, object_gid, life_secs, typename,
                      issuer_keyfile, issuer_certfile, trusted_roots):
    '''Create and Return a Credential object issued by given key/cert for the given caller
    and object GID objects, given life in seconds, and given type.
    Privileges are determined by type per sfa/trust/rights.py'''
    # FIXME: Validate args: my gids, >0 life,
    # type of cred one I can issue
    # and readable key and cert files
    if caller_gid is None:
        raise ValueError("Missing Caller GID")
    if object_gid is None:
        raise ValueError("Missing Object GID")
    if life_secs is None or life_secs < 1:
        raise ValueError("Credential life in seconds was 0")
    if trusted_roots is None:
        raise ValueError("Missing list of trusted roots")

    if typename is None or typename.strip() == '':
        raise ValueError("Missing credential type")
    typename = typename.strip().lower()
    if typename not in ("user", "sa", "ma", "authority", "slice", "component"):
        raise ValueError("Unknown credential type %s" % typename)

    if not os.path.isfile(issuer_keyfile):
        raise ValueError("Cant read issuer key file %s" % issuer_keyfile)

    if not os.path.isfile(issuer_certfile):
        raise ValueError("Cant read issuer cert file %s" % issuer_certfile)

    issuer_gid = gid.GID(filename=issuer_certfile)

    if not (object_gid.get_urn() == issuer_gid.get_urn() or
            (issuer_gid.get_type() == 'authority'
             and object_gid.get_urn().split('+')[1].startswith(
                 issuer_gid.get_urn().split('+')[1]))):
        raise ValueError(
            "Issuer not authorized to issue credential: Issuer=%s  Target=%s" %
            (issuer_gid.get_urn(), object_gid.get_urn()))

    ucred = cred.Credential()
    # FIXME: Validate the caller_gid and object_gid
    # are my user and slice
    # Do get_issuer and compare to the issuer cert?
    # Or do gid.is_signed_by_cert(issuer_certfile)?
    ucred.set_gid_caller(caller_gid)
    ucred.set_gid_object(object_gid)
    ucred.set_lifetime(life_secs)
    # Use sfa/trust/rights.py to figure out what privileges
    # the credential should have.
    # user means refresh, resolve, info
    # per the privilege_table that lets users do
    # remove, update, resolve, list, getcredential,
    # listslices, listnodes, getpolicy
    # Note that it does not allow manipulating slivers
    privileges = rights.determine_rights(typename, None)
    ucred.set_privileges(privileges)
    ucred.encode()
    ucred.set_issuer_keys(issuer_keyfile, issuer_certfile)
    ucred.sign()

    try:
        ucred.verify(trusted_roots)
    except Exception, exc:
        raise Exception(
            "Create Credential failed to verify new credential from trusted roots: %s"
            % exc)
Пример #8
0
class Clearinghouse(object):
    def __init__(self):
        self.logger = cred_util.logging.getLogger('gcf-ch')
        self.slices = {}
        self.aggs = []

    def load_aggregates(self):
        """Loads aggregates from the clearinghouse section of the config file.
        
        In the config section there are keys for each am, am_1, am_2, ..., am_n
        
        The value for each key is the urn and url of the aggregate separated by a comma
           
        Returns True if aggregates were loaded, False otherwise.
        """

        for (key, val) in self.config['clearinghouse'].items():
            if not key.startswith('am_'):
                continue

            (urn, url) = val.split(',')
            urn = urn.strip()
            url = url.strip()
            if not urn:
                self.logger.warn('Empty URN for aggregate %s in gcf_config' %
                                 key)
                continue

            if not url:
                self.logger.warn('Empty URL for aggregate %s in gcf_config' %
                                 key)
                continue
            if urn in [x for (x, _) in self.aggs]:
                self.logger.warn('Duplicate URN %s in gcf_config' % key)
                continue

            self.logger.info("Registering AM %s at %s", urn, url)
            self.aggs.append((urn, url))

    def runserver(self,
                  addr,
                  keyfile=None,
                  certfile=None,
                  ca_certs=None,
                  authority=None,
                  user_len=None,
                  slice_len=None,
                  config=None):
        """Run the clearinghouse server."""
        # ca_certs is a dir of several certificates for peering
        # If not supplied just use the certfile as the only trusted root
        self.keyfile = keyfile
        self.certfile = certfile

        self.config = config

        # Error check the keyfile, certfile all exist
        if keyfile is None or not os.path.isfile(
                os.path.expanduser(keyfile)) or os.path.getsize(
                    os.path.expanduser(keyfile)) < 1:
            raise Exception("Missing CH key file %s" % keyfile)
        if certfile is None or not os.path.isfile(
                os.path.expanduser(certfile)) or os.path.getsize(
                    os.path.expanduser(certfile)) < 1:
            raise Exception("Missing CH cert file %s" % certfile)

        if ca_certs is None:
            ca_certs = certfile
            self.logger.info("Using only my CH cert as a trusted root cert")

        self.trusted_root_files = cred_util.CredentialVerifier(
            ca_certs).root_cert_files

        if not os.path.exists(os.path.expanduser(ca_certs)):
            raise Exception("Missing CA cert(s): %s" % ca_certs)

        global SLICE_AUTHORITY, USER_CRED_LIFE, SLICE_CRED_LIFE
        SLICE_AUTHORITY = authority
        USER_CRED_LIFE = int(user_len)
        SLICE_CRED_LIFE = int(slice_len)

        # Load up the aggregates
        self.load_aggregates()

        # This is the arg to _make_server
        ca_certs_onefname = cred_util.CredentialVerifier.getCAsFileFromDir(
            ca_certs)

        # This is used below by CreateSlice
        self.ca_cert_fnames = []
        if os.path.isfile(os.path.expanduser(ca_certs)):
            self.ca_cert_fnames = [os.path.expanduser(ca_certs)]
        elif os.path.isdir(os.path.expanduser(ca_certs)):
            self.ca_cert_fnames = [
                os.path.join(os.path.expanduser(ca_certs), name)
                for name in os.listdir(os.path.expanduser(ca_certs))
                if name != cred_util.CredentialVerifier.CATEDCERTSFNAME
            ]

        # Create the xmlrpc server, load the rootkeys and do the ssl thing.
        self._server = self._make_server(addr, keyfile, certfile,
                                         ca_certs_onefname)
        self._server.register_instance(SampleClearinghouseServer(self))
        self.logger.info('GENI CH Listening on port %d...' % (addr[1]))
        self._server.serve_forever()

    def _make_server(self, addr, keyfile=None, certfile=None, ca_certs=None):
        """Creates the XML RPC server."""
        # ca_certs is a file of concatenated certs
        # make 2nd arg logRequests=True if --debug
        debug = False
        if self.config.has_key('debug'):
            debug = self.config['debug']
        return SecureXMLRPCServer(addr,
                                  logRequests=debug,
                                  keyfile=keyfile,
                                  certfile=certfile,
                                  ca_certs=ca_certs)

    def _naiveUTC(self, dt):
        """Converts dt to a naive datetime in UTC.

        if 'dt' has a timezone then
        convert to UTC
        strip off timezone (make it "naive" in Python parlance)
        """
        if dt.tzinfo:
            tz_utc = dateutil.tz.tzutc()
            dt = dt.astimezone(tz_utc)
            dt = dt.replace(tzinfo=None)
        return dt

    def GetVersion(self):
        self.logger.info("Called GetVersion")
        version = dict()
        version['gcf-ch_api'] = 1
        return version

    # FIXME: Change that URN to be a name and non-optional
    # Currently gcf-test.py doesnt supply it, and
    # Omni takes a name and constructs a URN to supply
    def CreateSlice(self, urn_req=None):
        self.logger.info("Called CreateSlice URN REQ %r" % urn_req)
        slice_gid = None

        if urn_req and self.slices.has_key(urn_req):
            # If the Slice has expired, treat this as
            # a request to renew
            slice_cred = self.slices[urn_req]
            slice_exp = self._naiveUTC(slice_cred.expiration)
            if slice_exp <= datetime.datetime.utcnow():
                # Need to renew this slice
                self.logger.info(
                    "CreateSlice on %r found existing cred that expired at %r - will renew",
                    urn_req, slice_exp)
                slice_gid = slice_cred.get_gid_object()
            else:
                self.logger.debug(
                    "Slice cred is still valid at %r until %r - return it",
                    datetime.datetime.utcnow(), slice_exp)
                return slice_cred.save_to_string()

        # Create a random uuid for the slice
        slice_uuid = uuid.uuid4()

        # First ensure we have a slice_urn
        if urn_req:
            # Validate urn_req has the right form
            # to be issued by this CH
            if not urn_util.is_valid_urn(urn_req):
                # FIXME: make sure it isnt empty, etc...
                urn = urn_util.publicid_to_urn(urn_req)
            else:
                urn = urn_req

            # Validate the urn meets name restrictions
            if not urn_util.is_valid_urn_bytype(urn, 'slice', self.logger):
                raise Exception(
                    "Cannot create slice with urn %s: URN is invalid" % urn)
        else:
            # Generate a unique URN for the slice
            # based on this CH location and a UUID

            # Where was the slice created?
            (ipaddr, port) = self._server.socket._sock.getsockname()
            # FIXME: Get public_id start from a properties file
            # Create a unique name for the slice based on uuid
            slice_name = slice_uuid.__str__()[4:12]
            public_id = 'IDN %s slice %s//%s:%d' % (SLICE_AUTHORITY,
                                                    slice_name, ipaddr, port)
            # this func adds the urn:publicid:
            # and converts spaces to +'s, and // to :
            urn = urn_util.publicid_to_urn(public_id)

        # Now create a GID for the slice (signed credential)
        if slice_gid is None:
            # FIXME: For APIv3 compliance, we need
            # - slice email address
            # - unique cert serial number
            try:
                slice_gid = cert_util.create_cert(urn,
                                                  self.keyfile,
                                                  self.certfile,
                                                  uuidarg=slice_uuid)[0]
            except Exception, exc:
                self.logger.error("Cant create slice gid for slice urn %s: %s",
                                  urn, traceback.format_exc())
                raise Exception(
                    "Failed to create slice %s. Cant create slice gid" % urn,
                    exc)

        # Now get the user GID which will have permissions on this slice.
        # Get client x509 cert from the SSL connection
        # It doesnt have the chain but should be signed
        # by this CHs cert, which should also be a trusted
        # root at any federated AM. So everyone can verify it as is.
        # Note that if a user from a different CH (installed
        # as trusted by this CH for some reason) called this method,
        # that user would be used here - and can still get a valid slice
        try:
            user_gid = gid.GID(string=self._server.pem_cert)
        except Exception, exc:
            self.logger.error(
                "CreateSlice failed to create user_gid from SSL client cert: %s",
                traceback.format_exc())
            raise Exception(
                "Failed to create slice %s. Cant get user GID from SSL client certificate."
                % urn, exc)
Пример #9
0
def create_credential(caller_gid,
                      object_gid,
                      expiration,
                      typename,
                      issuer_keyfile,
                      issuer_certfile,
                      trusted_roots,
                      delegatable=False):
    '''Create and Return a Credential object issued by given key/cert for the given caller
    and object GID objects, given life in seconds, and given type.
    Privileges are determined by type per sfa/trust/rights.py
    Privileges are delegatable if requested.'''
    # FIXME: Validate args: my gids, >0 life,
    # type of cred one I can issue
    # and readable key and cert files
    if caller_gid is None:
        raise ValueError("Missing Caller GID")
    if object_gid is None:
        raise ValueError("Missing Object GID")
    if expiration is None:
        raise ValueError("Missing expiration")
    naive_expiration = naiveUTC(expiration)
    duration = naive_expiration - datetime.datetime.utcnow()
    life_secs = duration.seconds + duration.days * 24 * 3600
    if life_secs < 1:
        raise ValueError("Credential expiration is in the past")
    if trusted_roots is None:
        raise ValueError("Missing list of trusted roots")

    if typename is None or typename.strip() == '':
        raise ValueError("Missing credential type")
    typename = typename.strip().lower()
    if typename not in ("user", "sa", "ma", "authority", "slice", "component"):
        raise ValueError("Unknown credential type %s" % typename)

    if not os.path.isfile(issuer_keyfile):
        raise ValueError("Cant read issuer key file %s" % issuer_keyfile)

    if not os.path.isfile(issuer_certfile):
        raise ValueError("Cant read issuer cert file %s" % issuer_certfile)

    issuer_gid = gid.GID(filename=issuer_certfile)

    if not (object_gid.get_urn() == issuer_gid.get_urn() or
            (issuer_gid.get_type().find('authority') == 0
             and hrn_authfor_hrn(issuer_gid.get_hrn(), object_gid.get_hrn()))):
        raise ValueError(
            "Issuer not authorized to issue credential: Issuer=%s  Target=%s" %
            (issuer_gid.get_urn(), object_gid.get_urn()))

    ucred = cred.Credential()
    # FIXME: Validate the caller_gid and object_gid
    # are my user and slice
    # Do get_issuer and compare to the issuer cert?
    # Or do gid.is_signed_by_cert(issuer_certfile)?
    ucred.set_gid_caller(caller_gid)
    ucred.set_gid_object(object_gid)
    ucred.set_expiration(expiration)
    # Use sfa/trust/rights.py to figure out what privileges
    # the credential should have.
    # user means refresh, resolve, info
    # per the privilege_table that lets users do
    # remove, update, resolve, list, getcredential,
    # listslices, listnodes, getpolicy
    # Note that it does not allow manipulating slivers

    # And every right is delegatable if any are delegatable (default False)
    privileges = rights.determine_rights(typename, None)
    privileges.delegate_all_privileges(delegatable)
    ucred.set_privileges(privileges)
    ucred.encode()
    ucred.set_issuer_keys(issuer_keyfile, issuer_certfile)
    ucred.sign()

    try:
        ucred.verify(trusted_roots)
    except Exception, exc:
        raise Exception(
            "Create Credential failed to verify new credential from trusted roots: %s"
            % exc)