Пример #1
0
    def register_via_preregistered_key(self):
        """Register this device with a zone, through the central server directly"""

        own_device = Device.get_own_device()

        # Since we can't know the version of the remote device (yet),
        #   we give it everything we possibly can (don't specify a dest_version)
        #
        # Note that (currently) this should never fail--the central server (which we're sending
        #   these objects to) should always have a higher version.
        r = self.post("register", {
            "client_device":
            engine.serialize([own_device], ensure_ascii=False),
        })

        # If they don't understand, our assumption is broken.
        if r.status_code == 500 and "Device has no field named 'version'" in r.content:
            raise Exception("Central server is of an older version than us?")

        # Failed to register with any certificate
        elif r.status_code != 200:
            raise Exception(r.content)

        else:
            # Save to our local store.  By NOT passing a src_version,
            #   we're saying it's OK to just store what we can.
            return engine.deserialize(r.content,
                                      src_version=None,
                                      dest_version=own_device.get_version())
Пример #2
0
    def register_via_preregistered_key(self):
        """Register this device with a zone, through the central server directly"""

        own_device = Device.get_own_device()

        # Since we can't know the version of the remote device (yet),
        #   we give it everything we possibly can (don't specify a dest_version)
        #
        # Note that (currently) this should never fail--the central server (which we're sending
        #   these objects to) should always have a higher version.
        r = self.post("register", {
            "client_device": engine.serialize([own_device], ensure_ascii=False),
        })

        # If they don't understand, our assumption is broken.
        if r.status_code == 500 and "Device has no field named 'version'" in r.content:
            raise Exception("Central server is of an older version than us?")

        # Failed to register with any certificate
        elif r.status_code != 200:
            raise Exception(r.content)

        else:
            # Save to our local store.  By NOT passing a src_version,
            #   we're saying it's OK to just store what we can.
            return engine.deserialize(r.content, src_version=None, dest_version=own_device.get_version())
Пример #3
0
    def register_prove_self_registration(self):
        """
        Prove that we belong on our zone by providing the chain of trust,
        from us to the creator of the zone.
        """
        # Get all the
        own_device = Device.get_own_device()
        try:
            own_devicezone = DeviceZone.objects.get(
                device=own_device)  # We exit if not found
        except DeviceZone.DoesNotExist:
            # This should never actually happen--when upgrading to this new code,
            #   all devices should be on a zone.
            # However, if somehow that fails, let's try to create one now!
            raise Exception(
                "Shared network not installed.  Try running the `generate_zone` command."
            )

        own_zone = own_devicezone.zone
        chain_of_trust = ChainOfTrust(device=own_device, zone=own_zone)

        # For now, just try with one certificate
        #
        # Serialize for any version; in the current implementation, we assume the central server has
        #   a version at least as new as ours, so can handle whatever data we send.
        #
        # the other side will have to reconstruct the chain from the object list
        object_list = [own_device] + chain_of_trust.objects()
        r = self.post("register", {
            "client_device":
            engine.serialize(object_list, ensure_ascii=False),
        })

        # Failed to register with any certificate
        if r.status_code != 200:
            raise Exception(r.content)

        # When we register, we should receive the model information we require.
        #   Make sure to deserialize for our version.
        return (engine.deserialize(r.content,
                                   dest_version=own_device.get_version()), r)
Пример #4
0
        def create_json_file(include_data):
            central_server = Device.get_central_server()
            if not zone_id:
                models = [central_server] if central_server else []

            else:
                # Get a chain of trust to the zone owner.
                #   Because we're on the central server, this will
                #   simply be the central server, but in the future
                #   this would return an actual chain.
                logging.debug("Generating a zone invitation...")
                zone = Zone.objects.get(id=zone_id)
                chain = ChainOfTrust(zone=zone)
                assert chain.validate()
                new_invitation = ZoneInvitation.generate(
                    zone=zone, invited_by=Device.get_own_device())
                new_invitation.save(
                )  # keep a record of the invitation, for future revocation.  Also, signs the thing

                # This ordering of objects is a bit be hokey, but OK--invitation usually must be
                #   inserted before devicezones--but because it's not pointing to any devices,
                #   it's OK to be at the end.
                # Note that the central server will always be at the front of the chain of trust,
                #   so no need to explicitly include.
                models = chain.objects() + [new_invitation]

                #
                if include_data:
                    logging.debug("Serializing entire dataset...")
                    devices = Device.objects.by_zone(zone)
                    devicezones = DeviceZone.objects.filter(zone=zone)
                    models += list(devices) + list(devicezones)
                    models += engine.get_models(
                        zone=zone, limit=None)  # get all models on this zone

            models_file = tempfile.mkstemp()[1]
            with open(models_file, "w") as fp:
                fp.write(engine.serialize(models))
            return models_file
Пример #5
0
    def register_prove_self_registration(self):
        """
        Prove that we belong on our zone by providing the chain of trust,
        from us to the creator of the zone.
        """
        # Get all the
        own_device = Device.get_own_device()
        try:
            own_devicezone = DeviceZone.objects.get(device=own_device)  # We exit if not found
        except DeviceZone.DoesNotExist:
            # This should never actually happen--when upgrading to this new code,
            #   all devices should be on a zone.
            # However, if somehow that fails, let's try to create one now!
            raise Exception("Shared network not installed.  Try running the `generate_zone` command.")

        own_zone = own_devicezone.zone
        chain_of_trust = ChainOfTrust(device=own_device, zone=own_zone)

        # For now, just try with one certificate
        #
        # Serialize for any version; in the current implementation, we assume the central server has
        #   a version at least as new as ours, so can handle whatever data we send.
        #
        # the other side will have to reconstruct the chain from the object list
        object_list = [own_device] + chain_of_trust.objects()
        r = self.post("register", {
            "client_device": engine.serialize(object_list, ensure_ascii=False),
        })

        # Failed to register with any certificate
        if r.status_code != 200:
            raise Exception(r.content)

        # When we register, we should receive the model information we require.
        #   Make sure to deserialize for our version.
        return (engine.deserialize(r.content, dest_version=own_device.get_version()), r)
Пример #6
0
        def create_json_file(include_data):
            central_server = Device.get_central_server()
            if not zone_id:
                models = [central_server] if central_server else []

            else:
                # Get a chain of trust to the zone owner.
                #   Because we're on the central server, this will
                #   simply be the central server, but in the future
                #   this would return an actual chain.
                logging.debug("Generating a zone invitation...")
                zone = Zone.objects.get(id=zone_id)
                chain = ChainOfTrust(zone=zone)
                assert chain.validate()
                new_invitation = ZoneInvitation.generate(zone=zone, invited_by=Device.get_own_device())
                new_invitation.save()  # keep a record of the invitation, for future revocation.  Also, signs the thing

                # This ordering of objects is a bit be hokey, but OK--invitation usually must be 
                #   inserted before devicezones--but because it's not pointing to any devices,
                #   it's OK to be at the end.
                # Note that the central server will always be at the front of the chain of trust,
                #   so no need to explicitly include.
                models = chain.objects() + [new_invitation]

                # 
                if include_data:
                    logging.debug("Serializing entire dataset...")
                    devices = Device.objects.by_zone(zone)
                    devicezones = DeviceZone.objects.filter(zone=zone)
                    models += list(devices) + list(devicezones)
                    models += engine.get_models(zone=zone, limit=None)  # get all models on this zone

            models_file = tempfile.mkstemp()[1]
            with open(models_file, "w") as fp:
                fp.write(engine.serialize(models))
            return models_file
Пример #7
0
def register_device(request):
    """Receives the client device info from the distributed server.
    Tries to register either because the device has been pre-registered,
    or because it has a valid INSTALL_CERTIFICATE."""
    # attempt to load the client device data from the request data
    data = simplejson.loads(request.raw_post_data or "{}")
    if "client_device" not in data:
        return JsonResponse(
            {"error": "Serialized client device must be provided."},
            status=500)
    try:
        # When hand-shaking on the device models, since we don't yet know the version,
        #   we have to just TRY with our own version.
        #
        # This is currently "central server" code, so
        #   this will only fail (currently) if the central server version
        #   is less than the version of a client--something that should never happen
        try:
            local_version = Device.get_own_device().get_version()
            models = engine.deserialize(data["client_device"],
                                        src_version=local_version,
                                        dest_version=local_version)
        except db_models.FieldDoesNotExist as fdne:
            raise Exception(
                "Central server version is lower than client version.  This is ... impossible!"
            )
        client_device = models.next().object
    except Exception as e:
        return JsonResponse(
            {
                "error": "Could not decode the client device model: %r" % e,
                "code": "client_device_corrupted",
            },
            status=500)

    # Validate the loaded data
    if not isinstance(client_device, Device):
        return JsonResponse(
            {
                "error":
                "Client device must be an instance of the 'Device' model.",
                "code": "client_device_not_device",
            },
            status=500)
    if not client_device.verify():
        return JsonResponse(
            {
                "error":
                "Client device must be self-signed with a signature matching its own public key.",
                "code": "client_device_invalid_signature",
            },
            status=500)

    try:
        zone = register_self_registered_device(client_device, models, data)
    except Exception as e:
        if e.message == "Client not yet on zone.":
            zone = None
        else:
            # Client not on zone: allow fall-through via "old route"

            # This is the codepath for unregistered devices trying to start a session.
            #   This would only get hit, however, if they visit the registration page.
            # But still, good to keep track of!
            UnregisteredDevicePing.record_ping(id=client_device.id,
                                               ip=get_request_ip(request))

            return JsonResponse(
                {
                    "error": "Failed to validate the chain of trust (%s)." % e,
                    "code": "chain_of_trust_invalid",
                },
                status=500)

    if not zone:  # old code-path
        try:
            registration = RegisteredDevicePublicKey.objects.get(
                public_key=client_device.public_key)
            if not registration.is_used():
                registration.use()

            elif get_object_or_None(Device,
                                    public_key=client_device.public_key):
                return JsonResponse(
                    {
                        "error": "This device has already been registered",
                        "code": "device_already_registered",
                    },
                    status=500)
            else:
                # If not... we're in a very weird state--we have a record of their
                #   registration, but no device record.
                # Let's just let the registration happens, so we can refresh things here.
                #   No harm, and some failsafe benefit.
                # So, pass through... no code :)
                pass

            # Use the RegisteredDevicePublicKey, now that we've initialized the device and put it in its zone
            zone = registration.zone

        except RegisteredDevicePublicKey.DoesNotExist:
            try:
                device = Device.objects.get(
                    public_key=client_device.public_key)
                return JsonResponse(
                    {
                        "error": "This device has already been registered",
                        "code": "device_already_registered",
                    },
                    status=500)
            except Device.DoesNotExist:
                return JsonResponse(
                    {
                        "error":
                        "Device registration with public key not found; login and register first?",
                        "code": "public_key_unregistered",
                    },
                    status=500)

    client_device.save(imported=True)

    try:
        device_zone = DeviceZone.objects.get(device=client_device, zone=zone)
        device_zone.save(
        )  # re-save, to give it a central server signature that will be honored by old clients
    except DeviceZone.DoesNotExist:
        device_zone = DeviceZone(device=client_device, zone=zone)
        device_zone.save(
        )  # create the DeviceZone for the new device, with an 'upgraded' signature

    # return our local (server) Device, its Zone, and the newly created DeviceZone, to the client
    #   Note the order :)
    #
    # Addition: always back central server object--in case they didn't get it during install,
    #   they need it for software updating.
    return JsonResponse(
        engine.serialize([
            Device.get_central_server(),
            Device.get_own_device(), zone, device_zone
        ],
                         dest_version=client_device.version,
                         ensure_ascii=False))
Пример #8
0
def register_device(request):
    """Receives the client device info from the distributed server.
    Tries to register either because the device has been pre-registered,
    or because it has a valid INSTALL_CERTIFICATE."""
    # attempt to load the client device data from the request data
    data = simplejson.loads(request.raw_post_data or "{}")
    if "client_device" not in data:
        return JsonResponseMessageError("Serialized client device must be provided.")
    try:
        # When hand-shaking on the device models, since we don't yet know the version,
        #   we have to just TRY with our own version.
        #
        # This is currently "central server" code, so
        #   this will only fail (currently) if the central server version
        #   is less than the version of a client--something that should never happen
        try:
            local_version = Device.get_own_device().get_version()
            models = engine.deserialize(data["client_device"], src_version=local_version, dest_version=local_version)
        except db_models.FieldDoesNotExist as fdne:
            raise Exception("Central server version is lower than client version.  This is ... impossible!")
        client_device = models.next().object
    except Exception as e:
        return JsonResponseMessageError("Could not decode the client device model: %s" % e, code="client_device_corrupted")

    # Validate the loaded data
    if not isinstance(client_device, Device):
        return JsonResponseMessageError("Client device must be an instance of the 'Device' model.", code="client_device_not_device")
    if not client_device.verify():
        return JsonResponseMessageError("Client device must be self-signed with a signature matching its own public key.", code="client_device_invalid_signature")

    try:
        zone = register_self_registered_device(client_device, models, data)
    except Exception as e:
        if e.message == "Client not yet on zone.":
            zone = None
        else:
            # Client not on zone: allow fall-through via "old route"

            # This is the codepath for unregistered devices trying to start a session.
            #   This would only get hit, however, if they visit the registration page.
            # But still, good to keep track of!
            UnregisteredDevicePing.record_ping(id=client_device.id, ip=get_request_ip(request))

            return JsonResponseMessageError("Failed to validate the chain of trust (%s)." % e, code="chain_of_trust_invalid")

    if not zone: # old code-path
        try:
            registration = RegisteredDevicePublicKey.objects.get(public_key=client_device.public_key)
            if not registration.is_used():
                registration.use()

            elif get_object_or_None(Device, public_key=client_device.public_key):
                return JsonResponseMessageError("This device has already been registered", code="device_already_registered")
            else:
                # If not... we're in a very weird state--we have a record of their
                #   registration, but no device record.
                # Let's just let the registration happens, so we can refresh things here.
                #   No harm, and some failsafe benefit.
                # So, pass through... no code :)
                pass

            # Use the RegisteredDevicePublicKey, now that we've initialized the device and put it in its zone
            zone = registration.zone

        except RegisteredDevicePublicKey.DoesNotExist:
            try:
                device = Device.objects.get(public_key=client_device.public_key)
                return JsonResponseMessageError("This device has already been registered", code="device_already_registered")
            except Device.DoesNotExist:
                return JsonResponseMessageError("Device registration with public key not found; login and register first?", code="public_key_unregistered")

    client_device.save(imported=True)

    try:
        device_zone = DeviceZone.objects.get(device=client_device, zone=zone)
        device_zone.save()  # re-save, to give it a central server signature that will be honored by old clients
    except DeviceZone.DoesNotExist:
        device_zone = DeviceZone(device=client_device, zone=zone)
        device_zone.save()     # create the DeviceZone for the new device, with an 'upgraded' signature

    # return our local (server) Device, its Zone, and the newly created DeviceZone, to the client
    #   Note the order :)
    #
    # Addition: always back central server object--in case they didn't get it during install,
    #   they need it for software updating.
    return JsonResponse(
        engine.serialize([Device.get_central_server(), Device.get_own_device(), zone, device_zone], dest_version=client_device.version, ensure_ascii=False)
    )