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));
}
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();
});
}
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);
}
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);
}
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);
}
Aggregations