Skip to content

Add reversible encryption to the shared-secret used in subscription #322

Description

@ThiwankaChanditha

Background

In the DPDP Accelerator Event Notification component, subscriptions for webhook dispatch and poll delivery configure a sharedSecret. This secret is used for:

  1. Generating HMAC-SHA256 signatures (event-signature header) on outgoing webhook deliveries.
  2. Authenticating incoming polling requests (event-signature header).

Currently, sharedSecret is persisted in plain text directly into the SHARED_SECRET column of the DPDP_SUBSCRIPTION database table.

In contrast, WSO2 Identity Server (IS) protects sensitive credentials stored in relational tables (such as OAuth consumer secrets in IDN_OAUTH_CONSUMER_APPS) using keystore-backed reversible encryption via Carbon's CryptoUtil (encryptAndBase64Encode / base64DecodeAndDecrypt). Because sharedSecret must be read at runtime to calculate and verify HMAC digests, it cannot be one-way hashed and must follow this same reversible encryption approach.


Problem Statement

Storing sharedSecret in plain text exposes sensitive cryptographic material at rest in the database. Anyone with read access to the database or database backups can extract the shared secrets and forge webhook signatures or poll events unauthorized.


Proposed Solution

Adopt the standard WSO2 IS reversible encryption mechanism using org.wso2.carbon.core.util.CryptoUtil to encrypt subscription shared secrets before persisting them, and decrypt them upon retrieval.

  1. Cryptographic Engine:

    • Use CryptoUtil.getDefaultCryptoUtil() backed by the Carbon server's primary/internal keystore ([keystore.internal] / [keystore.primary]):
      • Encrypt: CryptoUtil.getDefaultCryptoUtil().encryptAndBase64Encode(plainText.getBytes(StandardCharsets.UTF_8))
      • Decrypt: new String(CryptoUtil.getDefaultCryptoUtil().base64DecodeAndDecrypt(cipherText), StandardCharsets.UTF_8)
  2. Persistence Layer Integration:

    • Write Path (SubscriptionDAOImpl): Encrypt sharedSecret before binding it to INSERT and UPDATE SQL statements.
    • Read Path (SubscriptionDAOImpl & DeliveryDAOImpl): Decrypt SHARED_SECRET when constructing Subscription and Delivery domain objects so business logic (WebhookDeliveryTask, PollDeliveryService, HmacSigner) continues to work with plain-text secrets seamlessly in memory.
  3. Graceful Backward Compatibility:

    • Ensure a fallback mechanism: If CryptoException occurs during decryption (e.g. for existing unencrypted database records), fall back to treating the stored value as plain text.

Scope of Changes

  • org.wso2.dpdp.accelerator.common (or relevant module):
    • Provide a reusable encryption helper wrapping CryptoUtil with error handling and fallback logic.
  • org.wso2.dpdp.accelerator.event.notifications.dao:
    • Update SubscriptionDAOImpl (insert, update, and get methods).
    • Update DeliveryDAOImpl (queries populating delivery subscription context).
  • Unit and Integration Tests:
    • Add unit tests validating encryption on save, decryption on read, error handling, and plain-text fallback.
    • Verify existing webhook dispatch and polling tests continue to pass.

Acceptance Criteria

  • Subscription sharedSecret is stored encrypted (Base64-encoded ciphertext) in DPDP_SUBSCRIPTION.SHARED_SECRET.
  • Plain-text secrets are never stored in the database for new subscriptions or secret updates.
  • Outgoing webhooks calculate valid HMAC signatures matching the original plaintext secret.
  • Polling delivery HMAC validation succeeds with the original plaintext secret.
  • Existing subscriptions containing plain-text secrets continue to function without errors (graceful fallback).
  • Unit and integration tests covering encryption, decryption, and backward compatibility pass across all supported database dialects (H2, MySQL, PostgreSQL).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions