/** * Retrieves credentials from the Credentials service. * * @param deviceCredentials The credentials provided by the device. * @return A future containing the credentials on record as retrieved from * Hono's <em>Credentials</em> API. * @throws NullPointerException if device credentials is {@code null}. */ protected final Future<CredentialsObject> getCredentialsForDevice(final DeviceCredentials deviceCredentials) { Objects.requireNonNull(deviceCredentials); if (credentialsServiceClient == null) { return Future.failedFuture(new IllegalStateException("Credentials API client is not set")); } else { return getCredentialsClient(deviceCredentials.getTenantId()).compose(client -> client.get(deviceCredentials.getType(), deviceCredentials.getAuthId())); } }
private Future<DeviceUser> authenticate(final DeviceCredentials credentials, final Span currentSpan) { final Future<DeviceUser> result = Future.future(); usernamePasswordAuthProvider.authenticate(credentials, handler -> { if (handler.succeeded()) { final DeviceUser authenticatedDevice = handler.result(); currentSpan.log("device authenticated"); LOG.debug("successfully authenticated device [tenant-id: {}, auth-id: {}, device-id: {}]", authenticatedDevice.getTenantId(), credentials.getAuthId(), authenticatedDevice.getDeviceId()); result.complete(authenticatedDevice); } else { LOG.debug("Failed to authenticate device [tenant-id: {}, auth-id: {}] ", credentials.getTenantId(), credentials.getAuthId(), handler.cause()); result.fail(handler.cause()); } }); return result; }
@Override protected Future<Device> validateCredentials( final DeviceCredentials deviceCredentials, final CredentialsObject credentialsOnRecord) { final Context currentContext = Vertx.currentContext(); if (currentContext == null) { return Future.failedFuture(new IllegalStateException("not running on vert.x Context")); } else { final Future<Device> resultHandler = Future.future(); currentContext.executeBlocking(blockingCodeHandler -> { log.debug("validating password hash on vert.x worker thread [{}]", Thread.currentThread().getName()); if (deviceCredentials.validate(credentialsOnRecord)) { blockingCodeHandler.complete(new Device(deviceCredentials.getTenantId(), credentialsOnRecord.getDeviceId())); } else { blockingCodeHandler.fail(new ClientErrorException(HttpURLConnection.HTTP_UNAUTHORIZED, "bad credentials")); } }, false, resultHandler); return resultHandler; } } }
private Future<Device> handleEndpointConnectionWithAuthentication(final MqttEndpoint endpoint, final Span currentSpan) { final Future<DeviceCredentials> credentialsTracker = getCredentials(endpoint); return credentialsTracker .compose(credentials -> authenticate(credentials, currentSpan)) .compose(device -> CompositeFuture.all( getTenantConfiguration(device.getTenantId(), currentSpan.context()) .compose(tenant -> isAdapterEnabled(tenant)), checkDeviceRegistration(device, currentSpan.context())) .map(ok -> device)) .compose(device -> createLinks(device, currentSpan)) .compose(device -> registerHandlers(endpoint, device)) .recover(t -> { if (credentialsTracker.result() == null) { LOG.debug("error establishing connection with device", t); } else { LOG.debug("cannot establish connection with device [tenant-id: {}, auth-id: {}]", credentialsTracker.result().getTenantId(), credentialsTracker.result().getAuthId(), t); } return Future.failedFuture(t); }); }
/** * Verifies that the credentials provided by a device during the authentication * process match the credentials on record for that device. * <p> * This default implementation simply invokes the {@link DeviceCredentials#validate(CredentialsObject)} * method in order to validate the credentials. * <p> * Subclasses may override this method in order to perform more specific checks * for certain types of credentials. * * @param deviceCredentials The credentials provided by the device. * @param credentialsOnRecord The credentials on record. * @return A future that is succeeded with the authenticated device if the * credentials have been validated successfully. Otherwise, the * future is failed with a {@link ServiceInvocationException}. */ protected Future<Device> validateCredentials( final DeviceCredentials deviceCredentials, final CredentialsObject credentialsOnRecord) { final Future<Device> result = Future.future(); if (deviceCredentials.validate(credentialsOnRecord)) { result.complete(new Device(deviceCredentials.getTenantId(), credentialsOnRecord.getDeviceId())); } else { result.fail(new ClientErrorException(HttpURLConnection.HTTP_UNAUTHORIZED, "bad credentials")); } return result; }
/** * Retrieves credentials from the Credentials service. * * @param deviceCredentials The credentials provided by the device. * @param spanContext The {@code SpanContext} (may be {@code null}). * @return A future containing the credentials on record as retrieved from * Hono's <em>Credentials</em> API. * @throws NullPointerException if device credentials is {@code null}. */ protected final Future<CredentialsObject> getCredentialsForDevice(final DeviceCredentials deviceCredentials, final SpanContext spanContext) { Objects.requireNonNull(deviceCredentials); if (credentialsServiceClient == null) { return Future.failedFuture(new IllegalStateException("Credentials API client is not set")); } else { return getCredentialsClient(deviceCredentials.getTenantId()).compose(client -> client.get(deviceCredentials.getType(), deviceCredentials.getAuthId(), new JsonObject(), spanContext)); } }