/** * Invokes the <em>Get Credentials</em> operation of Hono's * <a href="https://www.eclipse.org/hono/api/Credentials-API">Credentials API</a> * on the service represented by the <em>sender</em> and <em>receiver</em> links. */ @Override public final Future<CredentialsObject> get(final String type, final String authId, final JsonObject clientContext) { Objects.requireNonNull(type); Objects.requireNonNull(authId); final Future<CredentialsResult<CredentialsObject>> responseTracker = Future.future(); final JsonObject specification = new JsonObject() .put(CredentialsConstants.FIELD_TYPE, type) .put(CredentialsConstants.FIELD_AUTH_ID, authId) .mergeIn(clientContext); createAndSendRequest(CredentialsConstants.CredentialsAction.get.toString(), specification.toBuffer(), responseTracker.completer()); return responseTracker.map(response -> { switch(response.getStatus()) { case HttpURLConnection.HTTP_OK: return response.getPayload(); case HttpURLConnection.HTTP_NOT_FOUND: throw new ClientErrorException(response.getStatus(), "no such credentials"); default: throw StatusCodeMapper.from(response); } }); } }
remove(tenantId, type, authId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setCacheDirective(res.getCacheDirective()); }); removeAll(tenantId, deviceId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setCacheDirective(res.getCacheDirective());
private Future<EventBusMessage> processAddRequest(final EventBusMessage request) { final String tenantId = request.getTenant(); final CredentialsObject payload = Optional.ofNullable(request.getJsonPayload()) .map(json -> json.mapTo(CredentialsObject.class)).orElse(null); if (tenantId == null) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, "missing tenant ID")); } else if (payload == null) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, "missing payload")); } else { try { payload.checkValidity(this::checkSecret); final Future<CredentialsResult<JsonObject>> result = Future.future(); add(tenantId, JsonObject.mapFrom(payload), result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(payload.getDeviceId()) .setCacheDirective(res.getCacheDirective()); }); } catch (IllegalStateException e) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, e.getMessage())); } } }
private Future<EventBusMessage> processUpdateRequest(final EventBusMessage request) { final String tenantId = request.getTenant(); final CredentialsObject payload = Optional.ofNullable(request.getJsonPayload()) .map(json -> json.mapTo(CredentialsObject.class)).orElse(null); if (tenantId == null) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, "missing tenant ID")); } else if (payload == null) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, "missing payload")); } else { try { payload.checkValidity(this::checkSecret); final Future<CredentialsResult<JsonObject>> result = Future.future(); update(tenantId, JsonObject.mapFrom(payload), result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(payload.getDeviceId()) .setCacheDirective(res.getCacheDirective()); }); } catch (IllegalStateException e) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, e.getMessage())); } } }
remove(tenantId, type, authId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setCacheDirective(res.getCacheDirective()); }); removeAll(tenantId, deviceId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setCacheDirective(res.getCacheDirective());
private Future<EventBusMessage> processGetByAuthIdRequest(final EventBusMessage request, final String tenantId, final JsonObject payload, final String type, final String authId, final Span span) { log.debug("getting credentials [tenant: {}, type: {}, auth-id: {}]", tenantId, type, authId); span.setTag(TAG_CREDENTIALS_TYPE, type); span.setTag(TAG_AUTH_ID, authId); final Future<CredentialsResult<JsonObject>> result = Future.future(); get(tenantId, type, authId, payload, span, result.completer()); return result.map(res -> { final String deviceIdFromPayload = Optional.ofNullable(res.getPayload()) .map(p -> getTypesafeValueForField(String.class, p, TenantConstants.FIELD_PAYLOAD_DEVICE_ID)) .orElse(null); if (deviceIdFromPayload != null) { span.setTag(MessageHelper.APP_PROPERTY_DEVICE_ID, deviceIdFromPayload); } return request.getResponse(res.getStatus()) .setDeviceId(deviceIdFromPayload) .setJsonPayload(res.getPayload()) .setCacheDirective(res.getCacheDirective()); }); }
private Future<EventBusMessage> doAdd(final EventBusMessage request, final String tenantId, final CredentialsObject payload) { try { payload.checkValidity(this::checkSecret); final Future<CredentialsResult<JsonObject>> result = Future.future(); add(tenantId, JsonObject.mapFrom(payload), result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(payload.getDeviceId()) .setCacheDirective(res.getCacheDirective()); }); } catch (IllegalStateException e) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, e.getMessage())); } }
private Future<EventBusMessage> doUpdate(final EventBusMessage request, final String tenantId, final CredentialsObject payload) { try { payload.checkValidity(this::checkSecret); final Future<CredentialsResult<JsonObject>> result = Future.future(); update(tenantId, JsonObject.mapFrom(payload), result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(payload.getDeviceId()) .setCacheDirective(res.getCacheDirective()); }); } catch (IllegalStateException e) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, e.getMessage())); } }
protected static void register( final CompleteCredentialsService svc, final String tenant, final String deviceId, final String authId, final String type, final JsonObject clientContext, final JsonArray secrets, final TestContext ctx) { final JsonObject data = new JsonObject() .put(CredentialsConstants.FIELD_PAYLOAD_DEVICE_ID, deviceId) .put(CredentialsConstants.FIELD_AUTH_ID, authId) .put(CredentialsConstants.FIELD_TYPE, type) .put(CredentialsConstants.FIELD_SECRETS, secrets); if (clientContext != null) { data.mergeIn(clientContext); } final Async registration = ctx.async(); svc.add("tenant", data, ctx.asyncAssertSuccess(s -> { assertThat(s.getStatus(), is(HttpURLConnection.HTTP_CREATED)); registration.complete(); })); registration.await(); } }
private Future<EventBusMessage> processGetByDeviceIdRequest(final EventBusMessage request, final String tenantId, final String type, final String deviceId, final Span span) { log.debug("getting credentials for device [tenant: {}, device-id: {}]", tenantId, deviceId); span.setTag(TAG_CREDENTIALS_TYPE, type); span.setTag(MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId); final Future<CredentialsResult<JsonObject>> result = Future.future(); getAll(tenantId, deviceId, span, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setJsonPayload(res.getPayload()) .setCacheDirective(res.getCacheDirective()); }); }
/** * Verifies that only one set of credentials can be registered for an auth-id and type (per tenant). * * @param ctx The vert.x test context. */ @Test public void testAddCredentialsRefusesDuplicateRegistration(final TestContext ctx) { register(getCompleteCredentialsService(), "tenant", "device", "myId", "myType", ctx); final JsonObject payload2 = new JsonObject() .put(CredentialsConstants.FIELD_PAYLOAD_DEVICE_ID, "other-device") .put(CredentialsConstants.FIELD_AUTH_ID, "myId") .put(CredentialsConstants.FIELD_TYPE, "myType") .put(CredentialsConstants.FIELD_SECRETS, new JsonArray()); final Async add = ctx.async(); getCompleteCredentialsService().add("tenant", payload2, ctx.asyncAssertSuccess(s -> { assertThat(s.getStatus(), is(HttpURLConnection.HTTP_CONFLICT)); add.complete(); })); add.await(); }
TenantConstants.FIELD_PAYLOAD_DEVICE_ID)) .orElse(null); return request.getResponse(res.getStatus()) .setDeviceId(deviceIdFromPayload) .setJsonPayload(res.getPayload()) getAll(tenantId, deviceId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setJsonPayload(res.getPayload())
/** * Verifies that service returns 404 if a client provides wrong client context. * * @param ctx The vert.x test context. */ @Test public void testGetCredentialsFailsForWrongClientContext(final TestContext ctx) { final JsonObject clientContext = new JsonObject() .put("client-id", "gateway-one"); register(getCompleteCredentialsService(), "tenant", "device", "myId", "myType", clientContext, new JsonArray(), ctx); final JsonObject testContext = new JsonObject() .put("client-id", "gateway-two"); final Async get = ctx.async(); getCompleteCredentialsService().get("tenant", "myType", "myId", testContext, ctx.asyncAssertSuccess(s -> { assertThat(s.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND)); get.complete(); })); get.await(2000); }
protected static void assertRegistered( final CompleteCredentialsService svc, final String tenant, final String authId, final String type, final TestContext ctx) { final Async registration = ctx.async(); svc.get(tenant, type, authId, ctx.asyncAssertSuccess(t -> { assertThat(t.getStatus(), is(HttpURLConnection.HTTP_OK)); registration.complete(); })); registration.await(); }
/** * Verifies that service returns existing credentials for proper client context. * * @param ctx The vert.x test context. */ @Test public void testGetCredentialsSucceedsForProperClientContext(final TestContext ctx) { final JsonObject clientContext = new JsonObject() .put("client-id", "gateway-one"); register(getCompleteCredentialsService(), "tenant", "device", "myId", "myType", clientContext, new JsonArray(), ctx); final Async get = ctx.async(); getCompleteCredentialsService().get("tenant", "myType", "myId", clientContext, ctx.asyncAssertSuccess(s -> { assertThat(s.getStatus(), is(HttpURLConnection.HTTP_OK)); assertThat(s.getPayload().getString(CredentialsConstants.FIELD_AUTH_ID), is("myId")); assertThat(s.getPayload().getString(CredentialsConstants.FIELD_TYPE), is("myType")); get.complete(); })); get.await(2000); }
protected static void assertNotRegistered( final CompleteCredentialsService svc, final String tenant, final String authId, final String type, final TestContext ctx) { final Async registration = ctx.async(); svc.get(tenant, type, authId, ctx.asyncAssertSuccess(t -> { assertThat(t.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND)); registration.complete(); })); registration.await(); }
/** * Verifies that the service returns existing credentials. * * @param ctx The vert.x test context. */ @Test public void testGetCredentialsSucceedsForExistingCredentials(final TestContext ctx) { register(getCompleteCredentialsService(), "tenant", "device", "myId", "myType", ctx); final Async get = ctx.async(); getCompleteCredentialsService().get("tenant", "myType", "myId", ctx.asyncAssertSuccess(s -> { assertThat(s.getStatus(), is(HttpURLConnection.HTTP_OK)); assertThat(s.getPayload().getString(CredentialsConstants.FIELD_AUTH_ID), is("myId")); assertThat(s.getPayload().getString(CredentialsConstants.FIELD_TYPE), is("myType")); get.complete(); })); get.await(); }
/** * Verifies that the service returns 404 if a client wants to retrieve non-existing credentials. * * @param ctx The vert.x test context. */ @Test public void testGetCredentialsFailsForNonExistingCredentials(final TestContext ctx) { final Async get = ctx.async(); getCompleteCredentialsService().get("tenant", "myType", "non-existing", ctx.asyncAssertSuccess(s -> { assertThat(s.getStatus(), is(HttpURLConnection.HTTP_NOT_FOUND)); get.complete(); })); get.await(); }
/** * Verifies that the service removes credentials for a given auth-id and type. * * @param ctx The vert.x test context. */ @Test public void testRemoveCredentialsByAuthIdAndTypeSucceeds(final TestContext ctx) { register(getCompleteCredentialsService(), "tenant", "device", "myId", "myType", ctx); final Async remove = ctx.async(); getCompleteCredentialsService().remove("tenant", "myType", "myId", ctx.asyncAssertSuccess(s -> { assertThat(s.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT)); assertNotRegistered(getCompleteCredentialsService(), "tenant", "myId", "myType", ctx); remove.complete(); })); remove.await(); }
/** * Verifies that the service removes all credentials for a device but keeps credentials * of other devices. * * @param ctx The vert.x test context. */ @Test public void testRemoveCredentialsByDeviceSucceeds(final TestContext ctx) { register(getCompleteCredentialsService(), "tenant", "device", "myId", "myType", ctx); register(getCompleteCredentialsService(), "tenant", "device", "myOtherId", "myOtherType", ctx); register(getCompleteCredentialsService(), "tenant", "other-device", "thirdId", "myType", ctx); final Async remove = ctx.async(); getCompleteCredentialsService().removeAll("tenant", "device", ctx.asyncAssertSuccess(s -> { assertThat(s.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT)); assertNotRegistered(getCompleteCredentialsService(), "tenant", "myId", "myType", ctx); assertNotRegistered(getCompleteCredentialsService(), "tenant", "myOtherId", "myOtherType", ctx); assertRegistered(getCompleteCredentialsService(), "tenant", "thirdId", "myType", ctx); remove.complete(); })); remove.await(); }