Skip to content

Commit

Permalink
Merge pull request #2047 from beyonnex-io/add-permission-availability…
Browse files Browse the repository at this point in the history
…-api

Add new endpoint checkpermissions
  • Loading branch information
thjaeckle authored Nov 6, 2024
2 parents 51ea5e3 + 880c3f1 commit df6f261
Show file tree
Hide file tree
Showing 38 changed files with 2,492 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ entries:
- title: Authentication and Authorization
url: /basic-auth.html
output: web
subfolders:
- title: Checking Permissions for Resources
url: /basic-auth-checkpermissions.html
output: web
- title: Messages
url: /basic-messages.html
output: web
Expand Down
64 changes: 64 additions & 0 deletions documentation/src/main/resources/openapi/ditto-api-2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6567,6 +6567,31 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/AdvancedError'
/api/2/checkPermissions:
post:
summary: "Check Permissions for Resources"
description: "An endpoint to verify permissions on specified resources."
tags:
- Policies
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PermissionCheckRequest'
responses:
'200':
description: "Permissions check result"
content:
application/json:
schema:
$ref: '#/components/schemas/PermissionCheckResponse'
'401':
description: The request could not be completed due to missing authentication.
content:
application/json:
schema:
$ref: '#/components/schemas/AdvancedError'
/api/2/search/things:
get:
summary: Search for things
Expand Down Expand Up @@ -10430,6 +10455,45 @@ components:
- security
- securityDefinitions
additionalProperties: true
PermissionCheckRequest:
type: object
description: "Request to check permissions for various entities and resources."
additionalProperties:
$ref: '#/components/schemas/PermissionEntityCheck'
example:
lamp_reader:
resource: "thing:/features/lamp/properties/on"
entityId: "org.eclipse.ditto:some-thing-1"
hasPermissions: [ "READ" ]
lamp_toggler:
resource: "message:/features/lamp/inbox/messages/toggle"
entityId: "org.eclipse.ditto:some-thing-1"
hasPermissions: [ "WRITE" ]
PermissionEntityCheck:
type: object
description: "Details for a specific permission check request."
properties:
resource:
type: string
pattern: "^(thing|message|policy):(/[a-zA-Z0-9._-]+)*$"
description: "Resource key to be checked, beginning with 'thing:', 'message:', or 'policy:', followed by the specific resource path. This defines the scope of the permission request."
entityId:
type: string
description: "ID of the entity performing the action, which could be a ThingId or PolicyId, depending on the resource context."
hasPermissions:
type: array
items:
type: string
enum: [ "READ", "WRITE" ]
description: "Required permissions on the resource."
PermissionCheckResponse:
type: object
description: "Response with permission check results for each entity."
additionalProperties:
type: boolean
example:
lamp_reader: true
lamp_toggler: false
TextUnauthorizeError:
type: string
example: The supplied authentication is invalid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ paths:
'/api/2/whoami':
$ref: "./paths/whoami/index.yml"

###
### Check Permissions
###
'/api/2/checkPermissions':
$ref: "./paths/checkPermissions/index.yml"

###
### Things-Search
###
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright (c) 2024 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0
#
# SPDX-License-Identifier: EPL-2.0
post:
summary: Check permissions for specified entities
description: |-
This endpoint allows you to verify permissions for various entities on specific resources.
tags:
- Policies
requestBody:
description: JSON payload containing entities and their permissions to be checked.
required: true
content:
application/json:
schema:
$ref: '../../schemas/checkPermissions/permissionCheckRequest.yml'
responses:
'200':
description: Permission check results for each entity.
content:
application/json:
schema:
$ref: '../../schemas/checkPermissions/permissionCheckResponse.yml'
'401':
description: Unauthorized request due to missing authentication.
content:
application/json:
schema:
$ref: '../../schemas/errors/advancedError.yml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) 2024 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0
#
# SPDX-License-Identifier: EPL-2.0
type: object
description: |-
Request to check permissions for various entities and resources.
additionalProperties:
$ref: 'permissionEntityCheck.yml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) 2024 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0
#
# SPDX-License-Identifier: EPL-2.0
type: object
description: "Response with permission check results for each entity."
additionalProperties:
type: boolean
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright (c) 2024 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0
#
# SPDX-License-Identifier: EPL-2.0
type: object
description: |-
Details for a specific permission check request.
properties:
resource:
type: string
description: "Resource path the permission check applies to."
entityId:
type: string
description: "thingId of the entity performing the action."
hasPermissions:
type: array
items:
type: string
enum: ["READ", "WRITE"]
description: "Required permissions on the resource."
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Checking Permissions for Resources
keywords: permissions, authorization, resources, policy, checkPermissions
tags: [model]
permalink: basic-auth-checkpermissions.html
---

The `/checkPermissions` endpoint allows clients to validate permissions for specified entities on various resources, verifying access rights as defined in Ditto's policies.

## Overview

The `/checkPermissions` endpoint is part of Ditto's HTTP API, enhancing its policy-based authorization system by enabling permission validation checks on resources without modifying them.
This functionality is valuable for UI-driven applications, where permissions checks can determine whether certain UI elements should be displayed or disabled based on the user’s access rights.

## Request Structure

Submit a `POST` request with a JSON payload specifying entities, resources, and permissions:

```json
{
"entity_name": {
"resource": "thing:/features/lamp/properties/on",
"entityId": "org.eclipse.ditto:some-thing-1",
"hasPermissions": ["READ"]
},
"another_entity": {
"resource": "message:/features/lamp/inbox/messages/toggle",
"entityId": "org.eclipse.ditto:some-thing-2",
"hasPermissions": ["WRITE"]
}
}
```
## Fields
- entity_name: Identifier for the entity performing the action.
- resource: Path of the target resource, starting with thing:, message:, or policy: followed by a valid resource path.
- entityId: Unique identifier for the entity, such as a thingId or policyId, depending on the resource.
- hasPermissions: Array of required permissions, such as READ or WRITE.

## Response Structure
The response indicates permission status for each entity and resource, returning a JSON object mapping entities to true (authorized) or false (unauthorized) values.

```json
{
"entity_name": true,
"another_entity": false
}
```
This endpoint is especially useful for applications requiring quick permission validation for multiple entities across various resources.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ managed.

In the HTTP API, some endpoints are static and can be seen as the "schema" of Ditto. They are in sync with the JSON
representation of the model classes, e.g. [Thing](basic-thing.html#model-specification) for the layout of the `/things`
endpoint and [Policy](basic-policy.html) for the layout of the `/policies` endpoint.
endpoint and [Policy](basic-policy.html) for the layout of the `/policies` endpoint, and `/checkPermissions` for verifying
access rights of entities on specific resources based on defined policies.

### API version 2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@
import org.eclipse.ditto.internal.utils.config.ScopedConfig;
import org.eclipse.ditto.messages.model.signals.commands.MessageCommand;
import org.eclipse.ditto.messages.model.signals.commands.MessageCommandResponse;
import org.eclipse.ditto.policies.api.commands.sudo.CheckPolicyPermissions;
import org.eclipse.ditto.policies.model.PolicyConstants;
import org.eclipse.ditto.policies.model.signals.commands.PolicyCommand;
import org.eclipse.ditto.things.api.commands.sudo.SudoRetrieveThing;
import org.eclipse.ditto.things.api.commands.sudo.SudoRetrieveThings;
import org.eclipse.ditto.things.model.ThingConstants;
import org.eclipse.ditto.things.model.signals.commands.ThingCommand;
Expand Down Expand Up @@ -144,7 +146,9 @@ public Receive createReceive() {
)
.match(RetrieveThings.class, this::forwardToThingsAggregatorProxy)
.match(SudoRetrieveThings.class, this::forwardToThingsAggregatorProxy)
.match(SudoRetrieveThing.class, this::forwardToThings)
.match(PolicyCommand.class, this::forwardToPolicies)
.match(CheckPolicyPermissions.class, this::forwardToPolicies)
.match(RetrieveAllConnectionIds.class, this::forwardToConnectivityPubSub)
.match(ConnectivityCommand.class, this::forwardToConnectivity)
.match(ConnectivitySudoCommand.class, this::forwardToConnectivity)
Expand Down Expand Up @@ -291,6 +295,7 @@ private void forwardToThingSearch(final Command<?> command) {
pubSubMediator.tell(DistPubSubAccess.send(ThingsSearchConstants.SEARCH_ACTOR_PATH, command), getSender());
}


private void handleUnknownSignal(final Signal<?> signal) {
applySignalTransformation(signal, sender())
.thenAccept(transformedSignal -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import org.eclipse.ditto.edge.service.acknowledgements.things.ThingLiveCommandAckRequestSetter;
import org.eclipse.ditto.edge.service.acknowledgements.things.ThingModifyCommandAckRequestSetter;
import org.eclipse.ditto.gateway.api.GatewayServiceUnavailableException;
import org.eclipse.ditto.gateway.service.endpoints.routes.checkpermissions.CheckPermissions;
import org.eclipse.ditto.gateway.service.endpoints.routes.whoami.DefaultUserInformation;
import org.eclipse.ditto.gateway.service.endpoints.routes.whoami.Whoami;
import org.eclipse.ditto.gateway.service.endpoints.routes.whoami.WhoamiResponse;
Expand Down Expand Up @@ -236,6 +237,7 @@ public AbstractActor.Receive handleMessage() {
}
})
.match(Whoami.class, this::handleWhoami)
.match(CheckPermissions.class, this::handleCheckPermissions)
.match(DittoRuntimeException.class, this::handleDittoRuntimeException)
.match(ReceiveTimeout.class,
receiveTimeout -> {
Expand Down Expand Up @@ -346,6 +348,14 @@ private void rememberResponseLocationUri(final CommandResponse<?> commandRespons
}
}

private void handleCheckPermissions(final CheckPermissions command) {
final ActorRef checkPermissionsActor = getContext().actorOf(
CheckPermissionsActor.props(proxyActor, getSelf(), getReceiveTimeout(command, commandConfig))
);
getContext().become(getResponseAwaitingBehavior());
checkPermissionsActor.tell(command, getSelf());
}

private void handleWhoami(final Whoami command) {
logger.withCorrelationId(command).debug("Got <{}>.", command);

Expand Down
Loading

0 comments on commit df6f261

Please sign in to comment.