chore(deps): build on QQQ 4.1.0-RC.5 (#20) #23
No files matched your search
@@ -40,7 +40,7 @@ CI=true ./mvnw verify # + contract ITs: Authentik 2026.8.3 server+worker, Post
|
||||
|
||||
## Invariants (do not break)
|
||||
|
||||
- Every `AuthentikActionUtil` entry point calls the guard first (QQQ core does not enforce permissions for non-HTTP callers, qqq#1061).
|
||||
- Every `AuthentikActionUtil` entry point calls the guard first (in addition to core action permission enforcement, retain Authentik-specific rules and protection for direct util calls).
|
||||
- Never log query strings (search terms are PII), the token, successful GET bodies, or bodies of sensitive endpoints; run anything stored through `AuthentikRedactor`.
|
||||
- Never filter client-side; reject what Authentik cannot evaluate.
|
||||
- Multi-value params are repeated plain names (`type=a&type=b`). Authentik silently ignores `type[]=`.
|
||||
@@ -54,7 +54,7 @@ CI=true ./mvnw verify # + contract ITs: Authentik 2026.8.3 server+worker, Post
|
||||
|
||||
## Dependencies
|
||||
|
||||
Java 21. Parent `qbit-build-parent:2.0.0`. The default-active `qqq-snapshot` profile imports `qqq-bom-pom:4.1.0-RC.2` (ADR-0007, as in qbit-sql-workbench). The project uses `qqq-backend-core` and `qqq-backend-module-api`. Test dependencies: JUnit 5, AssertJ, Mockito, Testcontainers 1.21.4, and Jackson YAML (from qqq) for the schema tests.
|
||||
Java 21. Parent `qbit-build-parent:2.0.0`. The default-active `qqq-snapshot` profile imports `qqq-bom-pom:4.1.0-RC.5` (ADR-0007, as in qbit-sql-workbench). The project uses `qqq-backend-core` and `qqq-backend-module-api`. Test dependencies: JUnit 5, AssertJ, Mockito, Testcontainers 1.21.4, and Jackson YAML (from qqq) for the schema tests.
|
||||
|
||||
## Release
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ All notable changes to this project are documented here. Format: [Keep a Changel
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed (core baseline, #20 / F19)
|
||||
- Build against the released QQQ BOM `4.1.0-RC.5` through the existing `qqq.snapshot.version` property; no core SNAPSHOT is used. No Java API compatibility fixes were needed.
|
||||
- Core actions now enforce permissions for non-HTTP callers. Authentik-specific guards remain for direct util calls and domain rules. See [UPGRADE.md](UPGRADE.md) for host impact and the remaining test stand-in.
|
||||
|
||||
### Added (automated sessions)
|
||||
- `AuthentikGroupPermissionMapper` resolves tokenless automated sessions by a unique active Authentik email match, applying direct and inherited group permissions, static fallbacks and the sign-in cut-over guard while preserving existing session permissions.
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ CI=true ./mvnw verify # + contract ITs: Authentik 2026.8.3 server+worker, Post
|
||||
|
||||
## Invariants (do not break)
|
||||
|
||||
- Every `AuthentikActionUtil` entry point calls the guard first (QQQ core does not enforce permissions for non-HTTP callers, qqq#1061).
|
||||
- Every `AuthentikActionUtil` entry point calls the guard first (in addition to core action permission enforcement, retain Authentik-specific rules and protection for direct util calls).
|
||||
- Never log query strings (search terms are PII), the token, successful GET bodies, or bodies of sensitive endpoints; run anything stored through `AuthentikRedactor`.
|
||||
- Never filter client-side; reject what Authentik cannot evaluate.
|
||||
- Multi-value params are repeated plain names (`type=a&type=b`). Authentik silently ignores `type[]=`.
|
||||
@@ -59,7 +59,7 @@ CI=true ./mvnw verify # + contract ITs: Authentik 2026.8.3 server+worker, Post
|
||||
|
||||
## Dependencies
|
||||
|
||||
Java 21. Parent `qbit-build-parent:2.0.0`. The default-active `qqq-snapshot` profile imports `qqq-bom-pom:4.1.0-RC.2` (ADR-0007, as in qbit-sql-workbench). The project uses `qqq-backend-core` and `qqq-backend-module-api`. Test dependencies: JUnit 5, AssertJ, Mockito, Testcontainers 1.21.4, and Jackson YAML (from qqq) for the schema tests.
|
||||
Java 21. Parent `qbit-build-parent:2.0.0`. The default-active `qqq-snapshot` profile imports `qqq-bom-pom:4.1.0-RC.5` (ADR-0007, as in qbit-sql-workbench). The project uses `qqq-backend-core` and `qqq-backend-module-api`. Test dependencies: JUnit 5, AssertJ, Mockito, Testcontainers 1.21.4, and Jackson YAML (from qqq) for the schema tests.
|
||||
|
||||
## Release
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ QQQ permissions, held as `<name>.hasAccess`, granted through the group attribute
|
||||
|
||||
Policies also grant table feature permissions registered through core `TableFeaturePermissionsMetaData`: `analyze` (qbit-data-analysis) and `comment`, `attach`, `tag`, `share`, `task`, `assign` (qbit-collaboration), or any future registered feature. For example, `{"Effect":"Allow","Action":["analyze","comment"],"Resource":["person"]}` grants `person.analyze` and `person.comment`. The resource is the table's effective permission base name. Features must be granted explicitly: policy action `"*"` still means only `hasAccess`, `read`, `insert`, `edit`, `delete`.
|
||||
|
||||
The editor discovers features and labels through `PermissionsHelper.getAllAvailablePermissions`; they appear when the host's core version exposes them. This qbit does not compile against the unreleased metadata hook. See [the policy format](docs/POLICY-FORMAT.md) for validation and host customizer usage.
|
||||
The editor discovers features and labels through `PermissionsHelper.getAllAvailablePermissions`; they appear when the host's core version exposes them. The pinned RC.5 release does not include `TableFeaturePermissionsMetaData`; its later core implementation is a follow-up for the next baseline upgrade. See [the policy format](docs/POLICY-FORMAT.md) for validation and host customizer usage.
|
||||
|
||||
### Authentik side
|
||||
|
||||
@@ -82,7 +82,7 @@ See also the QQQ [adoption checklist](https://github.com/QRun-IO/qqq/blob/develo
|
||||
| Item | What to do |
|
||||
|---|---|
|
||||
| Coordinates | `com.kingsrook.qbits:qbit-authentik`. No release is on Maven Central yet; CircleCI publishes snapshots from `develop`. |
|
||||
| QQQ version | QQQ 4.1 (see `pom.xml` for the exact RC). Java 21. |
|
||||
| QQQ version | QQQ 4.1.0-RC.5 (released BOM, no core SNAPSHOT). Java 21. |
|
||||
| Infrastructure | Authentik, contract-tested against 2026.8.3. The API must be reachable from the app at `baseUrl`. |
|
||||
| Tables | Create `authentik_admin_action` and `authentik_approval_request` on your local RDBMS backend (`docs/schema.sql`) before turning write features on. |
|
||||
| Registration | `new AuthentikQBitProducer().withQBitConfig(config).produce(qInstance)`. |
|
||||
|
||||
+27
@@ -1,5 +1,32 @@
|
||||
# Upgrading qbit-authentik
|
||||
|
||||
## QQQ 4.1.0-RC.5 baseline (#20 / F19)
|
||||
|
||||
Hosts should align their QQQ dependencies with the released `qqq-bom-pom:4.1.0-RC.5`
|
||||
and use Java 21. The historical `qqq-snapshot` profile and `qqq.snapshot.version`
|
||||
property names remain, but the imported core version is a release, not a SNAPSHOT.
|
||||
Core actions now enforce permissions and field security locks for non-HTTP callers
|
||||
(QRun-IO/qqq#1061, #1062); callers must supply an appropriately authorized session.
|
||||
The qbit keeps its guards, scope checks and sensitive-field stripping because they
|
||||
also protect direct backend calls and implement Authentik-specific rules.
|
||||
No qbit configuration, stored policy format or schema changes are introduced.
|
||||
|
||||
Stand-in audit against core tag `v4.1.0-RC.5`:
|
||||
|
||||
- `PolicyFeaturePermissionsTest` supplies a synthetic available-permission catalog:
|
||||
`STAND-IN(core=QRun-IO/qqq#1136, removeBy=4.1.0-RC.6)`. RC.6 is the removal target,
|
||||
subject to verifying that release contains the metadata hook. Retain malformed
|
||||
and duplicate catalog test cases when adding real metadata registration coverage.
|
||||
- The requested stand-in/RC grep found only the old baseline references; the broader
|
||||
audit found the test catalog above and stale core-enforcement explanations.
|
||||
No production bridge can safely be removed by this baseline bump.
|
||||
- `TableFeaturePermissionsMetaData` (core commit `9a302136d`, #1136) and client
|
||||
channels (core commit `741bb4974`, PR #1141) exist after RC.5, but neither commit
|
||||
is an ancestor of the RC.5 tag and neither API is present in that release.
|
||||
Follow up on a released baseline containing them: verify the policy editor's
|
||||
catalog with real feature metadata and adopt client-channel attribution and
|
||||
identity/credential channel restrictions. These features are not added here.
|
||||
|
||||
## Permissions renamed `identity.*` → `authentik.*` (unreleased → first release)
|
||||
|
||||
The qbit's permissions follow the same owner naming rule (2026-10-12) and now
|
||||
|
||||
+4
-4
@@ -24,7 +24,7 @@ Seven design rules shape everything below:
|
||||
- A group's QQQ permissions live in the group attribute `qqq.io/permissions`.
|
||||
- The reusable `AuthentikGroupPermissionMapper` turns a user's groups, including inherited parents, into QQQ session permissions.
|
||||
- Who can operate the qbit is decided by those same permissions (`authentik.*`). No operator group is hard-coded.
|
||||
4. **The qbit checks permissions itself.** QQQ core actions do not enforce permissions (QRun-IO/qqq#1061), and `FieldSecurityLock` is not enforced (#1062). An `AuthentikGuard` in the backend action layer checks every read and write.
|
||||
4. **The qbit checks permissions itself.** The original core gaps (QRun-IO/qqq#1061, #1062) are fixed in the RC.5 baseline. Direct backend calls and Authentik-specific rules still require local checks. An `AuthentikGuard` in the backend action layer checks every read and write.
|
||||
5. **No escalation.**
|
||||
- Operators can only grant permissions they hold themselves, whether through memberships or permission attributes.
|
||||
- Operators cannot edit themselves.
|
||||
@@ -668,7 +668,7 @@ This is weaker than revision 1's per-group object permissions. That is the cost
|
||||
- `AuthentikActionUtil.doQuery/doGet/doInsert/doUpdate/doDelete` call `AuthentikGuard.check(table, op, session)` first. The guard checks the QQQ permission, the feature flag, `readOnly` and scope.
|
||||
- A session with no user is refused, except `MirrorSync`'s internal read-only session.
|
||||
- Every qbit process's first backend step re-checks `checkProcessPermissionThrowing` and the per-record rules (§5.4). It does not trust that the middleware ran.
|
||||
- Field-level protection does not use `FieldSecurityLock` (#1062):
|
||||
- Field-level protection retains explicit stripping for direct backend calls; core also enforces `FieldSecurityLock` in the RC.5 baseline (#1062):
|
||||
- Sensitive columns are removed in `jsonObjectToRecord` without `authentik.audit.read`. These are `attributes` (except the `qqq.io/*` keys, shown under `users.read`), `last_ip`, `user_agent` and `geo_ip`.
|
||||
- Filters on those fields are rejected for that session.
|
||||
- Tables also declare `QPermissionRules`, so the UI hides what the user can't use.
|
||||
@@ -955,7 +955,7 @@ Authenticated API calls are not throttled by Authentik, and kof22's Authentik sh
|
||||
| A blueprint re-apply reverts QQQ edits | No `present` identity entries, no member lists (CI lint); bootstrap as `created` (verified, §4.2); reversion detector |
|
||||
| Lost update between QQQ and the Authentik UI | Stale check at execute; attribute merge-patch after a fresh read |
|
||||
| Account takeover through a recovery link | Links are never shown; email only |
|
||||
| A non-HTTP caller bypasses permissions (#1061) | Guard in the backend util, plus ArchUnit |
|
||||
| A direct backend caller bypasses core actions | Guard in the backend util, plus ArchUnit |
|
||||
| A field leaks because `FieldSecurityLock` isn't enforced (#1062) | Sensitive fields stripped in the util |
|
||||
| A forged webhook | Shared secret, constant-time compare; it only triggers re-reads |
|
||||
| Stale session permissions after a demotion | Re-evaluation on token refresh plus webhook-triggered marking (§5.6); live groups used for guard checks |
|
||||
@@ -1033,7 +1033,7 @@ The estimates assume one senior engineer with AI assistance, plus about 20% of a
|
||||
| The service account can lock administrators out (remove members from `authentik Admins`, deactivate break-glass, strip `qqq.io/protected`, §0.2 ii-b). Re-parenting under a superuser group **is** refused by Authentik (§0.2 ii) | Guard refusal of every write that targets a protected account or a superuser group; drift report; recovery through cluster access |
|
||||
| Load on the shared Postgres | Throttle, caps, mirror |
|
||||
| Webhook loss | Inbox, 15-minute reconcile, nightly sweep |
|
||||
| QQQ core gaps (#1061, #1062) | Guard in the backend util, ArchUnit, field stripping |
|
||||
| Direct backend calls outside core enforcement | Guard in the backend util, ArchUnit, field stripping |
|
||||
| Token leakage | Redaction tests; no body logging on sensitive paths |
|
||||
| An Authentik upgrade changes fields | Pinned schema, fixtures per version, version check |
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ Authentik puts the merged document into the token through a scope mapping. Steps
|
||||
- `AuthentikGroupPermissionMapper`, which also reads the claim and the group graph, or
|
||||
- your own customizer, calling `PolicyPermissions.fromClaims(claims, config.getPolicyFormat(), PolicyCatalog.of(qInstance))`.
|
||||
|
||||
The catalog-aware overloads of `PolicyParser`, `PolicyGenerator`, `PolicyPermissions`, `PolicyStore.fingerprint` and `GroupGraph.fromGroups` support features. The older overloads without a catalog continue to accept only standard actions. Both bundled mappers and the editor pass the catalog, as do group-policy resolution and access comparison. This qbit consumes the existing available-permission API without compiling against the unreleased `TableFeaturePermissionsMetaData` hook; features become available when the host's core supplies those entries.
|
||||
The catalog-aware overloads of `PolicyParser`, `PolicyGenerator`, `PolicyPermissions`, `PolicyStore.fingerprint` and `GroupGraph.fromGroups` support features. The older overloads without a catalog continue to accept only standard actions. Both bundled mappers and the editor pass the catalog, as do group-policy resolution and access comparison. This qbit consumes the existing available-permission API without compiling against the `TableFeaturePermissionsMetaData` hook (absent from the pinned RC.5 release); features become available when the host's core supplies those entries.
|
||||
|
||||
The mapping merges the statements of every group in `request.user.all_groups()` (direct groups and their ancestors) whose document has the right spec and version. It always emits a document, with an empty `Statement` array when the user has no policies.
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
<profiles>
|
||||
<!-- Needs qqq 4.1 (QBit producer API). Until qbit-build-parent imports the -->
|
||||
<!-- released 4.1 BOM, this profile is active by default and imports -->
|
||||
<!-- qqq-bom-pom 4.1.0-RC.2 ahead of the parent 4.0.0 BOM, as in -->
|
||||
<!-- qqq-bom-pom 4.1.0-RC.5 ahead of the parent 4.0.0 BOM, as in -->
|
||||
<!-- qbit-sql-workbench and qbit-quick-search (ADR-0007). -->
|
||||
<profile>
|
||||
<id>qqq-snapshot</id>
|
||||
@@ -245,7 +245,7 @@
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<qqq.snapshot.version>4.1.0-RC.2</qqq.snapshot.version>
|
||||
<qqq.snapshot.version>4.1.0-RC.5</qqq.snapshot.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
|
||||
/*******************************************************************************
|
||||
** Renders the drift report as a TableData. Re-checks authentik.admin itself
|
||||
** (QQQ core does not enforce permissions for non-HTTP callers, qqq#1061).
|
||||
** for direct renderer calls as well as calls through core RenderWidgetAction.
|
||||
*******************************************************************************/
|
||||
public class AuthentikDriftReportWidgetRenderer extends AbstractWidgetRenderer
|
||||
{
|
||||
|
||||
@@ -36,9 +36,9 @@ import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** The qbit's own enforcement point (DESIGN.md section 5.3). QQQ core actions
|
||||
** do not enforce permissions for non-HTTP callers (QRun-IO/qqq#1061), so every
|
||||
** call into AuthentikActionUtil is checked here first:
|
||||
** The qbit's own enforcement point (DESIGN.md section 5.3). Core actions now
|
||||
** enforce permissions (QRun-IO/qqq#1061); direct AuthentikActionUtil calls and
|
||||
** Authentik-specific rules still need this guard:
|
||||
** - reads need the table's authentik.* permission (system sessions may read,
|
||||
** for the mirror sync);
|
||||
** - sensitive fields need authentik.audit.read;
|
||||
|
||||
+3
-1
@@ -45,7 +45,9 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/*******************************************************************************
|
||||
** Table features use generic permission suffixes from core's existing catalog
|
||||
** API. No test or production code depends on the unreleased metadata hook.
|
||||
** API. The metadata hook is absent from the pinned core RC.5 release.
|
||||
** STAND-IN(core=QRun-IO/qqq#1136, removeBy=4.1.0-RC.6)
|
||||
** Replace the synthetic feature catalog with metadata registration when upgrading.
|
||||
*******************************************************************************/
|
||||
class PolicyFeaturePermissionsTest
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user