Search in sources :

Example 41 with ResourceIdentifier

use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.

the class TenantMessageFilterTest method testVerifySucceedsForValidGetAction.

/**
 * Verifies that {@link TenantMessageFilter#verify(ResourceIdentifier, Message)} succeeds for a valid message.
 */
@Test
public void testVerifySucceedsForValidGetAction() {
    // GIVEN a tenant GET message for tenant DEFAULT_TENANT
    final Message msg = givenAMessageHavingProperties(TenantConstants.TenantAction.get);
    MessageHelper.addProperty(msg, MessageHelper.APP_PROPERTY_TENANT_ID, DEFAULT_TENANT);
    // WHEN receiving the message via a link with matching target address
    final ResourceIdentifier linkTarget = getResourceIdentifier(DEFAULT_TENANT);
    // THEN message validation succeeds
    assertTrue(TenantMessageFilter.verify(linkTarget, msg));
}
Also used : ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) Message(org.apache.qpid.proton.message.Message) Test(org.junit.jupiter.api.Test)

Example 42 with ResourceIdentifier

use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.

the class AbstractRequestResponseEndpoint method handleRequestMessage.

/**
 * Handles a request message received from a client.
 * <p>
 * The message gets rejected if
 * <ul>
 * <li>the message does not pass {@linkplain #passesFormalVerification(ResourceIdentifier, Message) formal
 * verification} or</li>
 * <li>the client is not {@linkplain #isAuthorized(HonoUser, ResourceIdentifier, Message) authorized to execute the
 * operation} indicated by the message's <em>subject</em> or</li>
 * <li>its payload cannot be parsed</li>
 * </ul>
 *
 * @param con The connection with the client.
 * @param receiver The link over which the message has been received.
 * @param targetAddress The address the message is sent to.
 * @param delivery The message's delivery status.
 * @param requestMessage The request message.
 */
protected final void handleRequestMessage(final ProtonConnection con, final ProtonReceiver receiver, final ResourceIdentifier targetAddress, final ProtonDelivery delivery, final Message requestMessage) {
    final HonoUser clientPrincipal = Constants.getClientPrincipal(con);
    final String replyTo = requestMessage.getReplyTo();
    final SpanContext spanContext = TracingHelper.extractSpanContext(tracer, requestMessage);
    final Span currentSpan = TracingHelper.buildServerChildSpan(tracer, spanContext, "process request message", getName()).withTag(Tags.HTTP_METHOD.getKey(), requestMessage.getSubject()).withTag(Tags.MESSAGE_BUS_DESTINATION.getKey(), targetAddress.toString()).start();
    if (!passesFormalVerification(targetAddress, requestMessage)) {
        MessageHelper.rejected(delivery, new ErrorCondition(Constants.AMQP_BAD_REQUEST, "malformed request message"));
        flowCreditToRequestor(receiver, replyTo);
        TracingHelper.logError(currentSpan, "malformed request message");
        currentSpan.finish();
        return;
    }
    ProtonHelper.accepted(delivery, true);
    currentSpan.log("request message accepted");
    getSenderForConnection(con, replyTo).compose(sender -> isAuthorized(clientPrincipal, targetAddress, requestMessage).map(authorized -> {
        logger.debug("client [{}] is {}authorized to {}:{}", clientPrincipal.getName(), authorized ? "" : "not ", targetAddress, requestMessage.getSubject());
        if (authorized) {
            return authorized;
        } else {
            throw new ClientErrorException(HttpURLConnection.HTTP_FORBIDDEN, "not authorized to invoke operation");
        }
    }).compose(authorized -> handleRequestMessage(requestMessage, targetAddress, currentSpan.context())).compose(amqpMessage -> filterResponse(clientPrincipal, requestMessage, amqpMessage)).otherwise(t -> {
        logger.debug("error processing request [resource: {}, op: {}]: {}", targetAddress, requestMessage.getSubject(), t.getMessage());
        currentSpan.log("error processing request");
        TracingHelper.logError(currentSpan, t);
        final ServiceInvocationException ex = getServiceInvocationException(t);
        Tags.HTTP_STATUS.set(currentSpan, ex.getErrorCode());
        return RequestResponseApiConstants.getErrorMessage(ex.getErrorCode(), ex.getMessage(), requestMessage);
    }).map(amqpMessage -> {
        Tags.HTTP_STATUS.set(currentSpan, MessageHelper.getStatus(amqpMessage));
        if (HonoProtonHelper.isLinkOpenAndConnected(sender)) {
            final ProtonDelivery responseDelivery = sender.send(amqpMessage);
            // TODO handle send exception
            logger.debug("sent response message to client  [correlation-id: {}, content-type: {}]", amqpMessage.getCorrelationId(), amqpMessage.getContentType());
            currentSpan.log("sent response message to client");
            return responseDelivery;
        } else {
            TracingHelper.logError(currentSpan, "cannot send response, reply-to link is closed");
            return null;
        }
    })).onComplete(s -> {
        // allow client to send another request
        flowCreditToRequestor(receiver, replyTo);
        currentSpan.finish();
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) ProtonDelivery(io.vertx.proton.ProtonDelivery) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) HonoUser(org.eclipse.hono.auth.HonoUser) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) ServiceConfigProperties(org.eclipse.hono.config.ServiceConfigProperties) Constants(org.eclipse.hono.util.Constants) Tags(io.opentracing.tag.Tags) HonoProtonHelper(org.eclipse.hono.util.HonoProtonHelper) Map(java.util.Map) Message(org.apache.qpid.proton.message.Message) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) JsonObject(io.vertx.core.json.JsonObject) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) TracingHelper(org.eclipse.hono.tracing.TracingHelper) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) ProtonQoS(io.vertx.proton.ProtonQoS) MessageHelper(org.eclipse.hono.util.MessageHelper) RequestResponseApiConstants(org.eclipse.hono.util.RequestResponseApiConstants) Future(io.vertx.core.Future) SpanContext(io.opentracing.SpanContext) Objects(java.util.Objects) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) Span(io.opentracing.Span) ProtonSender(io.vertx.proton.ProtonSender) ClaimsBasedAuthorizationService(org.eclipse.hono.service.auth.ClaimsBasedAuthorizationService) AuthorizationService(org.eclipse.hono.service.auth.AuthorizationService) ReplyException(io.vertx.core.eventbus.ReplyException) HonoUser(org.eclipse.hono.auth.HonoUser) SpanContext(io.opentracing.SpanContext) ProtonDelivery(io.vertx.proton.ProtonDelivery) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) Span(io.opentracing.Span)

Example 43 with ResourceIdentifier

use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.

the class DelegatingCommandRouterAmqpEndpoint method processEnableCommandRouting.

/**
 * Processes an <em>enable command request</em> request message.
 *
 * @param request The request message.
 * @param targetAddress The address the message is sent to.
 * @param spanContext The span context representing the request to be processed.
 * @return The response to send to the client via the event bus.
 */
protected Future<Message> processEnableCommandRouting(final Message request, final ResourceIdentifier targetAddress, final SpanContext spanContext) {
    final Span span = TracingHelper.buildServerChildSpan(tracer, spanContext, SPAN_NAME_ENABLE_COMMAND_ROUTING, getClass().getSimpleName()).start();
    final Future<Message> response = parseTenantIdentifiers(request).compose(tenantIds -> {
        span.log(Map.of("no_of_tenants", tenantIds.size()));
        return getService().enableCommandRouting(tenantIds, span);
    }).map(result -> CommandRouterConstants.getAmqpReply(targetAddress.getEndpoint(), null, request, result));
    return finishSpanOnFutureCompletion(span, response);
}
Also used : HttpURLConnection(java.net.HttpURLConnection) DecodeException(io.vertx.core.json.DecodeException) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) CommandRouterConstants(org.eclipse.hono.util.CommandRouterConstants) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AbstractDelegatingRequestResponseEndpoint(org.eclipse.hono.service.amqp.AbstractDelegatingRequestResponseEndpoint) MessageHelper(org.eclipse.hono.util.MessageHelper) Collectors(java.util.stream.Collectors) ServiceConfigProperties(org.eclipse.hono.config.ServiceConfigProperties) Future(io.vertx.core.Future) SpanContext(io.opentracing.SpanContext) Objects(java.util.Objects) JsonArray(io.vertx.core.json.JsonArray) List(java.util.List) Buffer(io.vertx.core.buffer.Buffer) Duration(java.time.Duration) Map(java.util.Map) Span(io.opentracing.Span) Message(org.apache.qpid.proton.message.Message) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) JsonObject(io.vertx.core.json.JsonObject) TracingHelper(org.eclipse.hono.tracing.TracingHelper) Message(org.apache.qpid.proton.message.Message) Span(io.opentracing.Span)

Example 44 with ResourceIdentifier

use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.

the class DelegatingCommandRouterAmqpEndpoint method processUnregisterCommandConsumer.

/**
 * Processes a <em>unregister command consumer</em> request message.
 *
 * @param request The request message.
 * @param targetAddress The address the message is sent to.
 * @param spanContext The span context representing the request to be processed.
 * @return The response to send to the client via the event bus.
 */
protected Future<Message> processUnregisterCommandConsumer(final Message request, final ResourceIdentifier targetAddress, final SpanContext spanContext) {
    final String tenantId = targetAddress.getTenantId();
    final String deviceId = MessageHelper.getDeviceId(request);
    final String adapterInstanceId = MessageHelper.getApplicationProperty(request.getApplicationProperties(), MessageHelper.APP_PROPERTY_ADAPTER_INSTANCE_ID, String.class);
    final Span span = TracingHelper.buildServerChildSpan(tracer, spanContext, SPAN_NAME_UNREGISTER_COMMAND_CONSUMER, getClass().getSimpleName()).start();
    final Future<Message> resultFuture;
    if (tenantId == null || deviceId == null || adapterInstanceId == null) {
        TracingHelper.logError(span, "missing tenant, device and/or adapter instance id");
        resultFuture = Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST));
    } else {
        TracingHelper.TAG_TENANT_ID.set(span, tenantId);
        TracingHelper.TAG_DEVICE_ID.set(span, deviceId);
        span.setTag(MessageHelper.APP_PROPERTY_ADAPTER_INSTANCE_ID, adapterInstanceId);
        logger.debug("unregister command consumer [tenant-id: {}, device-id: {}, adapter-instance-id {}]", tenantId, deviceId, adapterInstanceId);
        resultFuture = getService().unregisterCommandConsumer(tenantId, deviceId, adapterInstanceId, span).map(res -> CommandRouterConstants.getAmqpReply(CommandRouterConstants.COMMAND_ROUTER_ENDPOINT, tenantId, request, res));
    }
    return finishSpanOnFutureCompletion(span, resultFuture);
}
Also used : HttpURLConnection(java.net.HttpURLConnection) DecodeException(io.vertx.core.json.DecodeException) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) CommandRouterConstants(org.eclipse.hono.util.CommandRouterConstants) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AbstractDelegatingRequestResponseEndpoint(org.eclipse.hono.service.amqp.AbstractDelegatingRequestResponseEndpoint) MessageHelper(org.eclipse.hono.util.MessageHelper) Collectors(java.util.stream.Collectors) ServiceConfigProperties(org.eclipse.hono.config.ServiceConfigProperties) Future(io.vertx.core.Future) SpanContext(io.opentracing.SpanContext) Objects(java.util.Objects) JsonArray(io.vertx.core.json.JsonArray) List(java.util.List) Buffer(io.vertx.core.buffer.Buffer) Duration(java.time.Duration) Map(java.util.Map) Span(io.opentracing.Span) Message(org.apache.qpid.proton.message.Message) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) JsonObject(io.vertx.core.json.JsonObject) TracingHelper(org.eclipse.hono.tracing.TracingHelper) Message(org.apache.qpid.proton.message.Message) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Span(io.opentracing.Span)

Example 45 with ResourceIdentifier

use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.

the class AmqpAdapterClientCommandConsumer method create.

/**
 * Creates a new command consumer for the given device.
 * <p>
 * The underlying receiver link will be created with its <em>autoAccept</em> property set to {@code true} and with
 * the connection's default pre-fetch size.
 *
 * @param con The connection to the server.
 * @param tenantId The tenant to consume commands from.
 * @param deviceId The device for which the commands should be consumed.
 * @param messageHandler The handler to invoke with every message received.
 * @return A future indicating the outcome of the creation attempt.
 * @throws NullPointerException if any of the parameters are {@code null}.
 */
public static Future<CommandConsumer> create(final HonoConnection con, final String tenantId, final String deviceId, final BiConsumer<ProtonDelivery, Message> messageHandler) {
    Objects.requireNonNull(con);
    Objects.requireNonNull(tenantId);
    Objects.requireNonNull(deviceId);
    Objects.requireNonNull(messageHandler);
    final ResourceIdentifier address = ResourceIdentifier.from(CommandConstants.NORTHBOUND_COMMAND_REQUEST_ENDPOINT, tenantId, deviceId);
    return createCommandConsumer(con, messageHandler, address);
}
Also used : ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier)

Aggregations

ResourceIdentifier (org.eclipse.hono.util.ResourceIdentifier)82 Message (org.apache.qpid.proton.message.Message)30 Future (io.vertx.core.Future)24 HttpURLConnection (java.net.HttpURLConnection)22 MessageHelper (org.eclipse.hono.util.MessageHelper)22 ClientErrorException (org.eclipse.hono.client.ClientErrorException)20 Test (org.junit.Test)20 Test (org.junit.jupiter.api.Test)19 Handler (io.vertx.core.Handler)18 Map (java.util.Map)18 Span (io.opentracing.Span)17 Buffer (io.vertx.core.buffer.Buffer)17 SpanContext (io.opentracing.SpanContext)16 Constants (org.eclipse.hono.util.Constants)16 Promise (io.vertx.core.Promise)15 Objects (java.util.Objects)14 AsyncResult (io.vertx.core.AsyncResult)13 Vertx (io.vertx.core.Vertx)13 ProtonConnection (io.vertx.proton.ProtonConnection)13 ProtonReceiver (io.vertx.proton.ProtonReceiver)13