예제 #1
0
def delete_device_from_spacebridge(device_id,
                                   system_authtoken,
                                   key_bundle=None):
    """
    Deletes device from spacebridge
    :param device_id:
    :param system_authtoken:
    :return: response from spacebridge
    """
    sodium_client = SodiumClient(LOGGER.getChild("sodium_client"))
    encryption_context = SplunkEncryptionContext(
        system_authtoken, constants.SPACEBRIDGE_APP_NAME, sodium_client)
    public_key_hash = encryption_context.sign_public_key(
        transform=encryption_context.generichash_hex)

    unregister_proto = http_pb2.DeviceUnregistrationRequest()
    unregister_proto.deviceId = b64decode(device_id)
    unregister_proto.deploymentId = encryption_context.sign_public_key(
        transform=encryption_context.generichash_raw)

    headers = {
        'Authorization': public_key_hash,
        'Content-Type': 'application/x-protobuf'
    }

    with requests_ssl_context(key_bundle):
        try:
            response = requests.delete(
                "%s/api/session" % config.get_spacebridge_domain(),
                headers=headers,
                proxies=config.get_proxies(),
                data=unregister_proto.SerializeToString())
        except Exception:
            LOGGER.exception(
                "Exception attempting sending delete device request to Spacebridge"
            )
            raise Errors.SpacebridgeServerError('Unable to reach Spacebridge',
                                                503)

    LOGGER.info(
        "Received response=%s on delete device from Spacebridge request" %
        response.status_code)

    spacebridge_response = http_pb2.DeviceUnregistrationResponse()
    spacebridge_response.ParseFromString(response.content)

    LOGGER.info('Spacebridge response: %s' % str(spacebridge_response))

    if spacebridge_response.HasField(
            'error'
    ) and spacebridge_response.error.code != http_pb2.HttpError.Code.Value(
            'ERROR_ROUTING_UNDELIVERABLE'):
        raise Errors.SpacebridgeServerError(
            "Spacebridge error on delete device request=%s" %
            spacebridge_response.error.message)

    return response
예제 #2
0
def send_mdm_signing_key_to_spacebridge(authtoken,
                                        mdm_public_signing_key,
                                        key_bundle=None):
    """ Send the mdm public signing key to spacebridge
        Abstraction layer for the spacebridge request. This function:
        1. Creates the mdm_credentials_bundle
        2. Serializes the bundle to bytes
        3. Signs the serialized bundle with the splapps private signing key
        4. Creates a proto object with the serialized bundle + signature and sends to spacebridge
        5. Parses the protobuf response, checking for error objects

    """

    sodium_client = SodiumClient(LOGGER.getChild("sodium_client"))
    encryption_context = SplunkEncryptionContext(
        authtoken, constants.SPACEBRIDGE_APP_NAME, sodium_client)
    sign_func = partial(sign_detached, sodium_client,
                        encryption_context.sign_private_key())
    client_id = encryption_context.sign_public_key(
        transform=encryption_context.generichash_raw)

    request_proto = http_pb2.MdmAuthenticationGrantRequest()
    client_mdm_permission = request_proto.ClientMdmPermission()
    client_mdm_permission.clientId = client_id
    client_mdm_permission.mdmPublicKeyForSigning = mdm_public_signing_key
    serialized = client_mdm_permission.SerializeToString()
    signature = sign_func(serialized)
    request_proto.clientMdmPermission = serialized
    request_proto.signature = signature
    headers = {
        'Authorization':
        encryption_context.sign_public_key(
            transform=encryption_context.generichash_hex),
        'Content-Type':
        'application/x-protobuf'
    }

    def call_grants():
        with requests_ssl_context(key_bundle) as cert:
            return requests.post('{}/api/mdm/grants'.format(
                config.get_spacebridge_domain()),
                                 headers=headers,
                                 data=request_proto.SerializeToString(),
                                 proxies=config.get_proxies(),
                                 timeout=constants.TIMEOUT_SECONDS,
                                 cert=cert.name)

    try:
        response = call_grants()
    except requests.exceptions.Timeout as e:
        raise Errors.SpacebridgeServerError(
            'Failed to receive a response from spacebridge', 500)

    sb_response_proto = http_pb2.MdmAuthenticationGrantResponse()
    sb_response_proto.ParseFromString(response.content)

    retries = 0
    while 500 <= response.status_code < 600 and retries < 3:
        wait = 2**retries
        retries = retries + 1
        time.sleep(wait)

        try:
            response = call_grants()
        except requests.exceptions.Timeout as e:
            raise Errors.SpacebridgeServerError(
                'Failed to receive a response from spacebridge', 500)

        sb_response_proto = http_pb2.MdmAuthenticationGrantResponse()
        sb_response_proto.ParseFromString(response.content)

    if sb_response_proto.HasField('error'):
        if response.status_code == 500:
            raise Errors.SpacebridgeServerError(
                'Spacebridge encountered an internal error:{}'.format(
                    sb_response_proto.error.message), 500)
        raise Errors.SpacebridgeServerError(
            'Spacebridge request error: {}'.format(
                sb_response_proto.error.message, response.status_code))

    if not (200 <= response.status_code < 300):
        raise Errors.SpacebridgeServerError(
            "Spacebridge error: {}".format(response.content),
            response.status_code)
예제 #3
0
def authentication_query_request(auth_code, encryption_context):
    """ Abstraction layer for the spacebridge request. This function:
        1. Makes the registration query GET request to the spacebridge endpoint
        2. Parses the protobuf response
        3. Packs the response values into a response object. Binary objects are encoded to ensure kvstore compatibility

    :param auth_code: Authorization code of the device being registered
    :return: response object containing "public_key", "device_id", and "conf_code"
    """

    # Makes the registration query GET request to the spacebridge endpoint
    try:
        headers = {
            'Authorization':
            encryption_context.sign_public_key(
                transform=encryption_context.generichash_hex)
        }
        response = requests.get('%s/api/registrations/%s' %
                                (config.get_spacebridge_domain(), auth_code),
                                headers=headers,
                                proxies=config.get_proxies())
    except Exception:
        LOGGER.exception("Exception contacting spacebridge")
        raise Errors.SpacebridgeServerError('Unable to reach Spacebridge', 503)

    # Parses the protobuf response
    spacebridge_response = http_pb2.AuthenticationQueryResponse()
    spacebridge_response.ParseFromString(response.content)

    if spacebridge_response.HasField('error'):
        if response.status_code == 500:
            raise Errors.SpacebridgeServerError(
                'Spacebridge encountered an internal error: %s' %
                spacebridge_response.error.message, 500)

        raise Errors.SpacebridgeServerError(
            'Spacebridge request error: %s' %
            spacebridge_response.error.message, response.status_code)

    if not str(response.status_code).startswith('2'):
        raise Errors.SpacebridgeServerError(
            "Spacebridge error: %s" % str(response.content),
            response.status_code)

    # Packs the response values into a response object. Binary objects are encoded to ensure kvstore compatibility
    encrypt_public_key = spacebridge_response.payload.publicKeyForEncryption
    sign_public_key = spacebridge_response.payload.publicKeyForSigning
    response = {
        'encrypt_public_key':
        py23.b64encode_to_str(encrypt_public_key),
        'sign_public_key':
        py23.b64encode_to_str(sign_public_key),
        'device_id':
        py23.b64encode_to_str(spacebridge_response.payload.deviceId),
        'conf_code':
        encryption_context.generichash_hex(sign_public_key).upper()[:8],
    }

    try:
        response[APP_TYPE_LABEL] = translate_app_name(
            http_pb2.AppType.Name(spacebridge_response.payload.appType))
    except ValueError as err:
        # When app_type is 'APPTYPE_INVALID'
        raise Errors.SpacebridgeRestError('Registration Error: %s' % str(err),
                                          501)

    return response
예제 #4
0
def device_pairing_confirmation_request(auth_header, auth_code, username,
                                        device_id, encrypt_public_key,
                                        sign_public_key,
                                        session_token_encrypted, encrypt,
                                        deployment_friendly_name):
    """ Abstraction layer for the spacebridge request. This function:
        1. Creates the encrypted_credentials_bundle
        2. Generates a protobuf object from the supplied dictionary, proto_object
        3. Makes the registration confirmation PUT request to the spacebridge endpoint
        4. Parses the protobuf response, checking for error objects

    :param auth_code: Authorization code of the device being registered
    :param proto_object: Dict containing protobuf values
    :param username: User username for the encrypted_credentials_bundle
    :param password: User password for the encrypted_credentials_bundle
    :return: None
    """

    # Creates the encrypted_credentials_bundle
    credentials_bundle_proto = http_pb2.CredentialsBundle()
    credentials_bundle_proto.sessionToken = session_token_encrypted
    credentials_bundle_proto.userName = username
    credentials_bundle_proto.deploymentName = deployment_friendly_name
    credentials_bundle = credentials_bundle_proto.SerializeToString()

    encrypted_credentials_bundle = encrypt(credentials_bundle)

    # Generates a protobuf object from the supplied dictionary, proto_object
    sb_request_proto = http_pb2.DevicePairingConfirmationRequest()
    sb_request_proto.authenticationCode = auth_code
    sb_request_proto.deviceId = device_id
    sb_request_proto.deploymentPublicKeyForEncryption = encrypt_public_key
    sb_request_proto.deploymentPublicKeyForSigning = sign_public_key
    sb_request_proto.encryptedCredentialsBundle = encrypted_credentials_bundle
    LOGGER.info("Registration Bundle deploymentPublicKey= %s" %
                str(sb_request_proto.deploymentPublicKey))
    LOGGER.info("Registration Bundle deviceId= %s" %
                str(sb_request_proto.deviceId))

    # Makes the registration confirmation PUT request to the spacebridge endpoint
    try:
        response = requests.put('%s/api/registrations/%s' %
                                (config.get_spacebridge_domain(), auth_code),
                                headers={
                                    'Content-Type': 'application/x-protobuf',
                                    'Authorization': str(auth_header)
                                },
                                data=sb_request_proto.SerializeToString(),
                                proxies=config.get_proxies())
    except Exception:
        raise Errors.SpacebridgeServerError('Unable to reach Spacebridge', 503)

    # Parses the protobuf response, checking for error objects
    sb_response_proto = http_pb2.DevicePairingConfirmationResponse()
    sb_response_proto.ParseFromString(response.content)

    if sb_response_proto.HasField('error'):
        if response.status_code == 500:
            raise Errors.SpacebridgeServerError(
                'Spacebridge encountered an internal error: %s' %
                sb_response_proto.error.message, 500)
        raise Errors.SpacebridgeServerError(
            'Spacebridge request error: %s' % sb_response_proto.error.message,
            response.status_code)

    if not (200 <= response.status_code < 300):
        raise Errors.SpacebridgeServerError(
            "Spacebridge error: %s" % str(response.content),
            response.status_code)