def sync(self): """ Goes through every user to identify those with registered devices, and syncs to KVstore. The list of old_registered_users must be fetched first to avoid a possible race condition. :return: """ old_registered_users = get_all_mobile_users(self.session_key) all_splunk_users = get_all_users(self.session_key) + ['nobody'] registered_users = [ user for user in all_splunk_users if user_has_registered_devices(user, self.session_key) ] kvstore_users = KvStore(constants.REGISTERED_USERS_COLLECTION_NAME, self.session_key) try: [ kvstore_users.insert_single_item({u'_key': user}) for user in registered_users if user not in old_registered_users ] [ kvstore_users.delete_item_by_key(user) for user in old_registered_users if user not in registered_users ] LOGGER.info( "Completed Registered Users Sync in process PID={}".format( os.getpid())) except: LOGGER.exception( "Exception performing RegisteredUsersSync for collection={}". format(constants.REGISTERED_USERS_COLLECTION_NAME))
def delete_device(user, device_owner, device_key, system_authtoken, user_authtoken): """ Deletes a specific device from the kvstore. This function: 1. Checks if the user has the necessary privileges to delete the given device 2. Attempts to delete the device from the kvstore :param user: User making the deletion request :param device_owner: User who owns the device being deleted :param device_key: kvstore _key of the device being deleted :param system_authtoken: Authorization token with system-level privileges. Used to allow users to delete their own devices even when they don't have unrestricted kvstore write access :param user_authtoken: Authorization token with the same permissions as "user" :return: Success message """ # Checks if the user has the necessary privileges to delete the given device kvstore_user = KvStore(constants.REGISTERED_DEVICES_COLLECTION_NAME, user_authtoken, owner=device_owner) if user == device_owner: kvstore_user = KvStore(constants.REGISTERED_DEVICES_COLLECTION_NAME, system_authtoken, owner=device_owner) kvstore_nobody = KvStore(constants.DEVICE_PUBLIC_KEYS_COLLECTION_NAME, system_authtoken) r, record = kvstore_user.get_item_by_key(device_key) record = json.loads(record) # Attempts to delete the device from the kvstore kvstore_user.delete_item_by_key(device_key) try: kvstore_nobody.delete_item_by_key(device_key) except splunk.RESTException: LOGGER.info("public for device not found, device_id=%s" % device_key) LOGGER.info('device_key=%s (of device_owner=%s) deleted from kvstore by user=%s' % (device_key, device_owner, user)) delete_device_from_spacebridge(record['device_id'], system_authtoken) LOGGER.info('device key=%s (of device_owner=%s) deleted from spacebridge by user=%s' % (device_key, device_owner, user)) if not user_has_registered_devices(device_owner, system_authtoken): kvstore_nobody = KvStore(constants.REGISTERED_USERS_COLLECTION_NAME, system_authtoken) kvstore_nobody.delete_item_by_key(device_owner) return { 'payload': 'Device with key %s successfully deleted' % device_key, 'status': 200, }
def handle_confirmation(auth_code, user, session_token, system_authtoken, body): """ Handler for the final DevicePairingConfirmationRequest call. This function: 1. Authenticates the supplied username and password 2. Retrieves temporary record from the kvstore 3. Checks if app_type has been disabled since registration 4. Makes the DevicePairingConfirmationRequest request to the server 5. Creates a new permanent record for the device in the kvstore 6. Deletes the temporary kvstore record :param auth_code: User-entered authorization code to be returned to Spacebridge :param body: Parsed JSON body of the incoming POST request :param kvstore_unconfirmed: Access object for the temporary registration kvstore :param system_authtoken: System-level access token for writing to the kvstore :return: Success message """ # Authenticates the supplied username and password kvstore_temp = KvStore(constants.UNCONFIRMED_DEVICES_COLLECTION_NAME, system_authtoken, owner=user) encryption_context = SplunkEncryptionContext(system_authtoken, constants.SPACEBRIDGE_APP_NAME) username = extract_parameter(body, USERNAME_LABEL, BODY_LABEL) password = extract_parameter(body, PASSWORD_LABEL, BODY_LABEL) try: # use what Splunk thinks the username is to generate the session token auth = BasicAuthHeader(username, password) content = get_current_context(auth) username = content[constants.ENTRY][0][constants.CONTENT][constants.USERNAME] except SpacebridgePermissionsError as e: LOGGER.exception('Invalid credentials passed to current-context API') raise e LOGGER.info('Received new registration confirmation request by user=%s for device_owner=%s' % (user, username)) # Retrieves temporary record from the kvstore temp_key = extract_parameter(body, KVSTORE_TEMPORARY_ID_LABEL, BODY_LABEL) r, temp_record = kvstore_temp.get_item_by_key(temp_key) temp_record = json.loads(temp_record) device_id = temp_record[DEVICE_ID_LABEL] device_id_raw = base64.b64decode(device_id) device_registration = {'_key': py23.urlsafe_b64encode_to_str(device_id_raw)} device_public_keys = {'_key': py23.urlsafe_b64encode_to_str(device_id_raw)} for k in temp_record.keys(): if k in DEVICE_REGISTRATION_ATTRS: device_registration[k] = temp_record[k] if k in DEVICE_PUBLIC_KEYS_ATTRS: device_public_keys[k] = temp_record[k] # Checks if app_type has been disabled since registration app_name = temp_record[DEVICE_TYPE_LABEL] if not retrieve_state_of_app(app_name, system_authtoken): disabled_message = 'Registration Error: Application type app_name="%s" is disabled' % app_name LOGGER.info(disabled_message) return { 'payload': { 'message': disabled_message, 'app_name': app_name, }, 'status': 422, } device_encryption_info = DeviceInfo( base64.b64decode(temp_record['encrypt_public_key']), base64.b64decode(temp_record['sign_public_key']), base64.b64decode(temp_record['device_id']), "NA", app_id=temp_record['app_id'], app_name=temp_record['device_type'] ) deployment_friendly_name = get_deployment_friendly_name(system_authtoken) try: credentials = SplunkJWTCredentials(username, password=password) credentials.load_jwt_token(SplunkAuthHeader(session_token)) LOGGER.info("Successfully fetched jwt token") except Exception as e: LOGGER.info("Failed to fetch jwt token with message={}. Using basic credentials instead.".format(e)) credentials = SimpleUserCredentials(username, password) pair_device(auth_code, credentials, device_encryption_info, encryption_context, server_name=deployment_friendly_name, config=config, server_app_id=constants.SPLAPP_APP_ID) # Creates a new permanent record for the device in the kvstore kvstore_user = KvStore(constants.REGISTERED_DEVICES_COLLECTION_NAME, system_authtoken, owner=username) kvstore_user.insert_single_item(device_registration) # Adds the user to the list of users with registered devices, if not already there kvstore_users = KvStore(constants.REGISTERED_USERS_COLLECTION_NAME, system_authtoken) kvstore_users.insert_or_update_item_containing_key({'_key': username}) kvstore_nobody = KvStore(constants.DEVICE_PUBLIC_KEYS_COLLECTION_NAME, system_authtoken) kvstore_nobody.insert_single_item(device_public_keys) # Deletes the temporary kvstore record kvstore_temp.delete_item_by_key(temp_key) LOGGER.info('Device registration confirmed. Device with device_name=\"%s\" was recorded in the kvstore.' % temp_record[DEVICE_NAME_LABEL]) return { 'payload': 'Device registration successful', 'status': 201, }
def register_device(auth_code, user, system_authtoken, temp_key): """ Handler for the final DevicePairingConfirmationRequest call. This function: 2. Retrieves temporary record from the kvstore 3. Checks if app_type has been disabled since registration 4. Makes the DevicePairingConfirmationRequest request to the server 5. Creates a new permanent record for the device in the kvstore 6. Deletes the temporary kvstore record :param auth_code: User-entered authorization code to be returned to Spacebridge :param body: Parsed JSON body of the incoming POST request :param kvstore_unconfirmed: Access object for the temporary registration kvstore :param system_authtoken: System-level access token for writing to the kvstore :return: Success message """ kvstore_temp = KvStore(constants.UNCONFIRMED_DEVICES_COLLECTION_NAME, system_authtoken, owner=user) encryption_context = SplunkEncryptionContext( system_authtoken, constants.SPACEBRIDGE_APP_NAME) LOGGER.info('Received new registration confirmation request by user=%s' % (user)) # Retrieves temporary record from the kvstore r, temp_record = kvstore_temp.get_item_by_key(temp_key) temp_record = json.loads(temp_record) device_id = temp_record[DEVICE_ID_LABEL] device_id_raw = base64.b64decode(device_id) device_registration = {'_key': base64.urlsafe_b64encode(device_id_raw)} device_public_keys = {'_key': base64.urlsafe_b64encode(device_id_raw)} for k in temp_record.keys(): if k in DEVICE_REGISTRATION_ATTRS: device_registration[k] = temp_record[k] if k in DEVICE_PUBLIC_KEYS_ATTRS: device_public_keys[k] = temp_record[k] # Checks if app_type has been disabled since registration app_name = temp_record[DEVICE_TYPE_LABEL] if not retrieve_state_of_app(app_name, system_authtoken): disabled_message = 'Registration Error: Application type app_name="%s" is disabled' % app_name LOGGER.info(disabled_message) return { 'payload': { 'message': disabled_message, 'app_name': app_name, }, 'status': 422, } device_encryption_info = DeviceInfo( base64.b64decode(temp_record['encrypt_public_key']), base64.b64decode(temp_record['sign_public_key']), base64.b64decode(temp_record['device_id']), "NA", app_id=temp_record['app_id'], app_name=temp_record['device_type']) deployment_friendly_name = get_deployment_friendly_name(system_authtoken) pair_device(auth_code, SimpleUserCredentials("dummy", "dummy"), device_encryption_info, encryption_context, server_name=deployment_friendly_name, config=config) # Creates a new permanent record for the device in the kvstore kvstore_user = KvStore(constants.REGISTERED_DEVICES_COLLECTION_NAME, system_authtoken, owner=user) kvstore_user.insert_single_item(device_registration) # Adds the user to the list of users with registered devices, if not already there kvstore_users = KvStore(constants.REGISTERED_USERS_COLLECTION_NAME, system_authtoken) kvstore_users.insert_or_update_item_containing_key({'_key': user}) kvstore_nobody = KvStore(constants.DEVICE_PUBLIC_KEYS_COLLECTION_NAME, system_authtoken) kvstore_nobody.insert_single_item(device_public_keys) # Deletes the temporary kvstore record kvstore_temp.delete_item_by_key(temp_key) LOGGER.info( 'Device registration confirmed. Device with device_name=\"%s\" was recorded in the kvstore.' % temp_record[DEVICE_NAME_LABEL]) return { 'payload': 'Device registration successful', 'status': 201, }
def handle_saml_confirmation(auth_code, user, session_token, system_authtoken, body): """ Handler for the final DevicePairingConfirmationRequest call. This function: 1. Authenticates the supplied user name 2. Retrieves temporary record from the kvstore 3. Checks if app_type has been disabled since registration 4. Makes the DevicePairingConfirmationRequest request to the server 5. Creates a new permanent record for the device in the kvstore 6. Deletes the temporary kvstore record :param auth_code: User-entered authorization code to be returned to Spacebridge :param user: User provided by rest handler :param body: Parsed JSON body of the incoming POST request :param kvstore_unconfirmed: Access object for the temporary registration kvstore :param system_authtoken: System-level access token for writing to the kvstore :return: Success message """ # Authenticates the supplied user name kvstore_temp = KvStore(constants.UNCONFIRMED_DEVICES_COLLECTION_NAME, system_authtoken, owner=user) encryption_context = SplunkEncryptionContext( system_authtoken, constants.SPACEBRIDGE_APP_NAME) LOGGER.info( 'Received new registration confirmation request by user={}'.format( user)) # Retrieves temporary record from the kvstore temp_key = extract_parameter(body, KVSTORE_TEMPORARY_ID_LABEL, BODY_LABEL) r, temp_record = kvstore_temp.get_item_by_key(temp_key) temp_record = json.loads(temp_record) device_id = temp_record[DEVICE_ID_LABEL] device_id_raw = base64.b64decode(device_id) device_registration = { constants.KEY: py23.urlsafe_b64encode_to_str(device_id_raw) } device_public_keys = { constants.KEY: py23.urlsafe_b64encode_to_str(device_id_raw) } for k in temp_record.keys(): if k in DEVICE_REGISTRATION_ATTRS: device_registration[k] = temp_record[k] if k in DEVICE_PUBLIC_KEYS_ATTRS: device_public_keys[k] = temp_record[k] # Checks if app_type has been disabled since registration app_name = temp_record[DEVICE_TYPE_LABEL] device_encryption_info = DeviceInfo( base64.b64decode(temp_record['encrypt_public_key']), base64.b64decode(temp_record['sign_public_key']), base64.b64decode(temp_record['device_id']), "NA", app_id=temp_record['app_id'], app_name=temp_record['device_type']) deployment_friendly_name = get_deployment_friendly_name(system_authtoken) valid_request = is_valid_session_token(user, session_token) if valid_request: try: credentials = SplunkJWTCredentials(user) credentials.load_jwt_token(SplunkAuthHeader(system_authtoken)) LOGGER.info( "Successfully fetched jwt token for SAML auth user with username={}" .format(user)) except Exception as e: LOGGER.info( "Failed to fetch jwt token for user={} with message={}".format( user, e.message)) jwt_error_message = 'Registration Error: Failed to fetch jwt token for user={}'.format( user) return { 'payload': { 'message': jwt_error_message, 'app_name': app_name, }, 'status': 422, } pair_device(auth_code, credentials, device_encryption_info, encryption_context, server_name=deployment_friendly_name, config=config, server_app_id=constants.SPLAPP_APP_ID) # Creates a new permanent record for the device in the kvstore kvstore_user = KvStore(constants.REGISTERED_DEVICES_COLLECTION_NAME, system_authtoken, owner=user) kvstore_user.insert_single_item(device_registration) # Adds the user to the list of users with registered devices, if not already there kvstore_users = KvStore(constants.REGISTERED_USERS_COLLECTION_NAME, system_authtoken) kvstore_users.insert_or_update_item_containing_key( {constants.KEY: user}) kvstore_nobody = KvStore(constants.DEVICE_PUBLIC_KEYS_COLLECTION_NAME, system_authtoken) kvstore_nobody.insert_single_item(device_public_keys) # Deletes the temporary kvstore record kvstore_temp.delete_item_by_key(temp_key) LOGGER.info( 'Device registration confirmed. Device with device_name=\"%s\" was recorded in the kvstore.' % temp_record[DEVICE_NAME_LABEL]) else: LOGGER.info("Error: Mismatched user={} and session token".format(user)) jwt_error_message = 'Registration Error: Failed to fetch jwt token for user={}'.format( user) return { 'payload': { 'message': jwt_error_message, 'app_name': app_name, }, 'status': 422, } return { 'payload': 'Device registration successful', 'status': 201, }