Skip to content

UNOMI-904: V2 API compatibility mode#762

Merged
sergehuber merged 6 commits into
masterfrom
UNOMI-904-v2-api-compatibility
Jun 8, 2026
Merged

UNOMI-904: V2 API compatibility mode#762
sergehuber merged 6 commits into
masterfrom
UNOMI-904-v2-api-compatibility

Conversation

@sergehuber

Copy link
Copy Markdown
Contributor

Stacked PR (merge order)

Role Branch
Base (merge into) UNOMI-139-platform (#760)
Head (this PR) UNOMI-904-v2-api-compatibility

Merge #760 first (multi-tenant platform). This PR adds V2 compatibility on top of that line.


JIRA: UNOMI-904V2 API Compatibility mode (sub-task of UNOMI-875)

Problem

Unomi 3.x uses tenant-scoped API keys for REST access. Existing V2 clients expect:

  • Public endpoints (e.g. /cxs/context.json) with no authentication
  • Private endpoints with system administrator credentials (e.g. Karaf karaf/karaf)
  • Protected events validated via source IP and X-Unomi-Peer, using legacy third-party provider configuration

Without a compatibility path, every client must be rewritten before a V3 rollout—high risk, no incremental migration, and no way to validate V3 with production-like V2 traffic.

Solution

This PR introduces an optional V2 compatibility mode (off by default) on the REST layer:

  1. Configuration — OSGi org.apache.unomi.rest.authentication.cfg, Karaf system properties, and environment variables (UNOMI_REST_AUTHENTICATION_V2COMPATIBILITYMODEENABLED, UNOMI_REST_AUTHENTICATION_V2COMPATIBILITYDEFAULTTENANTID). Mode can be toggled at runtime via Configuration Admin without restarting bundles.

  2. Authentication behaviour (when enabled) — AuthenticationFilter + DefaultRestAuthenticationConfig:

    • Public paths — no API key; requests run under a configured default tenant
    • Private paths — JAAS system-admin authentication (V2-style), then default tenant context for data operations
    • Protected eventsV2ThirdPartyConfigService reads legacy org.apache.unomi.thirdparty settings (provider key, allowed IPs, allowed event types) and validates IP + X-Unomi-Peer like V2
  3. Packaging — REST auth config is deployed from the unomi-rest Karaf feature; defaults are documented in the cfg file and overridable in custom.system.properties.

Mapping to UNOMI-904 acceptance criteria

Criterion Status in this PR
V2 clients can use V3 without client code changes (auth patterns) ✅ Public / private / protected-event paths implemented
Public endpoints work without authentication
Private endpoints work with system administrator authentication
Protected events work with IP + X-Unomi-Peer ✅ via V2ThirdPartyConfigService
Mode enabled/disabled via configuration ✅ default off; runtime updates supported
Default tenant for all operations in compatibility mode v2.compatibilitymode.defaultTenantId
Supports gradual migration (test V3, migrate apps over time) ✅ operational goal; mode is temporary by design

Broader REST surface (profiles, segments, rules, schemas) continues to use the same CXS endpoints; with compatibility mode on, V2 auth rules apply before tenant API-key enforcement. Dedicated IT coverage focuses on context, configuration persistence, default tenant, and protected events.

Configuration (summary)

Setting Default Purpose
v2.compatibilitymode.enabled false Enable V2 compatibility mode
v2.compatibilitymode.defaultTenantId default Tenant used for all operations in V2 mode (should match migration target tenant)

Third-party providers (protected events): thirdparty.{name}.key, .ipAddresses, .allowedEvents in org.apache.unomi.thirdparty.cfg (unchanged V2 layout).

Tests

  • V2CompatibilityModeIT — registered in AllITs; Pax Exam / Karaf integration tests:
    • Switch V2 mode on/off and verify public vs private behaviour
    • Protected events (view event + third-party config)
    • Default tenant resolution
    • Configuration persistence via Configuration Admin
  • Full integration test suite run locally with OpenSearch (same harness as other platform ITs).

Licence

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@sergehuber sergehuber force-pushed the UNOMI-139-platform branch from 4c5828e to d2093d1 Compare June 2, 2026 17:47
@sergehuber sergehuber force-pushed the UNOMI-904-v2-api-compatibility branch from 2419ae7 to a7c5f92 Compare June 2, 2026 17:47
@sergehuber sergehuber force-pushed the UNOMI-139-platform branch from d2093d1 to 6f3f768 Compare June 2, 2026 18:29
@sergehuber sergehuber force-pushed the UNOMI-904-v2-api-compatibility branch from a7c5f92 to 39595c8 Compare June 2, 2026 18:44
@sergehuber sergehuber force-pushed the UNOMI-139-platform branch from 6f3f768 to c36e1fd Compare June 2, 2026 19:44
@sergehuber sergehuber force-pushed the UNOMI-904-v2-api-compatibility branch from 39595c8 to 3bc0172 Compare June 2, 2026 19:44
@sergehuber sergehuber deleted the branch master June 3, 2026 05:46
@sergehuber sergehuber closed this Jun 3, 2026
@sergehuber sergehuber reopened this Jun 6, 2026
@sergehuber sergehuber changed the base branch from UNOMI-139-platform to master June 6, 2026 06:10
@sergehuber sergehuber force-pushed the UNOMI-904-v2-api-compatibility branch from 3bc0172 to 219abb7 Compare June 6, 2026 06:22
@sergehuber sergehuber requested a review from Copilot June 6, 2026 06:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 10 comments.

Comment thread rest/src/main/java/org/apache/unomi/rest/service/impl/RestServiceUtilsImpl.java Outdated
Comment thread itests/src/test/java/org/apache/unomi/itests/V2CompatibilityModeIT.java Outdated
Comment thread itests/src/test/java/org/apache/unomi/itests/V2CompatibilityModeIT.java Outdated
Comment thread itests/src/test/java/org/apache/unomi/itests/V2CompatibilityModeIT.java Outdated
Comment thread rest/src/main/resources/org.apache.unomi.rest.authentication.cfg
Introduce the Unomi 3.1 platform core: tenant-scoped execution, unified
multi-type caching, cluster-aware scheduling, and 3.1.0 migration
tooling. REST layers use V3 tenant resolution and role-based auth.

UNOMI-139 — Multi-tenancy
- Tenant model and APIs (Tenant, TenantService, API keys, security and
  audit hooks, quotas, lifecycle listeners)
- ExecutionContextManager and tenant propagation across services,
  persistence (Elasticsearch/OpenSearch), GraphQL, and REST
- Tenant-scoped items and definitions (system tenant vs tenant overrides)

UNOMI-880 — Unified multi-tenant caching
- MultiTypeCacheService, CacheableTypeConfig, and shared cache lifecycle
  (refresh, statistics, predefined item bundling)
- Migrate DefinitionsService and SegmentService onto the unified cache;
  remove superseded ad-hoc cache listeners

UNOMI-878 — Cluster-aware task scheduling
- SchedulerService with persistent and in-memory tasks, TaskExecutor
  registration, and cluster-aware execution
- Integrate periodic work (cache refresh, cluster heartbeat, router
  jobs, rule refresh) via the new scheduler API

UNOMI-884 — Migration to V3
- 3.1.0 migration Groovy scripts and Elasticsearch request bodies
  (tenant document IDs, system item ID fixes, tenant initialization,
  legacy queryBuilder updates)
- MigrationUtils extensions and MigrationUtilsTest

Integration tests updated for platform behaviour (including migration
and ScopeIT). Verified locally with OpenSearch integration tests.
Let V2 client applications run on the V3 multi-tenant platform without
rewriting authentication first: compatibility mode can be toggled at runtime,
legacy third-party API keys and IP/X-Unomi-Peer checks apply for protected
events, and public endpoints such as /context.json stay usable without tenant
API keys while V3 tenant auth remains the default when the mode is off.

- V2ThirdPartyConfigService wired to org.apache.unomi.thirdparty.cfg
- REST authentication filter and config for V2 compatibility routing
- Event collector allowlist checks in RestServiceUtilsImpl
- Karaf packaging for org.apache.unomi.rest.authentication.cfg
- V2CompatibilityModeIT in the integration test suite
testV2CompatibilityModeWithProtectedEvents loads events/viewEvent.json;
resource was missing after V peel (Appendix J peel-fix).
- Fix ordering-dependent data loss in V2ThirdPartyConfigService.modified()
  by using a two-pass approach: collect raw properties first, then build
  ProviderConfig objects (OSGi ConfigAdmin property order is undefined)
- Mask X-Unomi-Peer secret in debug logs (RestServiceUtilsImpl,
  V2ThirdPartyConfigService) using a maskSecret() helper
- Add @Designate annotation to DefaultRestAuthenticationConfig so OSGi
  metatype descriptors are generated correctly by bnd
- Trim and blank-check v2CompatibilityDefaultTenantId in
  DefaultRestAuthenticationConfig, falling back to "default" if blank
- Replace null checks with StringUtils.isNotBlank() for defaultTenantId
  in AuthenticationFilter.handleV2CompatibilityMode() (both public-path
  and JAAS sections)
- Wrap CloseableHttpClient/CloseableHttpResponse pairs in try-with-resources
  in V2CompatibilityModeIT to avoid connection pool leaks
- Fix misleading test comments: V3 API keys in V2 mode are ignored, not
  rejected — requests return 200 with 0 processed events
…duplication

Move the maskSecret() helper from V2ThirdPartyConfigService and
RestServiceUtilsImpl into a new SecurityUtils class in services-common,
which is already the home for security utilities like IPValidationUtils.
Add unit tests covering null, empty, short, boundary, and typical
32-char shared-secret inputs.
The main fix is that private endpoints with JAAS auth were always
returning 401 in V2 mode — the JAAS subject had no TenantPrincipal,
so resolveTenantId() couldn't find the tenant. We now build a merged
subject with a TenantPrincipal for the default tenant before handing
off to downstream processing. Two smaller filter bugs are fixed
alongside: a blank defaultTenantId on a public path would silently
fall through to the private-endpoint handler, and a null security
context after JAAS was ignored rather than denied. The default tenant
is now checked for existence before use, and V2ThirdPartyConfigService
logs a clear warning when falling back to the well-known default key.
On the test side, session and profile IDs are now per-test UUIDs,
three negative cases cover the main rejection branches (unknown key,
wrong IP, wrong event type), PatchIT polls for sendMailAction instead
of asserting immediately, and GraphQLListIT refreshes Profile
persistence before querying list membership.
@sergehuber sergehuber force-pushed the UNOMI-904-v2-api-compatibility branch from a4d2d2d to ad94a66 Compare June 7, 2026 19:39
@sergehuber sergehuber merged commit b0fd9ce into master Jun 8, 2026
6 checks passed
@sergehuber sergehuber deleted the UNOMI-904-v2-api-compatibility branch June 8, 2026 09:49
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.

2 participants