Example #1
0
    def reauthorize_device(self, device_id):
        # Mark it as enabled.
        paired_device = PairedDevice.by_id(device_id)
        paired_device.auth_enabled = True
        paired_device.save()

        # Store the device credentials in the RADIUS server.
        self.radius_server.add_user_credentials(paired_device.device_id, paired_device.password)
Example #2
0
    def revoke_device(self, device_id):
        # Mark it as disabled.
        paired_device = PairedDevice.by_id(device_id)
        paired_device.auth_enabled = False
        paired_device.save()
        paired_device.stop_associated_instance()

        # Remove from RADIUS server.
        print 'Removing paired device from RADIUS server.'
        self.radius_server.remove_user_credentials([device_id])
Example #3
0
    def unpair_device(self, device_id):
        # Remove it from the list.
        print 'Removing paired device from DB.'
        paired_device = PairedDevice.by_id(device_id)
        paired_device.stop_associated_instance()
        PairedDevice.find_and_remove(device_id)

        # Remove from RADIUS server.
        print 'Removing paired device from RADIUS server.'
        self.radius_server.remove_user_credentials([device_id])
Example #4
0
    def GET_reauthorize(self, id):
        # Mark it as enabled.
        paired_device = PairedDevice.by_id(id)
        paired_device.auth_enabled = True
        paired_device.save()

        # Store the device credentials in the RADIUS server.
        radius_server = radius.RadiusServer(app_globals.cloudlet.radius_users_file,
                                            app_globals.cloudlet.radius_certs_folder,
                                            app_globals.cloudlet.radius_eap_conf_file)
        radius_server.add_user_credentials(paired_device.device_id, paired_device.password)

        # Go to the main page.
        return h.redirect_to(controller='devices', action='list')
Example #5
0
    def GET_revoke(self, id):
        # Mark it as disabled.
        paired_device = PairedDevice.by_id(id)
        paired_device.auth_enabled = False
        paired_device.save()
        stop_associated_instance(id)

        # Remove from RADIUS server.
        print 'Removing paired device from RADIUS server.'
        radius_server = radius.RadiusServer(app_globals.cloudlet.radius_users_file,
                                            app_globals.cloudlet.radius_certs_folder,
                                            app_globals.cloudlet.radius_eap_conf_file)
        radius_server.remove_user_credentials([id])

        # Go to the main page.
        return h.redirect_to(controller='devices', action='list')
Example #6
0
    def pair_device(self, device_internal_id, connection_id, device_type):
        try:
            # Check if the device was already paired, and if so, abort.
            previously_paired_device = PairedDevice.by_id(device_internal_id)
            if previously_paired_device:
                raise DeviceAlreadyPairedException("Device with id {} is already paired.".format(device_internal_id))
            else:
                print "Pairing with {}.".format(device_internal_id)

            # Generate credentials, register the device, and return them.
            device_keys = self.__generate_device_credentials(device_internal_id)
            self.__register_device(device_internal_id, connection_id, device_keys.auth_password,
                                   device_keys.encryption_password, device_type)

            return device_keys
        except DeviceAlreadyPairedException as e:
            raise e
        except Exception as e:
            raise Exception("Error pairing with device: " + str(e))
Example #7
0
    def POST_command(self):
        # Check what device is sending this request.
        device_id = request.headers['X-Device-ID']
        print ''
        print 'Received encrypted request from device ' + device_id
        device_info = PairedDevice.by_id(device_id)
        if not device_info:
            # We can't encrypt the reply since we got an invalid device id.
            self.send_abort_response(
                401, '#Device with id %s is not paired to this cloudlet' %
                device_id, None)

        # Get the device password.
        password = device_info.password

        # Check if device is authorized to send messages, and permission has not expired.
        if not device_info.auth_enabled:
            error = '#Authorization has been revoked for device with id %s' % device_id
            self.send_abort_response(403, error, password)
        if device_info.auth_start + datetime.timedelta(
                minutes=device_info.auth_duration) < datetime.datetime.now():
            error = '#Authorization has expired for device with id %s' % device_id
            self.send_abort_response(403, error, password)

        # Decrypt the request.
        encrypted_request = request.params['command']
        print 'Encrypted request: ' + encrypted_request
        decrypted_request = encryption.decrypt_message(encrypted_request,
                                                       password)
        print 'Decrypted request: ' + decrypted_request

        # Parse the request.
        controller_name = None
        action_name = ''
        parts = decrypted_request.split("&")
        command = parts[0]
        print 'Received command: ' + command
        command_parts = command.split("/")
        if len(command_parts) > 1:
            controller_name = command_parts[1]
        if len(command_parts) > 2:
            action_name = command_parts[2]

        # Parse params, if any.
        params_dict = {}
        if len(parts) > 1:
            params = parts[1:]
            for param in params:
                key = param.split("=")[0]
                value = param.split("=")[1]
                params_dict[key] = value

        # Find the appropriate controller.
        controller = None
        if controller_name == 'services':
            controller = ServicesController()
        elif controller_name == 'servicevm':
            controller = ServiceVMController()
        elif controller_name == 'apps':
            controller = AppPushController()
        elif controller_name == 'system':
            controller = CloudletController()

        is_invalid_command = controller is None or action_name not in controller.API_ACTIONS_MAP
        if is_invalid_command:
            self.send_abort_response(
                404,
                "#Command {} not found (controller: {}, action: {})".format(
                    command, controller_name, action_name), password)

        # Prepare the reply format and method.
        reply_format = controller.API_ACTIONS_MAP[action_name]['reply_type']
        request.method = 'GET'
        if 'method' in controller.API_ACTIONS_MAP[action_name]:
            request.method = controller.API_ACTIONS_MAP[action_name]['method']

        # Prepare the received params in the request object.
        print params_dict
        for param in params_dict:
            request.GET[param] = params_dict[param]

        # Execute the request we are redirecting to, and get its response.
        request.environ['pylons.routes_dict'][
            'action'] = controller.API_ACTIONS_MAP[action_name]['action']
        internal_response = controller(self.environ, self.dummy_start_response)
        raw_response = internal_response[0]

        # TODO: find a way to make this hack cleaner....
        # Hack to store SVM id in DB along with paired device info to stop it when mission ends.
        if controller_name == 'servicevm' and action_name == 'start':
            associate_instance_to_device(device_info, raw_response)

        # Check if the reply is an error.
        if reply_format == 'json':
            try:
                json.loads(raw_response)
            except ValueError:
                print 'Error in reply: not a json object, assuming internal error. Will return a 500 error.'
                self.send_abort_response(500, raw_response, password)

        # Encrypt the reply.
        encrypted_reply = encryption.encrypt_message(raw_response, password)
        print 'Encrypted reply '  #+ encrypted_reply

        # Reset the response body that each controller may have added, and set the content length to the length of the
        # encrypted reply.
        response.body = ''
        response.content_length = len(encrypted_reply)

        # If there was no error, respond with OK and the encrypted reply.
        print 'Sending encrypted reply, length: {}'.format(
            len(encrypted_reply))
        return encrypted_reply
Example #8
0
    def POST_command(self):
        # Check what device is sending this request.
        device_id = request.headers['X-Device-ID']
        print ''
        print 'Received encrypted request from device ' + device_id
        device_info = PairedDevice.by_id(device_id)
        if not device_info:
            # We can't encrypt the reply since we got an invalid device id.
            error = '#Device with id %s is not paired to this cloudlet' % device_id
            print error
            abort(401, error)

        # Get the device password.
        password = device_info.password

        # Check if device is authorized to send messages, and permission has not expired.
        if not device_info.auth_enabled:
            error = '#Authorization has been revoked for device with id %s' % device_id
            self.encrypted_abort(403, error, password)
        if device_info.auth_start + datetime.timedelta(minutes=device_info.auth_duration) < datetime.datetime.now():
            error = '#Authorization has expired for device with id %s' % device_id
            self.encrypted_abort(403, error, password)

        # Decrypt the request.
        encrypted_request = request.params['command']
        print 'Encrypted request: ' + encrypted_request
        decrypted_request = encryption.decrypt_message(encrypted_request, password)
        print 'Decrypted request: ' + decrypted_request

        # Parse the request.
        parts = decrypted_request.split("&")
        command = parts[0]
        if len(parts) > 1:
            params = parts[1:]
            params_dict = {}
            for param in params:
                key = param.split("=")[0]
                value = param.split("=")[1]
                params_dict[key] = value

        # Then redirect to the appropriate controller.
        print 'Received command: ' + command
        reply = ''
        reply_format = 'json'
        if command == '/services':
            controller = ServicesController()
            request.environ['pylons.routes_dict']['action'] = 'list'
            request.method = 'GET'
            reply = controller(self.environ, self.dummy_start_response)
        elif command == '/services/get':
            request.GET['serviceId'] = params_dict['serviceId']
            controller = ServicesController()
            request.environ['pylons.routes_dict']['action'] = 'find'
            request.method = 'GET'
            reply = controller(self.environ, self.dummy_start_response)
        elif command == '/servicevm/start':
            request.GET['serviceId'] = params_dict['serviceId']
            controller = ServiceVMController()
            request.environ['pylons.routes_dict']['action'] = 'start'
            request.method = 'GET'
            reply = controller(self.environ, self.dummy_start_response)

            # Hack to store SVM id in DB along with paired device info to stop it when mission ends.
            associate_instance_to_device(device_info, reply[0])
        elif command == '/servicevm/stop':
            request.GET['instanceId'] = params_dict['instanceId']
            controller = ServiceVMController()
            request.environ['pylons.routes_dict']['action'] = 'stop'
            request.method = 'GET'
            reply = controller(self.environ, self.dummy_start_response)
        elif command == '/apps':
            for param in params_dict:
                request.GET[param] = params_dict[param]
            controller = AppPushController()
            request.environ['pylons.routes_dict']['action'] = 'getList'
            request.method = 'GET'
            reply = controller(self.environ, self.dummy_start_response)
        elif command == '/apps/get':
            request.GET['appId'] = params_dict['appId']
            controller = AppPushController()
            request.environ['pylons.routes_dict']['action'] = 'getApp'
            request.method = 'GET'
            reply = controller(self.environ, self.dummy_start_response)
            reply_format = 'binary'
        elif command == '/system':
            controller = CloudletController()
            request.environ['pylons.routes_dict']['action'] = 'metadata'
            request.method = 'GET'
            reply = controller(self.environ, self.dummy_start_response)
        else:
            self.encrypted_abort(404, '404 Not Found - command %s not found' % command, password)

        text_repy = reply[0]

        # Check if the reply is an error.
        if reply_format == 'json':
            try:
                json_object = json.loads(text_repy)
            except ValueError, e:
                print 'Error in repy: not a json object, assuming internal error. Will return a 500 error.'
                self.encrypted_abort(500, text_repy, password)
Example #9
0
    def GET_pair(self, id):
        connection = request.params.get('connection', None)
        if connection is None:
            connection = 'bt'

        curr_device = None
        try:
            # Create a device depending on the type.
            if connection == 'bt':
                port = request.params.get('port', None)
                name = request.params.get('name', None)
                curr_device = BluetoothSKADevice({'host': id, 'port': int(port), 'name': name})
            else:
                curr_device = ADBSKADevice(id)

            # Now the pairing process will be followed, generating all required credentials.
            # The first step is to connect to the device.
            successful_connection = curr_device.connect()
            if not successful_connection:
                return ajaxutils.show_and_return_error_dict("Could not connect to device with id {}.".format(id))

            # Get the device id.
            id_data = curr_device.get_data({'device_id': 'none'})
            device_internal_id = id_data['device_id']
            print 'Device id: ' + device_internal_id

            # Check if the device was already paired, and if so, abort.
            previously_paired_device = PairedDevice.by_id(device_internal_id)
            if previously_paired_device:
                return ajaxutils.show_and_return_error_dict("Device with id {} is already paired.".format(device_internal_id))

            # Prepare the server and device credential objects.
            server_keys = credentials.ServerCredentials.create_object(app_globals.cloudlet.credentials_type,
                                                                      app_globals.cloudlet.data_folder)
            device_keys = credentials.DeviceCredentials.create_object(app_globals.cloudlet.credentials_type,
                                                                      app_globals.cloudlet.data_folder,
                                                                      device_internal_id,
                                                                      server_keys.private_key_path)

            # Create the device's private key and the device's passwords.
            device_keys.generate_and_save_to_file()

            # Send the server's public key.
            curr_device.send_file(server_keys.public_key_path, 'server_public.key')

            # Send the device's private key to the device.
            curr_device.send_file(device_keys.private_key_path, 'device.key')

            # Send RADIUS certificate to the device.
            radius_server = radius.RadiusServer(app_globals.cloudlet.radius_users_file,
                                                app_globals.cloudlet.radius_certs_folder,
                                                app_globals.cloudlet.radius_eap_conf_file)
            cert_file_name = radius.RADIUS_CERT_FILE_NAME
            curr_device.send_file(radius_server.cert_file_path, cert_file_name)

            # Send a command to create a Wi-Fi profile on the device. The message has to contain three key pairs:
            # ssid, the RADIUS certificate filename, and the password to be used in the profile.
            ssid = app_globals.cloudlet.ssid
            curr_device.send_data({'command': 'wifi-profile', 'ssid': ssid, 'server_cert_name': cert_file_name,
                                   'password': device_keys.auth_password})

            # Remove the device private key and password files, for security cleanup.
            device_keys.delete_key_files()

        except Exception, e:
            return ajaxutils.show_and_return_error_dict("Error pairing with device: " + str(e))