Skip to content

feat(mediaauth): policy-based playback authorization#22

Merged
ntt0601zcoder merged 1 commit into
mainfrom
fix/media-playback-auth
Jun 15, 2026
Merged

feat(mediaauth): policy-based playback authorization#22
ntt0601zcoder merged 1 commit into
mainfrom
fix/media-playback-auth

Conversation

@ntt0601zcoder

Copy link
Copy Markdown
Owner

Summary

Reworks media-plane (playback) authorization from a single global config into first-class, reusable Policy objects.

  • A Policy is a stored entity (CRUD via /policies) that carries a complete, self-contained rule set: require_token + its own token_secret, plus static allow/deny lists for IP (exact or CIDR), country (ISO-3166-1 alpha-2), user-agent (substring), and referer domain.
  • A stream binds to at most one policy via playback_policy (templates carry the same field and inherit it). A stream with no policy is public (allow-all); a reference to an unknown policy fails closed (deny).
  • There is no global media-auth config anymore — every rule lives on a policy.

API

/policies (admin-auth group):

  • GET /policies — list
  • GET /policies/{code} — get
  • POST /policies/{code} — create/replace (validated; URL code is authoritative)
  • DELETE /policies/{code} — refused with 409 POLICY_IN_USE while any stream or template still references it

Tokens are client-signed, server-verify-only (HMAC-SHA256 over <stream_code>|<exp>, keyed by the policy's secret). The MAC binds to the stream code, so a token minted for one stream never authorizes another.

Behaviour

  • The authorizer keeps the compiled policy set in an atomic pointer; every CRUD change hot-swaps it with no stream restart, and it is loaded once at boot.
  • Resolution: live streams use the publisher's in-memory binding (no store read on the hot path); stopped streams serving a DVR archive fall back to the store + template.

Breaking change / migration

The global media-auth config block and the playback_auth field are removed. Recreate playback rules as Policy entities and bind streams via playback_policy. Streams that previously set playback_auth become public until re-bound to a policy.

Tests

  • New: domain Policy.Validate, json/yaml PolicyRepository, mediaauth chain rewritten for the per-policy model (deny/allow per dimension, token sign/verify/expiry/tamper/cross-stream, unknown-policy fail-closed, hot-reload).
  • go build, go vet, golangci-lint (0 issues), and go test -race -shuffle=on ./... all green.

Replace the single global media-auth config with first-class Policy
entities. Each Policy carries its own token secret and its own static
allow/deny chain (IP / country / user-agent / referer-domain). A stream
binds to at most one Policy via PlaybackPolicy; a stream with no policy
is public, and a reference to an unknown policy fails closed.

- domain.Policy + PolicyCode + Validate; rename Stream/Template
  PlaybackAuth -> PlaybackPolicy (a code reference), inherited via
  ResolveStream
- store.PolicyRepository (json + yaml) + fixtures + round-trip tests
- mediaauth.Authorizer resolves a stream's policy and runs the chain
  using that policy's own secret; the compiled set is hot-swapped via
  SetPolicies (atomic)
- /policies CRUD handler inside the admin-auth group; delete is refused
  (409) while any stream or template still references the policy; every
  change hot-reloads the authorizer
- remove the global media-auth config block and its config-reload hook

BREAKING CHANGE: the global media-auth config and the playback_auth
field are removed. Recreate playback rules as Policy entities and bind
streams via playback_policy.
@ntt0601zcoder ntt0601zcoder merged commit a516cab into main Jun 15, 2026
4 checks passed
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.

1 participant