use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class CommandResponseResourceTest method testUploadCommandResponseWaitsForAcceptedOutcome.
/**
* Verifies that the adapter waits for a command response being successfully sent
* downstream before responding with a 2.04 status to the device.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadCommandResponseWaitsForAcceptedOutcome(final VertxTestContext ctx) {
// GIVEN an adapter with a downstream application attached
givenAnAdapter(properties);
final var resource = givenAResource(adapter);
final Promise<Void> outcome = Promise.promise();
final CommandResponseSender sender = givenACommandResponseSenderForAnyTenant(outcome);
// WHEN a device publishes an command response
final String reqId = Commands.encodeRequestIdParameters("correlation", "replyToId", "device", MessagingType.amqp);
final Buffer payload = Buffer.buffer("some payload");
final OptionSet options = new OptionSet();
options.addUriPath(CommandConstants.COMMAND_RESPONSE_ENDPOINT).addUriPath(reqId);
options.addUriQuery(String.format("%s=%d", Constants.HEADER_COMMAND_RESPONSE_STATUS, 200));
options.setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, options);
final Device authenticatedDevice = new Device("tenant", "device");
final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "device", span);
final Future<Void> result = resource.uploadCommandResponseMessage(context);
// THEN the command response is being forwarded downstream
verify(sender).sendCommandResponse(any(TenantObject.class), any(RegistrationAssertion.class), any(CommandResponse.class), any(SpanContext.class));
// but the device does not get a response
verify(coapExchange, never()).respond(any(Response.class));
// and the response has not been reported as forwarded
verify(metrics, never()).reportCommand(eq(Direction.RESPONSE), eq("tenant"), any(), eq(ProcessingOutcome.FORWARDED), anyInt(), any());
// until the message has been accepted
outcome.complete();
result.onComplete(ctx.succeeding(code -> {
ctx.verify(() -> {
verify(coapExchange).respond(argThat((Response res) -> res.getCode() == ResponseCode.CHANGED));
verify(metrics).reportCommand(eq(Direction.RESPONSE), eq("tenant"), any(), eq(ProcessingOutcome.FORWARDED), eq(payload.length()), any());
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class DeviceRegistryBasedPskStore method loadCredentialsForDevice.
/**
* Load credentials for an identity used by a device in a PSK based DTLS handshake.
*
* @param cid the connection id to report the result.
* @param identity the psk identity of the device.
*/
private void loadCredentialsForDevice(final ConnectionId cid, final PskPublicInformation identity) {
final String publicInfo = identity.getPublicInfoAsString();
LOG.debug("getting PSK secret for identity [{}]", publicInfo);
final Span span = tracer.buildSpan("look up pre-shared key").withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(Tags.COMPONENT.getKey(), adapter.getTypeName()).start();
final PreSharedKeyDeviceIdentity handshakeIdentity = getHandshakeIdentity(publicInfo, span);
if (handshakeIdentity == null) {
TracingHelper.logError(span, "could not determine auth-id from PSK identity");
span.finish();
return;
}
TracingHelper.TAG_TENANT_ID.set(span, handshakeIdentity.getTenantId());
TracingHelper.TAG_AUTH_ID.set(span, handshakeIdentity.getAuthId());
applyTraceSamplingPriority(handshakeIdentity, span).compose(v -> adapter.getCredentialsClient().get(handshakeIdentity.getTenantId(), handshakeIdentity.getType(), handshakeIdentity.getAuthId(), new JsonObject(), span.context())).map(credentials -> {
final String deviceId = credentials.getDeviceId();
TracingHelper.TAG_DEVICE_ID.set(span, deviceId);
final SecretKey key = getCandidateKey(credentials);
if (key == null) {
TracingHelper.logError(span, "PSK credentials for device do not contain proper key");
return new PskSecretResult(cid, identity, null, null);
} else {
span.log("successfully retrieved PSK for device");
// set AdditionalInfo as customArgument here
final AdditionalInfo info = DeviceInfoSupplier.createDeviceInfo(new Device(handshakeIdentity.getTenantId(), credentials.getDeviceId()), handshakeIdentity.getAuthId());
return new PskSecretResult(cid, identity, key, info);
}
}).otherwise(t -> {
TracingHelper.logError(span, "could not retrieve PSK credentials for device", t);
LOG.debug("error retrieving credentials for PSK identity [{}]", publicInfo, t);
return new PskSecretResult(cid, identity, null, null);
}).onSuccess(result -> {
span.finish();
californiumResultHandler.apply(result);
});
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class TracingSupportingHonoResource method getAuthenticatedDevice.
/**
* Gets an authenticated device's identity for a CoAP request.
*
* @param exchange The CoAP exchange with the authenticated device's principal.
* @return A future indicating the outcome of the operation.
* The future will be succeeded if the authenticated device can be determined from the CoAP exchange,
* otherwise the future will be failed with a {@link ClientErrorException}.
*/
public static Future<Device> getAuthenticatedDevice(final CoapExchange exchange) {
final Promise<Device> result = Promise.promise();
final Principal peerIdentity = exchange.advanced().getRequest().getSourceContext().getPeerIdentity();
if (peerIdentity instanceof ExtensiblePrincipal) {
final ExtensiblePrincipal<?> extPrincipal = (ExtensiblePrincipal<?>) peerIdentity;
final Device authenticatedDevice = extPrincipal.getExtendedInfo().get(DeviceInfoSupplier.EXT_INFO_KEY_HONO_DEVICE, Device.class);
if (authenticatedDevice != null) {
result.complete(authenticatedDevice);
} else {
result.fail(new ClientErrorException(HttpURLConnection.HTTP_UNAUTHORIZED, "DTLS session does not contain authenticated Device"));
}
} else {
result.fail(new ClientErrorException(HttpURLConnection.HTTP_UNAUTHORIZED, "DTLS session does not contain ExtensiblePrincipal"));
}
return result.future();
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class VertxBasedAmqpProtocolAdapterTest method testUploadCommandResponseSucceeds.
/**
* Verify that the AMQP adapter forwards command responses downstream.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadCommandResponseSucceeds(final VertxTestContext ctx) {
// GIVEN an AMQP adapter
givenAnAdapter(properties);
final CommandResponseSender responseSender = givenACommandResponseSenderForAnyTenant();
when(responseSender.sendCommandResponse(any(TenantObject.class), any(RegistrationAssertion.class), any(CommandResponse.class), (SpanContext) any())).thenReturn(Future.succeededFuture());
// which is enabled for the test tenant
final TenantObject tenantObject = givenAConfiguredTenant(TEST_TENANT_ID, true);
// WHEN an unauthenticated device publishes a command response
final String replyToAddress = String.format("%s/%s/%s", getCommandResponseEndpoint(), TEST_TENANT_ID, Commands.getDeviceFacingReplyToId("test-reply-id", TEST_DEVICE, MessagingType.amqp));
final Map<String, Object> propertyMap = new HashMap<>();
propertyMap.put(MessageHelper.APP_PROPERTY_STATUS, 200);
final ApplicationProperties props = new ApplicationProperties(propertyMap);
final Buffer payload = Buffer.buffer("some payload");
final Message message = getFakeMessage(replyToAddress, payload);
message.setCorrelationId("correlation-id");
message.setApplicationProperties(props);
final ProtonDelivery delivery = mock(ProtonDelivery.class);
adapter.onMessageReceived(AmqpContext.fromMessage(delivery, message, span, null)).onComplete(ctx.succeeding(ok -> {
ctx.verify(() -> {
// THEN the adapter forwards the command response message downstream
verify(responseSender).sendCommandResponse(eq(tenantObject), any(RegistrationAssertion.class), any(CommandResponse.class), (SpanContext) any());
// and reports the forwarded message
verify(metrics).reportCommand(eq(Direction.RESPONSE), eq(TEST_TENANT_ID), eq(tenantObject), eq(ProcessingOutcome.FORWARDED), eq(payload.length()), any());
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class EventResourceTest method testUploadEventFailsForRejectedOutcome.
/**
* Verifies that the adapter fails the upload of an event with a 4.00 result if it is rejected by the downstream
* peer.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadEventFailsForRejectedOutcome(final VertxTestContext ctx) {
// GIVEN an adapter with a downstream event consumer attached
givenAnAdapter(properties);
final Promise<Void> outcome = Promise.promise();
givenAnEventSenderForAnyTenant(outcome);
final var resource = givenAResource(adapter);
// WHEN a device publishes an event that is not accepted by the peer
final Buffer payload = Buffer.buffer("some payload");
final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, MediaTypeRegistry.TEXT_PLAIN);
final Device authenticatedDevice = new Device("tenant", "device");
final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "device", span);
final Future<Void> result = resource.handlePostRequest(context);
assertEventHasBeenSentDownstream("tenant", "device", "text/plain");
outcome.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed message"));
// THEN the device gets a 4.00
result.onComplete(ctx.failing(t -> {
ctx.verify(() -> {
assertThat(result.cause()).isInstanceOf(ClientErrorException.class);
assertThat(((ClientErrorException) result.cause()).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_BAD_REQUEST);
verify(metrics).reportTelemetry(eq(MetricsTags.EndpointType.EVENT), eq("tenant"), any(), eq(MetricsTags.ProcessingOutcome.UNPROCESSABLE), eq(MetricsTags.QoS.AT_LEAST_ONCE), eq(payload.length()), eq(TtdStatus.NONE), any());
});
ctx.completeNow();
}));
}
Aggregations