[ 
https://issues.apache.org/jira/browse/UNOMI-1016?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Serge Huber updated UNOMI-1016:
-------------------------------
    Fix Version/s: unomi-4.0.0
                       (was: unomi-4.1.0)

> Public API key lookup reads every tenant on each request
> --------------------------------------------------------
>
>                 Key: UNOMI-1016
>                 URL: https://issues.apache.org/jira/browse/UNOMI-1016
>             Project: Apache Unomi
>          Issue Type: Improvement
>    Affects Versions: unomi-4.0.0
>            Reporter: Serge Huber
>            Priority: Major
>             Fix For: unomi-4.0.0
>
>
> h3. Summary
> Every request to a public endpoint (context.json, eventcollector, client) 
> looks up its tenant by API key with {{TenantServiceImpl.getTenantByApiKey}}. 
> That method loads every tenant from the search engine 
> ({{persistenceService.getAllItems(Tenant.class)}}, which is a scroll query 
> over all tenant documents), deserializes them, and compares the key against 
> each tenant's key hashes. The GraphQL endpoint does the same for public keys 
> and for private keys.
> The cost grows with the number of tenants and is paid on every tracked page 
> view and event. On a server where tenants are created at runtime, with 
> hundreds or thousands of tenants, this becomes the dominant per-request cost, 
> and it opens a scroll context in the search engine for each request.
> h3. Where
> * {{TenantServiceImpl.getTenantByApiKey(String, ApiKeyType)}}: 
> {{executeAsSystem(() -> persistenceService.getAllItems(Tenant.class))}}, then 
> a linear scan.
> * Callers: {{AuthenticationFilter}} (public paths), 
> {{GraphQLServletSecurityValidator}} (public and private keys).
> * Key hashes are SHA-256 ({{SecretHashServiceImpl}}), so the comparison 
> itself is cheap; the cost is the query and the deserialization.
> h3. Ways to explore
> * Keep an in-memory index from key hash to tenant id, rebuilt when tenants or 
> keys change (the same snapshot approach UNOMI-1013 uses for tenant origins: 
> loaded at start, updated on save, refreshed periodically and on a miss, 
> rate-limited).
> * Or query by key hash: store the hash in an indexed field and look it up 
> with a term query instead of loading every tenant. Revoked and expired keys 
> must still be refused.
> * Either way: a key that was just generated or revoked must take effect 
> promptly on all nodes; document the propagation delay.
> h3. How to test
> * A public request with a valid key does not load all tenants (unit test on 
> the lookup, counting persistence calls).
> * A newly generated key works on the next request; a revoked or expired key 
> is refused.
> * Measure request latency with, for example, 1,000 tenants before and after.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to