Esempio n. 1
0
def validate_user_cert(user_cert, signing_user_id, check_admin=False):
    """
   Given a deserialized user certificate, check its validity:
   * make sure user identified by signing_user_id exists
   * make sure the admin identified in user_cert exists, if check_admin is set
   * verify that the user identified by signing_user_id has signed the cert

   Return the signing user and the admin user on success
   Raise an exception on error
   """

    from common.api import verify_data

    signing_user_fut = SyndicateUser.Read(signing_user_id, async=True)
    admin_user_fut = None

    if user_cert.admin_id != signing_user_id:
        admin_user_fut = SyndicateUser.Read(user_cert.admin_id, async=True)
        storagetypes.wait_futures([signing_user_fut, admin_user_fut])

    else:
        storagetypes.wait_futures([signing_user_fut])

    signing_user = signing_user_fut.get_result()

    if admin_user_fut is not None:
        admin_user = admin_user_fut.get_result()
    else:

        # signing user and admin are the same
        admin_user = signing_user

    if check_admin:

        if admin_user is None:
            raise Exception(
                "The admin (%s) who signed this user cert does not exist" %
                user_cert.admin_id)

        if not admin_user.is_admin:
            raise Exception("User '%s' is not an admin" % (admin_user.email))

    if signing_user is None:
        raise Exception("No such user '%s'" % signing_user_id)

    user_pubkey = signing_user.public_key
    user_sig = user_cert.signature

    user_cert.signature = ""

    user_cert_nosigs = user_cert.SerializeToString()

    rc = verify_data(user_pubkey, user_cert_nosigs, base64.b64decode(user_sig))

    user_cert.signature = user_sig

    if not rc:
        raise Exception("User '%s' did not sign cert" % (signing_user.email))

    return signing_user, admin_user
Esempio n. 2
0
def validate_user_cert( user_cert, signing_user_id, check_admin=False ):
   """
   Given a deserialized user certificate, check its validity:
   * make sure user identified by signing_user_id exists
   * make sure the admin identified in user_cert exists, if check_admin is set
   * verify that the user identified by signing_user_id has signed the cert
   
   Return the signing user and the admin user on success
   Raise an exception on error
   """
   
   from common.api import verify_data 
   
   signing_user_fut = SyndicateUser.Read( signing_user_id, async=True )
   admin_user_fut = None
   
   if user_cert.admin_id != signing_user_id:
      admin_user_fut = SyndicateUser.Read( user_cert.admin_id, async=True )
      storagetypes.wait_futures( [signing_user_fut, admin_user_fut] )
   
   else:
      storagetypes.wait_futures( [signing_user_fut] )
   
   signing_user = signing_user_fut.get_result()
   
   if admin_user_fut is not None:
      admin_user = admin_user_fut.get_result()
   else:
      
      # signing user and admin are the same
      admin_user = signing_user 
      
   if check_admin:
      
      if admin_user is None:
         raise Exception("The admin (%s) who signed this user cert does not exist" % user_cert.admin_id )
      
      if not admin_user.is_admin:
         raise Exception("User '%s' is not an admin" % (admin_user.email))
   
   if signing_user is None:
      raise Exception("No such user '%s'" % signing_user_id )
   
   user_pubkey = signing_user.public_key 
   user_sig = user_cert.signature 
   
   user_cert.signature = ""
   
   user_cert_nosigs = user_cert.SerializeToString()
   
   rc = verify_data( user_pubkey, user_cert_nosigs, base64.b64decode( user_sig ) )
   
   user_cert.signature = user_sig 
   
   if not rc:
      raise Exception("User '%s' did not sign cert" % (signing_user.email))
   
   return signing_user, admin_user
Esempio n. 3
0
def _read_user_and_volume( email_or_id, volume_name_or_id ):
   user_fut = SyndicateUser.Read( email_or_id, async=True )
   volume_fut = Volume.Read( volume_name_or_id, async=True )
   
   storagetypes.wait_futures( [user_fut, volume_fut] )
   
   user = user_fut.get_result()
   volume = volume_fut.get_result()
   
   return user, volume
Esempio n. 4
0
def _read_user_and_volume(email_or_id, volume_name_or_id):
    user_fut = SyndicateUser.Read(email_or_id, async=True)
    volume_fut = Volume.Read(volume_name_or_id, async=True)

    storagetypes.wait_futures([user_fut, volume_fut])

    user = user_fut.get_result()
    volume = volume_fut.get_result()

    return user, volume
Esempio n. 5
0
def list_volume_user_ids( volume_name_or_id, **q_opts ):
   caller_user = _check_authenticated( q_opts )
   
   volume_id = _get_volume_id( volume_name_or_id )
   
   def __user_from_access_request( req ):
      return SyndicateUser.Read_ByOwnerID( req.requester_owner_id, async=True )
   
   q_opts["map_func"] = __user_from_access_request
   user_futs = VolumeAccessRequest.ListAll( {"VolumeAccessRequest.volume_id ==": volume_id}, **q_opts )
   
   storagetypes.wait_futures( user_futs )
   
   ret = [u.email for u in filter( lambda x: x != None, [uf.get_result() for uf in user_futs] )]
   return ret
Esempio n. 6
0
def _read_user_and_volume(email, volume_name_or_id):
    user_fut = SyndicateUser.Read(email, async=True)
    volume_fut = Volume.Read(volume_name_or_id, async=True)

    storagetypes.wait_futures([user_fut, volume_fut])

    user = user_fut.get_result()
    volume = volume_fut.get_result()

    if user == None:
        raise Exception("No such User '%s'" % email)

    if volume == None:
        raise Exception("No such Volume '%s'" % volume_name_or_id)

    return user, volume
Esempio n. 7
0
def _read_user_and_volume( email, volume_name_or_id ):
   user_fut = SyndicateUser.Read( email, async=True )
   volume_fut = Volume.Read( volume_name_or_id, async=True )
   
   storagetypes.wait_futures( [user_fut, volume_fut] )
   
   user = user_fut.get_result()
   volume = volume_fut.get_result()
   
   if user == None:
      raise Exception("No such User '%s'" % email)
   
   if volume == None:
      raise Exception("No such Volume '%s'" % volume_name_or_id )
   
   return user, volume
Esempio n. 8
0
def list_volume_user_ids(volume_name_or_id, **q_opts):
    caller_user = _check_authenticated(q_opts)

    volume_id = _get_volume_id(volume_name_or_id)

    def __user_from_access_request(req):
        return SyndicateUser.Read_ByOwnerID(req.requester_owner_id, async=True)

    q_opts["map_func"] = __user_from_access_request
    user_futs = VolumeAccessRequest.ListAll(
        {"VolumeAccessRequest.volume_id ==": volume_id}, **q_opts)

    storagetypes.wait_futures(user_futs)

    ret = [
        u.email for u in filter(lambda x: x != None,
                                [uf.get_result() for uf in user_futs])
    ]
    return ret
Esempio n. 9
0
def validate_cert_bundle( cert_bundle, user, volume_id, volume_version, new_gateway_cert=None ):
   """
   Given a deserialized cert bundle, check its validity:
   * make sure the user it points to exists
   * make sure it has the right volume ID (load from the datastore by default, or use volume_id or volume kw if given)
   * make sure the user signed it, or verify that the user identified by signing_user_id did.
   * make sure its volume version is equal to or exceeds the given volume_version
   * make sure the cert bundle's timestamp exceeds the previous cert bundle's timestamp
   * make sure each of its gateway versions are equal to or exceeds the local copies of the gateway certs' versions
   --- if new_gateway_cert is given, it will be checked in place of an on-file gateway cert.  This is useful 
       when updating a gateway--we need to check the gateway cert that will be written, not the one on file.
       
   Return True if so 
   Raise an exception on error.
   """
   
   from common.api import verify_data 
   
   if user.owner_id != cert_bundle.owner_id:
      raise Exception("Invalid cert bundle: invalid owner ID")
   
   # verify the user signed the cert 
   owner_pubkey = user.public_key 
   owner_sig = cert_bundle.signature 
   
   cert_bundle.signature = ""
   cert_bundle_nosigs = cert_bundle.SerializeToString()
   
   rc = verify_data( owner_pubkey, cert_bundle_nosigs, base64.b64decode( owner_sig ) )
   
   cert_bundle.signature = owner_sig 
   
   if not rc:
      raise Exception("Cert bundle not signed by user '%s'" % signing_user_id)
   
   # volume ID must match
   if volume_id != cert_bundle.volume_id:
      raise Exception("Invalid volume ID: %s != %s" % (volume_id, cert_bundle.volume_id))
   
   # volume version must increase or stay the same
   # NOTE: Manifest.file_version encodes the volume version, when being used as a cert bundle
   if volume_version > cert_bundle.file_version:
      raise Exception("Stale volume version for %s: expected > %s, got %s" % (volume_id, volume_version, cert_bundle.file_version))
   
   # get the previous cert bundle 
   prev_cert_bundle_rec = VolumeCertBundle.Get( volume_id )
   if prev_cert_bundle_rec is not None:
      
      # this cert bundle's timestamp must be newer 
      prev_cert_bundle = VolumeCertBundle.Load( prev_cert_bundle_rec )
      if prev_cert_bundle is not None:
         
         if prev_cert_bundle.mtime_sec > cert_bundle.mtime_sec or (prev_cert_bundle.mtime_sec == cert_bundle.mtime_sec and prev_cert_bundle.mtime_nsec > cert_bundle.mtime_nsec):
            # stale 
            raise Exception("Stale cert bundle for %s: expected > %s.%s, got %s.%s" % (volume_id, prev_cert_bundle.mtime_sec, prev_cert_bundle.mtime_nsec, cert_bundle.mtime_sec, cert_bundle.mtime_nsec))
         
   
   gateway_cert_and_fut = {}    # map gateway ID to (gateway cert block, gateway future)
   all_futs = []
   
   # cert is valid.
   # validate volume cert--it must match information in the cert manifest 
   if len(cert_bundle.blocks) == 0:
       raise Exception("Missing volume cert in cert bundle")
   
   volume_cert_block = cert_bundle.blocks[0]
   if volume_cert_block.block_id != volume_id:
       raise Exception("Cert block for volume does not match volume ID (expected %s, got %s)" % (volume_id, volume_cert_block.block_id))
   
   if volume_cert_block.block_version != cert_bundle.file_version:
       raise Exception("Cert block for volume does not match volume version (expected %s, got %s)" % (cert_bundle.file_version, volume_cert_block.block_version))
   
   if volume_cert_block.owner_id != user.owner_id:
       raise Exception("Cert block for volume does not match owner ID (expected %s, got %s)" % (user.owner_id, volume_cert_block.owner_id))
   
   # go validate the affected gateways    
   # NOTE: blocks[0] contains the volume cert (used by gateways)
   for i in xrange( 1, len(cert_bundle.blocks) ):
      
      block = cert_bundle.blocks[i]
      gateway_id = block.block_id
      
      if new_gateway_cert is not None and new_gateway_cert.gateway_id == gateway_id:
         # skip this one--we'll check below
         continue
      
      gateway_fut = Gateway.Read( gateway_id, async=True )
      
      gateway_cert_and_fut[ gateway_id ] = (block, gateway_fut)
      all_futs.append( gateway_fut )
   
   
   storagetypes.wait_futures( all_futs )
   
   for (gateway_id, (block, gateway_fut)) in gateway_cert_and_fut.items():
      
      # from the cert bundle
      given_gateway_version = None 
      given_gateway_caps = None 
      
      # on file
      gateway_version = None 
      gateway_caps = None
      
      if new_gateway_cert is not None and new_gateway_cert.gateway_id == gateway_id:
         
         # make sure the new gateway cert has an appropriate version 
         given_gateway_version = new_gateway_cert.gateway_version
         given_gateway_caps = new_gateway_cert.caps
         
         # don't worry about the caps--we'll be updating them shortly 
         gateway_version = gateway.version
         gateway_caps = new_gateway_cert.caps
         
      else:
         
         # use the gateway on file
         gateway = gateway_fut.get_result()
         if gateway is None:
            
            # requested a gateway that didn't exist 
            raise Exception("Cert bundle identifies non-existant gateway")
         
         if gateway.g_id != gateway_id:
            
            # this is a bug--the gateway is keyed by id 
            raise Exception("BUG: requested %s, got %s" % (gateway_id, gateway.g_id))
         
         given_gateway_caps = block.caps 
         given_gateway_version = gateway.cert_version      # can only check new gateway certs
         
         # check against on-file cert 
         gateway_version = gateway.cert_version 
         gateway_caps = gateway.caps
      
      
      # gateway version must increase or stay the same
      if gateway_version > given_gateway_version:
         
         # stale version
         raise Exception("Stale version for %s: expected >= %s, got %s" % (gateway_id, gateway_version, given_gateway_version))
      
      if (gateway_caps | given_gateway_caps) != given_gateway_caps:
         
         # invalid caps (only works when checked against on-file gateways)
         raise Exception("Invalid caps for %s: expected %s, got %s" % (gateway_id, gateway.caps, given_gateway_caps))
      
   # valid!
   return True
Esempio n. 10
0
def validate_cert_bundle(cert_bundle,
                         user,
                         volume_id,
                         volume_version,
                         new_gateway_cert=None):
    """
   Given a deserialized cert bundle, check its validity:
   * make sure the user it points to exists
   * make sure it has the right volume ID (load from the datastore by default, or use volume_id or volume kw if given)
   * make sure the user signed it, or verify that the user identified by signing_user_id did.
   * make sure its volume version is equal to or exceeds the given volume_version
   * make sure the cert bundle's timestamp exceeds the previous cert bundle's timestamp
   * make sure each of its gateway versions are equal to or exceeds the local copies of the gateway certs' versions
   --- if new_gateway_cert is given, it will be checked in place of an on-file gateway cert.  This is useful
       when updating a gateway--we need to check the gateway cert that will be written, not the one on file.

   Return True if so
   Raise an exception on error.
   """

    from common.api import verify_data

    if user.owner_id != cert_bundle.owner_id:
        raise Exception("Invalid cert bundle: invalid owner ID")

    # verify the user signed the cert
    owner_pubkey = user.public_key
    owner_sig = cert_bundle.signature

    cert_bundle.signature = ""
    cert_bundle_nosigs = cert_bundle.SerializeToString()

    rc = verify_data(owner_pubkey, cert_bundle_nosigs,
                     base64.b64decode(owner_sig))

    cert_bundle.signature = owner_sig

    if not rc:
        raise Exception("Cert bundle not signed by user '%s'" %
                        signing_user_id)

    # volume ID must match
    if volume_id != cert_bundle.volume_id:
        raise Exception("Invalid volume ID: %s != %s" %
                        (volume_id, cert_bundle.volume_id))

    # volume version must increase or stay the same
    # NOTE: Manifest.file_version encodes the volume version, when being used as a cert bundle
    if volume_version > cert_bundle.file_version:
        raise Exception("Stale volume version for %s: expected > %s, got %s" %
                        (volume_id, volume_version, cert_bundle.file_version))

    # get the previous cert bundle
    prev_cert_bundle_rec = VolumeCertBundle.Get(volume_id)
    if prev_cert_bundle_rec is not None:

        # this cert bundle's timestamp must be newer
        prev_cert_bundle = VolumeCertBundle.Load(prev_cert_bundle_rec)
        if prev_cert_bundle is not None:

            if prev_cert_bundle.mtime_sec > cert_bundle.mtime_sec or (
                    prev_cert_bundle.mtime_sec == cert_bundle.mtime_sec
                    and prev_cert_bundle.mtime_nsec > cert_bundle.mtime_nsec):
                # stale
                raise Exception(
                    "Stale cert bundle for %s: expected > %s.%s, got %s.%s" %
                    (volume_id, prev_cert_bundle.mtime_sec,
                     prev_cert_bundle.mtime_nsec, cert_bundle.mtime_sec,
                     cert_bundle.mtime_nsec))

    gateway_cert_and_fut = {
    }  # map gateway ID to (gateway cert block, gateway future)
    all_futs = []

    # cert is valid.
    # validate volume cert--it must match information in the cert manifest
    if len(cert_bundle.blocks) == 0:
        raise Exception("Missing volume cert in cert bundle")

    volume_cert_block = cert_bundle.blocks[0]
    if volume_cert_block.block_id != volume_id:
        raise Exception(
            "Cert block for volume does not match volume ID (expected %s, got %s)"
            % (volume_id, volume_cert_block.block_id))

    if volume_cert_block.block_version != cert_bundle.file_version:
        raise Exception(
            "Cert block for volume does not match volume version (expected %s, got %s)"
            % (cert_bundle.file_version, volume_cert_block.block_version))

    if volume_cert_block.owner_id != user.owner_id:
        raise Exception(
            "Cert block for volume does not match owner ID (expected %s, got %s)"
            % (user.owner_id, volume_cert_block.owner_id))

    # go validate the affected gateways
    # NOTE: blocks[0] contains the volume cert (used by gateways)
    for i in xrange(1, len(cert_bundle.blocks)):

        block = cert_bundle.blocks[i]
        gateway_id = block.block_id

        if new_gateway_cert is not None and new_gateway_cert.gateway_id == gateway_id:
            # skip this one--we'll check below
            continue

        gateway_fut = Gateway.Read(gateway_id, async=True)

        gateway_cert_and_fut[gateway_id] = (block, gateway_fut)
        all_futs.append(gateway_fut)

    storagetypes.wait_futures(all_futs)

    for (gateway_id, (block, gateway_fut)) in gateway_cert_and_fut.items():

        # from the cert bundle
        given_gateway_version = None
        given_gateway_caps = None

        # on file
        gateway_version = None
        gateway_caps = None

        if new_gateway_cert is not None and new_gateway_cert.gateway_id == gateway_id:

            # make sure the new gateway cert has an appropriate version
            given_gateway_version = new_gateway_cert.gateway_version
            given_gateway_caps = new_gateway_cert.caps

            # don't worry about the caps--we'll be updating them shortly
            gateway_version = gateway.version
            gateway_caps = new_gateway_cert.caps

        else:

            # use the gateway on file
            gateway = gateway_fut.get_result()
            if gateway is None:

                # requested a gateway that didn't exist
                raise Exception(
                    "Cert bundle identifies non-existant gateway %s" %
                    gateway_id)

            if gateway.g_id != gateway_id:

                # this is a bug--the gateway is keyed by id
                raise Exception("BUG: requested %s, got %s" %
                                (gateway_id, gateway.g_id))

            given_gateway_caps = block.caps
            given_gateway_version = gateway.cert_version  # can only check new gateway certs

            # check against on-file cert
            gateway_version = gateway.cert_version
            gateway_caps = gateway.caps

        # gateway version must increase or stay the same
        if gateway_version > given_gateway_version:

            # stale version
            raise Exception(
                "Stale version for %s: expected >= %s, got %s" %
                (gateway_id, gateway_version, given_gateway_version))

        if (gateway_caps | given_gateway_caps) != given_gateway_caps:

            # invalid caps (only works when checked against on-file gateways)
            raise Exception("Invalid caps for %s: expected %s, got %s" %
                            (gateway_id, gateway.caps, given_gateway_caps))

    # valid!
    return True