diff --git a/secret-provider/secret-provider-gateway/src/main/java/com/inductiveautomation/ignition/examples/secretprovider/mongodb/MongoDbSecretProviderExtensionPoint.java b/secret-provider/secret-provider-gateway/src/main/java/com/inductiveautomation/ignition/examples/secretprovider/mongodb/MongoDbSecretProviderExtensionPoint.java index f3ee808..9e04da5 100644 --- a/secret-provider/secret-provider-gateway/src/main/java/com/inductiveautomation/ignition/examples/secretprovider/mongodb/MongoDbSecretProviderExtensionPoint.java +++ b/secret-provider/secret-provider-gateway/src/main/java/com/inductiveautomation/ignition/examples/secretprovider/mongodb/MongoDbSecretProviderExtensionPoint.java @@ -20,6 +20,37 @@ public MongoDbSecretProviderExtensionPoint() { super(EXTENSION_POINT_TYPE, "MongoDbSecretProvider.SecretProviderType.Name", "MongoDbSecretProvider.SecretProviderType.Desc"); + + // The password in our configuration might be a referenced secret that points to a secret provider, so we need + // to add a reference property for it. We need to register our reference property and consume updates / renames + // of the SecretProvider to keep our configuration in sync. + addReferenceProperty("password", builder -> builder + .targetType(SecretProviderConfig.RESOURCE_TYPE) + .value(resource -> { + // Return the SecretProvider name if the password is a referenced secret. + SecretConfig secretConfig = resource.password(); + if (secretConfig != null && secretConfig.isReferenced()) { + return secretConfig.getAsReferenced().getProviderName(); + } + return null; + }) + .caseSensitive(true) + .onUpdate((resource, newName) -> { + // Return a new resource with the updated SecretProvider name if the password is a + // referenced secret. + SecretConfig secretConfig = resource.password(); + if (secretConfig != null && secretConfig.isReferenced()) { + return new MongoDbSecretProviderResource( + resource.connectionString(), + resource.databaseName(), + resource.username(), + SecretConfig.referenced(newName, secretConfig.getAsReferenced().getSecretName()), + resource.authenticationDb() + ); + } + return resource; // Should never get here, but return the original resource if we do. + }) + ); } public SecretProvider createProvider(SecretProviderContext context) throws SecretProviderTypeException { diff --git a/user-source-profile/README.md b/user-source-profile/README.md index 898fa1f..07ab3ac 100644 --- a/user-source-profile/README.md +++ b/user-source-profile/README.md @@ -1,4 +1,4 @@ -# UserSourceProfile +# User Source Profile This module provides an implementation of the `UserSourceProvider` interface, which allows for the management of user profiles in a system. It includes methods for creating, updating, and deleting user profiles, as well as retrieving user diff --git a/user-source-profile/user-source-gateway/src/main/java/com/inductiveautomation/ignition/examples/usersource/mongodb/MongoDbUserSource.java b/user-source-profile/user-source-gateway/src/main/java/com/inductiveautomation/ignition/examples/usersource/mongodb/MongoDbUserSource.java index 499bc3e..4fb4dab 100644 --- a/user-source-profile/user-source-gateway/src/main/java/com/inductiveautomation/ignition/examples/usersource/mongodb/MongoDbUserSource.java +++ b/user-source-profile/user-source-gateway/src/main/java/com/inductiveautomation/ignition/examples/usersource/mongodb/MongoDbUserSource.java @@ -27,12 +27,11 @@ import org.apache.log4j.Level; import org.bson.Document; import org.bson.conversions.Bson; -import org.joda.time.DateTime; -import org.joda.time.Days; import javax.annotation.Nonnull; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -264,13 +263,9 @@ private boolean isPasswordInvalid(Document document, String pwd, boolean bypassE // Password is valid, now check if the password is expired if (settings.passwordMaxAge() > 0 && !bypassExpiration) { long pwdTimestamp = document.getLong(KEY_PASSWORD_DATE); - if (pwdTimestamp > 0) { - DateTime passwordCreatedOn = new DateTime(pwdTimestamp); - DateTime now = DateTime.now(); - int days = Days.daysBetween(passwordCreatedOn.toLocalDate(), now.toLocalDate()).getDays(); - if (days > settings.passwordMaxAge()) { - throw new PasswordExpiredException(getName(), uname); - } + long pwdExpiration = pwdTimestamp + TimeUnit.DAYS.toMillis(settings.passwordMaxAge()); + if (pwdTimestamp > 0 && System.currentTimeMillis() >= pwdExpiration) { + throw new PasswordExpiredException(getName(), uname); } } diff --git a/user-source-profile/user-source-gateway/src/main/java/com/inductiveautomation/ignition/examples/usersource/mongodb/MongoDbUserSourceExtensionPoint.java b/user-source-profile/user-source-gateway/src/main/java/com/inductiveautomation/ignition/examples/usersource/mongodb/MongoDbUserSourceExtensionPoint.java index f6fb1c3..542206e 100644 --- a/user-source-profile/user-source-gateway/src/main/java/com/inductiveautomation/ignition/examples/usersource/mongodb/MongoDbUserSourceExtensionPoint.java +++ b/user-source-profile/user-source-gateway/src/main/java/com/inductiveautomation/ignition/examples/usersource/mongodb/MongoDbUserSourceExtensionPoint.java @@ -5,6 +5,8 @@ import com.inductiveautomation.ignition.gateway.config.ValidationErrors; import com.inductiveautomation.ignition.gateway.dataroutes.openapi.SchemaUtil; import com.inductiveautomation.ignition.gateway.model.GatewayContext; +import com.inductiveautomation.ignition.gateway.secrets.SecretConfig; +import com.inductiveautomation.ignition.gateway.secrets.SecretProviderConfig; import com.inductiveautomation.ignition.gateway.user.UserSourceExtensionPoint; import com.inductiveautomation.ignition.gateway.user.UserSourceProfile; import com.inductiveautomation.ignition.gateway.user.UserSourceProfileConfig; @@ -26,6 +28,39 @@ public MongoDbUserSourceExtensionPoint() { "MongoDbUserSource.UserSourceType.Name", "MongoDbUserSource.UserSourceType.Desc", MongoDbUserSourceResource.class); + + // The password in our configuration might be a referenced secret that points to a secret provider, so we need + // to add a reference property for it. We need to register our reference property and consume updates / renames + // of the SecretProvider to keep our configuration in sync. + addReferenceProperty("password", builder -> builder + .targetType(SecretProviderConfig.RESOURCE_TYPE) + .value(resource -> { + // Return the SecretProvider name if the password is a referenced secret. + SecretConfig secretConfig = resource.password(); + if (secretConfig != null && secretConfig.isReferenced()) { + return secretConfig.getAsReferenced().getProviderName(); + } + return null; + }) + .caseSensitive(true) + .onUpdate((resource, newName) -> { + // Return a new resource with the updated SecretProvider name if the password is a + // referenced secret. + SecretConfig secretConfig = resource.password(); + if (secretConfig != null && secretConfig.isReferenced()) { + return new MongoDbUserSourceResource( + resource.connectionString(), + resource.databaseName(), + resource.username(), + SecretConfig.referenced(newName, secretConfig.getAsReferenced().getSecretName()), + resource.authenticationDb(), + resource.passwordMaxAge(), + resource.passwordHistory() + ); + } + return resource; // Should never get here, but return the original resource if we do. + }) + ); } @Override