Conversation
The role, menu and HTTP method pages called endpoints the rebuilt server does not have, so nothing they configured took effect. Remove them from the navigation, the router and the page permission manifest, together with the components and helpers only they used and their messages. Roles come back with the console's own permission model. The dashboard no longer counts roles, menus and methods through the old API; it shows accounts, departments, user groups and positions, and only loads the counts of pages the user may open.
The plugin API passed its tests but not every static check: a Javadoc summary ended in a colon, a test kept an unused import, and PMD flagged a null assignment, an unused parameter, an allocation in a loop and two intended designs (a Comparable record and a provider interface with one abstract method), now suppressed with the reason.
Add the authorization module with the resource catalog: applications and their resource trees of modules, menus, pages, tabs, buttons, APIs, data entities and fields. Each type only sits where it belongs (buttons and tabs on pages, fields on data entities), trees are materialized paths of at most 16 levels, codes are unique per application, and resources declared by GrantForge itself keep their code and cannot be deleted. The catalog is shared by all tenants: tenant administrators read it, platform administrators change it, and every change is audited. The console registers itself as a built-in application at start-up. Platform administrators get a resource catalog page that switches between applications, shows the tree with type badges, and creates, edits, moves (buttons, a target dialog, or dragging in the tree) and deletes resources and applications.
Every controller method now declares who may call it: @PublicEndpoint, @AuthenticatedEndpoint or @RequirePermission with a permission code such as system.user.read, which several endpoints may share. At start-up the server scans its handlers and refuses to start when one declares nothing or two things; the public routes of the security configuration are tested against the declarations. The scan keeps an API catalog in step with the code: every permission becomes a built-in API resource below a built-in API module of the console, ready to be granted, and every endpoint is recorded with its access. Endpoints that appeared, changed their access or went away are marked until a platform administrator confirms them, which is audited. The OpenAPI document publishes each operation's access as x-permission. The console gets an API catalog page with counts, filters by text, access and state, and confirmation of the pending changes.
Menus, pages, tabs and buttons can now depend on APIs, pages, tabs and buttons of the same application, as required or optional. Dependencies never form a cycle: a new one that would is refused, and a resource others still need cannot be deleted, while deleting a resource removes its own dependencies. Dependencies declared by GrantForge itself cannot be removed by hand. A dependency graph answers what a set of resources requires, transitively, for deriving grants later. Every change is audited. The resource catalog page shows, for each resource, what it needs and what needs it; platform administrators add dependencies, switch them between required and optional and remove them, and a drawing lays out everything around a resource: what needs it on the left, what it needs, also indirectly, on the right.
The web console's permission manifest (src/permissions/manifest.json) now lists its modules, pages and buttons, each with the API permissions and other entries it needs; the console derives its page permissions from it. The server packages the same file and, at start-up and right after the API catalog, creates every entry as a built-in resource, refreshes names and routes, and keeps the declared dependencies exactly as listed, taking over manual ones the manifest now declares. A manifest that repeats codes, names unknown permissions or resources, places an entry where its type does not fit or closes a cycle stops the start. Built-in resources carry the message key of their name, so the resource catalog shows the console's own pages and buttons in the user's language. The message check counts keys named by the manifest.
Tenant administrators create, edit, copy, enable, disable and delete the roles of their tenant; codes are unique per tenant and every change is audited. Every tenant gets system roles: a tenant administrator role, and in the platform tenant also a platform administrator role. They are created when a tenant is created (identity now announces new tenants once committed) and at start-up for existing tenants; they cannot be changed, disabled or deleted, only copied. The console gets a roles page with search, system roles named in the user's language, and dialogs to create, edit and copy roles; the page and its buttons are declared in the permission manifest.
Tenant administrators give roles to accounts, user groups, departments (optionally including their sub-departments) and positions, for a while or for good, change those terms and take roles away; every change is audited. An account's roles are worked out from its direct assignments and those of its groups, departments, parent departments and positions, within their validity and only while the role is enabled. System accounts get their tenant's system roles, when a tenant is created and at start-up, and keep them; only platform administrators give the platform administrator role. Identity now announces deleted accounts, groups, departments and positions, and their assignments go with them; deleting a role removes its assignments. The roles page opens who has a role, with pickers for each kind of subject, validity dates and the sub-department option; the user list shows each account's roles and how it has them.
Roles now allow or deny menus, pages, tabs, buttons and APIs, optionally until a time. Only explicit grants are stored; the rest is derived and explained: denials win and reach everything below, an allowed resource makes its ancestors visible and implies what it requires, transitively, and every derived state names its reasons. System roles have whole modules (the tenant administrator the access-control module, the platform administrator also the platform module) and cannot be changed; platform resources can only be granted in the platform tenant. Copying a role copies its grants, deleting a role removes them, and a granted resource cannot be deleted from the catalog. Changes are audited. The roles page gets a grant matrix: the application's resource tree with allow and deny choices, each choice previewed by the server so derived states and their reasons show at once, and the changes saved together.
The console now asks the server what the signed-in user may reach, and the server answers from every effective role: denials win and reach down, allowed resources make their ancestors visible and bring along what they require, and system roles cover their modules. Administrators can no longer hand out a role or grant a resource beyond their own permissions. Property tests check the derivation laws on random catalogs.
Every API that declares a permission now checks it against the caller's current permissions, worked out from their roles on each call, so a changed grant, assignment or role status applies to the very next request. Handlers without a declaration are refused. The identity services no longer reserve administration for the tenant's built-in account: any role granted the matching permission may use them. A matrix test calls every guarded API anonymously, without roles, as tenant administrator and as platform administrator.
Menus, pages and every action button now follow the signed-in user's permissions: v-permission hides a button (or disables it with :disable) and PermissionGuard shows content only with a resource. Answers to guarded calls report the version of the caller's permissions, and the console reloads them when it changes, so a revoked role disappears from the console at the next call. The full-stack test signs in a user holding one role and checks the menus and buttons they see, the pages they are kept from, and an API call refused with 403.
check_permission_manifest.py keeps the console's permission manifest consistent: entries nest and are named as the server expects, the APIs they need exist in the API contract, their requirements exist and form no cycle, every API permission is needed by a page or button or listed as granted directly with a reason, page routes exist in the router, and every resource or permission code the console quotes exists. Also adds the unit test of the permission guard that the test mapping check asks for.
A check-up of an application finds what gives nothing or cannot work: grants of disabled resources, of retired APIs or past their expiry (in every tenant), buttons whose dependencies reach no API in service, APIs nothing needs and no role is granted, and dependencies on disabled resources or retired APIs. The new platform page lists the findings by issue; the check-up only reads.
The role, grant, assignment and catalog services, and tenant management, no longer reserve their work for each tenant's built-in administrator account: whoever holds the permission may do it, as the API checks. What remains are the tenant boundaries: only accounts of the platform tenant change the shared catalog and manage tenants, and only holders of the platform administrator role give, change or remove it. A page shown because a button below it is allowed now also works: it brings along the APIs it requires, so allowing only the create-role button lets the holder list roles too.
| } | ||
| function field(label: string) { | ||
| const owner = [...document.querySelectorAll<HTMLLabelElement>('dialog[open] label')] | ||
| .find(item => item.textContent?.replace('*', '').trim() === label) |
| return found as HTMLButtonElement | ||
| } | ||
| async function fill(label: string, value: string) { | ||
| const owner = [...document.querySelectorAll<HTMLLabelElement>('dialog[open] label')].find(item => item.textContent?.replace('*', '').trim() === label) |
| await flushPromises() | ||
| } | ||
| const field = (label: string) => { | ||
| const owner = [...document.querySelectorAll<HTMLLabelElement>('dialog[open] label')].find(item => item.textContent?.replace('*', '').trim() === label) |
Dependency ReviewThe following issues were found:
License Issuescore/grantforge-authz/pom.xml
pom.xml
core/grantforge-server/pom.xml
OpenSSF ScorecardScorecard details
Scanned Files
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changelog category (leave one)
Changelog entry (Details of this change)
Affected version