use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class AmqpServiceBase method handleReceiverOpen.
/**
* Handles a request from a client to establish a link for sending messages to this server.
* The already established connection must have an authenticated user as principal for doing the authorization check.
*
* @param con the connection to the client.
* @param receiver the receiver created for the link.
*/
protected void handleReceiverOpen(final ProtonConnection con, final ProtonReceiver receiver) {
if (receiver.getRemoteTarget().getAddress() == null) {
LOG.debug("client [container: {}] wants to open an anonymous link for sending messages to arbitrary addresses, closing link ...", con.getRemoteContainer());
receiver.setCondition(ProtonHelper.condition(AmqpError.NOT_ALLOWED, "anonymous relay not supported"));
receiver.close();
} else {
LOG.debug("client [container: {}] wants to open a link [address: {}] for sending messages", con.getRemoteContainer(), receiver.getRemoteTarget());
try {
final ResourceIdentifier targetResource = getResourceIdentifier(receiver.getRemoteTarget().getAddress());
final AmqpEndpoint endpoint = getEndpoint(targetResource);
if (endpoint == null) {
handleUnknownEndpoint(con, receiver, targetResource);
} else {
final HonoUser user = Constants.getClientPrincipal(con);
getAuthorizationService().isAuthorized(user, targetResource, Activity.WRITE).setHandler(authAttempt -> {
if (authAttempt.succeeded() && authAttempt.result()) {
Constants.copyProperties(con, receiver);
receiver.setTarget(receiver.getRemoteTarget());
endpoint.onLinkAttach(con, receiver, targetResource);
} else {
LOG.debug("subject [{}] is not authorized to WRITE to [{}]", user.getName(), targetResource);
receiver.setCondition(ProtonHelper.condition(AmqpError.UNAUTHORIZED_ACCESS.toString(), "unauthorized"));
receiver.close();
}
});
}
} catch (final IllegalArgumentException e) {
LOG.debug("client has provided invalid resource identifier as target address", e);
receiver.setCondition(ProtonHelper.condition(AmqpError.NOT_FOUND, "no such address"));
receiver.close();
}
}
}
use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class RequestResponseEndpoint method handleMessage.
/**
* 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 message The message.
*/
protected final void handleMessage(final ProtonConnection con, final ProtonReceiver receiver, final ResourceIdentifier targetAddress, ProtonDelivery delivery, Message message) {
final Future<Void> formalCheck = Future.future();
if (passesFormalVerification(targetAddress, message)) {
formalCheck.complete();
} else {
formalCheck.fail(new AmqpErrorException(AmqpError.DECODE_ERROR, "malformed payload"));
}
final HonoUser clientPrincipal = Constants.getClientPrincipal(con);
formalCheck.compose(ok -> isAuthorized(clientPrincipal, targetAddress, message)).compose(authorized -> {
logger.debug("client [{}] is {}authorized to {}:{}", clientPrincipal.getName(), authorized ? "" : "not ", targetAddress, message.getSubject());
if (authorized) {
try {
processRequest(message, targetAddress, clientPrincipal);
ProtonHelper.accepted(delivery, true);
return Future.succeededFuture();
} catch (DecodeException e) {
return Future.failedFuture(new AmqpErrorException(AmqpError.DECODE_ERROR, "malformed payload"));
}
} else {
return Future.failedFuture(new AmqpErrorException(AmqpError.UNAUTHORIZED_ACCESS, "unauthorized"));
}
}).otherwise(t -> {
if (t instanceof AmqpErrorException) {
AmqpErrorException cause = (AmqpErrorException) t;
MessageHelper.rejected(delivery, cause.asErrorCondition());
} else {
logger.debug("error processing request [resource: {}, op: {}]: {}", targetAddress, message.getSubject(), t.getMessage());
MessageHelper.rejected(delivery, ProtonHelper.condition(AmqpError.INTERNAL_ERROR, "internal error"));
}
return null;
});
}
use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class AmqpServiceBase method handleSenderOpen.
/**
* Handles a request from a client to establish a link for receiving messages from this server.
*
* @param con the connection to the client.
* @param sender the sender created for the link.
*/
protected void handleSenderOpen(final ProtonConnection con, final ProtonSender sender) {
final Source remoteSource = sender.getRemoteSource();
log.debug("client [container: {}] wants to open a link [address: {}] for receiving messages", con.getRemoteContainer(), remoteSource);
if (!ResourceIdentifier.isValid(remoteSource.getAddress())) {
handleUnknownEndpoint(con, sender, remoteSource.getAddress());
return;
}
final ResourceIdentifier targetResource = ResourceIdentifier.fromString(remoteSource.getAddress());
final AmqpEndpoint endpoint = getEndpoint(targetResource);
if (endpoint == null) {
handleUnknownEndpoint(con, sender, targetResource.toString());
} else {
final HonoUser user = Constants.getClientPrincipal(con);
getAuthorizationService().isAuthorized(user, targetResource, Activity.READ).onComplete(authAttempt -> {
if (authAttempt.succeeded() && authAttempt.result()) {
sender.setSource(sender.getRemoteSource());
sender.setTarget(sender.getRemoteTarget());
endpoint.onLinkAttach(con, sender, targetResource);
} else {
log.debug("subject [{}] is not authorized to READ from [{}]", user.getName(), targetResource);
sender.setCondition(ProtonHelper.condition(AmqpError.UNAUTHORIZED_ACCESS.toString(), "unauthorized"));
sender.close();
}
});
}
}
use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class DelegatingCommandRouterAmqpEndpoint method processRegisterCommandConsumer.
/**
* Processes a <em>register 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> processRegisterCommandConsumer(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 Integer lifespanSecondsOrNull = MessageHelper.getApplicationProperty(request.getApplicationProperties(), MessageHelper.APP_PROPERTY_LIFESPAN, Integer.class);
final Span span = TracingHelper.buildServerChildSpan(tracer, spanContext, SPAN_NAME_REGISTER_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 {
final Duration lifespan = lifespanSecondsOrNull != null ? Duration.ofSeconds(lifespanSecondsOrNull) : Duration.ofSeconds(-1);
TracingHelper.TAG_TENANT_ID.set(span, tenantId);
TracingHelper.TAG_DEVICE_ID.set(span, deviceId);
span.setTag(MessageHelper.APP_PROPERTY_ADAPTER_INSTANCE_ID, adapterInstanceId);
span.setTag(MessageHelper.APP_PROPERTY_LIFESPAN, lifespan.getSeconds());
logger.debug("register command consumer [tenant-id: {}, device-id: {}, adapter-instance-id {}, lifespan: {}s]", tenantId, deviceId, adapterInstanceId, lifespan.getSeconds());
resultFuture = getService().registerCommandConsumer(tenantId, deviceId, adapterInstanceId, lifespan, 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 DelegatingCommandRouterAmqpEndpoint method processSetLastKnownGatewayRequest.
/**
* Processes a <em>set last known gateway</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> processSetLastKnownGatewayRequest(final Message request, final ResourceIdentifier targetAddress, final SpanContext spanContext) {
final String tenantId = targetAddress.getTenantId();
final String deviceIdAppProperty = MessageHelper.getDeviceId(request);
final String gatewayIdAppProperty = MessageHelper.getGatewayId(request);
final Span span = TracingHelper.buildServerChildSpan(tracer, spanContext, SPAN_NAME_SET_LAST_GATEWAY, getClass().getSimpleName()).start();
final Future<CommandRouterResult> resultFuture;
if (tenantId == null) {
TracingHelper.logError(span, "missing tenant");
resultFuture = Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "missing tenant"));
} else {
if (deviceIdAppProperty != null && gatewayIdAppProperty != null) {
logger.debug("setting last known gateway for tenant [{}], device [{}] to {}", tenantId, deviceIdAppProperty, gatewayIdAppProperty);
TracingHelper.TAG_TENANT_ID.set(span, tenantId);
TracingHelper.TAG_DEVICE_ID.set(span, deviceIdAppProperty);
TracingHelper.TAG_GATEWAY_ID.set(span, gatewayIdAppProperty);
if (MessageHelper.getPayloadSize(request) != 0) {
logger.debug("ignoring payload in last known gateway request containing device/gateway properties");
}
resultFuture = getService().setLastKnownGatewayForDevice(tenantId, deviceIdAppProperty, gatewayIdAppProperty, span);
} else if (MessageHelper.getPayloadSize(request) != 0) {
TracingHelper.TAG_TENANT_ID.set(span, tenantId);
final Buffer payload = MessageHelper.getPayload(request);
resultFuture = parseSetLastKnownGatewayJson(payload).compose(deviceToGatewayMap -> {
logger.debug("setting {} last known gateway entries for tenant [{}]", deviceToGatewayMap.size(), tenantId);
span.log(Map.of("no_of_entries", deviceToGatewayMap.size()));
return getService().setLastKnownGatewayForDevice(tenantId, deviceToGatewayMap, span);
});
} else {
final String error = "either device_id and gateway_id application properties or alternatively a JSON payload must be set";
TracingHelper.logError(span, error);
resultFuture = Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, error));
}
}
return finishSpanOnFutureCompletion(span, resultFuture.map(res -> CommandRouterConstants.getAmqpReply(CommandRouterConstants.COMMAND_ROUTER_ENDPOINT, tenantId, request, res)));
}
Aggregations