Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 50 additions & 24 deletions docs/Authorization/AuthorizationBundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,20 @@ public KeyStore amsKeyStore() {

## Startup Check

While it is possible to synchronously block application startup until the AMS module becomes ready, we recommend including AMS in the application's **readiness probes**. This allows the application process to become healthy for the cloud platform but prevent traffic from being routed to the process until the AMS module is ready to serve authorization checks.
The application must ensure that the `AuthorizationManagementService` instance has loaded its initial authorization bundle before it performs authorization checks. Otherwise, exceptions are thrown because no authorization data is available yet.

If an application does not provide readiness probes, it can alternatively include the AMS readiness state in its **health endpoint**.
There are two general approaches to achieve this:

- **Synchronous startup check**: block application startup until the instance is ready, failing after a timeout. This is the most robust option because it prevents *any* premature usage of the instance during startup, including *internal* usage by frameworks such as CAP — not just *external* traffic.
- **Readiness endpoint integration**: expose the instance's readiness state through a health or readiness endpoint so that the platform does not route traffic to the process until the instance is ready. This only delays authorization checks triggered by *external* traffic.

::: tip Spring Boot starters do this for you
The [Spring Boot starters](/Authorization/GettingStarted#java) perform a synchronous startup check out of the box, so no manual startup check is required there. Its timeout can be adjusted and it can be disabled via configuration (see the `Spring Boot` examples below).

Other setups — including the [Node.js CAP plugin](/Authorization/GettingStarted#node-js) — must implement the startup check themselves, as shown in the examples below.
:::

The following examples show, per framework, how the startup check is performed or configured, and how to expose the readiness state in a custom health endpoint. For Spring Boot the check runs automatically and the tabs only show how to adjust the timeout or opt out. Disabling the check is discouraged: the application then becomes responsible for ensuring readiness before performing authorization checks (e.g. via the programmatic APIs shown here).

::: code-group
```js [Node.js (CAP)]
Expand All @@ -164,17 +175,17 @@ const cds = require('@sap/cds');
const { amsCapPluginRuntime } = require("@sap/ams");

cds.on('served', async () => {
// effectively a synchronous startup check that prevents the server
// from serving requests for up to 30s before throwing an error
// CAP awaits all 'served' handlers to finish before it serves traffic.
// So even though whenReady is awaited asynchronously here, it effectively
// blocks application startup until AMS is ready — or aborts it if the handler
// throws after the 30s timeout.
await amsCapPluginRuntime.ams.whenReady(30);
console.log("AMS has become ready.");
});

// *better*: use amsCapPluginRuntime.ams.isReady() in health or readiness endpoint
```

```js [Node.js]
// uses readiness status in health endpoint
// demonstrates readiness status via health endpoint

let isReady = false;
const healthCheck = (req, res) => {
Expand Down Expand Up @@ -204,15 +215,38 @@ const server = app.listen(PORT, () => {
amsStartupCheck();
```

```yaml [Spring Boot (CAP)]
# The synchronous startup check runs automatically.
# Adjust its timeout or opt out via configuration:
cds:
security:
authorization:
ams:
startup-check:
enabled: true # perform synchronous startup check (default: true)
timeout: 30s # fail startup if not ready within this duration (default: 30s)
```

```yaml [Spring Boot]
# The synchronous startup check runs automatically.
# Adjust its timeout or opt out via configuration:
sap:
ams:
startup-check:
enabled: true # perform synchronous startup check (default: true)
timeout: 30s # fail startup if not ready within this duration (default: 30s)
```

```java [Java]
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

// Synchronous startup check:
// throws an error if the AMS module doesn't get ready within 30 seconds
ams.whenReady().get(30, TimeUnit.SECONDS);
ams.awaitReady(Duration.ofSeconds(30));

// Asynchronous startup check: uses readiness status in health endpoint
// Asynchronous startup check: demonstrates readiness status in health endpoint
private static final AtomicBoolean isReady = new AtomicBoolean(false);

app.get("/health", ctx -> {
Expand All @@ -234,21 +268,13 @@ ams.whenReady().orTimeout(30, TimeUnit.SECONDS).thenRun(() -> {
});
```

```java [Spring Boot Readiness]
// The spring-boot-starter-ams-readiness module provides an auto-config for a
// AmsReadinessContributor bean. It autowires an AuthorizationManagementService
// instance and uses AvailabilityChangeEvent.publish
// to integrate its readiness state with Spring Boot's availability state.
// The AMS readiness starter is included transitively in all AMS Spring Boot starters.
```
:::

```java [Spring Boot Health Actuator]
// The spring-boot-starter-ams-health and spring-boot-3-starter-ams-health modules
// provide an auto-config for a HealthIndicator bean that integrates with the
// Spring Boot Actuator health endpoint. It autowires an
// AuthorizationManagementService instance and includes its readiness state
// in the health status.
// The AMS health starter is NOT included transitively in any AMS Spring Boot starter.
```
::: tip Expose AMS readiness in the Spring Boot Actuator health endpoint
Beyond the startup check, applications can expose the AMS readiness state through the **Spring Boot Actuator health endpoint** (for example, to observe the time since the last bundle refresh at runtime) by including one of the optional health starters:

- `spring-boot-starter-ams-health` for Spring Boot 4
- `spring-boot-3-starter-ams-health` for Spring Boot 3

These provide an auto-configured `HealthIndicator` bean that autowires the `AuthorizationManagementService` and includes its readiness state in the health status. They are *not* included transitively by any AMS starter.
:::
9 changes: 4 additions & 5 deletions docs/Authorization/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,10 @@ Use the `ams-bom` for consistent version management across all AMS modules:

:::

::: tip Health Indicators
The `spring-boot-starter-ams-readiness` module provides readiness state integration via `AvailabilityChangeEvent` and
is already included **transitively** in all Spring Boot starters. The optional health modules listed above provide
alternatively `HealthIndicator` beans for Spring Boot Actuator health endpoint integration
(see [Startup Check](/Authorization/AuthorizationBundle#startup-check)).
::: tip Startup check & health indicators
All AMS Spring Boot starters perform a synchronous [startup check](/Authorization/AuthorizationBundle#startup-check) by
default, blocking startup until the initial authorization bundle is loaded. The optional health modules listed above can additionally expose the AMS readiness state (e.g. time since the last bundle refresh) through a
`HealthIndicator` bean for the Spring Boot Actuator health endpoint.
:::

#### Tooling
Expand Down
5 changes: 5 additions & 0 deletions docs/Libraries/java/cap-ams.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ cds:
ams:
edge-service:
url: http://localhost:8080 # Edge service URL (optional)
startup-check:
enabled: true # Block startup until initial bundle is loaded (default: true)
timeout: 30s # Fail startup if not ready within this duration (default: 30s)
bundle-loader:
polling-interval: 20000 # Bundle update polling interval in ms (default: 20000)
initial-retry-delay: 1000 # Initial retry delay after failure in ms (default: 1000)
Expand All @@ -163,3 +166,5 @@ cds:
features:
generateExists: true # Generate EXISTS predicates for filter attributes behind 1:N associations (default: true)
```

See [Startup Check](/Authorization/AuthorizationBundle#startup-check) for details on the synchronous startup check and the optional health actuator integration.
6 changes: 6 additions & 0 deletions docs/Libraries/java/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Version 4

### 4.4.0

- Feature: Synchronous startup readiness check in Spring Boot starters. The `AuthorizationManagementService` bean now blocks during application startup until the initial authorization bundle has been loaded. This is enabled by default; see [Startup Check](/Authorization/AuthorizationBundle#startup-check) for details, including how to adjust the timeout or opt out. The new utility method `AuthorizationManagementService.awaitReady(Duration)` simplifies synchronously awaiting the first bundle outside Spring.
- Fix: The auto-configuration matcher that decides whether to use ZTIS certificates now extracts the `identity` binding app-identifier from the correct location in the service binding credentials.
- Fix: A policy `USE` with multiple `RESTRICT` clauses now correctly interprets each restriction set as an independent alternative, i.e.`(b = 10 AND c = 100) OR (b = 20 AND c = 200)` (correct) instead of `(b = 10 OR b = 20) AND (c = 100 OR c = 200)` (incorrect).

### 4.3.0

- Feature: The `spring-boot-starter-ams-test` auto-configuration no longer matches when an `identity` service binding is found. This enables CAP applications to include `spring-boot-starter-cap-ams-test` as regular (instead of test-scoped) dependency to start locally with mock users and file-based authorization bundles without explicitly including test-scoped dependencies. To override this auto-configuration matcher, the property `sap.ams.test.enabled` can be explicitly set to `true` or `false`.
Expand Down
12 changes: 8 additions & 4 deletions docs/Libraries/java/spring-boot-ams.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The starter automatically configures:
- Request-scoped `Authorizations` proxy bean for the current request
- `AmsRouteSecurity` bean for route-level authorization
- `AmsMethodSecurity` bean for method-level authorization
- Readiness state integration (via `spring-boot-starter-ams-readiness`)
- Synchronous [startup check](/Authorization/AuthorizationBundle#startup-check) that blocks startup until the initial authorization bundle is loaded

## Declarative Authorization

Expand Down Expand Up @@ -183,9 +183,13 @@ sap:
method-security:
enabled: true # Enable method-level security (default: true)

startup-check:
enabled: true # Block startup until initial bundle is loaded (default: true)
timeout: 30s # Fail startup if not ready within this duration (default: 30s)

actuator:
health:
enabled: true # Enable health indicator (default: true)
readiness:
enabled: true # Enable readiness state contributor (default: true)
enabled: true # Enable AMS health indicator, requires spring-boot(-3)-starter-ams-health (default: true)
```

See [Startup Check](/Authorization/AuthorizationBundle#startup-check) for details on the synchronous startup check and the optional health actuator integration.
2 changes: 1 addition & 1 deletion docs/Libraries/java/v3/migration-v3-to-v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ If you are using a Spring Boot starter, the `AuthorizationManagementService` and
- Implement startup check as described [here](/Authorization/AuthorizationBundle#startup-check)

::: tip
If you use a Spring Boot starter, it automatically integrates into Spring Boot readiness. Alternatively, you can use the Spring Boot 3 or 4 starter for health actuator integration.
If you use a Spring Boot starter, it performs a synchronous startup check by default, blocking startup until the initial authorization bundle is loaded. Optionally, you can add the Spring Boot 3 or 4 health starter for health actuator integration.
:::

### AttributesProcessor Removal
Expand Down
Loading