FileBasedCredentialsService extends AbstractCredentialsManagementService implements CredentialsService, Lifecycle { @Override public Future<Void> start() { final Promise<Void> startPromise = Promise.promise(); if (running.compareAndSet(false, true)) { if (!getConfig().isModificationEnabled()) { LOG.info("modification of credentials has been disabled"); } if (getConfig().getFilename() == null) { LOG.debug("credentials filename is not set, no credentials will be loaded"); startPromise.complete(); } else { checkFileExists(getConfig().isSaveToFile()) .compose(ok -> loadCredentials()) .onSuccess(ok -> { if (getConfig().isSaveToFile()) { LOG.info("saving credentials to file every 3 seconds"); vertx.setPeriodic(3000, saveIdentities -> saveToFile()); } else { LOG.info("persistence is disabled, will not save credentials to file"); } }) .onFailure(t -> { LOG.error("failed to start up service", t); running.set(false); }) .onComplete(startPromise); } } else { startPromise.complete(); } return startPromise.future(); } @Autowired  FileBasedCredentialsService(
            final Vertx vertx,
            final FileBasedCredentialsConfigProperties configuration,
            final HonoPasswordEncoder passwordEncoder); FileBasedCredentialsConfigProperties getConfig(); @Override Future<Void> start(); @Override Future<Void> stop(); @Override Future<CredentialsResult<JsonObject>> get(final String tenantId, final String type, final String authId,
            final Span span); @Override Future<CredentialsResult<JsonObject>> get(
            final String tenantId,
            final String type,
            final String authId,
            final JsonObject clientContext,
            final Span span); void remove(
            final String tenantId,
            final String deviceId,
            final Span span,
            final Handler<AsyncResult<Result<Void>>> resultHandler); @Override Future<CredentialsResult<JsonObject>> get(final String tenantId, final String type, final String authId); @Override Future<CredentialsResult<JsonObject>> get(final String tenantId, final String type, final String authId,
            final JsonObject clientContext); void clear(); @Override String toString(); static final String ARRAY_CREDENTIALS; static final String FIELD_TENANT; }
@SuppressWarnings({ "unchecked", "rawtypes" }) @Test public void testDoStartCreatesFile(final VertxTestContext ctx) { credentialsConfig.setSaveToFile(true); credentialsConfig.setFilename(CREDENTIALS_FILE_NAME); registrationConfig.setSaveToFile(true); registrationConfig.setFilename(REGISTRATION_FILE_NAME); when(fileSystem.existsBlocking(credentialsConfig.getFilename())).thenReturn(Boolean.FALSE); when(fileSystem.existsBlocking(registrationConfig.getFilename())).thenReturn(Boolean.FALSE); doAnswer(invocation -> { final Handler handler = invocation.getArgument(1); handler.handle(Future.succeededFuture()); return null; }).when(fileSystem).createFile(eq(credentialsConfig.getFilename()), any(Handler.class)); doAnswer(invocation -> { final Handler handler = invocation.getArgument(1); handler.handle(Future.failedFuture("malformed file")); return null; }).when(fileSystem).readFile(eq(credentialsConfig.getFilename()), any(Handler.class)); doAnswer(invocation -> { final Handler handler = invocation.getArgument(1); handler.handle(Future.succeededFuture()); return null; }).when(fileSystem).createFile(eq(registrationConfig.getFilename()), any(Handler.class)); doAnswer(invocation -> { final Handler handler = invocation.getArgument(1); handler.handle(Future.failedFuture("malformed file")); return null; }).when(fileSystem).readFile(eq(registrationConfig.getFilename()), any(Handler.class)); final Promise<?> startupTracker = Promise.promise(); startupTracker.future().onComplete(ctx.succeeding(started -> ctx.verify(() -> { verify(fileSystem).createFile(eq(credentialsConfig.getFilename()), any(Handler.class)); ctx.completeNow(); }))); start(startupTracker); }
@SuppressWarnings({ "unchecked" }) @Test public void testDoStartFailsIfFileCannotBeCreated(final VertxTestContext ctx) { credentialsConfig.setSaveToFile(true); credentialsConfig.setFilename(CREDENTIALS_FILE_NAME); when(fileSystem.existsBlocking(credentialsConfig.getFilename())).thenReturn(Boolean.FALSE); doAnswer(invocation -> { final Handler<AsyncResult<Void>> handler = invocation.getArgument(1); handler.handle(Future.failedFuture("no access")); return null; }).when(fileSystem).createFile(eq(credentialsConfig.getFilename()), any(Handler.class)); final Promise<Void> startupTracker = Promise.promise(); startupTracker.future().onComplete(ctx.failing(started -> { ctx.completeNow(); })); start(startupTracker); }
@SuppressWarnings({ "unchecked" }) @Test public void testDoStartIgnoresMalformedJson(final VertxTestContext ctx) { credentialsConfig.setFilename(CREDENTIALS_FILE_NAME); when(fileSystem.existsBlocking(credentialsConfig.getFilename())).thenReturn(Boolean.TRUE); doAnswer(invocation -> { final Handler<AsyncResult<Buffer>> handler = invocation.getArgument(1); handler.handle(Future.succeededFuture(Buffer.buffer("NO JSON"))); return null; }).when(fileSystem).readFile(eq(credentialsConfig.getFilename()), any(Handler.class)); registrationConfig.setFilename(REGISTRATION_FILE_NAME); when(fileSystem.existsBlocking(registrationConfig.getFilename())).thenReturn(Boolean.TRUE); doAnswer(invocation -> { final Handler<AsyncResult<Buffer>> handler = invocation.getArgument(1); handler.handle(Future.succeededFuture(Buffer.buffer("NO JSON"))); return null; }).when(fileSystem).readFile(eq(registrationConfig.getFilename()), any(Handler.class)); final Promise<Void> startupTracker = Promise.promise(); startupTracker.future().onComplete(ctx.succeeding(started -> { ctx.completeNow(); })); start(startupTracker); }
@SuppressWarnings({ "unchecked" }) @Test public void testDoStartLoadsCredentials(final VertxTestContext ctx) { credentialsConfig.setFilename(CREDENTIALS_FILE_NAME); when(fileSystem.existsBlocking(credentialsConfig.getFilename())).thenReturn(Boolean.TRUE); doAnswer(invocation -> { final Buffer data = DeviceRegistryTestUtils.readFile(credentialsConfig.getFilename()); final Handler<AsyncResult<Buffer>> handler = invocation.getArgument(1); handler.handle(Future.succeededFuture(data)); return null; }).when(fileSystem).readFile(eq(credentialsConfig.getFilename()), any(Handler.class)); registrationConfig.setFilename(REGISTRATION_FILE_NAME); when(fileSystem.existsBlocking(registrationConfig.getFilename())).thenReturn(Boolean.TRUE); doAnswer(invocation -> { final Buffer data = DeviceRegistryTestUtils.readFile(registrationConfig.getFilename()); final Handler<AsyncResult<Buffer>> handler = invocation.getArgument(1); handler.handle(Future.succeededFuture(data)); return null; }).when(fileSystem).readFile(eq(registrationConfig.getFilename()), any(Handler.class)); final Promise<Void> startTracker = Promise.promise(); startTracker.future() .compose(s -> assertRegistered(getCredentialsService(), Constants.DEFAULT_TENANT, "sensor1", CredentialsConstants.SECRETS_TYPE_HASHED_PASSWORD)) .compose(s -> getCredentialsManagementService() .readCredentials(Constants.DEFAULT_TENANT, "4711", NoopSpan.INSTANCE) .map(r -> { if (r.getStatus() == HttpURLConnection.HTTP_OK) { return null; } else { throw new ClientErrorException(HttpURLConnection.HTTP_PRECON_FAILED); } })) .onComplete(ctx.completing()); start(startTracker); }
@SuppressWarnings({ "unchecked" }) @Test public void testDoStartIgnoreCredentialIfStartEmptyIsSet(final VertxTestContext ctx) { credentialsConfig.setFilename(CREDENTIALS_FILE_NAME); credentialsConfig.setStartEmpty(true); registrationConfig.setFilename(REGISTRATION_FILE_NAME); registrationConfig.setStartEmpty(true); when(fileSystem.existsBlocking(credentialsConfig.getFilename())).thenReturn(Boolean.TRUE); when(fileSystem.existsBlocking(registrationConfig.getFilename())).thenReturn(Boolean.TRUE); final Promise<Void> startTracker = Promise.promise(); startTracker.future().onComplete(ctx.succeeding(s -> ctx.verify(() -> { verify(fileSystem, never()).readFile(anyString(), any(Handler.class)); ctx.completeNow(); }))); start(startTracker); }