Skip to content

feat(py-amqp): add SAS-token CBS path alongside Entra ID JWT#291

Merged
clemensv merged 1 commit into
mainfrom
feat/py-amqp-cbs-sastoken
May 22, 2026
Merged

feat(py-amqp): add SAS-token CBS path alongside Entra ID JWT#291
clemensv merged 1 commit into
mainfrom
feat/py-amqp-cbs-sastoken

Conversation

@clemensv
Copy link
Copy Markdown
Collaborator

feat(py-amqp): add SAS-token CBS path alongside Entra ID JWT

Resolves #290.

The generated Python AMQP producer's CBS handshake previously only
supported Entra ID JWT bearer tokens (type=jwt). That blocked the
Azure Service Bus emulator (which validates the CBS type field
strictly and only accepts type=servicebus.windows.net:sastoken) and
namespaces configured for SAS authentication.

This change introduces a _CbsTokenProvider abstraction with two
implementations:

  • _JwtTokenProvider -- wraps an azure-identity TokenCredential and
    emits type=jwt (existing behavior, untouched on the wire).
  • _SasTokenProvider -- builds a SAS token (HMAC-SHA256 over
    url_quote(resource_uri) + LF + expiry, base64-encoded, wrapped as
    "SharedAccessSignature sr=...&sig=...&se=...&skn=...") and emits
    type=servicebus.windows.net:sastoken.

Constructor surface gains sas_key_name, sas_key, and
sas_token_ttl_seconds arguments. SAS, Entra credential, and SASL PLAIN
auth are mutually exclusive and validated at init. The reactor
handler now takes a token_provider and consults provider.token_type
when filling the put-token application properties.

The azure-identity import is now soft-loaded so SAS-only deployments
do not require the dependency to be installed at runtime.

All 12 test_python amqp tests pass.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Resolves #290.

The generated Python AMQP producer's CBS handshake previously only
supported Entra ID JWT bearer tokens (type=jwt). That blocked the
Azure Service Bus emulator (which validates the CBS type field
strictly and only accepts type=servicebus.windows.net:sastoken) and
namespaces configured for SAS authentication.

This change introduces a _CbsTokenProvider abstraction with two
implementations:

  * _JwtTokenProvider -- wraps an azure-identity TokenCredential and
    emits type=jwt (existing behavior, untouched on the wire).
  * _SasTokenProvider -- builds a SAS token (HMAC-SHA256 over
    url_quote(resource_uri) + LF + expiry, base64-encoded, wrapped as
    "SharedAccessSignature sr=...&sig=...&se=...&skn=...") and emits
    type=servicebus.windows.net:sastoken.

Constructor surface gains sas_key_name, sas_key, and
sas_token_ttl_seconds arguments. SAS, Entra credential, and SASL PLAIN
auth are mutually exclusive and validated at __init__. The reactor
handler now takes a token_provider and consults provider.token_type
when filling the put-token application properties.

The azure-identity import is now soft-loaded so SAS-only deployments
do not require the dependency to be installed at runtime.

All 12 test_python amqp tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Clemens Vasters <clemens@vasters.com>
@clemensv clemensv force-pushed the feat/py-amqp-cbs-sastoken branch from 8ee5857 to 1dfb477 Compare May 22, 2026 20:28
@clemensv clemensv merged commit 5f13077 into main May 22, 2026
@clemensv clemensv deleted the feat/py-amqp-cbs-sastoken branch May 22, 2026 20:29
clemensv added a commit to clemensv/real-time-sources that referenced this pull request May 22, 2026
Now that xrcg 0.10.5 ships the SAS-token CBS path
(xregistry/codegen#291, resolving #290), enable SAS auth end-to-end:

* tools/require-xrcg.ps1: bump pin to 0.10.5.
* pegelonline/pegelonline_amqp_producer/**: regenerate against
  xrcg 0.10.5. The producer module now exposes the new
  sas_key_name / sas_key / sas_token_ttl_seconds constructor args
  alongside the existing Entra credential path; wire-level behavior
  on the JWT path is unchanged.
* pegelonline/pegelonline_amqp/app.py: add auth-mode=sas (--sas-key-name
  / --sas-key, env AMQP_SAS_KEY_NAME / AMQP_SAS_KEY). Mutually exclusive
  with password and entra modes; validated up front.
* pegelonline_mqtt_producer + pegelonline_producer regenerated for
  consistency (no functional change to either).
* tests/docker_e2e/test_docker_amqp_sb_emulator_flow.py: drop the
  pytest.mark.skip and the placeholder "post-#290" comment. Also
  tighten the readiness wait to watch for "Emulator Service is
  Successfully Up" in the emulator container log instead of just an
  open TCP socket -- the AMQP listener accepts connections a few
  seconds before the broker is actually ready, which caused the first
  connection attempt to be torn down at the SASL layer.

Verified locally: SB emulator E2E passes in ~107s (cached images).
CloudEvents Station + CurrentMeasurement events arrive on the queue,
validate against the JsonStructure schemas, and confirm both the
cloudEvents: AMQP property prefix and the binary body shape.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

py amqpproducer CBS: support SAS-token (sastoken) auth, not just JWT

1 participant