Skip to content

Commit

Permalink
[eclipse-ditto#964] review: changed HTTP request payload of `activate…
Browse files Browse the repository at this point in the history
…TokenIntegration` POST endpoint to be wrapped in an "annoucement" JsonObject

* fixed swagger documentation which had some dead references

Signed-off-by: Thomas Jaeckle <thomas.jaeckle@bosch.io>
  • Loading branch information
thjaeckle committed Mar 1, 2021
1 parent f0169d1 commit 96eb7cc
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 90 deletions.
67 changes: 32 additions & 35 deletions documentation/src/main/resources/openapi/ditto-api-2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3493,23 +3493,7 @@ paths:
* containing a a subject ID matching the JWT's authenticated subject
* containing a `READ` permission granted to a `thing:/` resource path
requestBody:
content:
application/json:
schema:
type: object
description: Settings for announcements to be made about the subject.
properties:
beforeExpiry:
type: string
description: 'The duration before expiry when an announcement should be made. Must be a positive integer followed by one of `h` (hour), `m` (minute) or `s` (second).'
whenDeleted:
type: boolean
description: Whether an announcement should be made when this subject is deleted.
example:
beforeExpiry: 5m
whenDeleted: true
description: Settings for announcements to be made about the injected subject.
required: false
$ref: '#/components/requestBodies/ActivateTokenIntegration'
'/policies/{policyId}/actions/deactivateTokenIntegration':
post:
summary: Deactivate subjects for this policy derived from the token
Expand Down Expand Up @@ -3978,11 +3962,7 @@ paths:
* containing a a subject ID matching the JWT's authenticated subject
* containing a `READ` permission granted to a `thing:/` resource path
requestBody:
content:
application/json:
schema:
$ref: '#/paths/~1policies~1%7BpolicyId%7D~1actions~1activateTokenIntegration/post/requestBody/content/application~1json/schema'
description: Settings for announcements to be made about the injected subjects.
$ref: '#/components/requestBodies/ActivateTokenIntegration'
'/policies/{policyId}/entries/{label}/actions/deactivateTokenIntegration':
post:
summary: Deactivate a subject for this policy entry derived from the token
Expand Down Expand Up @@ -5142,6 +5122,19 @@ components:
* for an list, the JSON value is the list: `[ 1,2,3 ]`
required: true
ActivateTokenIntegration:
content:
application/json:
schema:
properties:
announcement:
$ref: '#/components/schemas/SubjectAnnouncement'
example:
announcement:
beforeExpiry: 5m
whenDeleted: true
description: Optional request payload for `activateTokenIntegration` policy action.
required: false
responses:
EntityTooLarge:
description: The created or modified entity is larger than the accepted limit of 100 kB.
Expand Down Expand Up @@ -5923,24 +5916,13 @@ components:
description: The optional expiry timestamp (formatted in ISO-8601) indicates how long this subject should be considered active before it is automatically deleted from the Policy.
format: date-time
announcement:
type: object
description: Settings for announcements to be made about the subject.
properties:
beforeExpiry:
type: string
description: 'The duration before expiry when an announcement should be made. Must be a positive integer followed by one of `h` (hour), `m` (minute) or `s` (second).'
whenDeleted:
type: boolean
description: Whether an announcement should be made when this subject is deleted.
example:
beforeExpiry: 5m
whenDeleted: true
$ref: '#/components/schemas/SubjectAnnouncement'
example:
type: 'This is some description for this subject, adjust as needed.'
expiry: '2020-12-07T11:36:40Z'
announcement:
beforeExpiry: 5m
onDeletion: true
whenDeleted: true
Resources:
type: object
description: |-
Expand Down Expand Up @@ -5988,6 +5970,21 @@ components:
enum:
- READ
- WRITE
SubjectAnnouncement:
type: object
description: Settings for announcements to be made about the subject.
properties:
beforeExpiry:
type: string
description: |-
The duration before expiry when an announcement should be made.
Must be a positive integer followed by one of `h` (hour), `m` (minute) or `s` (second).
whenDeleted:
type: boolean
description: Whether an announcement should be made when this subject is deleted.
example:
beforeExpiry: 5m
whenDeleted: true
Features:
type: object
description: |-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ components:
$ref: "./requests/payload.yml"
Value:
$ref: "./requests/value.yml"
ActivateTokenIntegration:
$ref: "./requests/policies/actions/activateTokenIntegration.yml"

responses:
EntityTooLarge:
Expand Down Expand Up @@ -267,6 +269,8 @@ components:
$ref: "./schemas/policies/resourceEntry.yml"
Permission:
$ref: "./schemas/policies/permission.yml"
SubjectAnnouncement:
$ref: "./schemas/policies/subjectAnnouncement.yml"
Features:
$ref: "./schemas/features/features.yml"
WhoAmI:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,4 @@ post:
* containing a a subject ID matching the JWT's authenticated subject
* containing a `READ` permission granted to a `thing:/` resource path
requestBody:
content:
application/json:
schema:
$ref: '../../schemas/policies/subjectAnnouncementRequestEntity.yml'
description: Settings for announcements to be made about the injected subject.
required: false
$ref: '../../requests/policies/actions/activateTokenIntegration.yml'
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,4 @@ post:
* containing a a subject ID matching the JWT's authenticated subject
* containing a `READ` permission granted to a `thing:/` resource path
requestBody:
content:
application/json:
schema:
$ref: '../../schemas/policies/subjectAnnouncementRequestEntity.yml'
description: Settings for announcements to be made about the injected subjects.
$ref: '../../requests/policies/actions/activateTokenIntegration.yml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright (c) 2021 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
content:
application/json:
schema:
properties:
announcement:
$ref: '../../../schemas/policies/subjectAnnouncement.yml'
example:
announcement:
beforeExpiry: "5m"
whenDeleted: true
description: Optional request payload for `activateTokenIntegration` policy action.
required: false
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ description: Settings for announcements to be made about the subject.
properties:
beforeExpiry:
type: string
description: The duration before expiry when an announcement should be made. Must be a positive integer followed by one of `h` (hour), `m` (minute) or `s` (second).
description: |-
The duration before expiry when an announcement should be made.
Must be a positive integer followed by one of `h` (hour), `m` (minute) or `s` (second).
whenDeleted:
type: boolean
description: Whether an announcement should be made when this subject is deleted.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ example:
type: "This is some description for this subject, adjust as needed."
expiry: "2020-12-07T11:36:40Z"
announcement:
"beforeExpiry": "5m"
"onDeletion": true
beforeExpiry: "5m"
whenDeleted: true
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private Attributes createSupervisionStrategy() {
} else {
LOGGER.warn("Exception during materialization of HTTP request: {}", exc.getMessage(), exc);
}
return Supervision.stop(); // in any case, stop!
return (Supervision.Directive) Supervision.stop(); // in any case, stop!
});
}

Expand Down Expand Up @@ -187,16 +187,16 @@ public static <T> Flow<T, T, NotUsed> throttleByConfig(final ThrottlingConfig th
public Route handlePerRequest(final RequestContext ctx,
final DittoHeaders dittoHeaders,
final Source<ByteString, ?> payloadSource,
final Function<String, Command> requestJsonToCommandFunction) {
final Function<String, Command<?>> requestJsonToCommandFunction) {

return handlePerRequest(ctx, dittoHeaders, payloadSource, requestJsonToCommandFunction, null);
}

protected Route handlePerRequest(final RequestContext ctx, final Command command) {
protected Route handlePerRequest(final RequestContext ctx, final Command<?> command) {
return handlePerRequest(ctx, command.getDittoHeaders(), Source.empty(), emptyRequestBody -> command);
}

protected Route handlePerRequest(final RequestContext ctx, final Command command,
protected Route handlePerRequest(final RequestContext ctx, final Command<?> command,
final Function<JsonValue, JsonValue> responseTransformFunction) {

return handlePerRequest(ctx, command.getDittoHeaders(), Source.empty(),
Expand All @@ -206,7 +206,7 @@ protected Route handlePerRequest(final RequestContext ctx, final Command command
protected Route handlePerRequest(final RequestContext ctx,
final DittoHeaders dittoHeaders,
final Source<ByteString, ?> payloadSource,
final Function<String, Command> requestJsonToCommandFunction,
final Function<String, Command<?>> requestJsonToCommandFunction,
@Nullable final Function<JsonValue, JsonValue> responseTransformFunction) {

// check if Akka HTTP timeout was overwritten by our code (e.g. for claim messages)
Expand Down Expand Up @@ -236,7 +236,7 @@ protected <M> M runWithSupervisionStrategy(final RunnableGraph<M> graph) {
private Route doHandlePerRequest(final RequestContext ctx,
final DittoHeaders dittoHeaders,
final Source<ByteString, ?> payloadSource,
final Function<String, Command> requestJsonToCommandFunction,
final Function<String, Command<?>> requestJsonToCommandFunction,
@Nullable final Function<JsonValue, JsonValue> responseTransformFunction) {

final CompletableFuture<HttpResponse> httpResponseFuture = new CompletableFuture<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import javax.annotation.Nullable;

import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonFieldDefinition;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonValue;
import org.eclipse.ditto.model.base.headers.DittoHeaders;
Expand All @@ -30,6 +31,7 @@
import org.eclipse.ditto.model.policies.PoliciesModelFactory;
import org.eclipse.ditto.model.policies.Policy;
import org.eclipse.ditto.model.policies.PolicyId;
import org.eclipse.ditto.model.policies.Subject;
import org.eclipse.ditto.model.policies.SubjectAnnouncement;
import org.eclipse.ditto.model.policies.SubjectExpiry;
import org.eclipse.ditto.model.policies.SubjectId;
Expand Down Expand Up @@ -67,6 +69,9 @@ public final class PoliciesRoute extends AbstractRoute {

private static final Label DUMMY_LABEL = Label.of("-");

private static final JsonFieldDefinition<JsonObject> ACTION_ACTIVATE_TOKEN_INTEGRATION_ANNOUNCEMENT =
Subject.JsonFields.ANNOUNCEMENT;

private final PolicyEntriesRoute policyEntriesRoute;
private final TokenIntegrationSubjectIdFactory tokenIntegrationSubjectIdFactory;

Expand Down Expand Up @@ -226,7 +231,9 @@ private static SubjectAnnouncement toSubjectAnnouncement(final String body) {
if (body.isEmpty()) {
return null;
} else {
return SubjectAnnouncement.fromJson(JsonObject.of(body));
final Optional<JsonObject> announcement = JsonObject.of(body)
.getValue(ACTION_ACTIVATE_TOKEN_INTEGRATION_ANNOUNCEMENT);
return announcement.map(SubjectAnnouncement::fromJson).orElse(null);
}
}

Expand All @@ -247,7 +254,7 @@ static Route extractJwt(final DittoHeaders dittoHeaders,
}

static Route handleSubjectAnnouncement(final AbstractRoute route, final DittoHeaders dittoHeaders,
final Function<SubjectAnnouncement, Command> commandConstructor) {
final Function<SubjectAnnouncement, Command<?>> commandConstructor) {
return route.extractRequestContext(context ->
route.handlePerRequest(context, dittoHeaders, context.getRequest().entity().getDataBytes(),
body -> commandConstructor.apply(toSubjectAnnouncement(body))));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import java.util.List;

import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.model.base.auth.AuthorizationContext;
import org.eclipse.ditto.model.base.auth.AuthorizationSubject;
import org.eclipse.ditto.model.base.auth.DittoAuthorizationContextType;
Expand Down Expand Up @@ -166,8 +167,11 @@ public void activateTopLevelTokenIntegration() {
@Test
public void activateTopLevelTokenIntegrationWithAnnouncement() {
final var subjectAnnouncement = SubjectAnnouncement.of(DittoDuration.parseDuration("1h"), true);
final JsonObject requestPayload = JsonObject.newBuilder()
.set("announcement", subjectAnnouncement.toJson())
.build();
getRoute(getTokenAuthResult()).run(HttpRequest.POST("/policies/ns%3An/actions/activateTokenIntegration/")
.withEntity(APPLICATION_JSON, subjectAnnouncement.toJsonString()))
.withEntity(APPLICATION_JSON, requestPayload.toString()))
.assertStatusCode(StatusCodes.OK)
.assertEntity(TopLevelPolicyActionCommand.of(
ActivateTokenIntegration.of(PolicyId.of("ns:n"),
Expand Down Expand Up @@ -219,9 +223,12 @@ public void activateTokenIntegrationForEntry() {
@Test
public void activateTokenIntegrationForEntryWithAnnouncement() {
final var subjectAnnouncement = SubjectAnnouncement.of(DittoDuration.parseDuration("1s"), true);
final JsonObject requestPayload = JsonObject.newBuilder()
.set("announcement", subjectAnnouncement.toJson())
.build();
getRoute(getTokenAuthResult()).run(HttpRequest.POST(
"/policies/ns%3An/entries/label/actions/activateTokenIntegration/")
.withEntity(APPLICATION_JSON, subjectAnnouncement.toJsonString()))
.withEntity(APPLICATION_JSON, requestPayload.toString()))
.assertStatusCode(StatusCodes.OK)
.assertEntity(ActivateTokenIntegration.of(PolicyId.of("ns:n"),
Label.of("label"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,33 +438,33 @@ private static Stream<Pair<Label, Subject>> determineSubjectsWithExpiry(
.filter(pair -> pair.second().getExpiry().isPresent());
}

private static Optional<SubjectExpiry> findEarliestSubjectExpiryTimestamp(@Nullable final Policy policyEntries) {
private static Optional<SubjectExpiry> findEarliestSubjectExpiryTimestamp(@Nullable final Policy policy) {

return findMinValueSubject(policyEntries, Subject::getExpiry,
return findMinValueSubject(policy, Subject::getExpiry,
Comparator.comparing(SubjectExpiry::getTimestamp));
}

private static Optional<Instant> findEarliestAnnouncement(@Nullable final Policy policyEntries,
private static Optional<Instant> findEarliestAnnouncement(@Nullable final Policy policy,
final Instant lastAnnouncement) {
return findMinValueSubject(policyEntries, getRelevantAnnouncementInstantFunction(lastAnnouncement),
return findMinValueSubject(policy, getRelevantAnnouncementInstantFunction(lastAnnouncement),
Comparator.naturalOrder());
}

private static <T> Optional<T> findMinValueSubject(@Nullable final Policy policyEntries,
private static <T> Optional<T> findMinValueSubject(@Nullable final Policy policy,
final Function<Subject, Optional<T>> getValueFunction,
final Comparator<T> comparator) {

return streamAndFlatMapSubjects(policyEntries, getValueFunction).min(comparator);
return streamAndFlatMapSubjects(policy, getValueFunction).min(comparator);
}

private static <T> Stream<T> streamAndFlatMapSubjects(@Nullable final Policy policyEntries,
private static <T> Stream<T> streamAndFlatMapSubjects(@Nullable final Policy policy,
final Function<Subject, Optional<T>> flatMapFunction) {

if (null == policyEntries || policyEntries.getLifecycle().filter(PolicyLifecycle.DELETED::equals).isPresent()) {
if (null == policy || policy.getLifecycle().filter(PolicyLifecycle.DELETED::equals).isPresent()) {
return Stream.empty();
}

return StreamSupport.stream(policyEntries.spliterator(), false)
return StreamSupport.stream(policy.spliterator(), false)
.map(PolicyEntry::getSubjects)
.flatMap(Subjects::stream)
.map(flatMapFunction)
Expand Down

0 comments on commit 96eb7cc

Please sign in to comment.