use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class TelemetryResourceTest method testUploadTelemetryWithQoS0.
/**
* Verifies that the adapter immediately responds with a 2.04 status if a
* device publishes telemetry data using a NON message.
*/
@Test
public void testUploadTelemetryWithQoS0() {
// GIVEN an adapter with a downstream telemetry consumer attached
givenAnAdapter(properties);
givenATelemetrySenderForAnyTenant();
final var resource = givenAResource(adapter);
// WHEN a device publishes an telemetry message
final Buffer payload = Buffer.buffer("some payload");
final CoapExchange coapExchange = newCoapExchange(payload, Type.NON, MediaTypeRegistry.TEXT_PLAIN);
final Device authenticatedDevice = new Device("tenant", "device");
final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "device", span);
resource.handlePostRequest(context);
// THEN the device gets a response indicating success
verify(coapExchange).respond(argThat((Response res) -> ResponseCode.CHANGED.equals(res.getCode())));
// and the message has been forwarded downstream
assertTelemetryMessageHasBeenSentDownstream(QoS.AT_MOST_ONCE, "tenant", "device", "text/plain");
verify(metrics).reportTelemetry(eq(MetricsTags.EndpointType.TELEMETRY), eq("tenant"), any(), eq(MetricsTags.ProcessingOutcome.FORWARDED), eq(MetricsTags.QoS.AT_MOST_ONCE), eq(payload.length()), eq(TtdStatus.NONE), any());
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class TelemetryResourceTest method testUploadTelemetryFailsForEmptyBody.
/**
* Verifies that the adapter fails the upload of an event with a 4.00 result
* if the request body is empty but is not marked as an empty notification.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadTelemetryFailsForEmptyBody(final VertxTestContext ctx) {
// GIVEN an adapter
givenAnAdapter(properties);
givenATelemetrySenderForAnyTenant();
final var resource = givenAResource(adapter);
// WHEN a device publishes an empty message that doesn't contain
// a URI-query option
final CoapExchange coapExchange = newCoapExchange(null, Type.NON, MediaTypeRegistry.UNDEFINED);
final Device authenticatedDevice = new Device("my-tenant", "the-device");
final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "the-device", span);
resource.handlePostRequest(context).onComplete(ctx.failing(t -> {
ctx.verify(() -> {
// THEN the device gets a response with code 4.00
assertThat(t).isInstanceOf(ClientErrorException.class);
assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_BAD_REQUEST);
// and the message has not been forwarded downstream
assertNoTelemetryMessageHasBeenSentDownstream();
verify(metrics, never()).reportTelemetry(any(MetricsTags.EndpointType.class), anyString(), any(), any(MetricsTags.ProcessingOutcome.class), any(MetricsTags.QoS.class), anyInt(), any(TtdStatus.class), any());
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class CommandResponseResource method uploadCommandResponseMessage.
/**
* Forwards a command response to a downstream application.
*
* @param context The context representing the command response to be forwarded.
* @return A future indicating the outcome of the operation.
* The future will be succeeded if the message has been forwarded successfully.
* In this case one of the context's <em>respond</em> methods will have been invoked to send a CoAP response
* back to the device.
* Otherwise the future will be failed with a {@link org.eclipse.hono.client.ServiceInvocationException}.
* @throws NullPointerException if context is {@code null}.
*/
public final Future<Void> uploadCommandResponseMessage(final CoapContext context) {
Objects.requireNonNull(context);
final Device device = context.getOriginDevice();
final Device authenticatedDevice = context.getAuthenticatedDevice();
if (!context.isConfirmable()) {
return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "command response endpoint supports confirmable request messages only"));
}
final Buffer payload = context.getPayload();
final String contentType = context.getContentType();
final String commandRequestId = context.getCommandRequestId();
final Integer responseStatus = context.getCommandResponseStatus();
LOG.debug("processing response to command [tenantId: {}, deviceId: {}, cmd-req-id: {}, status code: {}]", device.getTenantId(), device.getDeviceId(), commandRequestId, responseStatus);
final Span currentSpan = TracingHelper.buildChildSpan(getTracer(), context.getTracingContext(), "upload Command response", getAdapter().getTypeName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_TENANT_ID, device.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, device.getDeviceId()).withTag(Constants.HEADER_COMMAND_RESPONSE_STATUS, responseStatus).withTag(Constants.HEADER_COMMAND_REQUEST_ID, commandRequestId).withTag(TracingHelper.TAG_AUTHENTICATED.getKey(), authenticatedDevice != null).start();
final Future<RegistrationAssertion> deviceRegistrationTracker = getAdapter().getRegistrationAssertion(device.getTenantId(), device.getDeviceId(), authenticatedDevice, currentSpan.context());
final Future<TenantObject> tenantTracker = getAdapter().getTenantClient().get(device.getTenantId(), currentSpan.context());
final Optional<CommandResponse> cmdResponse = Optional.ofNullable(CommandResponse.fromRequestId(commandRequestId, device.getTenantId(), device.getDeviceId(), payload, contentType, responseStatus));
final Future<CommandResponse> commandResponseTracker = cmdResponse.map(res -> Future.succeededFuture(res)).orElseGet(() -> Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, String.format("command-request-id [%s] or status code [%s] is missing/invalid", commandRequestId, responseStatus))));
return CompositeFuture.all(tenantTracker, commandResponseTracker, deviceRegistrationTracker).compose(ok -> CompositeFuture.all(getAdapter().isAdapterEnabled(tenantTracker.result()), getAdapter().checkMessageLimit(tenantTracker.result(), payload.length(), currentSpan.context())).mapEmpty()).compose(ok -> getAdapter().getCommandResponseSender(commandResponseTracker.result().getMessagingType(), tenantTracker.result()).sendCommandResponse(tenantTracker.result(), deviceRegistrationTracker.result(), commandResponseTracker.result(), currentSpan.context())).onSuccess(ok -> {
LOG.trace("forwarded command response [command-request-id: {}] to downstream application", commandRequestId);
currentSpan.log("forwarded command response to application");
getAdapter().getMetrics().reportCommand(Direction.RESPONSE, device.getTenantId(), tenantTracker.result(), ProcessingOutcome.FORWARDED, payload.length(), context.getTimer());
context.respondWithCode(ResponseCode.CHANGED);
}).onFailure(t -> {
LOG.debug("could not send command response [command-request-id: {}] to application", commandRequestId, t);
TracingHelper.logError(currentSpan, t);
getAdapter().getMetrics().reportCommand(Direction.RESPONSE, device.getTenantId(), tenantTracker.result(), ProcessingOutcome.from(t), payload.length(), context.getTimer());
}).onComplete(r -> currentSpan.finish());
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class DeviceRegistryBasedCertificateVerifier method validateCertificateAndLoadDevice.
/**
* Validates a device's client certificate and completes the DTLS handshake result handler.
*
* @param cid the connection id to report the result.
* @param certPath certificate path.
* @param session session.
* @see #setResultHandler(HandshakeResultHandler)
*/
private void validateCertificateAndLoadDevice(final ConnectionId cid, final CertPath certPath, final DTLSSession session) {
LOG.debug("validating client's X.509 certificate");
final Span span = tracer.buildSpan("validate client certificate").withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(Tags.COMPONENT.getKey(), adapter.getTypeName()).start();
validateCertificateAndLoadDevice(session, certPath, span).map(info -> {
// set AdditionalInfo as customArgument here
return new CertificateVerificationResult(cid, certPath, info);
}).otherwise(t -> {
TracingHelper.logError(span, "could not validate X509 for device", t);
LOG.debug("error validating X509", t);
final AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE, session.getPeer());
return new CertificateVerificationResult(cid, new HandshakeException("error validating X509", alert), null);
}).onSuccess(result -> {
span.finish();
californiumResultHandler.apply(result);
});
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class CoapContextTest method testStartAckTimerFallsBackToGlobalTimeout.
/**
* Verifies that the global ACK timeout is used if no tenant specific value is configured.
*/
@Test
void testStartAckTimerFallsBackToGlobalTimeout() {
final CoapExchange exchange = mock(CoapExchange.class);
final Adapter coapConfig = new Adapter(Constants.PROTOCOL_ADAPTER_TYPE_COAP);
final TenantObject tenant = TenantObject.from("tenant", true).addAdapter(coapConfig);
final Device authenticatedDevice = new Device(tenant.getTenantId(), "device-id");
final CoapContext ctx = CoapContext.fromRequest(exchange, authenticatedDevice, authenticatedDevice, "4711", span);
ctx.startAcceptTimer(vertx, tenant, 500);
verify(vertx).setTimer(eq(500L), VertxMockSupport.anyHandler());
}
Aggregations