FileBasedTenantService implements TenantService, TenantManagementService, Lifecycle { private OperationResult<Id> add(final String tenantId, final Tenant tenantSpec, final Span span) { Objects.requireNonNull(tenantId); Objects.requireNonNull(tenantSpec); if (tenants.containsKey(tenantId)) { TracingHelper.logError(span, "Conflict: tenantId already exists"); return OperationResult.empty(HttpURLConnection.HTTP_CONFLICT); } try { if (LOG.isTraceEnabled()) { LOG.trace("adding tenant [id: {}]: {}", tenantId, JsonObject.mapFrom(tenantSpec).encodePrettily()); } final boolean existsConflictingTenant = tenantSpec.getTrustedCertificateAuthoritySubjectDNs() .stream().anyMatch(subjectDn -> getByCa(subjectDn) != null); if (existsConflictingTenant) { TracingHelper.logError(span, "Conflict: CA already used by an existing tenant"); return OperationResult.empty(HttpURLConnection.HTTP_CONFLICT); } else { final Versioned<Tenant> tenant = new Versioned<>(tenantSpec); tenants.put(tenantId, tenant); dirty.set(true); return OperationResult.ok(HttpURLConnection.HTTP_CREATED, Id.of(tenantId), Optional.empty(), Optional.of(tenant.getVersion())); } } catch (final IllegalArgumentException e) { LOG.debug("error parsing payload of add tenant request", e); TracingHelper.logError(span, e); return OperationResult.empty(HttpURLConnection.HTTP_BAD_REQUEST); } } @Autowired  FileBasedTenantService(final Vertx vertx); @Autowired void setConfig(final FileBasedTenantsConfigProperties configuration); @Override Future<Void> start(); @Override Future<Void> stop(); @Override Future<TenantResult<JsonObject>> get(final String tenantId); @Override Future<TenantResult<JsonObject>> get(final String tenantId, final Span span); @Override Future<TenantResult<JsonObject>> get(final X500Principal subjectDn); @Override Future<OperationResult<Tenant>> readTenant(final String tenantId, final Span span); @Override Future<TenantResult<JsonObject>> get(final X500Principal subjectDn, final Span span); @Override Future<Result<Void>> deleteTenant(final String tenantId, final Optional<String> resourceVersion,
            final Span span); @Override Future<OperationResult<Id>> createTenant(final Optional<String> tenantId, final Tenant tenantSpec,
            final Span span); @Override Future<OperationResult<Void>> updateTenant(final String tenantId, final Tenant tenantSpec,
            final Optional<String> expectedResourceVersion,
            final Span span); OperationResult<Void> update(
            final String tenantId,
            final Tenant tenantSpec,
            final Optional<String> expectedResourceVersion,
            final Span span); void clear(); @Override String toString();  }
@Test public void testConversion() { final TenantTracingConfig tracingConfig = new TenantTracingConfig(); tracingConfig.setSamplingMode(TracingSamplingMode.ALL); tracingConfig.setSamplingModePerAuthId(Map.of( "authId1", TracingSamplingMode.ALL, "authId2", TracingSamplingMode.DEFAULT)); final TrustedCertificateAuthority ca1 = new TrustedCertificateAuthority() .setSubjectDn("CN=test.org") .setKeyAlgorithm("EC") .setPublicKey("NOT_A_PUBLIC_KEY".getBytes()) .setNotBefore(Instant.now().minus(1, ChronoUnit.DAYS)) .setNotAfter(Instant.now().plus(2, ChronoUnit.DAYS)); final TrustedCertificateAuthority ca2 = new TrustedCertificateAuthority() .setSubjectDn("CN=test.org") .setKeyAlgorithm("RSA") .setPublicKey("NOT_A_PUBLIC_KEY".getBytes()) .setNotBefore(Instant.now().plus(1, ChronoUnit.DAYS)) .setNotAfter(Instant.now().plus(20, ChronoUnit.DAYS)); final Tenant source = new Tenant(); source.setEnabled(true); source.setTracing(tracingConfig); source.setDefaults(Map.of("ttl", 30)); source.setExtensions(Map.of("custom", "value")); source.setTrustedCertificateAuthorities(List.of(ca1, ca2)); final JsonObject tracingConfigJsonObject = new JsonObject(); tracingConfigJsonObject.put(TenantConstants.FIELD_TRACING_SAMPLING_MODE, "all"); final JsonObject tracingSamplingModeJsonObject = new JsonObject() .put("authId1", "all") .put("authId2", "default"); tracingConfigJsonObject.put(TenantConstants.FIELD_TRACING_SAMPLING_MODE_PER_AUTH_ID, tracingSamplingModeJsonObject); final JsonArray expectedAuthorities = new JsonArray().add(new JsonObject() .put(TenantConstants.FIELD_PAYLOAD_SUBJECT_DN, "CN=test.org") .put(TenantConstants.FIELD_PAYLOAD_PUBLIC_KEY, "NOT_A_PUBLIC_KEY".getBytes()) .put(TenantConstants.FIELD_PAYLOAD_KEY_ALGORITHM, "EC") .put(TenantConstants.FIELD_AUTO_PROVISIONING_ENABLED, false)); final JsonObject target = DeviceRegistryUtils.convertTenant("4711", source, true); assertThat(target.getString(TenantConstants.FIELD_PAYLOAD_TENANT_ID)).isEqualTo("4711"); assertThat(target.getBoolean(TenantConstants.FIELD_ENABLED)).isTrue(); assertThat(target.getJsonObject(TenantConstants.FIELD_TRACING)).isEqualTo(tracingConfigJsonObject); assertThat(target.getJsonArray(TenantConstants.FIELD_PAYLOAD_TRUSTED_CA)).isEqualTo(expectedAuthorities); assertThat(target.getJsonArray(TenantConstants.FIELD_ADAPTERS)).isNull(); final JsonObject defaults = target.getJsonObject(TenantConstants.FIELD_PAYLOAD_DEFAULTS); assertThat(defaults).isNotNull(); assertThat(defaults.getInteger("ttl")).isEqualTo(30); final JsonObject extensions = target.getJsonObject(RegistryManagementConstants.FIELD_EXT); assertThat(extensions).isNotNull(); assertThat(extensions.getString("custom")).isEqualTo("value"); }