async def verify_run_as_token_signature(encryption_context,
                                        async_client_factory,
                                        system_auth_header,
                                        device_id,
                                        encrypted_session_token_with_expiry_bytes,
                                        signature):
    keys = await public_keys_for_device(device_id, system_auth_header, async_client_factory.kvstore_client())
    sender_sign_public_key, _ = keys
    signature_verified = sign_verify(encryption_context.sodium_client, sender_sign_public_key,
                                     encrypted_session_token_with_expiry_bytes, signature)

    return signature_verified
    def validate_signature(self, app_bundle):
        """
        Validate signature provided in app bundle. The signature should be generated by signing the app id using the
        signing private key and we verify this by using the app id and the signing public key.
        """

        app_id = app_bundle[APP_ID].encode('utf-8')

        try:
            signature = base64.b64decode(app_bundle['signature'])
            if not sign_verify(self.sodium_client, self.SSG_SIGNING_PK, app_id, signature):
                raise InvalidSignatureException()
        except Exception as e:
            raise InvalidSignatureException(msg=str(e))
Пример #3
0
    def decrypt_application_msg_payload(self, application_msg, signed_envelope, device_encryption_info):

        sender_sign_public_key = device_encryption_info.sign_public_key
        encryption_context = self.encryption_context
        sodium_client = encryption_context.sodium_client

        decryptor = partial(decrypt_for_receive,
                            sodium_client,
                            encryption_context.encrypt_public_key(),
                            encryption_context.encrypt_private_key())

        if not sign_verify(sodium_client, sender_sign_public_key, signed_envelope.serialized,
                           signed_envelope.signature):
            defer.returnValue("Signature validation failed")

        encrypted_payload = application_msg.payload
        decrypted_payload = decryptor(encrypted_payload)

        return decrypted_payload
Пример #4
0
def is_valid_response(self, user, user_token, response_headers):
    if "authorization" in response_headers and 'deployment-info' in response_headers:
        rAuthToken = base64.b64decode(response_headers['authorization'])
        deployment_info = base64.b64decode(response_headers['deployment-info'])

        nlp_device_info = get_nlp_device(user, user_token)

        if '_key' in nlp_device_info:
            device_key = nlp_device_info['_key']

        kvstore = KvStore(constants.DEVICE_PUBLIC_KEYS_COLLECTION_NAME,
                          user_token,
                          owner="nobody")
        r, record = kvstore.get_item_by_key(device_key)
        parsed = json.loads(record)
        sender_sign_public_key = base64.b64decode(parsed['sign_public_key'])
        sign = sign_verify(self.sodium_client, sender_sign_public_key,
                           deployment_info, rAuthToken)
        return sign
    else:
        LOGGER.info("authorization doesn't exist failed to verify response")
        return False
Пример #5
0
    def decrypt_application_msg_payload(self, application_msg, signed_envelope,
                                        device_encryption_info):
        """
        Decrypt incoming application message and return the decrypted playload
        """

        sender_sign_public_key = device_encryption_info.sign_public_key
        encryption_context = self.encryption_context
        sodium_client = encryption_context.sodium_client

        decryptor = partial(decrypt_for_receive, sodium_client,
                            encryption_context.encrypt_public_key(),
                            encryption_context.encrypt_private_key())

        if not sign_verify(sodium_client, sender_sign_public_key,
                           signed_envelope.serialized,
                           signed_envelope.signature):
            return "Signature validation failed"

        encrypted_payload = application_msg.payload
        decrypted_payload = decryptor(encrypted_payload)

        return decrypted_payload
Пример #6
0
async def handle_mdm_authentication_request(mdm_auth_request_proto,
                                            encryption_context, server_context,
                                            logger, config, request_id):
    """
    Takes a MDM Auth Request proto, decrypts the encrypted credentials bundle, validates the credentials, persists
    device information to the server and sends cloudgateway a confirmation result message
    Args:
        mdm_auth_request_proto (MdmAuthenticationRequest proto): request from the client to perform MDM registration
        encryption_context (EncryptionContext):
        server_context (ServerContext): object which specifies how mdm registration should be validated and how
            credentials should be persisted to the server
        logger (Logger): logger class to handle logging

    Returns:

    """

    logger.info(
        "Parsing MDM Authentication Request, request_id={}".format(request_id))
    client_credentials = sb_common_pb2.MdmAuthenticationRequest.ClientCredentials(
    )
    client_credentials.ParseFromString(
        mdm_auth_request_proto.clientCredentials)
    mdm_signature = mdm_auth_request_proto.mdmSignature
    client_signature = mdm_auth_request_proto.clientSignature

    try:
        logger.debug(
            "Validating MDM signature MDM request message, request_id={}".
            format(request_id))
        mdm_signing_key = await server_context.get_mdm_signing_key()

        if not sign_verify(encryption_context.sodium_client, mdm_signing_key,
                           mdm_auth_request_proto.clientCredentials,
                           mdm_signature):
            raise CloudgatewayMdmRegistrationError(
                CloudgatewayMdmRegistrationError.errortype.unknown_error,
                "mdm signature validation failed")

        logger.debug(
            "Validating registration version={}, request_id={}".format(
                client_credentials.registrationVersion, request_id))
        if client_credentials.registrationVersion != MDM_REGISTRATION_VERSION:
            raise CloudgatewayMdmRegistrationError(
                CloudgatewayMdmRegistrationError.ErrorType.UNKNOWN_ERROR,
                "Incompatible Mdm Registration Version. Expected={}".format(
                    MDM_REGISTRATION_VERSION))

        encrypted_credentials_bundle = client_credentials.encryptedCredentialsBundle

        credentials_bundle = mdm.parse_mdm_encrypted_credentials_bundle(
            encrypted_credentials_bundle, encryption_context)
        client_id = credentials_bundle.registeringAppId
        username = credentials_bundle.username
        password = credentials_bundle.password
        encrypt_public_key = credentials_bundle.publicKeyForEncryption
        sign_public_key = credentials_bundle.publicKeyForSigning
        login_type = credentials_bundle.loginType
        user_session_token = credentials_bundle.sessionToken  # JWT session token sent by the client after MDM SAML
        friendly_name = credentials_bundle.registeringAppFriendlyName
        platform = credentials_bundle.registeringAppPlatform

        logger.debug(
            "Validating publicKey signature of MDM request message, request_id={}"
            .format(request_id))

        if not sign_verify(encryption_context.sodium_client, sign_public_key,
                           mdm_auth_request_proto.clientCredentials,
                           client_signature):
            raise CloudgatewayMdmRegistrationError(
                CloudgatewayMdmRegistrationError.ErrorType.UNKNOWN_ERROR,
                "client signature validation failed")

        device_info = DeviceInfo(encrypt_public_key,
                                 sign_public_key,
                                 device_id=make_device_id(
                                     encryption_context, sign_public_key),
                                 app_id=client_id,
                                 client_version="",
                                 app_name=friendly_name,
                                 platform=platform)

        if login_type == constants.SAML:
            encrypted_session_token = user_session_token
            raw_token = base64.b64decode(encrypted_session_token)
            decrypted_session_token = decrypt_session_token(
                encryption_context.sodium_client, raw_token,
                encryption_context.encrypt_public_key(),
                encryption_context.encrypt_private_key())
            session_jsn = json.loads(decrypted_session_token)
            token_type = http_pb2.TokenType.Value('JWT')
            token_expires_at = calculate_token_info(
                session_jsn['token'])['exp']
        else:
            await server_context.validate(username, password, device_info)

            logger.debug(
                "Server validated mdm registration request. request_id={}".
                format(request_id))

            session_token = await server_context.create_session_token(
                username, password)

            encrypted_session_token = encryption_context.secure_session_token(
                session_token)
            token_type = http_pb2.TokenType.Value('SESSION')
            token_expires_at = 0

        server_version = await server_context.get_server_version()

        logger.debug("Server returned server_version={}, request_id={}".format(
            server_version, request_id))

        deployment_name = await server_context.get_deployment_name()

        logger.debug(
            "Server returned deployment_name={}, request_id={}".format(
                deployment_name, request_id))

        server_type_id = await server_context.get_server_type()
        env_metadata = await server_context.get_environment_meta(
            device_info, username)

        pairing_info = mdm.build_pairing_info(encrypted_session_token,
                                              credentials_bundle.username,
                                              server_version,
                                              deployment_name,
                                              server_type_id,
                                              token_type,
                                              token_expires_at,
                                              env_metadata=env_metadata)
        confirmation_result = mdm.build_successful_confirmation_result(
            pairing_info)

        await server_context.persist_device_info(device_info, username)

        logger.info(
            "Successfully persisted device registration information, request_id={}"
            .format(request_id))

    except CloudgatewayMdmRegistrationError as e:
        logger.exception(
            "MDM registration error occurred={}, request_id={}".format(
                e, request_id))
        confirmation_result = mdm.build_error_confirmation_result(e.to_proto())
    except Exception as e:
        logger.exception(
            "Unexpected error occurred during MDM registration={}, request_id={}"
            .format(e, request_id))
        error = http_pb2.HttpError()
        error.code = http_pb2.HttpError.ERROR_UNKNOWN
        error.message = str(e)
        confirmation_result = mdm.build_error_confirmation_result(error)

    mdm_authentication_confirmation_request = mdm.build_mdm_authentication_confirmation_request(
        confirmation_result, encryption_context, device_info)

    r = await mdm.async_send_confirmation_result(
        mdm_authentication_confirmation_request, encryption_context,
        server_context.async_spacebridge_client)
    resp = await r.text()

    logger.info(
        "Completed MDM Authentication Request with response={}, code={}, request_id={}"
        .format(resp, r.code, request_id))

    return mdm_authentication_confirmation_request
Пример #7
0
def process(system_auth_header, message, websocket_protocol, async_client_factory,
            guid_generator=get_guid, shard_id=None):
    """Accepts a message which is assumed to be serialized using protobuf,
    deserializes the message, unencrypts the payload and routes to the appropriate
    processor depending on the type of message.

    For example, we check whether the message is a client single request, if it is,
    we call the process_request method to process the contents. Analagously, we have
    methods for other message types as well such as process_subscription.

    Arguments:
        message {serialized proto} -- serialized protobuf object

    Returns:
        Serialized Application Message representing response from the server
    """

    # Deserialize Signed Envelope
    signed_envelope = parse_signed_envelope(message)

    # Deserialize application message
    if signed_envelope.messageType == sb_common_pb2.SignedEnvelope.MESSAGE_TYPE_APPLICATION_MESSAGE:
        LOGGER.info("message=RECEIVED_ENVELOPE type=application_message")
        application_message = parse_application_message(signed_envelope.serialized)
    elif signed_envelope.messageType == sb_common_pb2.SignedEnvelope.MESSAGE_TYPE_SPACEBRIDGE_MESSAGE:
        # TODO: error handling
        LOGGER.info("message=RECEIVED_ENVELOPE type=spacebridge_message")
        spacebridge_message = parse_spacebridge_message(signed_envelope.serialized)
        handle_spacebridge_message(system_auth_header, spacebridge_message,
                                   async_client_factory.splunk_client(), async_client_factory.kvstore_client())
        defer.returnValue(True)
    else:
        LOGGER.info("message=RECEIVED_ENVELOPE type={}".format(signed_envelope.messageType))
        defer.returnValue("Unknown message type")

    message_sender = application_message.sender
    keys = yield public_keys_for_device(message_sender, system_auth_header, async_client_factory.kvstore_client())

    sender_sign_public_key, sender_encrypt_public_key = keys

    encryption_context = websocket_protocol.encryption_context
    sodium_client = encryption_context.sodium_client

    decryptor = partial(decrypt_for_receive,
                        sodium_client,
                        encryption_context.encrypt_public_key(),
                        encryption_context.encrypt_private_key())
    encryptor = partial(encrypt_for_send,
                        sodium_client,
                        sender_encrypt_public_key)

    signer = partial(sign_detached, sodium_client, encryption_context.sign_private_key())

    generichash = encryption_context.generichash_raw

    if not sign_verify(sodium_client, sender_sign_public_key, signed_envelope.serialized, signed_envelope.signature):
        defer.returnValue("Signature validation failed")

    server_response_id = guid_generator()
    client_application_message = parse_client_application_message(application_message, decryptor)

    if application_message.ByteSize() == 0 or client_application_message.ByteSize() == 0:
        defer.returnValue("Unknown message type")

    server_application_message = envelope_pb2.ServerApplicationMessage()

    # Check if message is a request or subscription and then populate the server_application_response
    request_context = yield process_message(message_sender,
                                            client_application_message,
                                            server_application_message,
                                            async_client_factory,
                                            websocket_protocol.encryption_context,
                                            server_response_id,
                                            system_auth_header,
                                            shard_id)

    response = yield send_response(request_context,
                                   message_sender,
                                   server_application_message,
                                   websocket_protocol,
                                   encryptor,
                                   signer,
                                   generichash)

    # Post processing function
    yield post_process_message(request_context,
                               server_application_message,
                               async_client_factory,
                               guid_generator)
    defer.returnValue(response)
Пример #8
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
            })
Пример #9
0
def handle_mdm_authentication_request(mdm_auth_request_proto, encryption_context,
                                      server_context, logger, config, request_id):
    """
    Takes a MDM Auth Request proto, decrypts the encrypted credentials bundle, validates the credentials, persists
    device information to the server and sends cloudgateway a confirmation result message
    Args:
        mdm_auth_request_proto (MdmAuthenticationRequest proto): request from the client to perform MDM registration
        encryption_context (EncryptionContext):
        server_context (ServerContext): object which specifies how mdm registration should be validated and how
            credentials should be persisted to the server
        logger (Logger): logger class to handle logging

    Returns:

    """

    logger.info("Parsing MDM Authentication Request, request_id={}".format(request_id))
    client_credentials = sb_common_pb2.MdmAuthenticationRequest.ClientCredentials()
    client_credentials.ParseFromString(mdm_auth_request_proto.clientCredentials)
    mdm_signature = mdm_auth_request_proto.mdmSignature
    client_signature = mdm_auth_request_proto.clientSignature

    try:
        logger.debug("Validating MDM signature MDM request message, request_id={}".format(request_id))
        mdm_signing_key = yield add_error_back(defer.maybeDeferred(server_context.get_mdm_signing_key),
                                               logger=logger)
        if not sign_verify(encryption_context.sodium_client, mdm_signing_key,
                           mdm_auth_request_proto.clientCredentials, mdm_signature):
            raise CloudgatewayMdmRegistrationError(CloudgatewayMdmRegistrationError.errortype.unknown_error,
                                                   "mdm signature validation failed")

        logger.debug("Validating registration version={}, request_id={}"
                     .format(client_credentials.registrationVersion, request_id))
        if client_credentials.registrationVersion != MDM_REGISTRATION_VERSION:
            raise CloudgatewayMdmRegistrationError(CloudgatewayMdmRegistrationError.ErrorType.UNKNOWN_ERROR,
                                                   "Incompatible Mdm Registration Version. Expected={}"
                                                   .format(MDM_REGISTRATION_VERSION))

        encrypted_credentials_bundle = client_credentials.encryptedCredentialsBundle

        credentials_bundle = mdm.parse_mdm_encrypted_credentials_bundle(encrypted_credentials_bundle,
                                                                        encryption_context)
        client_id = credentials_bundle.registeringAppId
        username = credentials_bundle.username
        password = credentials_bundle.password
        encrypt_public_key = credentials_bundle.publicKeyForEncryption
        sign_public_key = credentials_bundle.publicKeyForSigning
        login_type = credentials_bundle.loginType
        user_session_token = credentials_bundle.sessionToken # JWT session token sent by the client after MDM SAML

        logger.debug("Validating publicKey signature of MDM request message, request_id={}".format(request_id))

        if not sign_verify(encryption_context.sodium_client, sign_public_key, mdm_auth_request_proto.clientCredentials,
                           client_signature):
            raise CloudgatewayMdmRegistrationError(CloudgatewayMdmRegistrationError.ErrorType.UNKNOWN_ERROR,
                                                   "client signature validation failed")

        device_info = DeviceInfo(encrypt_public_key, sign_public_key,
                                 device_id=make_device_id(encryption_context, sign_public_key),
                                 app_id=client_id, client_version="")

        encrypted_session_token = None
        if login_type == constants.SAML:
            encrypted_session_token = user_session_token
        else:
            yield add_error_back(defer.maybeDeferred(server_context.validate, username, password, device_info),
                                 logger=logger)

            logger.debug("Server validated mdm registration request. request_id={}".format(request_id))

            session_token = yield add_error_back(defer.maybeDeferred(server_context.create_session_token, username, password),
                logger=logger)

            encrypted_session_token = encryption_context.secure_session_token(session_token)

        server_version = yield add_error_back(defer.maybeDeferred(server_context.get_server_version),
                                              logger=logger)

        logger.debug("Server returned server_version={}, request_id={}".format(server_version, request_id))

        deployment_name = yield add_error_back(defer.maybeDeferred(server_context.get_deployment_name),
                                               logger=logger)

        logger.debug("Server returned deployment_name={}, request_id={}".format(deployment_name, request_id))

        server_type_id = yield add_error_back(defer.maybeDeferred(server_context.get_server_type),
                                               logger=logger)

        pairing_info = mdm.build_pairing_info(encrypted_session_token, credentials_bundle.username, server_version,
                                              deployment_name, server_type_id)
        confirmation_result = mdm.build_successful_confirmation_result(pairing_info)

        yield add_error_back(defer.maybeDeferred(server_context.persist_device_info, device_info, username),
                             logger=logger)

        logger.info("Successfully persisted device registration information, request_id={}".format(request_id))

    except CloudgatewayMdmRegistrationError as e:
        logger.exception("MDM registration error occurred={}, request_id={}".format(e, request_id))
        confirmation_result = mdm.build_error_confirmation_result(e.to_proto())
    except Exception as e:
        logger.exception("Unexpected error occurred during MDM registration={}, request_id={}".format(e, request_id))
        error = http_pb2.HttpError()
        error.code = http_pb2.HttpError.ERROR_UNKNOWN
        error.message = str(e)
        confirmation_result = mdm.build_error_confirmation_result(error)

    mdm_authentication_confirmation_request = mdm.build_mdm_authentication_confirmation_request(confirmation_result,
                                                                                                encryption_context,
                                                                                                device_info)

    r = yield mdm.async_send_confirmation_result(mdm_authentication_confirmation_request, encryption_context,
                                                 server_context.async_spacebridge_client)
    resp = yield r.content()

    logger.info("Completed MDM Authentication Request with response={}, code={}, request_id={}"
                .format(resp, r.code, request_id))

    defer.returnValue(mdm_authentication_confirmation_request)