use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.
the class VertxBasedHttpProtocolAdapterTest method testBasicAuthFailsWrongCredentials.
@SuppressWarnings("unchecked")
@Test
public final void testBasicAuthFailsWrongCredentials(final TestContext context) {
final Async async = context.async();
final String encodedUserPass = Base64.getEncoder().encodeToString("testuser@DEFAULT_TENANT:password123".getBytes(StandardCharsets.UTF_8));
doAnswer(invocation -> {
Handler<AsyncResult<User>> resultHandler = invocation.getArgument(1);
resultHandler.handle(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_UNAUTHORIZED, "bad credentials")));
return null;
}).when(credentialsAuthProvider).authenticate(any(JsonObject.class), any(Handler.class));
vertx.createHttpClient().put(httpAdapter.getInsecurePort(), HOST, "/somenonexistingroute").putHeader(HttpHeaders.CONTENT_TYPE, HttpUtils.CONTENT_TYPE_JSON).putHeader(HttpHeaders.AUTHORIZATION, "Basic " + encodedUserPass).handler(response -> {
context.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, response.statusCode());
response.bodyHandler(totalBuffer -> {
async.complete();
});
}).exceptionHandler(context::fail).end();
}
use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.
the class KuraProtocolAdapter method mapTopic.
Future<ResourceIdentifier> mapTopic(final MqttContext ctx) {
final Future<ResourceIdentifier> result = Future.future();
try {
final ResourceIdentifier topic = ResourceIdentifier.fromString(ctx.message().topicName());
ResourceIdentifier mappedTopic = null;
if (getConfig().getControlPrefix().equals(topic.getEndpoint())) {
// this is a "control" message
ctx.setContentType(getConfig().getCtrlMsgContentType());
final String[] mappedPath = Arrays.copyOf(topic.getResourcePath(), topic.getResourcePath().length);
mappedPath[0] = getEndpoint(ctx.message().qosLevel());
mappedTopic = ResourceIdentifier.fromPath(mappedPath);
} else {
// map "data" messages based on QoS
ctx.setContentType(getConfig().getDataMsgContentType());
final String[] mappedPath = new String[topic.getResourcePath().length + 1];
System.arraycopy(topic.getResourcePath(), 0, mappedPath, 1, topic.getResourcePath().length);
mappedPath[0] = getEndpoint(ctx.message().qosLevel());
mappedTopic = ResourceIdentifier.fromPath(mappedPath);
}
if (mappedTopic.getResourcePath().length < 3) {
// topic does not contain account_name and client_id
result.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "topic does not comply with Kura format"));
} else {
LOG.debug("mapped Kura message [topic: {}, QoS: {}] to Hono message [to: {}, device_id: {}, content-type: {}]", topic, ctx.message().qosLevel(), mappedTopic.getBasePath(), mappedTopic.getResourceId(), ctx.contentType());
result.complete(mappedTopic);
}
} catch (final IllegalArgumentException e) {
result.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed topic name"));
}
return result;
}
use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.
the class AbstractVertxBasedMqttProtocolAdapter method uploadMessage.
/**
* Uploads a message to Hono Messaging.
*
* @param ctx The context in which the MQTT message has been published.
* @param resource The resource that the message should be uploaded to.
* @param payload The message payload to send.
* @return A future indicating the outcome of the operation.
* <p>
* The future will succeed if the message has been uploaded successfully.
* Otherwise the future will fail with a {@link ServiceInvocationException}.
* @throws NullPointerException if any of context, resource or payload is {@code null}.
* @throws IllegalArgumentException if the payload is empty.
*/
public final Future<Void> uploadMessage(final MqttContext ctx, final ResourceIdentifier resource, final Buffer payload) {
Objects.requireNonNull(ctx);
Objects.requireNonNull(resource);
Objects.requireNonNull(payload);
switch(EndpointType.fromString(resource.getEndpoint())) {
case TELEMETRY:
return uploadTelemetryMessage(ctx, resource.getTenantId(), resource.getResourceId(), payload);
case EVENT:
return uploadEventMessage(ctx, resource.getTenantId(), resource.getResourceId(), payload);
default:
return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "unsupported endpoint"));
}
}
use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.
the class AbstractVertxBasedMqttProtocolAdapter method uploadMessage.
private Future<Void> uploadMessage(final MqttContext ctx, final String tenant, final String deviceId, final Buffer payload, final Future<MessageSender> senderTracker, final String endpointName) {
if (payload.length() == 0) {
return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "payload must not be empty"));
} else {
final Future<JsonObject> tokenTracker = getRegistrationAssertion(tenant, deviceId, ctx.authenticatedDevice());
final Future<TenantObject> tenantConfigTracker = getTenantConfiguration(tenant);
return CompositeFuture.all(tokenTracker, tenantConfigTracker, senderTracker).compose(ok -> {
if (tenantConfigTracker.result().isAdapterEnabled(getTypeName())) {
final Message downstreamMessage = newMessage(String.format("%s/%s", endpointName, tenant), deviceId, ctx.message().topicName(), ctx.contentType(), payload, tokenTracker.result());
customizeDownstreamMessage(downstreamMessage, ctx);
return senderTracker.result().send(downstreamMessage);
} else {
// this adapter is not enabled for the tenant
return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_FORBIDDEN));
}
}).compose(delivery -> {
LOG.trace("successfully processed message [topic: {}, QoS: {}] for device [tenantId: {}, deviceId: {}]", ctx.message().topicName(), ctx.message().qosLevel(), tenant, deviceId);
metrics.incrementProcessedMqttMessages(endpointName, tenant);
onMessageSent(ctx);
// check that the remote MQTT client is still connected before sending PUBACK
if (ctx.deviceEndpoint().isConnected() && ctx.message().qosLevel() == MqttQoS.AT_LEAST_ONCE) {
ctx.deviceEndpoint().publishAcknowledge(ctx.message().messageId());
}
return Future.<Void>succeededFuture();
}).recover(t -> {
if (ClientErrorException.class.isInstance(t)) {
ClientErrorException e = (ClientErrorException) t;
LOG.debug("cannot process message for device [tenantId: {}, deviceId: {}, endpoint: {}]: {} - {}", tenant, deviceId, endpointName, e.getErrorCode(), e.getMessage());
} else {
LOG.debug("cannot process message for device [tenantId: {}, deviceId: {}, endpoint: {}]", tenant, deviceId, endpointName, t);
metrics.incrementUndeliverableMqttMessages(endpointName, tenant);
onMessageUndeliverable(ctx);
}
return Future.failedFuture(t);
});
}
}
use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.
the class AbstractVertxBasedMqttProtocolAdapterTest method testOnUnauthenticatedMessageDoesNotSendPubAckOnFailure.
/**
* Verifies that the adapter does not send a PUBACK package to the device if
* an event message has not been accepted by the peer.
*
* @param ctx The vert.x test context.
*/
@Test
public void testOnUnauthenticatedMessageDoesNotSendPubAckOnFailure(final TestContext ctx) {
// GIVEN an adapter with a downstream event consumer
final Future<ProtonDelivery> outcome = Future.future();
givenAnEventSenderForOutcome(outcome);
final MqttServer server = getMqttServer(false);
final AbstractVertxBasedMqttProtocolAdapter<ProtocolAdapterProperties> adapter = getAdapter(server);
// WHEN a device publishes an event
final Buffer payload = Buffer.buffer("some payload");
final MqttEndpoint endpoint = mock(MqttEndpoint.class);
when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
final MqttPublishMessage messageFromDevice = mock(MqttPublishMessage.class);
when(messageFromDevice.qosLevel()).thenReturn(MqttQoS.AT_LEAST_ONCE);
when(messageFromDevice.messageId()).thenReturn(5555555);
final MqttContext context = new MqttContext(messageFromDevice, endpoint);
adapter.uploadEventMessage(context, "my-tenant", "4712", payload).setHandler(ctx.asyncAssertFailure());
// and the peer rejects the message
outcome.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST));
// THEN the device has not received a PUBACK
verify(endpoint, never()).publishAcknowledge(anyInt());
}
Aggregations