def GET_list(self): c.devices_active = 'active' page = DevicesPage() # Ensure the device types are initialized. BluetoothSKADevice.initialize(app_globals.cloudlet.data_folder) ADBSKADevice.initialize(app_globals.cloudlet.data_folder) # Get the overall deployment info. page.deployment = Deployment.get_instance() if page.deployment.auth_start is None: page.deployment_auth_start = 'not set' page.deployment_auth_duration = 'not set' page.deployment_auth_end = 'not set' else: page.deployment_auth_start = page.deployment.auth_start.strftime( '%Y-%m-%d %X') page.deployment_auth_duration = page.deployment.auth_duration page.deployment_auth_end = ( page.deployment.auth_start + datetime.timedelta(minutes=page.deployment.auth_duration) ).strftime('%Y-%m-%d %X') # Get the paired devices. page.paired_devices = PairedDevice.by_type('mobile') # Get the paired cloudlets. page.paired_cloudlets = PairedDevice.by_type('cloudlet') return page.render()
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])
def GET_authorize(self, did): connection_id = request.params.get('cid', None) auth_password = request.params.get('auth_password', None) enc_password = request.params.get('enc_password', None) # Create a new paired device with the id info we just received. print 'Adding paired device to DB.' paired_device = PairedDevice() paired_device.device_id = did paired_device.connection_id = connection_id paired_device.password = enc_password # By default, authorization for a device will be the same as the deployment info. deployment = Deployment.find_one() paired_device.auth_start = deployment.auth_start paired_device.auth_duration = deployment.auth_duration paired_device.auth_enabled = True # Store the paired device. paired_device.save() # Store the new 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, auth_password) # Go to the main page. print 'Device added to DB.' return ajaxutils.JSON_OK
def clear(self): # Remove users from RADIUS server. print 'Removing paired devices from RADIUS server.' devices = PairedDevice.find() device_ids = [] for device in devices: device_ids.append(device.device_id) device.stop_associated_instance() self.radius_server.remove_user_credentials(device_ids) # Remove all data from DB. print 'Clearing up database.' PairedDevice.clear_data()
def GET_unpair(self, id): # Remove it from the list. print 'Removing paired device from DB.' stop_associated_instance(id) PairedDevice.find_and_remove(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')
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)
def clear_deployment(self): # Remove users from RADIUS server. print 'Removing paired devices from RADIUS server.' devices = PairedDevice.find() device_ids = [] for device in devices: device_ids.append(device.device_id) stop_associated_instance(device.device_id) 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(device_ids) # Remove all data from DB. print 'Clearing up database.' PairedDevice.clear_data() Deployment.remove()
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])
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')
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')
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))
def GET_list(self): c.devices_active = 'active' page = DevicesPage() # Ensure the device types are initialized. BluetoothSKADevice.initialize(app_globals.cloudlet.data_folder) ADBSKADevice.initialize(app_globals.cloudlet.data_folder) # Get the overall deployment info. page.deployment = Deployment.find_one() if page.deployment is None: page.deployment_auth_start = 'not set' page.deployment_auth_duration = 'not set' page.deployment_auth_end = 'not set' else: page.deployment_auth_start = page.deployment.auth_start.strftime('%Y-%m-%d %X') page.deployment_auth_duration = page.deployment.auth_duration page.deployment_auth_end = (page.deployment.auth_start + datetime.timedelta(minutes=page.deployment.auth_duration)).strftime('%Y-%m-%d %X') # Get the paired devices. page.paired_devices = PairedDevice.find() return page.render()
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
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)
def __register_device(self, device_id, connection_id, auth_password, enc_password, device_type): # Create a new paired device with the id info we just received. print 'Adding paired device to DB.' paired_device = PairedDevice() paired_device.device_id = device_id paired_device.connection_id = connection_id paired_device.password = enc_password paired_device.type = device_type # By default, authorization for a device will be the same as the deployment info. paired_device.auth_start = self.auth_start paired_device.auth_duration = self.auth_duration paired_device.auth_enabled = True # Store the paired device. paired_device.save() # Store the new device credentials in the RADIUS server. self.radius_server.add_user_credentials(paired_device.device_id, auth_password) # Go to the main page. print 'Device added to DB.'
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))