Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#2825] Extend credentials management service to support auth-id template #2985

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public final class CredentialsConstants extends RequestResponseApiConstants {
* The name of the field that contains the authentication identifier.
*/
public static final String FIELD_AUTH_ID = "auth-id";
/**
* The name of the field that contains the generated authentication identifier
* by applying the template to the subject DN.
*/
public static final String FIELD_GENERATED_AUTH_ID = "generated-auth-id";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we still need this constant now that we do not expose the generated ID field anymore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is still being used in CredentialsServiceImpl.

/**
* The name of the field that contains the secret(s) of the credentials.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ public final class RegistryManagementConstants extends RequestResponseApiConstan
* The name of the field that contains the authentication identifier.
*/
public static final String FIELD_AUTH_ID = "auth-id";
/**
* The name of the field that contains the generated authentication identifier
* by applying the template to the subject DN.
*/
public static final String FIELD_GENERATED_AUTH_ID = "generated-auth-id";
/**
* The name of the field that contains the issuer DN of the client certificate.
*/
public static final String FIELD_ISSUER_DN = "issuer-dn";
/**
* The name of the field that contains the secret(s) of the credentials.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.eclipse.hono.service.management.device.Device;
import org.eclipse.hono.service.management.tenant.Tenant;
import org.eclipse.hono.tracing.TracingHelper;
import org.eclipse.hono.util.RegistryManagementConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -162,6 +163,7 @@ public TableManagementStore(final SQLClient client, final Tracer tracer, final S
"device_id",
"type",
"auth_id",
"generated_auth_id",
"data");

this.deleteAllCredentialsStatement = cfg
Expand Down Expand Up @@ -692,8 +694,9 @@ public Future<Versioned<Boolean>> setCredentials(
.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("type", c.getString(RegistryManagementConstants.FIELD_TYPE));
map.put("auth_id", c.getString(RegistryManagementConstants.FIELD_AUTH_ID));
map.put("generated_auth_id", c.getString(RegistryManagementConstants.FIELD_GENERATED_AUTH_ID));
map.put("data", c.toString());
})
.trace(this.tracer, span.context())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ insertCredentialEntry: |
device_id,
type,
auth_id,
generated_auth_id,
data
) VALUES (
:tenant_id,
:device_id,
:type,
:auth_id,
:generated_auth_id,
:data::jsonb
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ findCredentials: |
WHERE
tenant_id=:tenant_id
AND
auth_id=:auth_id
COALESCE(generated_auth_id, auth_id)=:auth_id
AND
type=:type

Expand All @@ -112,12 +112,14 @@ insertCredentialEntry: |
device_id,
type,
auth_id,
generated_auth_id,
data
) VALUES (
:tenant_id,
:device_id,
:type,
:auth_id,
:generated_auth_id,
:data
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ CREATE TABLE IF NOT EXISTS device_credentials
TENANT_ID VARCHAR(256) NOT NULL,
DEVICE_ID VARCHAR(256) NOT NULL,

TYPE VARCHAR(64) NOT NULL,
AUTH_ID VARCHAR(256) NOT NULL,
TYPE VARCHAR(64) NOT NULL,
AUTH_ID VARCHAR(256) NOT NULL,
GENERATED_AUTH_ID VARCHAR(256),

DATA TEXT,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ CREATE TABLE IF NOT EXISTS device_credentials
TENANT_ID VARCHAR(36) NOT NULL,
DEVICE_ID VARCHAR(256) NOT NULL,

TYPE VARCHAR(64) NOT NULL,
AUTH_ID VARCHAR(256) NOT NULL,
TYPE VARCHAR(64) NOT NULL,
AUTH_ID VARCHAR(256) NOT NULL,
GENERATED_AUTH_ID VARCHAR(256),

DATA JSONB,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.eclipse.hono.service.management.credentials.CommonCredential;
import org.eclipse.hono.service.management.credentials.CredentialsManagementService;
import org.eclipse.hono.service.management.credentials.PasswordCredential;
import org.eclipse.hono.service.management.credentials.X509CertificateCredential;
import org.eclipse.hono.service.management.tenant.Tenant;
import org.eclipse.hono.util.Futures;
import org.eclipse.hono.util.Lifecycle;
import org.eclipse.hono.util.Strings;
Expand Down Expand Up @@ -177,10 +179,11 @@ public final Future<OperationResult<Void>> updateCredentials(
Objects.requireNonNull(resourceVersion);
Objects.requireNonNull(span);

return this.tenantInformationService
.getTenant(tenantId, span)
final Future<Tenant> tenantFuture = tenantInformationService.getTenant(tenantId, span);
return tenantFuture
.compose(tenant -> tenant.checkCredentialsLimitExceeded(tenantId, credentials))
.compose(ok -> verifyAndEncodePasswords(credentials))
.compose(ok -> applyAuthIdTemplateForX509CertificateCredentials(tenantFuture.result(), credentials))
.compose(this::verifyAndEncodePasswords)
.compose(encodedCredentials -> processUpdateCredentials(
DeviceKey.from(tenantId, deviceId),
encodedCredentials,
Expand Down Expand Up @@ -279,4 +282,13 @@ protected List<CommonCredential> checkCredentials(final List<CommonCredential> c
return credentials;
}

private static Future<List<CommonCredential>> applyAuthIdTemplateForX509CertificateCredentials(
final Tenant tenant,
final List<CommonCredential> credentials) {
credentials.stream()
.filter(X509CertificateCredential.class::isInstance)
.map(X509CertificateCredential.class::cast)
.forEach(c -> c.applyAuthIdTemplate(tenant));
return Future.succeededFuture(credentials);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.eclipse.hono.util.CredentialsConstants;
import org.eclipse.hono.util.CredentialsResult;
import org.eclipse.hono.util.Lifecycle;
import org.eclipse.hono.util.RegistryManagementConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -180,6 +181,7 @@ public final Future<CredentialsResult<JsonObject>> get(
}
});
})
.map(AbstractCredentialsService::overrideAuthIdWithGeneratedAuthIdIfExists)
.recover(error -> {
LOG.debug("error getting credentials [tenant: {}, type: {}, auth-id: {}]", tenantId, type, authId, error);
TracingHelper.logError(span, error);
Expand All @@ -190,8 +192,20 @@ public final Future<CredentialsResult<JsonObject>> get(
});
}

private static CredentialsResult<JsonObject> overrideAuthIdWithGeneratedAuthIdIfExists(
final CredentialsResult<JsonObject> credentialsResult) {
if (!credentialsResult.isError()) {
final JsonObject credential = credentialsResult.getPayload();
Optional.ofNullable(credential)
.map(c -> c.getString(RegistryManagementConstants.FIELD_TYPE))
.filter(RegistryManagementConstants.SECRETS_TYPE_X509_CERT::equals)
.map(ok -> credential.getString(RegistryManagementConstants.FIELD_GENERATED_AUTH_ID))
.ifPresent(id -> credential.put(RegistryManagementConstants.FIELD_AUTH_ID, id));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is the Credentials service, I would assume that all these constants should be defined in CredentialsConstants, right?

}
return credentialsResult;
}

private boolean isAutoProvisioningConfigured() {
return this.deviceAndGatewayAutoProvisioner != null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ private DeviceRegistryUtils() {
*/
public static <T> Future<T> mapError(final Throwable error, final String tenantId) {
if (error instanceof IllegalArgumentException) {
return Future.failedFuture(new ClientErrorException(tenantId, HttpURLConnection.HTTP_BAD_REQUEST, error.getMessage()));
return Future.failedFuture(
new ClientErrorException(tenantId, HttpURLConnection.HTTP_BAD_REQUEST, error.getMessage(), error));
}
return Future.failedFuture(error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ public static PskCredential createPSKCredential(final String authId, final Strin
return new PskCredential(authId, List.of(s));
}

/**
* Creates a X509 certificate based credential from the given subject DN.
*
* @param subjectDN The subject DN.
* @return The X509 certificate credential.
*/
public static X509CertificateCredential createX509CertificateCredential(final String subjectDN) {
return X509CertificateCredential.fromSubjectDn(subjectDN, List.of(new X509CertificateSecret()));
}

/**
* Creates a password type based credential containing a hashed password secret.
*
Expand Down
Loading