def send_public_key_to_spacebridge(websocket_protocol, config=SplunkConfig()):
    """ Send the splapp public signing key to spacebridge
        Abstraction layer for the spacebrige request. This function:
        1. Signs the splapp public signing key with the splapp private signing key
        2. Creates a proto request with the public signing key and the signature
        3. Sends the proto request to spacebridge
        :param websocket_protocol: The websocket protocol
        :param config: The configuration used to make the request
    """

    websocket_protocol.logger.debug('Starting sending splapp public key to spacebridge')
    encryption_context = websocket_protocol.encryption_context
    sign_func = partial(sign_detached,
                        encryption_context.sodium_client,
                        encryption_context.sign_private_key()
                       )
    public_signing_key = encryption_context.sign_public_key()
    request_proto = http_pb2.RegisterSigningPublicKeyRequest()
    request_proto.publicKeyForSigning = public_signing_key
    request_proto.signature = sign_func(public_signing_key)
    serialized_proto = request_proto.SerializeToString()
    headers = {'Content-Type': 'application/x-protobuf',
               'Authorization': str(sb_auth_header(encryption_context))}
    client = AsyncClient()
    yield send_key(headers, serialized_proto, config, client, websocket_protocol)
    websocket_protocol.logger.debug('Finished send_key method. No logs after start message indicate success.')
Example #2
0
def pair_device(auth_code, user_auth_credentials, device_encryption_info, encryption_context, server_name="",
                server_app_id = "",
                config=SplunkConfig()):
    """
    Part 2/2 of the registration process.
    Send splunk app's public key information and encrypted credentials for user to cloudgateway. Upon success, this
    will complete the credential swap as now the client has the splunk app's credentials and the splunk app has received
    the app's public key

    :param auth_code:  auth code of the device
    :param user_auth_credentials: UserAuthCredentials object interface which captures different forms of session tokens
    :param device_encryption_info: DeviceInfo object which was returned in the authenticate_code api call
    :param encryption_context: EncryptionContext object. Can be a regular EncryptionContext or a subclass such
    as SplunkEncryptionContext depending on whether you want to run in standalone mode or not.
    :param server_name: optional parameter for name of server so that device can identify which instance it is paired
    with
    :param config: CloudgatewaySdkConfig object
    :return:
    """
    user_auth_credentials.validate()
    sodium_client = encryption_context.sodium_client

    encrypt_public_key = encryption_context.encrypt_public_key()
    sign_public_key = encryption_context.sign_public_key()
    encryption_func = partial(encrypt_for_send, sodium_client, device_encryption_info.encrypt_public_key)
    auth_header = sb_auth_header(encryption_context)

    session_token = user_auth_credentials.get_credentials() if sys.version_info < (3, 0) else str.encode(user_auth_credentials.get_credentials())
    encrypted_session_token = encryption_context.secure_session_token(session_token)
    encrypted_credentials_bundle = build_encypted_credentials_bundle(user_auth_credentials.get_username(),
                                                                     encrypted_session_token, encryption_func,
                                                                     server_app_id,
                                                                     deployment_name=server_name)
    pair_device_with_sb(auth_code, auth_header, device_encryption_info.device_id, encrypt_public_key, sign_public_key,
                        encrypted_credentials_bundle, config)
Example #3
0
def authenticate_code(auth_code, encryption_context, resolve_app_name, config=SplunkConfig(), key_bundle=None):
    """
    Part 1/2 of the registration process
    Submit an auth code to space bridge, and retrieve the encryption credentials for the device associated to
    that auth code

    :param auth_code: auth code shown on mobile device
    :param encryption_context: EncryptionContext object. Can be a regular EncryptionContext or a subclass such
    as SplunkEncryptionContext depending on whether you want to run in standalone mode or not.
    :param resolve_app_name: A function that, given an app id, will return a human friendly app name
    :param config: CloudgatewaySdkConfig object
    :return: DeviceInfo object
    """

    raw_response = submit_auth_code(auth_code, encryption_context, config, key_bundle)
    sb_response_proto = parse_spacebridge_response(raw_response)

    encrypt_public_key = sb_response_proto.payload.publicKeyForEncryption
    sign_public_key = sb_response_proto.payload.publicKeyForSigning

    app_friendly_name = sb_response_proto.payload.appFriendlyName
    app_name = app_friendly_name if app_friendly_name else resolve_app_name(sb_response_proto.payload.appId)
    platform = sb_response_proto.payload.appPlatform

    device_encryption_info = DeviceInfo(encrypt_public_key,
                                        sign_public_key,
                                        sb_response_proto.payload.deviceId,
                                        encryption_context.generichash_hex(sign_public_key).upper()[:8],
                                        sb_response_proto.payload.appId,
                                        app_name=app_name,
                                        platform=platform)

    return device_encryption_info
Example #4
0
def request_code(device_info, encryption_context, config=SplunkConfig(), key_bundle=None):
    """Submits device's public key information to Cloud Gateway and fetches 10 digit
    pairing code. First part of the registration process for the client.
    Args:
        device_info ([DeviceInfo]): device information of the client side
        encryption_context ([EncryptionContext]):

    Returns:
        [String]: 10-digit auth code
    """

    r = make_device_authentication_request(device_info, encryption_context, config, key_bundle)

    return parse_device_authentication_response(r)
Example #5
0
def unregister_device(device_id, encryption_context, config=SplunkConfig()):
    """
    Unregister ascljk a device from cloud gateway. Initiating this will cause cloud gateway to remove the routing entry
    and also force the client device to unregister

    :param device_id:  device id from DeviceInfo object
    :param encryption_context: EncryptionContext object. Can be a regular EncryptionContext or a subclass such
    as SplunkEncryptionContext depending on whether you want to run in standalone mode or not. 
    :return: DeviceUnregistrationResponse proto or throws an exception if the request can't be completed
    :param config: CloudgatewaySdkConfig object
    """

    unregister_proto = unregister.build_device_unregister_req(device_id, encryption_context)
    raw_response = unregister.make_unregister_req(unregister_proto, sb_auth_header(encryption_context), config)
    unregister.parse_sb_response(raw_response)

    return raw_response
Example #6
0
    def __init__(self, encryption_context, message_handler, logger=None, mode=WebsocketMode.THREADED,
                 config=SplunkConfig(), shard_id=None):
        """

        Args:
            encryption_context: [EncryptionContext] Can be a regular EncryptionContext or a subclass such
            as SplunkEncryptionContext depending on whether you want to run in standalone mode or not.
            handler can call Splunk APIs if needed
            message_handler: [AbstractMessageHandler] interface specifying how to handle messages from Cloudgateway
            logger: Optional logger parameter for logging purposes
            mode: [WebsocketMode] Enum specifying either threaded mode or async mode. Defaults to Threaded mode
            config: Optional [CloudgatewaySdkConfig] configuration class
        """
        self.encryption_context = encryption_context
        self.logger = logger or DummyLogger()
        self.logger.info(encryption_context)
        self.message_handler = message_handler
        self.mode = mode
        self.config = config
        self.shard_id = shard_id
Example #7
0
def fetch_server_credentials(auth_code, encryption_context, num_retries=10, config=SplunkConfig(), key_bundle=None):
    """Fetch server's encryption keys as well as session token. This is the last part of the registration process
    for the client side and needs to happen after the server side has finished the registration process on the
    server side. If the server side has not completed registration yet, Cloudgateway will wait up to 30s and
    return a 204. This api will continue to retry when it receives a 204 until it we exceed num_retries at which
    point it will return a max retries exceeded exception.

    Args:
        auth_code ([string]): 10-digit auth code
        encryption_context ([EncryptionContext]):
        num_retries ([int]): Number of times to retry. Only retries if Cloud gateway has not received registration
        from the server side.

    Returns:
        [(DeviceInfo, CredentialsBundle)]: Tuple where first element is a DeviceInfo object containing encryption
        information of the server side. The second element is a CredentialsBundle object which contains a session token
        and username which is used for authenticating with the server side and running splunk queries.
    """
    for i in range(num_retries):
        r = make_authentication_result_request(auth_code, encryption_context, config, key_bundle)
        try:
            payload = parse_authentication_result_response(r)
            break
        except CloudgatewayServerError as e:
            if e.status != 204:
                raise e

            if e.status == 204 and i == num_retries - 1:
                raise CloudgatewayMaxRetriesError("Server side device has not completed registration. Please try again",
                                                  204)

    signing_public_key = payload.deploymentPublicKeyForSigning
    encrypt_public_key = payload.deploymentPublicKeyForEncryption
    encrypted_credentials_bundle = payload.encryptedCredentialsBundle
    server_id = encryption_context.generichash_raw(signing_public_key)

    server_info = DeviceInfo(encrypt_public_key, signing_public_key, device_id=server_id)
    credentials_bundle = parse_credentials_bundle(encrypted_credentials_bundle, encryption_context)

    return server_info, credentials_bundle
Example #8
0
    def __init__(self,
                 encryption_context,
                 message_handler,
                 logger=None,
                 mode=WebsocketMode.THREADED,
                 config=SplunkConfig(),
                 shard_id=None,
                 websocket_context=None,
                 key_bundle=None):
        """

        Args:
            encryption_context: [EncryptionContext] Can be a regular EncryptionContext or a subclass such
            as SplunkEncryptionContext depending on whether you want to run in standalone mode or not.
            handler can call Splunk APIs if needed
            message_handler: [AbstractMessageHandler] interface specifying how to handle messages from Cloudgateway
            logger: Optional logger parameter for logging purposes
            mode: [WebsocketMode] Enum specifying either threaded mode or async mode. Defaults to Threaded mode
            config: Optional [CloudgatewaySdkConfig] configuration class
        """
        self.encryption_context = encryption_context
        self.logger = logger or DummyLogger()
        self.logger.info(encryption_context)
        self.message_handler = message_handler
        self.mode = mode
        self.config = config
        self.shard_id = shard_id
        self.key_bundle = key_bundle

        if self.mode == WebsocketMode.THREADED:
            websocket_mode = constants.THREADED_MODE

        elif self.mode == WebsocketMode.ASYNC:
            websocket_mode = constants.ASYNC_MODE
        else:
            raise ValueError("Unsupported websocket mode")

        if self.encryption_context.mode == cloudgateway.private.util.sdk_mode.SdkMode.SPLUNK:
            session_key = self.encryption_context.session_key
            parent_process_monitor = ParentProcessMonitor()

            cluster_monitor = None
            if self.shard_id is None:
                cluster_monitor = ClusterMonitor(self.logger)
        else:
            session_key = ""
            # parent_process_monitor = ParentProcessMonitor() # For testing only, remove
            parent_process_monitor = None
            cluster_monitor = None

        self.connector = CloudgatewayConnector(
            self.message_handler,
            self.encryption_context,
            session_key,
            parent_process_monitor,
            cluster_monitor,
            self.logger,
            self.config,
            mode=websocket_mode,
            shard_id=self.shard_id,
            websocket_context=websocket_context,
            key_bundle=self.key_bundle)