/** * Handles an unimplemented operation by failing the given handler * with a {@link ClientErrorException} having a <em>501 Not Implemented</em> status code. * * @param resultHandler The handler. */ protected void handleUnimplementedOperation(final Handler<AsyncResult<CredentialsResult<JsonObject>>> resultHandler) { resultHandler.handle(Future.succeededFuture(CredentialsResult.from(HttpURLConnection.HTTP_NOT_IMPLEMENTED))); } }
/** * Creates a new result for a status code and payload. * * @param status The status code indicating the outcome of the request. * @param payload The payload to convey to the sender of the request. * @param cacheDirective Restrictions regarding the caching of the payload by * the receiver of the result (may be {@code null}). * @param <T> The type of the payload that is conveyed in the result. * @return The result. */ public static <T> CredentialsResult<T> from(final int status, final T payload, final CacheDirective cacheDirective) { return new CredentialsResult<>(status, payload, cacheDirective); } }
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()); }); }
/** * 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); } }); } }
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())); } }
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 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); }
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())); } }
/** * 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(); }
/** * Handles an unimplemented operation by failing the given handler * with a {@link ClientErrorException} having a <em>501 Not Implemented</em> status code. * * @param resultHandler The handler. */ protected void handleUnimplementedOperation(final Handler<AsyncResult<CredentialsResult<JsonObject>>> resultHandler) { resultHandler.handle(Future.succeededFuture(CredentialsResult.from(HttpURLConnection.HTTP_NOT_IMPLEMENTED))); } }
get(tenantId, type, authId, payload, 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); return request.getResponse(res.getStatus()) .setDeviceId(deviceIdFromPayload) .setJsonPayload(res.getPayload()) .setCacheDirective(res.getCacheDirective()); }); } else if (deviceId != null && authId == null) { getAll(tenantId, deviceId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setJsonPayload(res.getPayload()) .setCacheDirective(res.getCacheDirective()); }); } else {
/** * 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(); }
remove(tenantId, type, authId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setCacheDirective(res.getCacheDirective()); }); } else if (deviceId != null && type.equals(CredentialsConstants.SPECIFIER_WILDCARD)) { removeAll(tenantId, deviceId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setCacheDirective(res.getCacheDirective()); }); } else {
/** * 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); }
/** * Creates a new result for a status code and payload. * * @param status The status code indicating the outcome of the request. * @param payload The payload to convey to the sender of the request. * @param cacheDirective Restrictions regarding the caching of the payload by * the receiver of the result (may be {@code null}). * @param <T> The type of the payload that is conveyed in the result. * @return The result. */ public static <T> CredentialsResult<T> from(final int status, final T payload, final CacheDirective cacheDirective) { return new CredentialsResult<>(status, payload, cacheDirective); } }
@Override protected final CredentialsResult<CredentialsObject> getResult( final int status, final String contentType, final Buffer payload, final CacheDirective cacheDirective) { if (payload == null) { return CredentialsResult.from(status); } else { try { return CredentialsResult.from( status, OBJECT_MAPPER.readValue(payload.getBytes(), CredentialsObject.class), cacheDirective); } catch (final IOException e) { LOG.warn("received malformed payload from Credentials service", e); return CredentialsResult.from(HttpURLConnection.HTTP_INTERNAL_ERROR); } } }
remove(tenantId, type, authId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setCacheDirective(res.getCacheDirective()); }); } else if (deviceId != null && type.equals(CredentialsConstants.SPECIFIER_WILDCARD)) { removeAll(tenantId, deviceId, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setCacheDirective(res.getCacheDirective()); }); } else {
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(); }
/** * Creates a new result for a status code. * * @param status The status code indicating the outcome of the request. * @param <T> The type of the payload that is conveyed in the result. * @return The result. */ public static <T> CredentialsResult<T> from(final int status) { return new CredentialsResult<>(status, null, CacheDirective.noCacheDirective()); }