@Override public final void assertRegistration( final String tenantId, final String deviceId, final String gatewayId, final Handler<AsyncResult<RegistrationResult>> resultHandler) { assertRegistration(tenantId, deviceId, gatewayId, NoopSpan.INSTANCE, resultHandler); }
/** * Gets device registration data by device ID. * <p> * This method is invoked by {@link #assertRegistration(String, String, String, Span, Handler)} to retrieve * device registration information from the persistent store. * <p> * This default implementation simply returns an empty result with status code 501 (Not Implemented). * Subclasses need to override this method and provide a reasonable implementation in order for this * class' default implementation of <em>assertRegistration</em> to work properly. * * @param tenantId The tenant the device belongs to. * @param deviceId The ID of the device to remove. * @param resultHandler The handler to invoke with the registration information. */ public void getDevice(final String tenantId, final String deviceId, final Handler<AsyncResult<RegistrationResult>> resultHandler) { handleUnimplementedOperation(resultHandler); }
/** * Verifies that a disabled device's status cannot be asserted. * * @param ctx The vertx unit test context. */ @Test public void testAssertDeviceRegistrationFailsForDisabledDevice(final TestContext ctx) { // GIVEN a registry that contains a disabled device final BaseRegistrationService<ServiceConfigProperties> registrationService = newRegistrationService(); registrationService.setRegistrationAssertionFactory(RegistrationAssertionHelperImpl.forSigning(vertx, props)); // WHEN trying to assert the device's registration status registrationService.assertRegistration(Constants.DEFAULT_TENANT, "4712", ctx.asyncAssertSuccess(result -> { // THEN the response does not contain a JWT token ctx.assertEquals(result.getStatus(), HttpURLConnection.HTTP_NOT_FOUND); ctx.assertNull(result.getPayload()); })); }
final Future<RegistrationResult> gatewayInfoTracker = Future.future(); getDevice(tenantId, deviceId, deviceInfoTracker.completer()); getDevice(tenantId, gatewayId, gatewayInfoTracker.completer()); final RegistrationResult gatewayResult = gatewayInfoTracker.result(); if (!isDeviceEnabled(deviceResult)) { return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_NOT_FOUND)); } else if (!isDeviceEnabled(gatewayResult)) { return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_FORBIDDEN)); } else { final JsonObject gatewayData = gatewayResult.getPayload().getJsonObject(RegistrationConstants.FIELD_DATA, new JsonObject()); if (isGatewayAuthorized(gatewayId, gatewayData, deviceId, deviceData)) { return Future.succeededFuture(RegistrationResult.from( HttpURLConnection.HTTP_OK, getAssertionPayload(tenantId, deviceId, deviceData), CacheDirective.maxAgeDirective(assertionFactory.getAssertionLifetime()))); } else {
private Future<EventBusMessage> processAssertRequest(final EventBusMessage request) { final String tenantId = request.getTenant(); final String deviceId = request.getDeviceId(); final String gatewayId = request.getGatewayId(); final SpanContext spanContext = request.getSpanContext(); final Span span = newChildSpan(SPAN_NAME_ASSERT_DEVICE_REGISTRATION, spanContext, tenantId, deviceId, gatewayId); final Future<EventBusMessage> resultFuture; if (tenantId == null || deviceId == null) { TracingHelper.logError(span, "missing tenant and/or device"); resultFuture = Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST)); } else { final Future<RegistrationResult> result = Future.future(); if (gatewayId == null) { log.debug("asserting registration of device [{}] with tenant [{}]", deviceId, tenantId); assertRegistration(tenantId, deviceId, span, result.completer()); } else { log.debug("asserting registration of device [{}] with tenant [{}] for gateway [{}]", deviceId, tenantId, gatewayId); assertRegistration(tenantId, deviceId, gatewayId, span, result.completer()); } resultFuture = result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setJsonPayload(res.getPayload()) .setCacheDirective(res.getCacheDirective()); }); } return finishSpanOnFutureCompletion(span, resultFuture); }
/** * {@inheritDoc} * <p> * Subclasses may override this method in order to implement a more sophisticated approach for asserting registration status, e.g. * using cached information etc. * This method requires a functional {@link #getDevice(String, String, Handler) getDevice} method to work. */ @Override public void assertRegistration( final String tenantId, final String deviceId, final Handler<AsyncResult<RegistrationResult>> resultHandler) { Objects.requireNonNull(tenantId); Objects.requireNonNull(deviceId); Objects.requireNonNull(resultHandler); final Future<RegistrationResult> getResultTracker = Future.future(); getDevice(tenantId, deviceId, getResultTracker.completer()); getResultTracker.map(result -> { if (isDeviceEnabled(result)) { return RegistrationResult.from( HttpURLConnection.HTTP_OK, getAssertionPayload(tenantId, deviceId, result.getPayload().getJsonObject(RegistrationConstants.FIELD_DATA)), CacheDirective.maxAgeDirective(assertionFactory.getAssertionLifetime())); } else { return RegistrationResult.from(HttpURLConnection.HTTP_NOT_FOUND); } }).setHandler(resultHandler); }
private boolean isDeviceEnabled(final RegistrationResult registrationResult) { return registrationResult.isOk() && isDeviceEnabled(registrationResult.getPayload().getJsonObject(RegistrationConstants.FIELD_DATA)); }
final JsonObject responsePayload = BaseRegistrationService.getResultPayload( "4711", new JsonObject() return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_OK, responsePayload)); } else if ("4712".equals(deviceId)) { final JsonObject responsePayload = BaseRegistrationService.getResultPayload( "4711", new JsonObject().put(RegistrationConstants.FIELD_ENABLED, false)); return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_OK, responsePayload)); } else if ("4713".equals(deviceId)) { final JsonObject responsePayload = BaseRegistrationService.getResultPayload( "4713", new JsonObject() return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_OK, responsePayload)); } else if ("gw-1".equals(deviceId)) { final JsonObject responsePayload = BaseRegistrationService.getResultPayload( "gw-1", new JsonObject().put(RegistrationConstants.FIELD_ENABLED, true)); return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_OK, responsePayload)); } else if ("gw-2".equals(deviceId)) { final JsonObject responsePayload = BaseRegistrationService.getResultPayload( "gw-2", new JsonObject().put(RegistrationConstants.FIELD_ENABLED, true)); return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_OK, responsePayload)); } else if ("gw-3".equals(deviceId)) { final JsonObject responsePayload = BaseRegistrationService.getResultPayload( "gw-3",
/** * Verifies that the service cannot be started without either <em>signingSecret</em> or * <em>signingKeyPath</em> being set. * * @param ctx The vertx unit test context. */ @Test public void testStartupFailsIfNoRegistrationAssertionFactoryIsSet(final TestContext ctx) { // GIVEN a registry without an assertion factory being set final BaseRegistrationService<ServiceConfigProperties> registrationService = newRegistrationService(); // WHEN starting the service final Async startupFailure = ctx.async(); final Future<Void> startFuture = Future.future(); startFuture.setHandler(ctx.asyncAssertFailure(t -> startupFailure.complete())); registrationService.doStart(startFuture); // THEN startup fails startupFailure.await(); }
/** * Verifies that a non existing device's status cannot be asserted. * * @param ctx The vertx unit test context. */ @Test public void testAssertDeviceRegistrationFailsForNonExistingDevice(final TestContext ctx) { // GIVEN a registry that does not contain any devices final BaseRegistrationService<ServiceConfigProperties> registrationService = newRegistrationService(); registrationService.setRegistrationAssertionFactory(RegistrationAssertionHelperImpl.forSigning(vertx, props)); // WHEN trying to assert a device's registration status registrationService.assertRegistration(Constants.DEFAULT_TENANT, "non-existent", ctx.asyncAssertSuccess(result -> { // THEN the response does not contain a JWT token ctx.assertEquals(result.getStatus(), HttpURLConnection.HTTP_NOT_FOUND); ctx.assertNull(result.getPayload()); })); }
final Future<RegistrationResult> gatewayInfoTracker = Future.future(); getDevice(tenantId, deviceId, deviceInfoTracker.completer()); getDevice(tenantId, gatewayId, gatewayInfoTracker.completer()); final RegistrationResult gatewayResult = gatewayInfoTracker.result(); if (!isDeviceEnabled(deviceResult)) { TracingHelper.logError(span, "device not enabled"); return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_NOT_FOUND)); } else if (!isDeviceEnabled(gatewayResult)) { TracingHelper.logError(span, "gateway not enabled"); return Future.succeededFuture(RegistrationResult.from(HttpURLConnection.HTTP_FORBIDDEN)); final JsonObject gatewayData = gatewayResult.getPayload().getJsonObject(RegistrationConstants.FIELD_DATA, new JsonObject()); if (isGatewayAuthorized(gatewayId, gatewayData, deviceId, deviceData)) { return Future.succeededFuture(RegistrationResult.from( HttpURLConnection.HTTP_OK, getAssertionPayload(tenantId, deviceId, deviceData), CacheDirective.maxAgeDirective(assertionFactory.getAssertionLifetime()))); } else {
getDevice(tenantId, deviceId, getResultTracker.completer()); if (isDeviceEnabled(result)) { return RegistrationResult.from( HttpURLConnection.HTTP_OK, getAssertionPayload(tenantId, deviceId, result.getPayload().getJsonObject(RegistrationConstants.FIELD_DATA)), CacheDirective.maxAgeDirective(assertionFactory.getAssertionLifetime())); } else {
private boolean isDeviceEnabled(final RegistrationResult registrationResult) { return registrationResult.isOk() && isDeviceEnabled(registrationResult.getPayload().getJsonObject(RegistrationConstants.FIELD_DATA)); }
/** * Verifies that a device's status cannot be asserted by a disabled gateway. * * @param ctx The vertx unit test context. */ @Test public void testAssertDeviceRegistrationFailsForDisabledGateway(final TestContext ctx) { // GIVEN a registry that contains an enabled device // and a gateway that the device is configured for but // which is disabled final BaseRegistrationService<ServiceConfigProperties> registrationService = newRegistrationService(); registrationService.setRegistrationAssertionFactory(RegistrationAssertionHelperImpl.forSigning(vertx, props)); // WHEN trying to assert the device's registration status for a gateway registrationService.assertRegistration(Constants.DEFAULT_TENANT, "4713", "gw-3", ctx.asyncAssertSuccess(result -> { // THEN the response contains a 403 status ctx.assertEquals(result.getStatus(), HttpURLConnection.HTTP_FORBIDDEN); // and does not contain a JWT token ctx.assertNull(result.getPayload()); })); }
@Override public final void assertRegistration( final String tenantId, final String deviceId, final Handler<AsyncResult<RegistrationResult>> resultHandler) { assertRegistration(tenantId, deviceId, NoopSpan.INSTANCE, resultHandler); }
/** * Gets device registration data by device ID. * <p> * This method is invoked by {@link #assertRegistration(String, String, String, Handler)} to retrieve * device registration information from the persistent store. * <p> * This default implementation simply returns an empty result with status code 501 (Not Implemented). * Subclasses need to override this method and provide a reasonable implementation in order for this * class' default implementation of <em>assertRegistration</em> to work properly. * * @param tenantId The tenant the device belongs to. * @param deviceId The ID of the device to remove. * @param resultHandler The handler to invoke with the registration information. */ public void getDevice(final String tenantId, final String deviceId, final Handler<AsyncResult<RegistrationResult>> resultHandler) { handleUnimplementedOperation(resultHandler); }
/** * Verifies that a device's status cannot be asserted by a non-existing gateway. * * @param ctx The vertx unit test context. */ @Test public void testAssertDeviceRegistrationFailsForNonExistingGateway(final TestContext ctx) { // GIVEN a registry that contains an enabled device but no gateway final BaseRegistrationService<ServiceConfigProperties> registrationService = newRegistrationService(); registrationService.setRegistrationAssertionFactory(RegistrationAssertionHelperImpl.forSigning(vertx, props)); // WHEN trying to assert the device's registration status for a gateway registrationService.assertRegistration(Constants.DEFAULT_TENANT, "4711", "non-existent-gw", ctx.asyncAssertSuccess(result -> { // THEN the response contains a 403 status ctx.assertEquals(result.getStatus(), HttpURLConnection.HTTP_FORBIDDEN); // and does not contain a JWT token ctx.assertNull(result.getPayload()); })); }
private Future<EventBusMessage> processAssertRequest(final EventBusMessage request) { final String tenantId = request.getTenant(); final String deviceId = request.getDeviceId(); final String gatewayId = request.getGatewayId(); if (tenantId == null || deviceId == null) { return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST)); } else if (gatewayId == null) { log.debug("asserting registration of device [{}] with tenant [{}]", deviceId, tenantId); final Future<RegistrationResult> result = Future.future(); assertRegistration(tenantId, deviceId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setJsonPayload(res.getPayload()) .setCacheDirective(res.getCacheDirective()); }); } else { log.debug("asserting registration of device [{}] with tenant [{}] for gateway [{}]", deviceId, tenantId, gatewayId); final Future<RegistrationResult> result = Future.future(); assertRegistration(tenantId, deviceId, gatewayId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setJsonPayload(res.getPayload()) .setCacheDirective(res.getCacheDirective()); }); } }
/** * Verifies that a device's status can be asserted by an existing gateway. * * @param ctx The vertx unit test context. */ @Test public void testAssertDeviceRegistrationSucceedsForExistingGateway(final TestContext ctx) { // GIVEN a registry that contains an enabled device that is configured to // be connected to an enabled gateway final BaseRegistrationService<ServiceConfigProperties> registrationService = newRegistrationService(); registrationService.setRegistrationAssertionFactory(RegistrationAssertionHelperImpl.forSigning(vertx, props)); // WHEN trying to assert the device's registration status for a gateway registrationService.assertRegistration(Constants.DEFAULT_TENANT, "4711", "gw-1", ctx.asyncAssertSuccess(result -> { // THEN the response contains a 200 status ctx.assertEquals(HttpURLConnection.HTTP_OK, result.getStatus()); final JsonObject payload = result.getPayload(); ctx.assertNotNull(payload); // and contains a JWT token ctx.assertNotNull(payload.getString(RegistrationConstants.FIELD_ASSERTION)); })); }
/** * Verifies that a device's status cannot be asserted by a gateway that does not * match the device's configured gateway. * * @param ctx The vertx unit test context. */ @Test public void testAssertDeviceRegistrationFailsForWrongGateway(final TestContext ctx) { // GIVEN a registry that contains an enabled device and two gateways: // 1. the gateway that the device is configured for. // 2. another gateway final BaseRegistrationService<ServiceConfigProperties> registrationService = newRegistrationService(); registrationService.setRegistrationAssertionFactory(RegistrationAssertionHelperImpl.forSigning(vertx, props)); // WHEN trying to assert the device's registration status for the wrong gateway registrationService.assertRegistration(Constants.DEFAULT_TENANT, "4711", "gw-2", ctx.asyncAssertSuccess(result -> { // THEN the response contains a 403 status ctx.assertEquals(result.getStatus(), HttpURLConnection.HTTP_FORBIDDEN); // and does not contain a JWT token ctx.assertNull(result.getPayload()); })); }