use of org.eclipse.hono.service.management.credentials.CommonCredential in project hono by eclipse.
the class CredentialsApiTests method testGetCredentialsFailsForNonMatchingClientContext.
/**
* Verifies that a request for credentials using a client context that does not match
* the credentials on record fails with a 404.
*
* @param ctx The vert.x test context.
*/
@Timeout(value = 5, timeUnit = TimeUnit.SECONDS)
@Test
public void testGetCredentialsFailsForNonMatchingClientContext(final VertxTestContext ctx) {
final String deviceId = getHelper().getRandomDeviceId(tenantId);
final String authId = UUID.randomUUID().toString();
final CommonCredential credentials = getRandomHashedPasswordCredential(authId).putExtension("client-id", UUID.randomUUID().toString());
final JsonObject clientContext = new JsonObject().put("client-id", "non-matching");
getHelper().registry.registerDevice(tenantId, deviceId).compose(httpResponse -> getHelper().registry.addCredentials(tenantId, deviceId, List.of(credentials))).compose(ok -> getClient().get(tenantId, CredentialsConstants.SECRETS_TYPE_HASHED_PASSWORD, authId, clientContext, spanContext)).onComplete(ctx.failing(t -> {
ctx.verify(() -> assertErrorCode(t, HttpURLConnection.HTTP_NOT_FOUND));
ctx.completeNow();
}));
}
use of org.eclipse.hono.service.management.credentials.CommonCredential in project hono by eclipse.
the class CredentialsApiTests method testGetCredentialsSucceedsForNonExistingClientContext.
/**
* Verifies that a request for credentials using a client context succeeds if the credentials on record
* do not have any extension properties with keys matching the provided client context.
*
* @param ctx The vert.x test context.
*/
@Timeout(value = 5, timeUnit = TimeUnit.SECONDS)
@Test
public void testGetCredentialsSucceedsForNonExistingClientContext(final VertxTestContext ctx) {
final String deviceId = getHelper().getRandomDeviceId(tenantId);
final String authId = UUID.randomUUID().toString();
final CommonCredential credentials = getRandomHashedPasswordCredential(authId).putExtension("other", "property");
final JsonObject clientContext = new JsonObject().put("client-id", "gateway-one");
getHelper().registry.registerDevice(tenantId, deviceId).compose(httpResponse -> getHelper().registry.addCredentials(tenantId, deviceId, List.of(credentials))).compose(httpResponse -> getClient().get(tenantId, CredentialsConstants.SECRETS_TYPE_HASHED_PASSWORD, authId, clientContext, spanContext)).onComplete(ctx.succeeding(credentialsObject -> {
ctx.verify(() -> {
assertThat(credentialsObject.getSecrets()).isNotEmpty();
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.service.management.credentials.CommonCredential in project hono by eclipse.
the class AbstractCredentialsManagementService method updateCredentials.
@Override
public final Future<OperationResult<Void>> updateCredentials(final String tenantId, final String deviceId, final List<CommonCredential> credentials, final Optional<String> resourceVersion, final Span span) {
Objects.requireNonNull(tenantId);
Objects.requireNonNull(deviceId);
Objects.requireNonNull(credentials);
Objects.requireNonNull(resourceVersion);
Objects.requireNonNull(span);
return this.tenantInformationService.getTenant(tenantId, span).compose(tenant -> tenant.checkCredentialsLimitExceeded(tenantId, credentials)).compose(ok -> verifyAndEncodePasswords(credentials)).compose(encodedCredentials -> processUpdateCredentials(DeviceKey.from(tenantId, deviceId), encodedCredentials, resourceVersion, span)).onSuccess(result -> NotificationEventBusSupport.sendNotification(vertx, new CredentialsChangeNotification(tenantId, deviceId, Instant.now()))).recover(t -> DeviceRegistryUtils.mapError(t, tenantId));
}
use of org.eclipse.hono.service.management.credentials.CommonCredential in project hono by eclipse.
the class DeviceAndGatewayAutoProvisionerTest method provisionAndVerifySuccessfulResult.
@SuppressWarnings("unchecked")
private void provisionAndVerifySuccessfulResult(final VertxTestContext ctx, final boolean isGateway, final String expectedDeviceId) throws CertificateEncodingException {
final JsonObject clientContext = new JsonObject().put(CredentialsConstants.FIELD_CLIENT_CERT, cert.getEncoded());
// WHEN provisioning a device/gateway from a certificate
deviceAndGatewayAutoProvisioner.provisionIfEnabled(tenantId, tenant, subjectDn, clientContext, NoopSpan.INSTANCE).onComplete(ctx.succeeding(result -> {
ctx.verify(() -> {
// VERIFY that that the device/gateway has been registered.
final ArgumentCaptor<Device> deviceCaptor = ArgumentCaptor.forClass(Device.class);
verify(deviceManagementService).createDevice(eq(tenantId), any(), deviceCaptor.capture(), any());
if (isGateway) {
// VERIFY that a gateway has been provisioned by checking the relevant property
assertThat(deviceCaptor.getValue().getAuthorities()).contains(RegistryManagementConstants.AUTHORITY_AUTO_PROVISIONING_ENABLED);
}
// VERIFY that the correct credentials are stored
final ArgumentCaptor<List<CommonCredential>> credentialsCaptor = ArgumentCaptor.forClass(List.class);
verify(credentialsManagementService).updateCredentials(eq(tenantId), eq(expectedDeviceId), credentialsCaptor.capture(), any(), any());
final List<CommonCredential> credentialsCaptorValue = credentialsCaptor.getValue();
assertThat(credentialsCaptorValue.size()).isEqualTo(1);
assertThat(credentialsCaptorValue.get(0).getType()).isEqualTo(RegistryManagementConstants.SECRETS_TYPE_X509_CERT);
assertThat(credentialsCaptorValue.get(0).getAuthId()).isEqualTo(subjectDn);
// VERIFY the returned credentials result after successful auto-provisioning
assertThat(result.getStatus()).isEqualTo(HttpURLConnection.HTTP_CREATED);
final JsonObject returnedCredential = result.getPayload();
assertThat(returnedCredential.getString(RegistryManagementConstants.FIELD_PAYLOAD_DEVICE_ID)).isEqualTo(expectedDeviceId);
assertThat(returnedCredential.getString(RegistryManagementConstants.FIELD_AUTH_ID)).isEqualTo(subjectDn);
assertThat(returnedCredential.getString(RegistryManagementConstants.FIELD_TYPE)).isEqualTo(RegistryManagementConstants.SECRETS_TYPE_X509_CERT);
// VERIFY that a auto-provisioning notification has been sent
final ArgumentCaptor<Map<String, Object>> messagePropertiesArgumentCaptor = ArgumentCaptor.forClass(Map.class);
verify(sender).sendEvent(argThat(tenant -> tenant.getTenantId().equals(tenantId)), argThat(assertion -> assertion.getDeviceId().equals(expectedDeviceId)), eq(EventConstants.CONTENT_TYPE_DEVICE_PROVISIONING_NOTIFICATION), any(), messagePropertiesArgumentCaptor.capture(), any());
final Map<String, Object> eventProperties = messagePropertiesArgumentCaptor.getValue();
assertThat(eventProperties.get(MessageHelper.APP_PROPERTY_REGISTRATION_STATUS)).isEqualTo(EventConstants.RegistrationStatus.NEW.name());
assertThat(eventProperties.get(MessageHelper.APP_PROPERTY_TENANT_ID)).isEqualTo(tenantId);
// VERIFY that the device registration has been updated as the auto-provisioning event has been
// successfully sent
verify(deviceManagementService).updateDevice(eq(tenantId), eq(expectedDeviceId), deviceCaptor.capture(), any(), any());
final DeviceStatus deviceStatus = deviceCaptor.getValue().getStatus();
assertThat(deviceStatus.isAutoProvisioned()).isTrue();
assertThat(deviceStatus.isAutoProvisioningNotificationSent()).isTrue();
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.service.management.credentials.CommonCredential in project hono by eclipse.
the class TableManagementStore method setCredentials.
/**
* Set all credentials for a device.
* <p>
* This will set/update all credentials of the device. If the device does not exist, the result
* will be {@code false}. If the update was successful, then the result will be {@code true}.
* If the resource version was provided, but the provided version was no longer the current version,
* then the future will fail with a {@link OptimisticLockingException}.
*
* @param key The key of the device to update.
* @param credentials The credentials to set.
* @param resourceVersion The optional resource version to update.
* @param spanContext The span to contribute to.
* @return A future, tracking the outcome of the operation.
*/
public Future<Versioned<Boolean>> setCredentials(final DeviceKey key, final List<CommonCredential> credentials, final Optional<String> resourceVersion, final SpanContext spanContext) {
final Span span = TracingHelper.buildChildSpan(this.tracer, spanContext, "set credentials", getClass().getSimpleName()).withTag(TracingHelper.TAG_TENANT_ID, key.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, key.getDeviceId()).withTag("num_credentials", credentials.size()).start();
resourceVersion.ifPresent(version -> span.setTag("version", version));
final String nextVersion = UUID.randomUUID().toString();
return SQL.runTransactionally(this.client, this.tracer, span.context(), (connection, context) -> readDeviceForUpdate(connection, key, context).compose(result -> extractVersionForUpdate(result, resourceVersion)).compose(version -> Future.succeededFuture().compose(x -> {
final Promise<CredentialsDto> result = Promise.promise();
final var updatedCredentialsDto = CredentialsDto.forUpdate(key.getTenantId(), key.getDeviceId(), credentials, nextVersion);
if (updatedCredentialsDto.requiresMerging()) {
getCredentialsDto(key, connection, span).map(updatedCredentialsDto::merge).onComplete(result);
} else {
// simply replace the existing credentials with the
// updated ones provided by the client
result.complete(updatedCredentialsDto);
}
return result.future();
}).compose(updatedCredentials -> this.deleteAllCredentialsStatement.expand(map -> {
map.put("tenant_id", key.getTenantId());
map.put("device_id", key.getDeviceId());
}).trace(this.tracer, span.context()).update(connection).map(updatedCredentials)).compose(updatedCredentials -> {
updatedCredentials.createMissingSecretIds();
return CompositeFuture.all(updatedCredentials.getData().stream().map(JsonObject::mapFrom).filter(c -> c.containsKey("type") && c.containsKey("auth-id")).map(c -> this.insertCredentialEntryStatement.expand(map -> {
map.put("tenant_id", key.getTenantId());
map.put("device_id", key.getDeviceId());
map.put("type", c.getString("type"));
map.put("auth_id", c.getString("auth-id"));
map.put("data", c.toString());
}).trace(this.tracer, span.context()).update(connection)).collect(Collectors.toList())).mapEmpty();
}).compose(x -> this.updateDeviceVersionStatement.expand(map -> {
map.put("tenant_id", key.getTenantId());
map.put("device_id", key.getDeviceId());
map.put("expected_version", version);
map.put("next_version", nextVersion);
}).trace(this.tracer, span.context()).update(connection).compose(TableManagementStore::checkUpdateOutcome)).map(true))).recover(err -> recoverNotFound(span, err, () -> false)).map(ok -> new Versioned<>(nextVersion, ok)).onComplete(x -> span.finish());
}
Aggregations