Skip to content

Acl fix - #392

Merged
whamm86 merged 7 commits into
mainfrom
acl-fix
Oct 14, 2026
Merged

whamm86 merged 7 commits into
mainfrom
acl-fix

Conversation

@whamm86

@whamm86 whamm86 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Title: Fix ACL merging (unconditional grants), add trust-list-based token validation

Summary

  • ACL bug fix: when several ACLs apply to a data record, an ACL that grants unconditional access was overruled by the
    row-level conditions of the other ACLs. An unconditional grant now takes precedence.
  • Token validation hardening: bearer tokens carrying a kid header are now accepted only from issuers/kids on the trust
    list. The JWKS URL is taken from the trust list entry, never from the token. Issuer and audience are validated.
  • Keycloak service accounts: the claim token:realm_access can now be used in access rules, so client-credentials tokens
    (no user name, no roleMapping match) can be granted access via a realm role.

Background

An empty SQL condition means "no restriction" (= TRUE). That makes it the neutral element for AND but the absorbing element
for OR. SqlConditionsMerger.OrMerge treated it as neutral in both cases, so with two matching rules
A: FORMULA {"$boolean": true} and B: FORMULA {<some predicate>}
the result was B's predicate only, silently dropping A's grant.

Changes

ACL merge (Contracts/SqlConditions.cs, AasSecurity/SecurityService.cs)

  • OrMerge / MergeConditions: empty or tautological operand absorbs under OR (result = unrestricted, all scope prefilters
    and path/match/exists joins dropped). Operation is now a MergeOp enum instead of a string.
  • New SqlConditionsMerger.IsUnrestricted().
  • GetSqlConditions: a rule with neither FORMULA nor FILTER, or a merged result that is unrestricted, now returns null (=
    no restriction) instead of being skipped.
  • Tree-submodel read evaluation: a rule without FORMULA is no longer "no opinion"; it grants READ, consistent with FORMULA {"$boolean": true}.

Trust list (AasSecurity/*)

  • New TrustedServer model replaces the six parallel lists in GlobalSecurityVariables (ServerCertificates, ServerKid,
    ...) which could get out of sync.
  • New JwksTokenValidator (HTTP injected for testability). Lookup is by iss first, then kid; unlisted issuers are
    rejected.
  • trustlist.txt parser rewritten (ParseTrustListText): supports issuer:, kid:, jwks:, audience:, domain:,
    certificate blocks; values are reset after each entry.
  • Audiences: per-entry audience:, falling back to env var TOKEN_AUDIENCE. If neither is set, the audience is not
    validated and a warning is logged.
  • Removed the debug dump of all ticket claims in AasSecurityAuthenticationHandler.
  • docs/security.md: new section 3.3 documenting the trust list format.

Config

  • accessrules.txt: new rule allowing all rights on * for tokens whose realm_access contains aas-writer.
  • trustlist.txt: added the Keycloak realm fx issuer with audience aasx-server.

Behavior changes to be aware of

  • Tokens with a kid header from issuers not in the trust list were previously accepted (issuer/audience were not
    validated); they are now rejected. Deployments relying on this need a trustlist.txt entry.
  • Rules without FORMULA/FILTER now grant unconditionally, as originally documented, instead of being silently ignored when
    combined with other rules.

Note on the diff

SecurityService.cs shows about 2,700 changed lines, but the real change is about 100 lines (line endings were normalized).
Use "Hide whitespace" in the Files changed view.

Tests

  • SecurityAccessRuleMergeTests (new): unconditional rule among restrictive rules, rule without FORMULA, OR-combination of
    restrictive rules, tree-submodel read, unchanged behavior for single restrictive rule.
  • SqlConditionsClaimScopeTests: updated for the new merge semantics.
  • TrustListTests (new): parser (issuer/kid/audience/no leakage between entries), lookup (issuer wins over kid, trailing
    slash), validator (untrusted issuer, wrong key, wrong audience, audience array, kid-only entry).
  • Added test host / collection setup in AasxServerDB.Tests.

Test plan

  • dotnet test for AasSecurityTests and AasxServerDB.Tests
  • Two overlapping ACLs (one $boolean: true, one restrictive): user sees all records
  • Keycloak service-account token with realm role aas-writer can write; without the role it cannot
  • Token from an issuer not in trustlist.txt is rejected; token with wrong aud is rejected

Things to check before you open the PR:

  1. Environment-specific config: the accessrules.txt and trustlist.txt additions point at identity.dev.pxcio.net and grant
    full write access to anyone with the aas-writer realm role. If those files are the defaults shipped in the repo, you may want
    to drop or comment out those entries.
  2. Missing description on the commits: the last commit's message only says "some refactioring" and has a Claude co-author
    trailer. The PR text above is more complete, so you may want to squash with a better message.
  3. Opening the PR: gh isn't installed here. You can paste this into the GitHub web UI at the acl-fix → main compare page, or
    install gh and I'll create it.

whamm86 and others added 4 commits October 7, 2026 09:40
…a access are incorrectly overruled by other ACLs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Comment thread src/AasSecurity/SecuritySettingsForServerParser.cs Fixed
Comment thread src/AasSecurity/GlobalSecurityVariables.cs Fixed
Comment thread src/AasSecurity/GlobalSecurityVariables.cs Fixed
Comment thread src/AasSecurity/JwksTokenValidator.cs Fixed
Comment thread src/AasSecurity/JwksTokenValidator.cs Fixed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/AasSecurity/SecurityService.cs Fixed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/AasSecurity/JwksTokenValidator.cs Fixed
Comment thread src/AasSecurity/SecurityService.cs Fixed
Comment thread src/AasSecurity/SecurityService.cs Fixed
Comment thread src/AasSecurity/SecurityService.cs Fixed
Comment thread src/AasSecurity/SecurityService.cs Fixed
Comment thread src/AasSecurity/SecurityService.cs Dismissed
Comment thread src/AasSecurity/SecurityService.cs Dismissed
Comment thread src/AasSecurity/JwksTokenValidator.cs Fixed
Comment on lines +98 to +101
catch (Exception ex)
{
logger.LogWarning("Could not access well-known from {Issuer}: {Reason}", LogSanitizer.Sanitize(issuer), LogSanitizer.Sanitize(ex.Message));
}
Comment on lines +69 to +74
catch (Exception ex)
{
logger.LogWarning("Token rejected for issuer {Issuer} / kid {Kid}: {Reason}",
LogSanitizer.Sanitize(iss), LogSanitizer.Sanitize(kid), LogSanitizer.Sanitize(ex.Message));
return false;
}
@whamm86
whamm86 merged commit b092dbe into main Oct 14, 2026
7 checks passed
@whamm86
whamm86 deleted the acl-fix branch October 14, 2026 13:07
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.

3 participants