1919#include " ConsumerImpl.h"
2020
2121#include < pulsar/DeadLetterPolicyBuilder.h>
22+ #include < pulsar/EncryptionContext.h>
2223#include < pulsar/MessageIdBuilder.h>
2324
2425#include < algorithm>
@@ -549,24 +550,27 @@ void ConsumerImpl::messageReceived(const ClientConnectionPtr& cnx, const proto::
549550 proto::MessageMetadata& metadata, SharedBuffer& payload) {
550551 LOG_DEBUG (getName () << " Received Message -- Size: " << payload.readableBytes ());
551552
552- if (!decryptMessageIfNeeded (cnx, msg, metadata, payload)) {
553- // Message was discarded or not consumed due to decryption failure
554- return ;
555- }
556-
557553 if (!isChecksumValid) {
558554 // Message discarded for checksum error
559555 discardCorruptedMessage (cnx, msg.message_id (), CommandAck_ValidationError_ChecksumMismatch);
560556 return ;
561557 }
562558
563- auto redeliveryCount = msg.redelivery_count ();
564- const bool isMessageUndecryptable =
565- metadata.encryption_keys_size () > 0 && !config_.getCryptoKeyReader ().get () &&
566- config_.getCryptoFailureAction () == ConsumerCryptoFailureAction::CONSUME;
559+ auto encryptionContext = metadata.encryption_keys_size () > 0
560+ ? optional<EncryptionContext>(std::in_place, metadata, false )
561+ : std::nullopt ;
562+ const auto decryptionResult = decryptMessageIfNeeded (cnx, msg, encryptionContext, payload);
563+ if (decryptionResult == DecryptionResult::FAILED) {
564+ // Message was discarded or not consumed due to decryption failure
565+ return ;
566+ } else if (decryptionResult == DecryptionResult::CONSUME_ENCRYPTED && encryptionContext.has_value ()) {
567+ // Message is encrypted, but we let the application consume it as-is
568+ encryptionContext->setDecryptionFailed (true );
569+ }
567570
571+ auto redeliveryCount = msg.redelivery_count ();
568572 const bool isChunkedMessage = metadata.num_chunks_from_msg () > 1 ;
569- if (!isMessageUndecryptable && !isChunkedMessage) {
573+ if (decryptionResult == DecryptionResult::SUCCESS && !isChunkedMessage) {
570574 if (!uncompressMessageIfNeeded (cnx, msg.message_id (), metadata, payload, true )) {
571575 // Message was discarded on decompression error
572576 return ;
@@ -590,6 +594,7 @@ void ConsumerImpl::messageReceived(const ClientConnectionPtr& cnx, const proto::
590594 m.impl_ ->cnx_ = cnx.get ();
591595 m.impl_ ->setTopicName (getTopicPtr ());
592596 m.impl_ ->setRedeliveryCount (msg.redelivery_count ());
597+ m.impl_ ->encryptionContext_ = std::move (encryptionContext);
593598
594599 if (metadata.has_schema_version ()) {
595600 m.impl_ ->setSchemaVersion (metadata.schema_version ());
@@ -610,7 +615,7 @@ void ConsumerImpl::messageReceived(const ClientConnectionPtr& cnx, const proto::
610615 return ;
611616 }
612617
613- if (metadata.has_num_messages_in_batch ()) {
618+ if (metadata.has_num_messages_in_batch () && decryptionResult == DecryptionResult::SUCCESS ) {
614619 BitSet::Data words (msg.ack_set_size ());
615620 for (int i = 0 ; i < words.size (); i++) {
616621 words[i] = msg.ack_set (i);
@@ -812,17 +817,18 @@ uint32_t ConsumerImpl::receiveIndividualMessagesFromBatch(const ClientConnection
812817 return batchSize - skippedMessages;
813818}
814819
815- bool ConsumerImpl::decryptMessageIfNeeded (const ClientConnectionPtr& cnx, const proto::CommandMessage& msg,
816- const proto::MessageMetadata& metadata, SharedBuffer& payload) {
817- if (!metadata.encryption_keys_size ()) {
818- return true ;
820+ auto ConsumerImpl::decryptMessageIfNeeded (const ClientConnectionPtr& cnx, const proto::CommandMessage& msg,
821+ const optional<EncryptionContext>& context, SharedBuffer& payload)
822+ -> DecryptionResult {
823+ if (!context.has_value ()) {
824+ return DecryptionResult::SUCCESS;
819825 }
820826
821827 // If KeyReader is not configured throw exception based on config param
822828 if (!config_.isEncryptionEnabled ()) {
823829 if (config_.getCryptoFailureAction () == ConsumerCryptoFailureAction::CONSUME) {
824830 LOG_WARN (getName () << " CryptoKeyReader is not implemented. Consuming encrypted message." );
825- return true ;
831+ return DecryptionResult::CONSUME_ENCRYPTED ;
826832 } else if (config_.getCryptoFailureAction () == ConsumerCryptoFailureAction::DISCARD) {
827833 LOG_WARN (getName () << " Skipping decryption since CryptoKeyReader is not implemented and config "
828834 " is set to discard" );
@@ -833,20 +839,20 @@ bool ConsumerImpl::decryptMessageIfNeeded(const ClientConnectionPtr& cnx, const
833839 auto messageId = MessageIdBuilder::from (msg.message_id ()).build ();
834840 unAckedMessageTrackerPtr_->add (messageId);
835841 }
836- return false ;
842+ return DecryptionResult::FAILED ;
837843 }
838844
839845 SharedBuffer decryptedPayload;
840- if (msgCrypto_->decrypt (metadata , payload, config_.getCryptoKeyReader (), decryptedPayload)) {
846+ if (msgCrypto_->decrypt (*context , payload, config_.getCryptoKeyReader (), decryptedPayload)) {
841847 payload = decryptedPayload;
842- return true ;
848+ return DecryptionResult::SUCCESS ;
843849 }
844850
845851 if (config_.getCryptoFailureAction () == ConsumerCryptoFailureAction::CONSUME) {
846852 // Note, batch message will fail to consume even if config is set to consume
847853 LOG_WARN (
848854 getName () << " Decryption failed. Consuming encrypted message since config is set to consume." );
849- return true ;
855+ return DecryptionResult::CONSUME_ENCRYPTED ;
850856 } else if (config_.getCryptoFailureAction () == ConsumerCryptoFailureAction::DISCARD) {
851857 LOG_WARN (getName () << " Discarding message since decryption failed and config is set to discard" );
852858 discardCorruptedMessage (cnx, msg.message_id (), CommandAck_ValidationError_DecryptionError);
@@ -855,7 +861,7 @@ bool ConsumerImpl::decryptMessageIfNeeded(const ClientConnectionPtr& cnx, const
855861 auto messageId = MessageIdBuilder::from (msg.message_id ()).build ();
856862 unAckedMessageTrackerPtr_->add (messageId);
857863 }
858- return false ;
864+ return DecryptionResult::FAILED ;
859865}
860866
861867bool ConsumerImpl::uncompressMessageIfNeeded (const ClientConnectionPtr& cnx,
0 commit comments