Exemple #1
0
def retrieve_state_of_app(app_name, authtoken):
    """
    Single function to encapsulate all app_type state retrieval behaviour. This function:
        1. Attempts to retrieve the record of the app from the kvstore
        2. Creates a new record if one does not already exist

    :param app_name: Name of app in kvstore
    :param authtoken: System level auth token (in case new record needs to be created)
    :return:
    """

    # Attempts to retrieve the record of the app from the kvstore
    kvstore = KvStore(constants.APPLICATION_TYPES_COLLECTION_NAME,
                      authtoken,
                      owner=NOBODY)
    r, app_record = kvstore.get_items_by_query({'application_name': app_name})
    app_record = json.loads(app_record)

    # Creates a new record if one does not already exist
    if not app_record:
        kvstore.insert_single_item({
            'application_name': app_name,
            'application_enabled': False
        })
        return False
    return app_record[0][APPLICATION_ENABLED_LABEL]
Exemple #2
0
def set_state_of_app(app_name, authtoken, system_authtoken, new_state):
    """
    Updates whether the specified app is enabled or not. This function:
        1. Validates the app_type for correctness
        2. If app is being disabled, delete all registered devices
        3. Attempts to retrieve the record of the app from the kvstore
        4. Updates or creates the new kvstore entry depending if one exists already
        5. Returns the state of the app_type

    :param app_name: Name of app in kvstore
    :param authtoken: User's authorization token
    :param system_authtoken: System authorization token
    :param new_state: Boolean signifying whether to enable the app
    :return: Success message
    """

    # Validates the app_type for correctness
    if app_name not in APP_TYPES:
        raise Errors.SpacebridgeRestError(
            'Error: Invalid app_type=%s' % app_name, 400)

    # If app is being disabled, delete all registered devices
    if not new_state:
        delete_all_devices_of_type(app_name, authtoken, system_authtoken)

    # Attempts to retrieve the record of the app from the kvstore
    kvstore = KvStore(constants.APPLICATION_TYPES_COLLECTION_NAME,
                      authtoken,
                      owner=NOBODY)
    r, app_record = kvstore.get_items_by_query({'application_name': app_name})
    app_record = json.loads(app_record)
    new_app = {'application_name': app_name, 'application_enabled': new_state}

    # Updates or creates the new kvstore entry depending if one exists already
    if app_record:
        kvstore.update_item_by_key(app_record[0]['_key'], new_app)
    else:
        kvstore.insert_single_item(new_app)

    result_string = 'Application app_type=%s is now new_state=%s' % (
        app_name, 'enabled' if new_state else 'disabled')

    LOGGER.info(result_string)

    # Returns the state of the app_type
    return {
        'payload': result_string,
        'status': 200,
    }
Exemple #3
0
    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))
Exemple #4
0
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_query(auth_code, device_name, user, system_authtoken):
    """
    Handler for the initial AuthenticationQueryRequest call. This function:
        1. Makes the AuthenticationQueryRequest request to the server
        2. Checks if app_type has been disabled
        3. Stores a temporary record in the kvstore

    :param auth_code: User-entered authorization code to be returned to Spacebridge
    :param device_name: Name of the new device
    :return: Confirmation code to be displayed to user, and id of temporary kvstore record to be returned later
    """

    LOGGER.info('Received new registration query request by user=%s' % user)

    # Makes the AuthenticationQueryRequest request to the server
    sodium_client = SodiumClient(LOGGER.getChild('sodium_client'))
    encryption_context = SplunkEncryptionContext(system_authtoken,
                                                 SPACEBRIDGE_APP_NAME,
                                                 sodium_client)
    client_device_info = authenticate_code(auth_code,
                                           encryption_context,
                                           resolve_app_name,
                                           config=config)
    app_name = client_device_info.app_name
    app_id = client_device_info.app_id

    LOGGER.info("client_device_info={}".format(client_device_info))

    user_devices = get_devices_for_user(user, system_authtoken)
    LOGGER.info("user_devices=%s" % user_devices)

    if any(device[DEVICE_NAME_LABEL] == device_name
           and device['device_type'] == app_name for device in user_devices):
        err_msg = (
            'Registration Error: user={} device_name={} of app_type={} already exists'
            .format(user, device_name, app_name))
        LOGGER.info(err_msg)
        raise Errors.SpacebridgeRestError(err_msg, http.CONFLICT)

    # Checks if app_type has been disabled
    if not retrieve_state_of_app(app_name, system_authtoken):
        disabled_message = 'Registration Error: Application type app_name="{}" is disabled'.format(
            app_name)
        LOGGER.info(disabled_message)
        return {
            'payload': {
                'message': disabled_message,
                'is_admin': user_is_administrator(user, system_authtoken),
                'app_name': app_name,
            },
            'status': 422,
        }

    # Stores a temporary record in the kvstore
    kvstore_unconfirmed = KvStore(UNCONFIRMED_DEVICES_COLLECTION_NAME,
                                  system_authtoken,
                                  owner=user)
    kvstore_payload = client_device_info.to_json()
    kvstore_payload['device_name'] = device_name
    kvstore_payload['device_type'] = app_name
    kvstore_payload['app_id'] = app_id
    _, content = kvstore_unconfirmed.insert_single_item(kvstore_payload)

    return {
        'payload': {
            'temp_key': json.loads(content)['_key'],
            'conf_code': client_device_info.confirmation_code
        },
        'status': http.OK,
    }
Exemple #7
0
def handle_query(auth_code, device_name, user, system_authtoken):
    """
    Handler for the initial AuthenticationQueryRequest call. This function:
        1. Makes the AuthenticationQueryRequest request to the server
        2. Checks if app_type has been disabled
        3. Stores a temporary record in the kvstore

    :param auth_code: User-entered authorization code to be returned to Spacebridge
    :param device_name: Name of the new device
    :return: Confirmation code to be displayed to user, and id of temporary kvstore record to be returned later
    """

    LOGGER.info('Received new registration query request by user=%s' % user)

    # Makes the AuthenticationQueryRequest request to the server
    sodium_client = SodiumClient(LOGGER.getChild('sodium_client'))
    encryption_context = SplunkEncryptionContext(system_authtoken,
                                                 SPACEBRIDGE_APP_NAME,
                                                 sodium_client)
    client_device_info = authenticate_code(auth_code,
                                           encryption_context,
                                           resolve_app_name,
                                           config=config)
    app_name = client_device_info.app_name
    app_id = client_device_info.app_id

    platform = client_device_info.platform

    # if platform not set and we know platform based on app id, use that.
    if not platform and app_id in APP_ID_TO_PLATFORM_MAP:
        platform = get_app_platform(app_id)

    LOGGER.info("client_device_info={}".format(client_device_info))

    user_devices = get_devices_for_user(user, system_authtoken)
    LOGGER.info("user_devices=%s" % user_devices)

    if any(device[DEVICE_NAME_LABEL] == device_name
           and device['device_type'] == app_name for device in user_devices):
        err_msg = (
            'Registration Error: user={} device_name={} of app_type={} already exists'
            .format(user, device_name, app_name))
        LOGGER.info(err_msg)
        raise Errors.SpacebridgeRestError(err_msg, HTTPStatus.CONFLICT)

    # Stores a temporary record in the kvstore
    kvstore_unconfirmed = KvStore(UNCONFIRMED_DEVICES_COLLECTION_NAME,
                                  system_authtoken,
                                  owner=user)
    kvstore_payload = client_device_info.to_json()
    kvstore_payload['device_name'] = device_name
    kvstore_payload['device_type'] = app_name
    kvstore_payload['app_name'] = app_name
    kvstore_payload['app_id'] = app_id
    kvstore_payload['platform'] = platform
    _, content = kvstore_unconfirmed.insert_single_item(kvstore_payload)

    return {
        'payload': {
            'temp_key': json.loads(content)['_key'],
            'conf_code': client_device_info.confirmation_code
        },
        'status': HTTPStatus.OK,
    }
Exemple #8
0
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,
    }