コード例 #1
0
 def from_rest_request(request):
     return RequestContext(
         auth_header=SplunkAuthHeader(request[SESSION][AUTHTOKEN]),
         request_id=str(uuid.uuid4()),
         current_user=request[SESSION][USER],
         system_auth_header=SplunkAuthHeader(request[SYSTEM_AUTHTOKEN])
         if SYSTEM_AUTHTOKEN in request else None,
         user_agent=request.get(HEADERS, {}).get(HEADER_USER_AGENT))
コード例 #2
0
 def __init__(self, session_key):
     """
     Delete Tokens Sync constructor
     :param session_key: session key passed by modular input
     """
     self.session_key = session_key
     self.system_auth_header = SplunkAuthHeader(self.session_key)
コード例 #3
0
async def get_http_port_number(async_splunk_client, system_authtoken):
    response = await async_splunk_client.async_get_server_settings(
        SplunkAuthHeader(system_authtoken))
    response_json = await response.json()
    http_port_number = response_json[constants.ENTRY][0][constants.CONTENT][
        constants.HTTP_PORT]
    return http_port_number
コード例 #4
0
    async def get(self, request):
        """
        REST handler to fetch all apps visible to current user
        """

        authtoken = request[SESSION][AUTHTOKEN]
        user = request[SESSION][USER]
        auth_header = SplunkAuthHeader(authtoken)
        request_context = RequestContext(auth_header,
                                         current_user=user,
                                         system_auth_header=auth_header)

        try:
            async_splunk_client = self.async_client_factory.splunk_client()
            app_list = await fetch_app_names(request_context,
                                             async_splunk_client)
            payload = [{
                APP_NAME: app.app_name,
                DISPLAY_APP_NAME: app.display_app_name
            } for app in app_list]
            return {
                'payload': payload,
                'status': HTTPStatus.OK,
            }
        except Exception as e:
            return {'error': e.message}
コード例 #5
0
 def __init__(self, session_key):
     """
     Registered Users Sync constructor
     :param session_key: session key passed by modular input
     :param async_kvstore_client:
     """
     self.session_key = session_key
     self.system_auth_header = SplunkAuthHeader(self.session_key)
コード例 #6
0
 def __init__(self, session_key, clean_up_time):
     """
     Subscription Clean Up constructor
     :param session_key: session key passed by modular input
     :param clean_up_time: configurable time given in days
     """
     self.session_key = session_key
     self.clean_up_time = clean_up_time
     self.system_auth_header = SplunkAuthHeader(self.session_key)
コード例 #7
0
async def do_trigger(alert_payload):
    auth_header = SplunkAuthHeader(alert_payload[SESSION_KEY])

    # Use default URI for alerts
    try:
        uri = rest.makeSplunkdUri()
    except Exception as e:
        LOGGER.exception("Failed to generate default URI")

    if not uri:
        return

    mtls_spacebridge_client = None
    mtls_enabled = config.get_mtls_enabled()
    if mtls_enabled:
        mtls_spacebridge_client = build_mtls_spacebridge_client(alert_payload[SESSION_KEY])

    async_client_factory = AsyncClientFactory(uri, spacebridge_client=mtls_spacebridge_client)
    async_kvstore_client = async_client_factory.kvstore_client()
    async_splunk_client = async_client_factory.splunk_client()
    async_spacebridge_client = async_client_factory.spacebridge_client()

    alert_sid = alert_payload[SEARCH_ID]
    preprocess_payload(alert_payload)

    # Default to empty string so urllib.quote doesn't fail if user doesn't exist
    user = alert_payload[RESULT].get(USER, '')
    request_context = RequestContext(auth_header=auth_header, is_alert=True, current_user=user)

    LOGGER.info("get_registered_devices alert_sid=%s", alert_sid)
    registered_devices = await get_registered_devices(request_context, async_kvstore_client, alert_payload)
    LOGGER.info("get_registered_devices ok alert_sid=%s", alert_sid)

    alert = await build_alert(request_context, alert_payload, async_splunk_client, async_kvstore_client)
    LOGGER.info("persist_alert alert_id=%s", alert_sid)
    response = persist_alert(alert, auth_header.session_token)
    LOGGER.info("persist_alert ok succeeded alert_id=%s", alert_sid)

    # If we get a proper response from KV Store, then we get the key of the stored alert
    # and create a (device_id, alert_id, timestamp) triplet for each device that should
    # receive the alert

    if response is not None and "_key" in response.keys():
        alert_id = response["_key"]
        alert.notification.alert_id = alert_id

        # Persisting (recipient device, alert id) pairs and sending push notifications happens simultaneously via async
        LOGGER.info("persist_recipient_devices alert_id=%s", alert_id)
        await persist_recipient_devices(request_context, alert_id, registered_devices, alert_payload,
                                        async_kvstore_client)
        LOGGER.info("persist_recipient_devices ok alert_id=%s", alert_id)
        LOGGER.info("send_push_notifications starting registered_devices=%s", len(registered_devices))
        await send_push_notifications(
            request_context, alert.notification, registered_devices, async_kvstore_client, async_spacebridge_client,
            async_splunk_client)
コード例 #8
0
def do_trigger(reactor, alert_payload):
    auth_header = SplunkAuthHeader(alert_payload[SESSION_KEY])

    # Use default URI for alerts
    try:
        uri = rest.makeSplunkdUri()
    except Exception as e:
        LOGGER.exception("Failed to generate default URI. {}".format(e))

    if not uri:
        return

    async_client_factory = AsyncClientFactory(uri)
    async_kvstore_client = async_client_factory.kvstore_client()
    async_splunk_client = async_client_factory.splunk_client()
    async_spacebridge_client = async_client_factory.spacebridge_client()

    alert_sid = alert_payload[SEARCH_ID]
    preprocess_payload(alert_payload)

    request_context = RequestContext(auth_header=auth_header, is_alert=True)

    LOGGER.info("get_registered_devices alert_sid=%s" % alert_sid)
    registered_devices = yield get_registered_devices(request_context,
                                                      async_kvstore_client,
                                                      alert_payload)
    LOGGER.info("get_registered_devices ok alert_sid=%s" % alert_sid)

    alert = yield build_alert(request_context, alert_payload,
                              async_splunk_client, async_kvstore_client)
    LOGGER.info("persist_alert alert_id=%s" % alert_sid)
    response = persist_alert(alert, auth_header.session_token)
    LOGGER.info("persist_alert ok succeeded alert_id=%s" % alert_sid)

    # If we get a proper response from KV Store, then we get the key of the stored alert
    # and create a (device_id, alert_id, timestamp) triplet for each device that should
    # receive the alert

    if response is not None and "_key" in response.keys():
        alert_id = response["_key"]
        alert.notification.alert_id = alert_id

        # Persisting (recipient device, alert id) pairs and sending push notifications happens simultaneously via async
        LOGGER.info("persist_recipient_devices alert_id=%s" % alert_id)
        persist_recipient_devices(request_context, alert_id,
                                  registered_devices, alert_payload,
                                  async_kvstore_client)
        LOGGER.info("persist_recipient_devices ok alert_id=%s" % alert_id)
        LOGGER.info("send_push_notifications starting registered_devices=%s" %
                    len(registered_devices))
        yield send_push_notifications(request_context, alert.notification,
                                      registered_devices, async_kvstore_client,
                                      async_spacebridge_client,
                                      async_splunk_client)
コード例 #9
0
    async def get(self, request):
        """
        Handler which retrieves kvstore app_list data for the current user
        """
        """
        REST handler to fetch the selected app list for the current user
        """
        authtoken = request[SESSION][AUTHTOKEN]
        user = request[SESSION][USER]
        auth_header = SplunkAuthHeader(authtoken)
        request_context = RequestContext(auth_header,
                                         current_user=user,
                                         system_auth_header=auth_header)

        try:
            """
            This method will process a DashboardAppListGetRequest.  This will return the list of app_names found under the
            dashboard_app_list key in the user_meta KVStore collection.

            :param request_context:
            :param client_single_request:
            :param single_server_response:
            :param async_client_factory:
            :return:
            """
            # async clients
            async_kvstore_client = self.async_client_factory.kvstore_client()
            async_splunk_client = self.async_client_factory.splunk_client()

            # Get dashboard_meta collection if key exists
            selected_apps = await fetch_dashboard_app_list_with_default(
                request_context=request_context,
                async_kvstore_client=async_kvstore_client,
                async_splunk_client=async_splunk_client)

            app_list = await fetch_app_names(request_context,
                                             async_splunk_client)
            app_dict = get_app_dict(app_list)
            # This filters out apps that are invalid from displaying in the app selection tab
            payload = [{
                APP_NAME: app,
                DISPLAY_APP_NAME: app_dict[app]
            } for app in selected_apps if app in app_dict]

            return {
                'payload': payload,
                'status': HTTPStatus.OK,
            }
        except Exception as e:
            return {'error': e.message}
コード例 #10
0
def is_valid_session_token(user, session_token):
    """
    Method to validate that the user provided session token matches the user
    :param user: string
    :param session_token: string
    :return: boolean
    """
    response = get_current_context(SplunkAuthHeader(session_token))
    context_user = response[constants.ENTRY][0][constants.CONTENT][
        constants.USERNAME]
    if user == context_user:
        return True
    else:
        return False
コード例 #11
0
async def async_is_valid_session_token(user, session_token, async_splunk_client):
    """
    Method to validate that the user provided session token matches the user
    :param user: string
    :param session_token: string
    :param async_splunk_client: AsyncSplunkClient
    :return: boolean
    """
    response = await async_splunk_client.async_get_current_context(SplunkAuthHeader(session_token))
    response_json = await response.json()
    context_user = response_json[constants.ENTRY][0][constants.CONTENT][constants.USERNAME]
    if user == context_user:
        return True
    else:
        return False
コード例 #12
0
    def _run_initialization(self, unused_reactor, async_client_factory):
        """
        Runs each initialization step required for the AR collections to run properly.

        :param unused_reactor: A Twisted reactor passed as an argument when called with task.react
        :param async_client_factory: An AsyncClientFactory for instantiating other async clients
        """
        try:
            auth_header = SplunkAuthHeader(self.session_key)
            kvstore = async_client_factory.kvstore_client()
            permissions = async_client_factory.ar_permissions_client()
            splunk = async_client_factory.splunk_client()
            yield init_workspace_component_ids(kvstore, auth_header)
            yield init_capabilities_collection(kvstore, auth_header)
            yield cleanup_deleted_roles(splunk, kvstore, permissions,
                                        auth_header)
        except Exception as e:
            LOGGER.exception(
                'Unhandled exception during AR modular input steps.')
            raise e
        defer.returnValue(True)
コード例 #13
0
 def __init__(self,
              input_config,
              encryption_context,
              session_key,
              async_splunk_client,
              parent_process_monitor=None,
              cluster_monitor=None,
              async_client_factory=None,
              async_kvstore_client=None,
              async_spacebridge_client=AsyncSpacebridgeClient()):
     """
     Subscription Manager constructor
     :param input_config:
     :param encryption_context:
     :param session_key:
     :param async_kvstore_client:
     :param async_splunk_client:
     :param async_spacebridge_client:
     """
     self.input_config = input_config
     self.encryption_context = encryption_context
     self.session_key = session_key
     self.parent_process_monitor = parent_process_monitor
     self.cluster_monitor = cluster_monitor
     self.async_splunk_client = async_splunk_client
     self.async_spacebridge_client = async_spacebridge_client
     self.system_auth_header = SplunkAuthHeader(self.session_key)
     if not async_client_factory:
         uri = get_uri(self.session_key)
         async_client_factory = AsyncClientFactory(uri)
     self.async_client_factory = async_client_factory
     if not async_kvstore_client:
         async_kvstore_client = self.async_client_factory.kvstore_client()
     self.async_kvstore_client = async_kvstore_client
     self.request_context = RequestContext(
         auth_header=self.system_auth_header,
         current_user=constants.ADMIN,
         system_auth_header=self.system_auth_header)
コード例 #14
0
async def clean_up_old_entries(timestamp, async_kvstore_client, session_token):
    """
    Delete entries in the devices to roles mapping collection older than input timestamp
    """
    try:
        query = {
            constants.OR_OPERATOR: [{
                constants.TIMESTAMP: {
                    constants.LESS_THAN_OPERATOR: timestamp
                }
            }, {
                constants.TIMESTAMP: {
                    constants.GREATER_THAN_OPERATOR: timestamp
                }
            }]
        }
        params = {constants.QUERY: json.dumps(query)}
        r = await async_kvstore_client.async_kvstore_delete_request(
            collection=constants.DEVICE_ROLES_COLLECTION_NAME,
            auth_header=SplunkAuthHeader(session_token),
            params=params)
        LOGGER.debug("finished deleting old entry with code=%s" % str(r.code))
    except:
        LOGGER.exception("exception deleting old entries")
コード例 #15
0
async def update(session_token, async_kvstore_client, async_splunk_client):
    """
    Update the devices to role mapping collection in KV Store
    """
    timestamp = get_current_timestamp()
    splunk_auth_header = SplunkAuthHeader(session_token)

    # for each user, fetch user to roles mapping
    response_code, user_to_role_dict = await async_splunk_client.async_get_users_roles_mapping(
        splunk_auth_header)

    LOGGER.debug("Fetched user role mapping with response code=%s, %s" %
                 (str(response_code), str(user_to_role_dict)))

    # For each user fetch devices registered to that user
    registered_devices_jsn = await get_registered_devices(
        splunk_auth_header, list(user_to_role_dict.keys()),
        async_kvstore_client)

    # Construct kvstore payload
    batch_payload = create_payloads(registered_devices_jsn, user_to_role_dict,
                                    timestamp)
    batch_post_to_kvstore(session_token, batch_payload)
    await clean_up_old_entries(timestamp, async_kvstore_client, session_token)
コード例 #16
0
    async def post(self, request):
        """
        Handler which creates a new app_list data entry in kvstore for the
        current user
        """
        authtoken = request[SESSION][AUTHTOKEN]
        user = request[SESSION][USER]
        auth_header = SplunkAuthHeader(authtoken)
        request_context = RequestContext(auth_header,
                                         current_user=user,
                                         system_auth_header=auth_header)

        async_splunk_client = self.async_client_factory.splunk_client()
        async_kvstore_client = self.async_client_factory.kvstore_client()

        total_app_list = await fetch_app_names(request_context,
                                               async_splunk_client)
        total_app_name_list = [app.app_name for app in total_app_list]

        selected_app_names = validate_write_request(request, total_app_list)
        # validate all app names
        for app_name in selected_app_names:
            if app_name not in total_app_name_list:
                error_message = f"The appName={app_name} is invalid.  Unable to set appName list."
                return {'error': error_message}

        # Store names in kvstore
        dashboard_app_list = await set_dashboard_app_list(
            request_context=request_context,
            app_names=selected_app_names,
            async_kvstore_client=async_kvstore_client,
            async_splunk_client=async_splunk_client)
        return {
            'payload': dashboard_app_list.app_names,
            'status': HTTPStatus.OK,
        }
コード例 #17
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 = {'_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)

    try:
        credentials = SplunkJWTCredentials(user)
        credentials.load_jwt_token(SplunkAuthHeader(session_token))
        LOGGER.info("Successfully fetched jwt token")
    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({'_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,
    }
コード例 #18
0
 def __init__(self, session_token, logger):
     self.session_token = session_token
     self.auth_header = SplunkAuthHeader(session_token)
     self.logger = logger
コード例 #19
0
    def handle_saml_mdm_request(self, user, session_token, system_authtoken,
                                mdm_signing_bundle, body):
        """
        Handles the MDM SAML Registration Request.
        Validates signature sent from client, validates session token, generates a JWT token,
        and sends it encrypted using splapp's keys and the client public key
        :param user: string provided by rest handler
        :param session_token: string
        :param system_authtoken: string
        :param mdm_signing_bundle: Object
        :param body: JSON
        :return: Reponse object with payload and status
        """
        public_key = base64.b64decode(
            extract_parameter(body, PUBLIC_KEY_LABEL, BODY_LABEL))
        mdm_signature = base64.b64decode(
            extract_parameter(body, MDM_SIGNATURE_LABEL, BODY_LABEL))

        client_keys = EncryptionKeys(None, None, public_key, None)
        client_encryption_context = EncryptionContext(client_keys)

        try:
            valid_signature = yield sign_verify(
                SodiumClient(LOGGER.getChild("sodium_client")),
                base64.b64decode(
                    mdm_signing_bundle['sign_public_key'].encode('utf8')),
                client_encryption_context.encrypt_public_key(), mdm_signature)
        except Exception as e:
            LOGGER.exception(
                "Exception verifying signature from client for user={}".format(
                    user))
            defer.returnValue({
                'payload': {
                    'token': "",
                    'user': user,
                    'status': http.UNAUTHORIZED
                },
                'status': http.OK
            })

        async_splunk_client = self.async_client_factory.splunk_client()
        valid_request = yield valid_session_token(user, session_token,
                                                  async_splunk_client)

        LOGGER.info(
            "Received new mdm registration request by user={}".format(user))

        if valid_signature and valid_request:
            try:
                credentials = SplunkJWTCredentials(user)
                credentials.load_jwt_token(SplunkAuthHeader(system_authtoken))
                LOGGER.info("Successfully fetched jwt token")
            except Exception as e:
                LOGGER.exception(
                    "Exception fetching jwt token for user={} with message={}".
                    format(user, e))
                defer.returnValue({
                    'payload': {
                        'token': "",
                        'user': user,
                        'status': 422
                    },
                    'status': http.OK
                })

            splapp_encryption_context = SplunkEncryptionContext(
                system_authtoken, constants.SPACEBRIDGE_APP_NAME,
                SodiumClient(LOGGER.getChild("sodium_client")))

            # Encrypt session token using splapp keys
            secured_session_token = splapp_encryption_context.secure_session_token(
                credentials.get_credentials())
            # Encrypt session token using client's given public key
            encrypted_jwt_token = yield encrypt_for_send(
                SodiumClient(LOGGER.getChild("sodium_client")),
                client_encryption_context.encrypt_public_key(),
                secured_session_token)
            base64_encrypted_jwt_token = base64.b64encode(encrypted_jwt_token)

            defer.returnValue({
                'payload': {
                    'token': base64_encrypted_jwt_token,
                    'user': user,
                    'status': http.OK
                },
                'status': http.OK
            })
        else:
            LOGGER.info(
                "Error: Mismatched user={} and session token".format(user))
            defer.returnValue({
                'payload': {
                    'token': "",
                    'user': user,
                    'status': http.UNAUTHORIZED
                },
                'status': http.OK
            })