5 Authorizing Access to Server-Side Operations
StorageAccessAuthorizer checks entry-level and map-level read/write access when it is configured for a partitioned cache. It is opt-in: absent authorization remains absent in either security profile. Configure it on every protected scheme and deploy the implementation and identity mapping consistently to the storage members.
The built-in auditing implementation is non-strict and can allow a null subject while logging. strict-auditing rejects missing subjects but does not by itself implement business roles or prove that a received subject was authenticated. Use a trusted identity path and a real application policy where role/resource decisions are required.
Use Implementing an Account Storage Authorizer for a complete example. The retained declaration/wiring topics show operational registration and backing-map scheme references. Proxy wrapper authorization can still be useful for its integration scope; storage-side checks cover the configured storage boundary rather than relying only on a particular proxy wrapper.
Operation coverage and cost
The authorizer receives the operation reason as well as the subject and resource context. Test reads, writes, invoke, aggregate, index add/remove, lock/unlock, listeners, and any application-specific path that is exposed. Single-key invoke uses write authorization; lock/unlock checks occur before lock state mutation; configured index removal checks must also handle an absent subject.
Do not use a null subject as an automatic internal-system bypass. Distinguish legitimate internal routes using the supported contract and a reviewed application policy. Authorization code executes on a hot path: local decisions over verified identity and resource data are usually preferable to a remote directory/policy request on every microsecond-scale cache operation. Bound caches and include policy-change/credential-retirement semantics.
Continuous Aggregation uses aggregate authorization for registration, removal, and full-result queries and entry-processor authorization for projections. No separate permission is implied merely because a maintained result is used. Check the feature's release availability and classify custom executable definitions.
- Implementing an Account Storage Authorizer
Map verified certificate principals to simple reader/writer permissions and wire the policy to the accounts cache. - Overview of Access Control Authorization
Access control authorization allows applications to define their own authorization logic to limit access to cluster operations. Authorization is based on identities that are represented as aPrincipalwithin aSubject. - Creating Access Control Authorization Implementations
Implement all storage-authorizer callbacks and validate both resource and authenticated identity. - Declaring Access Control Authorization Implementations
Access control authorization implementations must be declared so that the class is loaded when a cluster starts. - Enabling Access Control Authorization on a Partitioned Cache
A partition cache service must be configured to use an access control authorization implementation.
Implementing an Account Storage Authorizer
This complete Java 21+ example permits reads to a configured reader or writer certificate principal and writes only to the writer. It denies unknown caches, null subjects, and unmatched identities. It assumes the subject's certificate identity was established through the deployment's trusted authentication path. Adapt the identity-to-role mapping to the approved directory/token integration rather than trusting a role supplied by an unverified client.
package com.example.security;
import com.tangosol.net.BackingMapContext;
import com.tangosol.net.security.StorageAccessAuthorizer;
import com.tangosol.util.BinaryEntry;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
public final class AccountAuthorizer implements StorageAccessAuthorizer {
private final X500Principal reader = new X500Principal(System.getProperty(
"example.accounts.reader", "CN=reader,OU=Accounts,O=Example"));
private final X500Principal writer = new X500Principal(System.getProperty(
"example.accounts.writer", "CN=writer,OU=Accounts,O=Example"));
private void authorize(BackingMapContext context, Subject subject, boolean write) {
if (context == null || !"accounts".equals(context.getCacheName())
|| subject == null) {
throw new SecurityException("Access denied");
}
var identities = subject.getPrincipals(X500Principal.class);
if (!identities.contains(writer) && (write || !identities.contains(reader))) {
throw new SecurityException("Access denied");
}
}
@Override
public void checkRead(BinaryEntry entry, Subject subject, int reason) {
authorize(entry.getBackingMapContext(), subject, false);
}
@Override
public void checkWrite(BinaryEntry entry, Subject subject, int reason) {
authorize(entry.getBackingMapContext(), subject, true);
}
@Override
public void checkReadAny(BackingMapContext context, Subject subject, int reason) {
authorize(context, subject, false);
}
@Override
public void checkWriteAny(BackingMapContext context, Subject subject, int reason) {
authorize(context, subject, true);
}
}Register it under <cluster-config><storage-authorizers> in the operational override:
<storage-authorizers>
<storage-authorizer id="accounts-policy">
<class-name>com.example.security.AccountAuthorizer</class-name>
</storage-authorizer>
</storage-authorizers>Reference it from the protected distributed scheme's backing-map configuration:
<backing-map-scheme>
<storage-authorizer>accounts-policy</storage-authorizer>
<local-scheme/>
</backing-map-scheme>Map only the intended cache names to that scheme, deploy the authorizer class, and set the reader/writer principal configuration consistently. Unlike an executable sent by a remote client, a server-configured authorizer is trusted deployment code. Keep its artifact under the same change control as member configuration.
Verification
-
Verify the reader can read and cannot write, invoke a write processor, change indexes, or mutate locks where those routes require write policy.
-
Verify the writer's permitted reads/writes and an unknown principal's denial.
-
Verify a missing subject fails through the actual client and any applicable internal route.
-
Exercise map-wide and single-entry APIs, the actual proxy protocol, failover, and representative load. Check that a proxy-only success does not hide a storage configuration omission.
Parent topic: Authorizing Access to Server-Side Operations
Overview of Access Control Authorization
Principal within a Subject.Applications are responsible for ensuring that the Subject is present for caller threads. If the Subject is missing or cannot be retrieved, then the operation fails with a SecurityException error.
Applications implement the StorageAccessAuthorizer interface to provide authorization logic. The implementations are declared in the operational override configuration file and must also be enabled on a partitioned cache by configuring the backing map of a distributed scheme in a cache configuration file. Access control authorization is only available for partitioned caches.
The StorageAccessAuthorizer interface provides methods that are used to perform read, write, read any, and write any authorization checks. Coherence assumes that there is a logical consistency between authorization decisions made by StorageAccessAuthorizer implementations. That is, for a given Subject, the write authorization implies the read authorization for a given entry; the read any authorization implies read authorization for all entries; and, the write any authorization implies write and read authorization for all entries.
Table 5-1 lists which authorization checks are caused by NamedCache API and BinaryEntry API methods.
Table 5-1 Authorization Checks for Common Methods
| Authorization Check | NamedCache API Methods | BinaryEntry API Methods |
|---|---|---|
|
None |
|
|
|
Read |
|
|
|
Write |
|
|
|
Read Any |
|
|
|
Write Any |
|
Footnote 1
If a listener is a MapTriggerListener, then a Write Any authorization check is performed instead.
Parent topic: Authorizing Access to Server-Side Operations
Creating Access Control Authorization Implementations
Implement StorageAccessAuthorizer to decide entry-level and map-level read/write access. The callbacks receive a subject and reason plus the entry or backing-map context. Use those inputs to define a deliberate policy for the protected cache and operation.
| Callback | Resource scope |
|---|---|
checkRead
|
An entry read. |
checkWrite
|
An entry mutation or write-authorized operation. |
checkReadAny
|
Map-level read scope. |
checkWriteAny
|
Map-level mutation scope. |
Implementing an Account Storage Authorizer provides a complete current example and wiring. Handle null subjects explicitly and consider reason-specific restrictions where the policy distinguishes invoke, aggregation, index, or lock operations. Do not assume every caller is a client or that an internal route always has a subject.
Audit-only implementations can be useful during migration, but logging an operation is not enforcing a role. Use structured/bounded operation and resource metadata and avoid logging cache keys, values, secrets, or an entire credential-bearing subject. Measure hot-path cost with the real policy before deployment.
Parent topic: Authorizing Access to Server-Side Operations
Declaring Access Control Authorization Implementations
To declare access control authorizer implementations, edit the operational override file and include a <storage-authorizers> element, within the <cluster-config> element, and declare each authorization implementation using a <storage-authorizer> element. See storage-authorizer in Developing Applications with Oracle Coherence. Each declaration must include a unique id attribute that is used by a partitioned cache to select an implementation. For example:
<cluster-config>
<storage-authorizers>
<storage-authorizer id="LogAuthorizer">
<class-name>package.MyLogAuthorizer</class-name>
</storage-authorizer>
</storage-authorizers>
</cluster-config>
As an alternative, the <storage-authorizer> element supports the use of a <class-factory-name> element to use a factory class that is responsible for creating instances and a <method-name> element to specify the static factory method on the factory class that performs object instantiation. For example:
<cluster-config>
<storage-authorizers>
<storage-authorizer id="LogAuthorizer">
<class-factory-name>package.MyAuthorizerFactory</class-factory-name>
<method-name>getAuthorizer</method-name>
</storage-authorizer>
</storage-authorizers>
</cluster-config>
Any initialization parameters that are required for an implementation can be specified using the <init-params> element. For example:
<cluster-config>
<storage-authorizers>
<storage-authorizer id="LogAuthorizer">
<class-name>package.MyLogAuthorizer</class-name>
<init-params>
<init-param>
<param-name>f_fStrict</param-name>
<param-value>true</param-value>
</init-param>
</init-params>
</storage-authorizer>
</storage-authorizers>
</cluster-config>
Parent topic: Authorizing Access to Server-Side Operations
Enabling Access Control Authorization on a Partitioned Cache
To enable access control authorization on a partitioned cache, edit the cache configuration file and add a <storage-authorizer> element, within the <backing-map-scheme> element of a distributed scheme, whose value is the id attribute value of an authorization implementation that is declared in the operational override file. For example:
<distributed-scheme>
...
<backing-map-scheme>
<storage-authorizer>LogAuthorizer</storage-authorizer>
<local-scheme/>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
Parent topic: Authorizing Access to Server-Side Operations