CredentialsApiAuthProvider implements
        DeviceCredentialsAuthProvider<T> { @Override public final void authenticate( final T deviceCredentials, final SpanContext spanContext, final Handler<AsyncResult<DeviceUser>> resultHandler) { Objects.requireNonNull(deviceCredentials); Objects.requireNonNull(resultHandler); final Span currentSpan = TracingHelper.buildServerChildSpan(tracer, spanContext, "authenticate device", getClass().getSimpleName()) .withTag(MessageHelper.APP_PROPERTY_TENANT_ID, deviceCredentials.getTenantId()) .withTag(TracingHelper.TAG_AUTH_ID.getKey(), deviceCredentials.getAuthId()) .start(); getCredentialsForDevice(deviceCredentials, currentSpan.context()) .recover(t -> { if (t instanceof ServiceInvocationException) { final ServiceInvocationException e = (ServiceInvocationException) t; if (e.getErrorCode() == HttpURLConnection.HTTP_NOT_FOUND) { return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_UNAUTHORIZED, "bad credentials")); } } return Future.failedFuture(t); }).compose(credentialsOnRecord -> validateCredentials(deviceCredentials, credentialsOnRecord, currentSpan.context())) .map(device -> new DeviceUser(device.getTenantId(), device.getDeviceId())) .onComplete(authAttempt -> { if (authAttempt.succeeded()) { currentSpan.log("successfully authenticated device"); } else { currentSpan.log("authentication of device failed"); TracingHelper.logError(currentSpan, authAttempt.cause()); } currentSpan.finish(); resultHandler.handle(authAttempt); }); } CredentialsApiAuthProvider(final CredentialsClientFactory credentialsClientFactory, final Tracer tracer); @Override final void authenticate(
            final T deviceCredentials,
            final SpanContext spanContext,
            final Handler<AsyncResult<DeviceUser>> resultHandler); @Override final void authenticate(final JsonObject authInfo, final Handler<AsyncResult<User>> resultHandler);  }
@Test public void testAuthenticateFailsWithExceptionReportedByCredentialsClient(final VertxTestContext ctx) { final ServerErrorException reportedException = new ServerErrorException(503); when(credentialsClient.get(anyString(), anyString(), any(JsonObject.class), any())).thenReturn(Future.failedFuture(reportedException)); provider.authenticate(new JsonObject(), ctx.failing(t -> { ctx.verify(() -> assertThat(t).isEqualTo(reportedException)); ctx.completeNow(); })); }
@Test public void testAuthenticateFailsWith401ForMalformedCredentials(final VertxTestContext ctx) { provider = getProvider(null, NoopTracerFactory.create()); provider.authenticate(new JsonObject(), ctx.failing(t -> { ctx.verify(() -> assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAUTHORIZED)); ctx.completeNow(); })); }
@Test public void testAuthenticateFailsWith401ForNonExistingAuthId(final VertxTestContext ctx) { when(credentialsClient.get(anyString(), eq("user"), any(JsonObject.class), any())) .thenReturn(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND))); provider.authenticate(new JsonObject(), ctx.failing(t -> { ctx.verify(() -> assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAUTHORIZED)); ctx.completeNow(); })); }
@Test public void testValidateFailsIfCredentialsAreDisabled(final VertxTestContext ctx) { final AbstractDeviceCredentials creds = getDeviceCredentials("type", "tenant", "identity"); final CredentialsObject credentialsOnRecord = getCredentialsObject("type", "identity", "device", false) .addSecret(CredentialsObject.emptySecret(Instant.now().minusSeconds(120), null)); when(credentialsClient.get(eq("type"), eq("identity"), any(JsonObject.class), any())) .thenReturn(Future.succeededFuture(credentialsOnRecord)); provider.authenticate(creds, null, ctx.failing(t -> { ctx.verify(() -> assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAUTHORIZED)); ctx.completeNow(); })); }