diff --git a/advanced/odata.md b/advanced/odata.md
index abadb6d13..3e033140f 100644
--- a/advanced/odata.md
+++ b/advanced/odata.md
@@ -104,7 +104,7 @@ Content-Type: application/json
PATCH requests with delta payload are executed using batch delete and [upsert](../java/working-with-cql/query-api#bulk-upsert) statements, and are more efficient than OData [batch requests](https://docs.oasis-open.org/odata/odata/v4.01/csprd02/part1-protocol/odata-v4.01-csprd02-part1-protocol.html#sec_BatchRequests).
-Use PATCH on entity collections for uploading mass data using a dedicated service, which is secured using [role-based authorization](../java/security#role-based-auth). Delta updates must be explicitly enabled by annotating the entity with
+Use PATCH on entity collections for uploading mass data using a dedicated service, which is secured using [role-based authorization](../guides/security/authorization#requires). Delta updates must be explicitly enabled by annotating the entity with
```cds
@Capabilities.UpdateRestrictions.DeltaUpdateSupported
diff --git a/java/security.md b/java/security.md
index 91c7f41e6..93bf88770 100644
--- a/java/security.md
+++ b/java/security.md
@@ -106,11 +106,10 @@ service BooksService @(requires: 'any') {
| `/BooksService` | |
| `/BooksService/$metadata` | |
| `/BooksService/Books` | |
-| `/BooksService/Reviews` | 1 |
+| `/BooksService/Reviews` | |
| `/BooksService/Orders` | |
-> 1 Since version 1.25.0
::: tip
For multitenant applications, it's required to authenticate all endpoints as the tenant information is essential for processing the request.
:::
@@ -345,26 +344,19 @@ The mock user `Alice` is assigned to the mock tenant `CrazyCars` for which the f
CAP Java SDK provides a comprehensive authorization service. By defining authorization rules declaratively via annotations in your CDS model, the runtime enforces authorization of the requests in a generic manner. Two different levels of authorization can be distinguished:
-- [Role-based authorization](#role-based-auth) allows to restrict resource access depending on user roles.
-- [Instance-based authorization](#instance-based-auth) allows to define user privileges even on entity instance level, that is, a user can be restricted to instances that fulfill a certain condition.
+- [Role-based authorization](../guides/security/authorization#requires) allows to restrict resource access depending on user roles.
+- [Instance-based authorization](../guides/security/authorization#instance-based-auth) allows to define user privileges even on entity instance level, that is, a user can be restricted to instances that fulfill a certain condition.
It's recommended to configure authorization declaratively in the CDS model. If necessary, custom implementations can be built on the [Authorization API](#enforcement-api).
A precise description of the general authorization capabilities in CAP can be found in the [Authorization](../guides/security/authorization) guide.
-### Role-Based Authorization { #role-based-auth}
-
-Use CDS annotation `@requires` to specify in the CDS model which role a user requires to access the annotated CDS resources such as services, entities, actions, and functions (see [Restricting Roles with @requires](../guides/security/authorization#requires)). The generic authorization handler of the runtime rejects all requests with response code 403 that don't match the accepted roles.
-More specific access control is provided by the `@restrict` annotation, which allows to combine roles with the allowed set of events. For instance, this helps to distinguish between users that may only read an entity from those who are allowed to edit. See section [Control Access with @restrict](../guides/security/authorization#restrict-annotation) to find details about the possibilities.
-
-### Instance-Based Authorization { #instance-based-auth}
-
-Whereas role-based authorization applies to whole entities only, [Instance-Based Authorization](../guides/security/authorization#instance-based-auth) allows to add more specific conditions that apply on entity instance level and depend on the attributes that are assigned to the request user. A typical use case is to narrow down the set of visible entity instances depending on user properties (for example, `CountryCode` or `Department`). Instance-based authorization is also basis for [domain-driven authorizations](../guides/security/authorization#domain-driven-authorization) built on more complex model constraints.
+In addition to standard authorization, CAP Java provides additional out of the box capabilities to reduce custom code:
#### Deep Authorization { #deep-auth}
-Queries to Application Services are not only authorized by the target entity which has a `@restrict` or `@requires` annotation, but also for all __associated entities__ that are used in the statement. __Compositions__ are neither checked nor extended with additional filters.
-
+Queries to Application Services are not only authorized by the target entity which has a `@restrict` or `@requires` annotation, but also for all __associated entities__ that are used in the statement.
+__Compositions__ are neither checked nor extended with additional filters.
For instance, consider the following model:
```cds
@@ -381,15 +373,15 @@ entity Orders {
}
```
-For the following OData request `GET Orders(ID='1')/items?$expand=book`, authorizations for `Orders` and for `Books` are checked.
-If the entity `Books` has a `where` clause for [instance-based authorization](/java/security#instance-based-auth),
+For the following OData request `GET Orders(ID='1')/items?$expand=book`, authorizations for `Orders` and for `Books` are checked.
+If the entity `Books` has a `where` clause for [instance-based authorization](/java/security#instance-based-auth),
it will be added as a filter to the sub-request with the expand.
-Custom CQL statements submitted to the [Application Service](/java/cqn-services/application-services) instances
+Custom CQL statements submitted to the [Application Service](/java/cqn-services/application-services) instances
are also authorized by the same rules including the path expressions and subqueries used in them.
-For example, the following statement checks role-based authorizations for both `Orders` and `Books`,
-because the association to `Books` is used in the select list.
+For example, the following statement checks role-based authorizations for both `Orders` and `Books`,
+because the association to `Books` is used in the select list.
```java
Select.from(Orders_.class,
@@ -413,7 +405,28 @@ Be careful when you modify or extend the statements in custom handlers.
Make sure you keep the filters for authorization.
:::
-Deep authorizations are on by default and can be disabled by setting `cds.security.authorization.deep.enabled: false`.
+Starting with CAP Java `4.0`, deep authorization is on by default.
+It can be disabled by setting cds.security.authorization.deep.enabled: false.
+
+[Learn more about `@restrict.where` in the instance-based authorization guide.](/guides/security/authorization#instance-based-auth){.learn-more}
+
+#### Forbidden on Rejected Entity Selection { #reject-403 }
+
+Entities that have an instance-based authorization condition, that is [`@restrict.where`](/guides/security/authorization#restrict-annotation),
+are guarded by the CAP Java runtime by adding a filter condition to the DB query **excluding not matching instances from the result**.
+Hence, if the user isn't authorized to query an entity, requests targeting a *single* entity return *404 - Not Found* response and not *403 - Forbidden*.
+
+To allow the UI to distinguish between *not found* and *forbidden*, CAP Java can detect this situation and rejects`PATCH` and `DELETE` requests to single entities with forbidden accordingly.
+The additional authorization check may affect performance.
+
+::: warning
+To avoid to disclosure the existence of such entities to unauthorized users, make sure that the key is not efficiently enumerable or add custom code to overrule the default behaviour otherwise.
+:::
+
+Starting with CAP Java `4.0`, the reject behaviour is on by default.
+It can be disabled by setting cds.security.authorization.instance-based.reject-selected-unauthorized-entity.enabled: false.
+
+[Learn more about `@restrict.where` in the instance-based authorization guide.](/guides/security/authorization#instance-based-auth){.learn-more}
#### Authorization Checks On Input Data { #input-data-auth }
@@ -430,15 +443,11 @@ annotate Orders with @(restrict: [
A user with accounting areas `[Development, Research]` is not able to send an `UPDATE` request, that changes `accountingArea` from `Research` or `Development` to `CarFleet`, for example.
Note that the `UPDATE` on instances _not matching the request user's accounting areas_ (for example, `CarFleet`) are rejected by standard instance-based authorization checks.
-#### Current Limitations
+Starting with CAP Java `4.0`, deep authorization is on by default.
+It can be disabled by setting cds.security.authorization.instanceBased.checkInputData: false.
-The CAP Java SDK translates the `where`-condition in the `@restrict` annotation to a predicate, which is appended to the `CQN` statement of the request. This applies only to `READ`,`UPDATE`, and `DELETE` events. In the current version, the following limitations apply:
-* For `UPDATE` and `DELETE` events no paths in the `where`-condition are supported.
-* Paths in `where`-conditions with `to-many` associations or compositions can only be used with an [`exists` predicate](../guides/security/authorization#exists-predicate).
-* `UPDATE` and `DELETE` requests that address instances that aren't covered by the condition (for example, which aren't visible) aren't rejected, but work on the limited set of instances as expected.
-As a workaround for the limitations with paths in `where`-conditions, you may consider using the `exists` predicate instead.
+[Learn more about `@restrict.where` in the instance-based authorization guide.](/guides/security/authorization#instance-based-auth){.learn-more}
-CAP Java SDK supports [User Attribute Values](../guides/security/authorization#user-attrs) that can be referred by `$user.` in the where-clause of the `@restrict`-annotation. Currently, only comparison predicates with user attribute values are supported (`<,<=,=,=>,>`). Note that generally a user attribute represents an *array of strings* and *not* a single value. A given value list `[code1, code2]` for `$user.code` in predicate `$user.code = Code` evaluates to `(code1 = Code) or (code2 = Code)` in the resulting statement.
### Enforcement API & Custom Handlers { #enforcement-api}