Security configuration
View MarkdownStatus: Stable Package:
dev.vertique.security.configArtifact:vertique-security-configDepends on: security-core, config-core API reference: javadoc.io
Config/YAML-backed authorization adapters for the Vertique security model. This module reads the authorization section of the application config and contributes, via Dagger @IntoSet multibinding, a PolicyDefinitionSource and a RolePolicyResolver into the sets declared by dev.vertique:vertique-security-runtime’s SecurityAuthzModule.
The SPI contracts live in dev.vertique:vertique-security-core. The engine that consumes these contributions lives in dev.vertique:vertique-security-runtime.
When To Use It
Section titled “When To Use It”Include vertique-security-config when the application defines authorization policies and role→policy mappings in its config file rather than in code. An application using config-backed authorization includes both this module and SecurityAuthzModule in its Dagger component:
@Component(modules = { VertxModule.class, ConfigModule.class, SecurityAuthzModule.class, // declares the multibinding sets + builds the engine SecurityEventsModule.class, AuthzConfigModule.class, // contributes config-backed PolicyDefinitionSource + RolePolicyResolver // ... application action contributors})interface AppComponent { ... }AuthzConfigModule does not declare the Authorizer or AuthorizationIntrospector bindings — those remain owned by SecurityAuthzModule. This module only feeds config-derived entries into the engine’s multibinding sets.
Config Path
Section titled “Config Path”The module reads the authorization section of the root application config:
authorization: rolePolicies: admin: - admin-policy viewer: - viewer-policy policies: - name: admin-policy statements: - effect: ALLOW actions: - cms.content.* - name: viewer-policy statements: - effect: ALLOW actions: - cms.content.readWhen the authorization section is absent, the module falls back to AuthorizationConfig.defaults() (no role mappings, no inline policies).
Core Concepts
Section titled “Core Concepts”Startup Validation
Section titled “Startup Validation”Both contributed components are validated at startup (fail-fast), in sequence, governed by the dependency graph:
- Policy patterns vs. action registry. After
SecurityAuthzModulebuilds theActionRegistry, it callsPolicyDefinitionSource.validateAgainst(ActionRegistry)polymorphically on every contributed source — includingConfigBackedPolicyDefinitionSource. Exact action patterns must be registered; wildcard patterns must match at least one registered action. An offending pattern aborts startup. - Role→policy name vs. merged catalogue.
AuthzConfigModule.configBackedRolePolicyResolver(...)validates every policy name referenced inauthorization.rolePoliciesagainst the mergedSet<PolicyDefinitionSource>(union of all contributed sources’ policies). A mapping that references a policy contributed programmatically through another source is accepted; an unknown policy name aborts startup with anIllegalStateExceptionnaming the offending role and policy.
This two-step ordering ensures cross-source references (a config-backed role mapping pointing at a programmatically-contributed policy) are accepted, while fully unknown references fail fast.
Key Classes
Section titled “Key Classes”AuthzConfigModule
Section titled “AuthzConfigModule”Abstract Dagger @Module that is the primary entry point for this module. Provides three bindings:
| Provided binding | Scope | Description |
|---|---|---|
AuthorizationConfig |
@Singleton |
Parsed authorization config from the authorization section |
PolicyDefinitionSource (@IntoSet) |
@Singleton |
Config-backed policy source; not validated here — validation is polymorphic via SecurityAuthzModule |
RolePolicyResolver (@IntoSet) |
@Singleton |
Config-backed role resolver; validated against the merged policy catalogue before binding |
The configBackedRolePolicyResolver provider holds the merged-catalogue validation logic — it collects all policy names from every contributed PolicyDefinitionSource and checks each name in authorization.rolePolicies against that set. This is the only provider in the module that takes Set<PolicyDefinitionSource> as an argument, which is intentional: only the wiring layer can see the merged set.
AuthorizationConfig
Section titled “AuthorizationConfig”Root config record for the authorization section.
public record AuthorizationConfig( Map<String, List<String>> rolePolicies, // role → list of policy names List<PolicyDefinitionConfig> policies // inline policy definitions)Both fields are defensively deep-copied at construction (the map values are also immutably copied). rolePolicies is a true user-defined dictionary (rule R9-compliant): keys are operator-defined role names, values are open lists of policy identifiers.
AuthorizationConfig.fromJson(...) fills defaults for omitted fields (empty map / empty list). AuthorizationConfig.defaults() returns the canonical empty config.
PolicyDefinitionConfig
Section titled “PolicyDefinitionConfig”Config record for a single named authorization policy.
public record PolicyDefinitionConfig( String name, // non-null, non-blank List<PolicyStatementConfig> statements)Compact constructor validates non-null, non-blank name. statements defaults to an empty list when absent in config.
PolicyStatementConfig
Section titled “PolicyStatementConfig”Config record for a single authorization policy statement.
public record PolicyStatementConfig( Effect effect, // defaults to Effect.ALLOW when absent in config List<String> actions // action pattern strings, e.g. "cms.content.read" or "cms.*")The actions strings are converted to ActionPattern instances by ConfigBackedPolicyDefinitionSource at construction time. Invalid patterns (violating the ActionRef segment grammar, or a bare "*") fail at that conversion.
ConfigBackedPolicyDefinitionSource
Section titled “ConfigBackedPolicyDefinitionSource”@Singleton implementation of PolicyDefinitionSource. Converts AuthorizationConfig.policies() to PolicyDefinition objects at construction time:
PolicyDefinitionConfig→PolicyDefinition(name, statements)PolicyStatementConfig→PolicyStatement(effect, Set<ActionPattern>)- Action pattern strings →
ActionPattern(grammar-validated at construction)
validateAgainst(ActionRegistry) is inherited from the PolicyDefinitionSource default and validates all patterns against the registry polymorphically. The fluent withRegistry(ActionRegistry) convenience method chains the same check and returns this.
ConfigBackedRolePolicyResolver
Section titled “ConfigBackedRolePolicyResolver”@Singleton implementation of RolePolicyResolver. Reads its role→policy mappings from AuthorizationConfig.rolePolicies(). Policy-name existence is not validated here — the wiring layer (AuthzConfigModule.configBackedRolePolicyResolver) handles that against the merged catalogue.
@Overridepublic Set<String> policiesForRoles(Set<String> roles) { // Returns the union of all policy names mapped to any of the supplied roles. // Unknown roles contribute nothing (silently ignored).}The package-private rolePolicies() accessor is used by AuthzConfigModule during the startup validation step to iterate the role→policy mapping.
Extension Points
Section titled “Extension Points”This module contributes into the SPIs declared by SecurityAuthzModule. Applications add their own contributions alongside the config-backed ones:
// Contribute a programmatic policy source in addition to config-backed ones@Provides @IntoSetstatic PolicyDefinitionSource myPolicies(MyProgrammaticPolicySource s) { return s; }
// Contribute a programmatic role resolver in addition to config-backed one@Provides @IntoSetstatic RolePolicyResolver myResolver(MyRolePolicyResolver r) { return r; }Config-backed and programmatic contributions are merged by SecurityAuthzModule. Role mappings in config that reference a policy contributed programmatically are validated against the merged catalogue (not just the config-backed policies), so cross-source references work.
Dependencies
Section titled “Dependencies”dev.vertique:vertique-security-core—PolicyDefinitionSource,RolePolicyResolver,ActionRegistry,PolicyDefinition,PolicyStatement,ActionPattern,Effectdev.vertique:vertique-config-core—ConfigParser,JsonConfigPaths(parse boundary),@VertxConfig