diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessageList.java b/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessageList.java index e79bffc7723..d81cd7441b5 100644 --- a/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessageList.java +++ b/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessageList.java @@ -10,6 +10,8 @@ import jakarta.xml.bind.annotation.XmlRootElement; import java.util.List; +import io.jans.model.error.ErrorMessage; + /** * Represents an error message list in a configuration XML file. diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessages.java b/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessages.java index 3d5322b56b1..b0cf4746a93 100644 --- a/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessages.java +++ b/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessages.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.jans.model.error.ErrorMessage; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlElement; diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorResponseFactory.java b/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorResponseFactory.java index b873c1243c8..e5b7434a122 100644 --- a/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorResponseFactory.java +++ b/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorResponseFactory.java @@ -24,6 +24,7 @@ import io.jans.as.model.uma.UmaErrorResponseType; import io.jans.as.model.userinfo.UserInfoErrorResponseType; import io.jans.as.model.util.Util; +import io.jans.model.error.ErrorMessage; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.CacheControl; import jakarta.ws.rs.core.MediaType; diff --git a/jans-auth-server/server/pom.xml b/jans-auth-server/server/pom.xml index d12a23d6a46..686d0bf1355 100644 --- a/jans-auth-server/server/pom.xml +++ b/jans-auth-server/server/pom.xml @@ -391,6 +391,13 @@ ${project.version} + + + io.jans + jans-lock-service + ${project.version} + + jakarta.validation diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/service/AppInitializer.java b/jans-auth-server/server/src/main/java/io/jans/as/server/service/AppInitializer.java index 555536af5de..b925a87adb3 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/service/AppInitializer.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/service/AppInitializer.java @@ -205,8 +205,8 @@ public void createApplicationComponents() { public void applicationInitialized(@Observes @Initialized(ApplicationScoped.class) Object init) { log.debug("Initializing application services"); - // Start timer - initSchedulerService(); + // Load main app configuration first + configurationFactory.create(); // Initialize plugins configurations for (ApplicationConfigurationFactory configurationFactory : applicationConfigurationFactory) { @@ -235,6 +235,9 @@ public void applicationInitialized(@Observes @Initialized(ApplicationScoped.clas statService.init(); + // Start timer + initSchedulerService(); + // Schedule timer tasks metricService.initTimer(); loggerService.initTimer(true); diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/dev/ConfSerialization.java b/jans-auth-server/server/src/test/java/io/jans/as/server/dev/ConfSerialization.java index f603f7307d9..10489e2cdc2 100644 --- a/jans-auth-server/server/src/test/java/io/jans/as/server/dev/ConfSerialization.java +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/dev/ConfSerialization.java @@ -8,10 +8,11 @@ import io.jans.as.model.config.BaseDnConfiguration; import io.jans.as.model.config.StaticConfiguration; -import io.jans.as.model.error.ErrorMessage; import io.jans.as.model.error.ErrorMessages; import io.jans.as.model.jwk.JSONWebKeySet; import io.jans.as.server.util.ServerUtil; +import io.jans.model.error.ErrorMessage; + import org.testng.Assert; import org.testng.annotations.Test; diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java index 398104b5abc..21781bf6023 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java @@ -31,7 +31,7 @@ public class ConfigurationService { @Inject ConfigurationFactory configurationFactory; - + private StatsData statsData; public Conf findConf() { diff --git a/jans-core/message/src/main/java/io/jans/service/BaseMessageService.java b/jans-core/message/src/main/java/io/jans/service/BaseMessageService.java index 9e9e0357579..d9015ebf410 100644 --- a/jans-core/message/src/main/java/io/jans/service/BaseMessageService.java +++ b/jans-core/message/src/main/java/io/jans/service/BaseMessageService.java @@ -8,8 +8,8 @@ import org.slf4j.Logger; -import io.jans.service.message.MessageInterface; -import io.jans.service.message.MessageProvider; +import io.jans.service.message.provider.MessageInterface; +import io.jans.service.message.provider.MessageProvider; import io.jans.service.message.pubsub.PubSubInterface; import jakarta.inject.Inject; diff --git a/jans-core/message/src/main/java/io/jans/service/MessageService.java b/jans-core/message/src/main/java/io/jans/service/MessageService.java index 92e7bf13a06..400fed8e0c7 100644 --- a/jans-core/message/src/main/java/io/jans/service/MessageService.java +++ b/jans-core/message/src/main/java/io/jans/service/MessageService.java @@ -6,7 +6,7 @@ package io.jans.service; -import io.jans.service.message.MessageProvider; +import io.jans.service.message.provider.MessageProvider; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/jans-core/message/src/main/java/io/jans/service/message/consumer/MessageConsumer.java b/jans-core/message/src/main/java/io/jans/service/message/consumer/MessageConsumer.java new file mode 100644 index 00000000000..f3b8c6b03e3 --- /dev/null +++ b/jans-core/message/src/main/java/io/jans/service/message/consumer/MessageConsumer.java @@ -0,0 +1,18 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.service.message.consumer; + +/** + * Base message consumer + * + * @author Yuriy Movchan Date: 12/18/2023 + */ +public abstract class MessageConsumer implements MessageConsumerInterface { + + public abstract String getMessageConsumerType(); + +} diff --git a/jans-core/message/src/main/java/io/jans/service/message/consumer/MessageConsumerInterface.java b/jans-core/message/src/main/java/io/jans/service/message/consumer/MessageConsumerInterface.java new file mode 100644 index 00000000000..ab656d61cb4 --- /dev/null +++ b/jans-core/message/src/main/java/io/jans/service/message/consumer/MessageConsumerInterface.java @@ -0,0 +1,18 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.service.message.consumer; + +import io.jans.service.message.pubsub.PubSubInterface; + +/** + * Interface for each message consumer + * + * @author Yuriy Movchan Date: 12/18/2023 + */ +public interface MessageConsumerInterface extends PubSubInterface { + +} diff --git a/jans-core/message/src/main/java/io/jans/service/message/model/config/PostgresMessageConfiguration.java b/jans-core/message/src/main/java/io/jans/service/message/model/config/PostgresMessageConfiguration.java index f103fd9217e..296a87dcc22 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/model/config/PostgresMessageConfiguration.java +++ b/jans-core/message/src/main/java/io/jans/service/message/model/config/PostgresMessageConfiguration.java @@ -9,8 +9,7 @@ import java.io.Serializable; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import jakarta.xml.bind.annotation.XmlElement; +import com.fasterxml.jackson.annotation.JsonProperty; /** * @author Yuriy Movchan Date: 30/11/2023 @@ -18,33 +17,44 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class PostgresMessageConfiguration implements Serializable { - @XmlElement(name = "db-schema-name") + @JsonProperty("jdbc.driver.class-name") + private String driverClassName; + + @JsonProperty("db-schema-name") private String dbSchemaName; - @XmlElement(name = "connection-uri") + @JsonProperty( "connection-uri") private String connectionUri; - @XmlElement(name = "auth-userName") + @JsonProperty("auth-user-name") private String authUserName; - @XmlElement(name = "auth-userPassword") + @JsonProperty("auth-user-password") private String authUserPassword; - @XmlElement(name = "connection-pool-max-total") + @JsonProperty("connection-pool-max-total") private Integer connectionPoolMaxTotal; - @XmlElement(name = "connection-pool-max-idle") + @JsonProperty("connection-pool-max-idle") private Integer connectionPoolMaxIdle; - @XmlElement(name = "connection-pool-min-idle") + @JsonProperty("connection-pool-min-idle") private Integer connectionPoolMinIdle; - @XmlElement(name = "message-wait-millis") + @JsonProperty("message-wait-millis") private Integer messageWaitMillis; - @XmlElement(name = "message-sleep-thread-millis") + @JsonProperty("message-sleep-thread-millis") private Integer messageSleepThreadTime; + public String getDriverClassName() { + return driverClassName; + } + + public void setDriverClassName(String driverClassName) { + this.driverClassName = driverClassName; + } + public String getDbSchemaName() { return dbSchemaName; } @@ -119,9 +129,9 @@ public void setMessageSleepThreadTime(Integer messageSleepThreadTime) { @Override public String toString() { - return "PostgresMessageConfiguration [dbSchemaName=" + dbSchemaName + ", connectionUri=" + connectionUri - + ", authUserName=" + authUserName + ", authUserPassword=" + authUserPassword - + ", connectionPoolMaxTotal=" + connectionPoolMaxTotal + ", connectionPoolMaxIdle=" + return "PostgresMessageConfiguration [driverClassName=" + driverClassName + ", dbSchemaName=" + dbSchemaName + + ", connectionUri=" + connectionUri + ", authUserName=" + authUserName + ", authUserPassword=" + + authUserPassword + ", connectionPoolMaxTotal=" + connectionPoolMaxTotal + ", connectionPoolMaxIdle=" + connectionPoolMaxIdle + ", connectionPoolMinIdle=" + connectionPoolMinIdle + ", messageWaitMillis=" + messageWaitMillis + ", messageSleepThreadTime=" + messageSleepThreadTime + "]"; } diff --git a/jans-core/message/src/main/java/io/jans/service/message/AbstractMessageProvider.java b/jans-core/message/src/main/java/io/jans/service/message/provider/AbstractMessageProvider.java similarity index 92% rename from jans-core/message/src/main/java/io/jans/service/message/AbstractMessageProvider.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/AbstractMessageProvider.java index 740ffbb69ea..c11fe43ba33 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/AbstractMessageProvider.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/AbstractMessageProvider.java @@ -4,7 +4,7 @@ * Copyright (c) 2023, Janssen Project */ -package io.jans.service.message; +package io.jans.service.message.provider; import java.util.concurrent.ExecutorService; diff --git a/jans-core/message/src/main/java/io/jans/service/message/MessageInterface.java b/jans-core/message/src/main/java/io/jans/service/message/provider/MessageInterface.java similarity index 92% rename from jans-core/message/src/main/java/io/jans/service/message/MessageInterface.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/MessageInterface.java index 703ff55d228..e4eae311634 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/MessageInterface.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/MessageInterface.java @@ -4,7 +4,7 @@ * Copyright (c) 2023, Janssen Project */ -package io.jans.service.message; +package io.jans.service.message.provider; import io.jans.service.message.pubsub.PubSubInterface; diff --git a/jans-core/message/src/main/java/io/jans/service/message/MessageProvider.java b/jans-core/message/src/main/java/io/jans/service/message/provider/MessageProvider.java similarity index 93% rename from jans-core/message/src/main/java/io/jans/service/message/MessageProvider.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/MessageProvider.java index 466fb9e17c4..01a7374f1a4 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/MessageProvider.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/MessageProvider.java @@ -4,7 +4,7 @@ * Copyright (c) 2023, Janssen Project */ -package io.jans.service.message; +package io.jans.service.message.provider; import io.jans.service.message.model.config.MessageProviderType; diff --git a/jans-core/message/src/main/java/io/jans/service/message/MessageProviderFactory.java b/jans-core/message/src/main/java/io/jans/service/message/provider/MessageProviderFactory.java similarity index 84% rename from jans-core/message/src/main/java/io/jans/service/message/MessageProviderFactory.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/MessageProviderFactory.java index c6bf7c4d91c..a4a42c8d35b 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/MessageProviderFactory.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/MessageProviderFactory.java @@ -4,7 +4,7 @@ * Copyright (c) 2023, Janssen Project */ -package io.jans.service.message; +package io.jans.service.message.provider; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -68,12 +68,12 @@ public void destroy() { public MessageProvider getMessageProvider() { log.debug("Started to create message provider"); - messageProvider = getCacheProvider(messageConfiguration); + messageProvider = getMessageProvider(messageConfiguration); return messageProvider; } - public MessageProvider getCacheProvider(MessageConfiguration messageConfiguration) { + public MessageProvider getMessageProvider(MessageConfiguration messageConfiguration) { MessageProviderType messageProviderType = messageConfiguration.getMessageProviderType(); // Create proxied bean @@ -95,7 +95,14 @@ public MessageProvider getCacheProvider(MessageConfiguration messageConfiguratio "Failed to initialize messageProvider, messageProvider is unsupported: " + messageProviderType); } - messageProvider.create(executorService); + // Call message provider from context class loader to load JDBC driver + ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + try { + messageProvider.create(executorService); + } finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } return messageProvider; } diff --git a/jans-core/message/src/main/java/io/jans/service/message/NullMessageProvider.java b/jans-core/message/src/main/java/io/jans/service/message/provider/NullMessageProvider.java similarity index 97% rename from jans-core/message/src/main/java/io/jans/service/message/NullMessageProvider.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/NullMessageProvider.java index 0b728527bd0..915efb242f2 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/NullMessageProvider.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/NullMessageProvider.java @@ -4,7 +4,7 @@ * Copyright (c) 2023, Janssen Project */ -package io.jans.service.message; +package io.jans.service.message.provider; import java.util.concurrent.ExecutorService; diff --git a/jans-core/message/src/main/java/io/jans/service/message/NullPool.java b/jans-core/message/src/main/java/io/jans/service/message/provider/NullPool.java similarity index 69% rename from jans-core/message/src/main/java/io/jans/service/message/NullPool.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/NullPool.java index aac306313f2..b9c907f76da 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/NullPool.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/NullPool.java @@ -1,4 +1,4 @@ -package io.jans.service.message; +package io.jans.service.message.provider; /** * Null pool diff --git a/jans-core/message/src/main/java/io/jans/service/message/PostgresMessageProvider.java b/jans-core/message/src/main/java/io/jans/service/message/provider/PostgresMessageProvider.java similarity index 86% rename from jans-core/message/src/main/java/io/jans/service/message/PostgresMessageProvider.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/PostgresMessageProvider.java index 53d7c1a18b8..3f10c818703 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/PostgresMessageProvider.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/PostgresMessageProvider.java @@ -4,7 +4,7 @@ * Copyright (c) 2023, Janssen Project */ -package io.jans.service.message; +package io.jans.service.message.provider; import java.sql.Connection; import java.sql.SQLException; @@ -29,6 +29,7 @@ import io.jans.service.message.model.config.MessageProviderType; import io.jans.service.message.model.config.PostgresMessageConfiguration; import io.jans.service.message.pubsub.PubSubInterface; +import io.jans.util.StringHelper; import io.jans.util.security.StringEncrypter; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; @@ -106,38 +107,43 @@ public void configure(MessageConfiguration messageConfiguration, StringEncrypter private Properties toPostgresProperties(PostgresMessageConfiguration postgresMessageConfiguration) { Properties connectionProperties = new Properties(); - connectionProperties.setProperty("db.schema.name", postgresMessageConfiguration.getDbSchemaName()); - connectionProperties.setProperty("connection.uri", postgresMessageConfiguration.getConnectionUri()); - connectionProperties.setProperty("auth.userName", postgresMessageConfiguration.getAuthUserName()); - + setProperty(connectionProperties, "jdbc.driver.class-name", postgresMessageConfiguration.getDriverClassName()); + setProperty(connectionProperties, "db.schema.name", postgresMessageConfiguration.getDbSchemaName()); + setProperty(connectionProperties, "connection.uri", postgresMessageConfiguration.getConnectionUri()); + setProperty(connectionProperties, "auth.userName", postgresMessageConfiguration.getAuthUserName()); + + String password = postgresMessageConfiguration.getAuthUserPassword(); try { - String encryptedPassword = postgresMessageConfiguration.getAuthUserPassword(); - if (StringUtils.isNotBlank(encryptedPassword)) { - connectionProperties.setProperty("auth.userPassword", stringEncrypter.decrypt(encryptedPassword)); + if (StringUtils.isNotBlank(password)) { + password = stringEncrypter.decrypt(password); log.trace("Decrypted Postgres password successfully."); } } catch (StringEncrypter.EncryptionException e) { log.error("Error during Postgres password decryption", e); } + setProperty(connectionProperties, "auth.userPassword", password); if (postgresMessageConfiguration.getConnectionPoolMaxTotal() != null) { - connectionProperties.setProperty("connection.pool.max-total", - postgresMessageConfiguration.getConnectionPoolMaxTotal().toString()); + setProperty(connectionProperties, "connection.pool.max-total", postgresMessageConfiguration.getConnectionPoolMaxTotal().toString()); } if (postgresMessageConfiguration.getConnectionPoolMaxIdle() != null) { - connectionProperties.setProperty("connection.pool.max-idle", - postgresMessageConfiguration.getConnectionPoolMaxIdle().toString()); + setProperty(connectionProperties, "connection.pool.max-idle", postgresMessageConfiguration.getConnectionPoolMaxIdle().toString()); } if (postgresMessageConfiguration.getConnectionPoolMinIdle() != null) { - connectionProperties.setProperty("connection.pool.min-idle", - postgresMessageConfiguration.getConnectionPoolMinIdle().toString()); + setProperty(connectionProperties, "connection.pool.min-idle", postgresMessageConfiguration.getConnectionPoolMinIdle().toString()); } return connectionProperties; } + public void setProperty(Properties connectionProperties, String propertyName, String propertyValue) { + if (StringHelper.isNotEmpty(propertyValue)) { + connectionProperties.setProperty(propertyName, propertyValue); + } + } + public boolean isConnected() { return сonnectionProviderPool.isConnected(); } diff --git a/jans-core/message/src/main/java/io/jans/service/message/RedisMessageProvider.java b/jans-core/message/src/main/java/io/jans/service/message/provider/RedisMessageProvider.java similarity index 99% rename from jans-core/message/src/main/java/io/jans/service/message/RedisMessageProvider.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/RedisMessageProvider.java index ebe286e0571..9b9ae089fd1 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/RedisMessageProvider.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/RedisMessageProvider.java @@ -4,7 +4,7 @@ * Copyright (c) 2023, Janssen Project */ -package io.jans.service.message; +package io.jans.service.message.provider; import java.util.Arrays; import java.util.concurrent.CompletableFuture; diff --git a/jans-core/message/src/main/java/io/jans/service/message/StandaloneMessageProviderFactory.java b/jans-core/message/src/main/java/io/jans/service/message/provider/StandaloneMessageProviderFactory.java similarity index 98% rename from jans-core/message/src/main/java/io/jans/service/message/StandaloneMessageProviderFactory.java rename to jans-core/message/src/main/java/io/jans/service/message/provider/StandaloneMessageProviderFactory.java index ac321626b82..927b657a269 100644 --- a/jans-core/message/src/main/java/io/jans/service/message/StandaloneMessageProviderFactory.java +++ b/jans-core/message/src/main/java/io/jans/service/message/provider/StandaloneMessageProviderFactory.java @@ -4,7 +4,7 @@ * Copyright (c) 2023, Janssen Project */ -package io.jans.service.message; +package io.jans.service.message.provider; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; diff --git a/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandalonePostresMessageTest.java b/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandalonePostresMessageTest.java index 32da982f107..cb706bc94e3 100644 --- a/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandalonePostresMessageTest.java +++ b/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandalonePostresMessageTest.java @@ -6,11 +6,11 @@ package io.jans.service.message.test.dev; -import io.jans.service.message.MessageProvider; -import io.jans.service.message.StandaloneMessageProviderFactory; import io.jans.service.message.model.config.MessageConfiguration; import io.jans.service.message.model.config.MessageProviderType; import io.jans.service.message.model.config.PostgresMessageConfiguration; +import io.jans.service.message.provider.MessageProvider; +import io.jans.service.message.provider.StandaloneMessageProviderFactory; import io.jans.service.message.pubsub.PubSubInterface; import io.jans.util.security.StringEncrypter; import io.jans.util.security.StringEncrypter.EncryptionException; @@ -28,7 +28,7 @@ public static void main(String[] args) throws EncryptionException, InterruptedEx PostgresMessageConfiguration postgresMessageConfiguration = new PostgresMessageConfiguration(); postgresMessageConfiguration.setDbSchemaName("public"); - postgresMessageConfiguration.setConnectionUri("jdbc:postgresql://localhost:5432/postgres"); + postgresMessageConfiguration.setConnectionUri("jdbc:postgresql://localhost:5433/postgres"); postgresMessageConfiguration.setAuthUserName("postgres"); postgresMessageConfiguration.setAuthUserPassword("rgy1GUg+1kY="); // secret postgresMessageConfiguration.setMessageWaitMillis(100); diff --git a/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandalonePostresPubTokenMessageTest.java b/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandalonePostresPubTokenMessageTest.java new file mode 100644 index 00000000000..6238e6f85ed --- /dev/null +++ b/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandalonePostresPubTokenMessageTest.java @@ -0,0 +1,56 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.service.message.test.dev; + +import io.jans.service.message.model.config.MessageConfiguration; +import io.jans.service.message.model.config.MessageProviderType; +import io.jans.service.message.model.config.PostgresMessageConfiguration; +import io.jans.service.message.provider.MessageProvider; +import io.jans.service.message.provider.StandaloneMessageProviderFactory; +import io.jans.util.security.StringEncrypter; +import io.jans.util.security.StringEncrypter.EncryptionException; + +/** + * @author Yuriy Movchan Date: 30/11/2023 + */ +public class StandalonePostresPubTokenMessageTest { + + public static void main(String[] args) throws EncryptionException, InterruptedException { + StringEncrypter stringEncrypter = StringEncrypter.instance("aOm7B9mrWT66roqZCNcUr7ox"); + + MessageConfiguration messageConfiguration = new MessageConfiguration(); + messageConfiguration.setMessageProviderType(MessageProviderType.POSTGRES); + + PostgresMessageConfiguration postgresMessageConfiguration = new PostgresMessageConfiguration(); + postgresMessageConfiguration.setDbSchemaName("public"); + postgresMessageConfiguration.setConnectionUri("jdbc:postgresql://localhost:5433/postgres"); + postgresMessageConfiguration.setAuthUserName("postgres"); + postgresMessageConfiguration.setAuthUserPassword("rgy1GUg+1kY="); // secret + postgresMessageConfiguration.setMessageWaitMillis(100); + postgresMessageConfiguration.setMessageSleepThreadTime(200); + + messageConfiguration.setPostgresConfiguration(postgresMessageConfiguration); + + StandaloneMessageProviderFactory messageProviderFactory = new StandaloneMessageProviderFactory(stringEncrypter); + MessageProvider messageProvider = messageProviderFactory.getMessageProvider(messageConfiguration); + + System.out.printf("First test...\n"); + for (int i = 0; i < 1000; i++) { + messageProvider.publish("id_token", "1111111"); + messageProvider.publish("code_token", "22222222222"); + messageProvider.publish("id_token", "333333333333333333333"); + } + + Thread.sleep(5 * 1000L); + messageProvider.shutdown(); + System.out.printf("Active count %d, total: %d \n", messageProviderFactory.getActiveCount(), + messageProviderFactory.getPoolSize()); + + System.out.printf("End test...\n"); + } + +} diff --git a/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandaloneRedisMessageTest.java b/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandaloneRedisMessageTest.java index b11c78d2f9d..4693c9e07f9 100644 --- a/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandaloneRedisMessageTest.java +++ b/jans-core/message/src/test/java/io/jans/service/message/test/dev/StandaloneRedisMessageTest.java @@ -6,11 +6,11 @@ package io.jans.service.message.test.dev; -import io.jans.service.message.MessageProvider; -import io.jans.service.message.StandaloneMessageProviderFactory; import io.jans.service.message.model.config.MessageConfiguration; import io.jans.service.message.model.config.MessageProviderType; import io.jans.service.message.model.config.RedisMessageConfiguration; +import io.jans.service.message.provider.MessageProvider; +import io.jans.service.message.provider.StandaloneMessageProviderFactory; import io.jans.service.message.pubsub.PubSubInterface; import io.jans.util.security.StringEncrypter; import io.jans.util.security.StringEncrypter.EncryptionException; diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessage.java b/jans-core/model/src/main/java/io/jans/model/error/ErrorMessage.java similarity index 98% rename from jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessage.java rename to jans-core/model/src/main/java/io/jans/model/error/ErrorMessage.java index 287cec0775f..1a81fa3bd95 100644 --- a/jans-auth-server/model/src/main/java/io/jans/as/model/error/ErrorMessage.java +++ b/jans-core/model/src/main/java/io/jans/model/error/ErrorMessage.java @@ -4,7 +4,7 @@ * Copyright (c) 2020, Janssen Project */ -package io.jans.as.model.error; +package io.jans.model.error; import jakarta.xml.bind.annotation.XmlAttribute; import jakarta.xml.bind.annotation.XmlElement; diff --git a/jans-fido2/model/src/main/java/io/jans/fido2/model/error/ErrorResponseFactory.java b/jans-fido2/model/src/main/java/io/jans/fido2/model/error/ErrorResponseFactory.java index 8436d357310..b8c771ae92d 100644 --- a/jans-fido2/model/src/main/java/io/jans/fido2/model/error/ErrorResponseFactory.java +++ b/jans-fido2/model/src/main/java/io/jans/fido2/model/error/ErrorResponseFactory.java @@ -3,11 +3,11 @@ import io.jans.as.model.config.Constants; import io.jans.as.model.configuration.Configuration; import io.jans.as.model.error.DefaultErrorResponse; -import io.jans.as.model.error.ErrorMessage; import io.jans.as.model.error.IErrorType; import io.jans.fido2.model.assertion.AssertionErrorResponseType; import io.jans.fido2.model.attestation.AttestationErrorResponseType; import io.jans.fido2.model.conf.AppConfiguration; +import io.jans.model.error.ErrorMessage; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; diff --git a/jans-fido2/model/src/main/java/io/jans/fido2/model/error/Fido2ErrorMessages.java b/jans-fido2/model/src/main/java/io/jans/fido2/model/error/Fido2ErrorMessages.java index 2ce4ed2818b..eb38c5f891d 100644 --- a/jans-fido2/model/src/main/java/io/jans/fido2/model/error/Fido2ErrorMessages.java +++ b/jans-fido2/model/src/main/java/io/jans/fido2/model/error/Fido2ErrorMessages.java @@ -8,7 +8,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.jans.as.model.configuration.Configuration; -import io.jans.as.model.error.ErrorMessage; +import io.jans.model.error.ErrorMessage; import jakarta.xml.bind.annotation.*; import java.util.List; diff --git a/jans-linux-setup/jans_setup/templates/configuration.ldif b/jans-linux-setup/jans_setup/templates/configuration.ldif index 1a7337ac889..1a7d7d61660 100644 --- a/jans-linux-setup/jans_setup/templates/configuration.ldif +++ b/jans-linux-setup/jans_setup/templates/configuration.ldif @@ -1,6 +1,6 @@ dn: ou=configuration,o=jans jansCacheConf: {"cacheProviderType": "%(cache_provider_type)s", "memcachedConfiguration": {"servers":"localhost:11211", "maxOperationQueueLength":100000, "bufferSize":32768, "defaultPutExpiration":60, "connectionFactoryType": "DEFAULT"}, "inMemoryConfiguration": {"defaultPutExpiration":60}, "nativePersistenceConfiguration": {"defaultPutExpiration":60, "defaultCleanupBatchSize": 10000}, "redisConfiguration":{"servers":"localhost:6379", "defaultPutExpiration": 60}} -jansMessageConf: {"messageProviderType": "NULL", "postgresConfiguration": {"db-schema-name":"public", "message-wait-millis": 100, "message-sleep-thread-millis": 200}, "redisConfiguration":{"servers":"localhost:6379"}} +jansMessageConf: {"messageProviderType": "NULL", "postgresConfiguration": {"connection-uri" : "jdbc:postgresql://localhost:5432/postgres", "db-schema-name":"public", "auth-user-name" : "postgres", "auth-user-password" : "", "message-wait-millis": 100, "message-sleep-thread-millis": 200}, "redisConfiguration":{"servers":"localhost:6379"}} jansDocStoreConf: {"documentStoreType":"LOCAL","localConfiguration":{"baseLocation":"/"},"jcaConfiguration":{"serverUrl":"http://localhost:8080/rmi","workspaceName":"default","connectionTimeout":15,"userId":"admin","password":""},"webDavConfiguration":null} jansDbAuth: {"type": "auth", "name": null, "level": 0, "priority": 1, "enabled": false, "version": 0, "config": {"configId": "auth_ldap_server", "servers": ["%(ldap_hostname)s:%(ldaps_port)s"], "maxConnections": 1000, "bindDN": "%(ldap_binddn)s", "bindPassword": "%(ldap_bind_encoded_pw)s", "useSSL": "true", "baseDNs": ["ou=people,o=jans"], "primaryKey": "uid", "localPrimaryKey": "uid", "useAnonymousBind": false, "enabled": false}} jansSmtpConf: {"key_store":"%(smtp_jks_fn)s", "key_store_password":"%(smtp_jks_pass_enc)s", "key_store_alias":"%(smtp_alias)s", "signing_algorithm":"%(smtp_signing_alg)s"} diff --git a/jans-linux-setup/jans_setup/templates/jans-auth/role-scope-mappings.json b/jans-linux-setup/jans_setup/templates/jans-auth/role-scope-mappings.json index e42c176c5d9..6eb085353e3 100644 --- a/jans-linux-setup/jans_setup/templates/jans-auth/role-scope-mappings.json +++ b/jans-linux-setup/jans_setup/templates/jans-auth/role-scope-mappings.json @@ -198,6 +198,18 @@ "defaultPermissionInToken": false, "tag": "fido2" }, + { + "permission": "https://jans.io/oauth/config/message.readonly", + "description": null, + "defaultPermissionInToken": false, + "tag": "cache" + }, + { + "permission": "https://jans.io/oauth/config/message.write", + "description": null, + "defaultPermissionInToken": false, + "tag": "cache" + }, { "permission": "https://jans.io/oauth/config/cache.readonly", "description": null, @@ -472,6 +484,7 @@ "https://jans.io/oauth/config/database/ldap.readonly", "https://jans.io/oauth/config/jwks.readonly", "https://jans.io/oauth/config/fido2.readonly", + "https://jans.io/oauth/config/message.readonly", "https://jans.io/oauth/config/cache.readonly", "https://jans.io/oauth/jans-auth-server/config/properties.readonly", "https://jans.io/oauth/config/database/couchbase.readonly", @@ -504,6 +517,8 @@ "https://jans.io/oauth/config/jwks.write", "https://jans.io/oauth/config/fido2.readonly", "https://jans.io/oauth/config/fido2.write", + "https://jans.io/oauth/config/message.readonly", + "https://jans.io/oauth/config/message.write", "https://jans.io/oauth/config/cache.readonly", "https://jans.io/oauth/config/cache.write", "https://jans.io/oauth/config/database/couchbase.readonly", @@ -548,6 +563,8 @@ "https://jans.io/oauth/config/jwks.write", "https://jans.io/oauth/config/fido2.readonly", "https://jans.io/oauth/config/fido2.write", + "https://jans.io/oauth/config/message.readonly", + "https://jans.io/oauth/config/message.write", "https://jans.io/oauth/config/cache.readonly", "https://jans.io/oauth/config/cache.write", "https://jans.io/oauth/config/database/couchbase.readonly", @@ -592,6 +609,8 @@ "https://jans.io/oauth/config/jwks.write", "https://jans.io/oauth/config/fido2.readonly", "https://jans.io/oauth/config/fido2.write", + "https://jans.io/oauth/config/message.readonly", + "https://jans.io/oauth/config/message.write", "https://jans.io/oauth/config/cache.readonly", "https://jans.io/oauth/config/cache.write", "https://jans.io/oauth/config/database/couchbase.readonly", diff --git a/jans-linux-setup/jans_setup/templates/jans-lock/dynamic-conf.json b/jans-linux-setup/jans_setup/templates/jans-lock/dynamic-conf.json new file mode 100644 index 00000000000..84dd22e2895 --- /dev/null +++ b/jans-linux-setup/jans_setup/templates/jans-lock/dynamic-conf.json @@ -0,0 +1,21 @@ +{ + "tokenChannels":[ + "code_token", + "id_token" + ] + }, + + "cleanServiceInterval":60, + "cleanServiceBatchChunkSize":10000, + + "disableJdkLogger":true, + + "loggingLevel":"INFO", + "loggingLayout":"text", + "externalLoggerConfiguration":"", + + "metricReporterInterval":300, + "metricReporterKeepDataDays":15, + "metricReporterEnabled":true, + "errorReasonEnabled": false +} diff --git a/jans-linux-setup/jans_setup/templates/jans-lock/jans-lock-errors.json b/jans-linux-setup/jans_setup/templates/jans-lock/jans-lock-errors.json new file mode 100644 index 00000000000..c6cf6d78f14 --- /dev/null +++ b/jans-linux-setup/jans_setup/templates/jans-lock/jans-lock-errors.json @@ -0,0 +1,9 @@ +{ + "common": [ + { + "id": "unknown_error", + "description": "Unknown or not found error", + "uri": null + } + ] +} \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/templates/jans-lock/lock.ldif b/jans-linux-setup/jans_setup/templates/jans-lock/lock.ldif new file mode 100644 index 00000000000..8668a38972a --- /dev/null +++ b/jans-linux-setup/jans_setup/templates/jans-lock/lock.ldif @@ -0,0 +1,9 @@ +dn: ou=jans-lock,ou=configuration,o=jans +jansConfDyn::%(lock_dynamic_conf_base64)s +jansConfErrors::%(lock_error_base64)s +jansConfStatic::%(lock_static_conf_base64)s +jansRevision: 1 +objectClass: top +objectClass: jansAppConf +ou: lock + diff --git a/jans-linux-setup/jans_setup/templates/jans-lock/static-conf.json b/jans-linux-setup/jans_setup/templates/jans-lock/static-conf.json new file mode 100644 index 00000000000..f1860e1d973 --- /dev/null +++ b/jans-linux-setup/jans_setup/templates/jans-lock/static-conf.json @@ -0,0 +1,10 @@ +{ + "baseDn":{ + "configuration":"ou=configuration,o=jans", + "people":"ou=people,o=jans", + "scripts": "ou=scripts,o=jans", + "attributes":"ou=attributes,o=jans", + "sessions":"ou=sessions,o=jans", + "metric":"ou=statistic,o=metric" + } +} diff --git a/jans-linux-setup/jans_setup/templates/jans.properties b/jans-linux-setup/jans_setup/templates/jans.properties index 0ee748b1478..b62e6f26b5f 100644 --- a/jans-linux-setup/jans_setup/templates/jans.properties +++ b/jans-linux-setup/jans_setup/templates/jans.properties @@ -8,6 +8,7 @@ link_ConfigurationEntryDN=ou=jans-link,ou=configuration,o=jans keycloakLink_ConfigurationEntryDN=ou=jans-keycloak-link,ou=configuration,o=jans saml_ConfigurationEntryDN=ou=jans-saml,ou=configuration,o=jans idp_ConfigurationEntryDN=ou=jans-idp,ou=configuration,o=jans +lock_ConfigurationEntryDN=ou=jans-lock,ou=configuration,o=jans certsDir=%(certFolder)s confDir= diff --git a/jans-lock/server/src/main/java/io/jans/lock/model/status/FacterData.java b/jans-lock/server/src/main/java/io/jans/lock/model/status/FacterData.java new file mode 100644 index 00000000000..17cd5eb31a5 --- /dev/null +++ b/jans-lock/server/src/main/java/io/jans/lock/model/status/FacterData.java @@ -0,0 +1,116 @@ +/* + * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.lock.model.status; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "memoryfree", "swapfree", "hostname", "ipaddress", "uptime", "free_disk_space", "load_average" }) +public class FacterData { + + @JsonProperty("memoryfree") + private String memoryfree; + + @JsonProperty("swapfree") + private String swapfree; + + @JsonProperty("hostname") + private String hostname; + + @JsonProperty("ipaddress") + private String ipaddress; + + @JsonProperty("uptime") + private String uptime; + + @JsonProperty("free_disk_space") + private String freeDiskSpace; + + @JsonProperty("load_average") + private String loadAverage; + + + @JsonProperty("memoryfree") + public String getMemoryfree() { + return memoryfree; + } + + @JsonProperty("memoryfree") + public void setMemoryfree(String memoryfree) { + this.memoryfree = memoryfree; + } + + @JsonProperty("swapfree") + public String getSwapfree() { + return swapfree; + } + + @JsonProperty("swapfree") + public void setSwapfree(String swapfree) { + this.swapfree = swapfree; + } + + @JsonProperty("hostname") + public String getHostname() { + return hostname; + } + + @JsonProperty("hostname") + public void setHostname(String hostname) { + this.hostname = hostname; + } + + @JsonProperty("ipaddress") + public String getIpaddress() { + return ipaddress; + } + + @JsonProperty("ipaddress") + public void setIpaddress(String ipaddress) { + this.ipaddress = ipaddress; + } + + @JsonProperty("uptime") + public String getUptime() { + return uptime; + } + + @JsonProperty("uptime") + public void setUptime(String uptime) { + this.uptime = uptime; + } + + @JsonProperty("free_disk_space") + public String getFreeDiskSpace() { + return freeDiskSpace; + } + + @JsonProperty("free_disk_space") + public void setFreeDiskSpace(String freeDiskSpace) { + this.freeDiskSpace = freeDiskSpace; + } + + @JsonProperty("load_average") + public String getLoadAverage() { + return loadAverage; + } + + @JsonProperty("load_average") + public void setLoadAverage(String loadAverage) { + this.loadAverage = loadAverage; + } + + @Override + public String toString() { + return "FacterData [memoryfree=" + memoryfree + ", swapfree=" + swapfree + ", hostname=" + hostname + + ", ipaddress=" + ipaddress + ", uptime=" + uptime + ", freeDiskSpace=" + freeDiskSpace + + ", loadAverage=" + loadAverage + "]"; + } + +} diff --git a/jans-lock/server/src/main/java/io/jans/lock/model/status/StatsData.java b/jans-lock/server/src/main/java/io/jans/lock/model/status/StatsData.java new file mode 100644 index 00000000000..9fc7fff035b --- /dev/null +++ b/jans-lock/server/src/main/java/io/jans/lock/model/status/StatsData.java @@ -0,0 +1,57 @@ +/* + * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.lock.model.status; + +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "dbType", "lastUpdate", "facterData", }) +public class StatsData { + + @JsonProperty("dbType") + private String dbType; + + @JsonProperty("lastUpdate") + private Date lastUpdate; + + @JsonProperty("facterData") + private FacterData facterData; + + public String getDbType() { + return dbType; + } + + public void setDbType(String dbType) { + this.dbType = dbType; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } + + public FacterData getFacterData() { + return facterData; + } + + public void setFacterData(FacterData facterData) { + this.facterData = facterData; + } + + @Override + public String toString() { + return "StatsData [dbType=" + dbType + ", lastUpdate=" + lastUpdate + ", facterData=" + facterData + "]"; + } + +} diff --git a/jans-lock/server/src/main/java/io/jans/lock/server/service/AppInitializer.java b/jans-lock/server/src/main/java/io/jans/lock/server/service/AppInitializer.java index 3153d496f63..4decaf85e9a 100644 --- a/jans-lock/server/src/main/java/io/jans/lock/server/service/AppInitializer.java +++ b/jans-lock/server/src/main/java/io/jans/lock/server/service/AppInitializer.java @@ -17,6 +17,7 @@ import io.jans.exception.ConfigurationException; import io.jans.lock.service.config.ApplicationFactory; import io.jans.lock.service.config.ConfigurationFactory; +import io.jans.lock.service.status.StatusCheckerTimer; import io.jans.model.custom.script.CustomScriptType; import io.jans.orm.PersistenceEntryManager; import io.jans.orm.model.PersistenceConfiguration; @@ -93,6 +94,9 @@ public class AppInitializer { @Inject private MetricService metricService; + @Inject + private StatusCheckerTimer statusCheckerTimer; + @Inject private CustomScriptManager customScriptManager; @@ -114,13 +118,12 @@ public void createApplicationComponents() { public void applicationInitialized(@Observes @Initialized(ApplicationScoped.class) Object init) { log.debug("Initializing application services"); - // Start timer - initSchedulerService(); + // Load main app configuration first + configurationFactory.create(); // Initialize plugins configurations for (ApplicationConfigurationFactory configurationFactory : applicationConfigurationFactory) { configurationFactory.create(); - configurationFactory.initTimer(); } PersistenceEntryManager localPersistenceEntryManager = persistenceEntryManagerInstance.get(); @@ -134,8 +137,14 @@ public void applicationInitialized(@Observes @Initialized(ApplicationScoped.clas // Initialize script manager List supportedCustomScriptTypes = Lists.newArrayList(CustomScriptType.LOCK_EXTENSION); + // Start timer + initSchedulerService(); + + // Schedule timer tasks loggerService.initTimer(); + statusCheckerTimer.initTimer(); customScriptManager.initTimer(supportedCustomScriptTypes); + // Notify plugins about finish application initialization eventApplicationInitialized.select(ApplicationInitialized.Literal.APPLICATION) .fire(new ApplicationInitializedEvent()); diff --git a/jans-lock/server/src/main/java/io/jans/lock/server/service/AttributeService.java b/jans-lock/server/src/main/java/io/jans/lock/server/service/AttributeService.java index b6fc1df27c6..8f40f5c4649 100644 --- a/jans-lock/server/src/main/java/io/jans/lock/server/service/AttributeService.java +++ b/jans-lock/server/src/main/java/io/jans/lock/server/service/AttributeService.java @@ -1,19 +1,18 @@ /* * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. * - * Copyright (c) 2020, Janssen Project + * Copyright (c) 2023, Janssen Project */ package io.jans.lock.server.service; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import io.jans.lock.model.config.AppConfiguration; import io.jans.lock.model.config.StaticConfiguration; import io.jans.service.BaseCacheService; import io.jans.service.CacheService; import io.jans.service.LocalCacheService; import io.jans.util.StringHelper; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; /** * @@ -22,9 +21,6 @@ @ApplicationScoped public class AttributeService extends io.jans.service.AttributeService { - @Inject - private AppConfiguration appConfiguration; - @Inject private StaticConfiguration staticConfiguration; diff --git a/jans-lock/server/src/main/java/io/jans/lock/server/service/ConfigurationService.java b/jans-lock/server/src/main/java/io/jans/lock/server/service/ConfigurationService.java index 12003c41a91..c246fb09276 100644 --- a/jans-lock/server/src/main/java/io/jans/lock/server/service/ConfigurationService.java +++ b/jans-lock/server/src/main/java/io/jans/lock/server/service/ConfigurationService.java @@ -6,14 +6,14 @@ package io.jans.lock.server.service; +import org.slf4j.Logger; + import io.jans.as.persistence.model.configuration.GluuConfiguration; import io.jans.lock.model.config.StaticConfiguration; import io.jans.model.SmtpConfiguration; import io.jans.orm.PersistenceEntryManager; import io.jans.util.StringHelper; import io.jans.util.security.StringEncrypter.EncryptionException; -import org.slf4j.Logger; - import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; diff --git a/jans-lock/server/src/main/java/io/jans/lock/service/config/ApplicationFactory.java b/jans-lock/server/src/main/java/io/jans/lock/service/config/ApplicationFactory.java index f5c80747c3a..30aa9e5efc9 100644 --- a/jans-lock/server/src/main/java/io/jans/lock/service/config/ApplicationFactory.java +++ b/jans-lock/server/src/main/java/io/jans/lock/service/config/ApplicationFactory.java @@ -20,6 +20,9 @@ import io.jans.service.cache.InMemoryConfiguration; import io.jans.service.document.store.conf.DocumentStoreConfiguration; import io.jans.service.document.store.conf.LocalDocumentStoreConfiguration; +import io.jans.service.message.model.config.MessageConfiguration; +import io.jans.service.message.model.config.MessageProviderType; +import io.jans.service.message.model.config.NullMessageConfiguration; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.inject.Produces; @@ -75,6 +78,26 @@ public CacheConfiguration getCacheConfiguration() { return cacheConfiguration; } + @Produces + @ApplicationScoped + public MessageConfiguration getMessageConfiguration() { + MessageConfiguration messageConfiguration = configurationService.getConfiguration().getMessageConfiguration(); + if (messageConfiguration == null || messageConfiguration.getMessageProviderType() == null) { + log.error("Failed to read message configuration from DB. Please check configuration jsMessageConf attribute " + + "that must contain message configuration JSON represented by MessageConfiguration.class. Appliance DN: " + configurationService.getConfiguration().getDn()); + log.info("Creating fallback Null message configuration ... "); + + messageConfiguration = new MessageConfiguration(); + messageConfiguration.setMessageProviderType(MessageProviderType.NULL); + messageConfiguration.setNullConfiguration(new NullMessageConfiguration()); + + log.info("NULL message configuration is created."); + } + + log.info("Message configuration: " + messageConfiguration); + return messageConfiguration; + } + @Produces @ApplicationScoped public DocumentStoreConfiguration getDocumentStoreConfiguration() { diff --git a/jans-lock/server/src/main/java/io/jans/lock/service/status/StatusCheckerTimer.java b/jans-lock/server/src/main/java/io/jans/lock/service/status/StatusCheckerTimer.java new file mode 100644 index 00000000000..262e5caf285 --- /dev/null +++ b/jans-lock/server/src/main/java/io/jans/lock/service/status/StatusCheckerTimer.java @@ -0,0 +1,149 @@ +/* + * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.lock.service.status; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.commons.exec.CommandLine; +import org.slf4j.Logger; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.jans.lock.model.status.FacterData; +import io.jans.lock.model.status.StatsData; +import io.jans.lock.service.config.ConfigurationFactory; +import io.jans.lock.service.status.cdi.event.StatusCheckerTimerEvent; +import io.jans.service.cdi.async.Asynchronous; +import io.jans.service.cdi.event.Scheduled; +import io.jans.service.timer.event.TimerEvent; +import io.jans.service.timer.schedule.TimerSchedule; +import io.jans.util.StringHelper; +import io.jans.util.process.ProcessHelper; +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.RequestScoped; +import jakarta.enterprise.event.Event; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; + +@ApplicationScoped +public class StatusCheckerTimer { + + private static final int DEFAULT_INTERVAL = 5 * 60; // 1 minute + public static final String PROGRAM_FACTER = "facter"; + + @Inject + private Logger log; + + @Inject + private Event timerEvent; + + @Inject + private ConfigurationFactory configurationFactory; + + private StatsData statsData = new StatsData(); + + private AtomicBoolean isActive; + + @PostConstruct + public void create() { + log.debug("Creating Status Cheker Timer"); + } + + public void initTimer() { + log.debug("Initializing Status Checker Timer"); + this.isActive = new AtomicBoolean(false); + + final int delay = 1 * 60; + final int interval = DEFAULT_INTERVAL; + + timerEvent.fire(new TimerEvent(new TimerSchedule(delay, interval), new StatusCheckerTimerEvent(), + Scheduled.Literal.INSTANCE)); + } + + @Asynchronous + public void process(@Observes @Scheduled StatusCheckerTimerEvent statusCheckerTimerEvent) { + log.debug("Status Checker Timer Process"); + if (this.isActive.get()) { + return; + } + + if (!this.isActive.compareAndSet(false, true)) { + return; + } + + try { + processInt(); + } finally { + this.isActive.set(false); + } + } + + /** + * Gather periodically site and server status + * + * @param when Date + * @param interval Interval + */ + private void processInt() { + log.debug("Starting update of sever status"); + + StatsData statsData = new StatsData(); + Date currentDateTime = new Date(); + statsData.setLastUpdate(currentDateTime); + statsData.setFacterData(getFacterData()); + statsData.setDbType(configurationFactory.getBaseConfiguration().getString("persistence.type")); + + log.debug("Configuration status update finished"); + } + + private FacterData getFacterData() { + log.debug("Getting Server status"); + FacterData facterData = new FacterData(); + ObjectMapper mapper = new ObjectMapper(); + if (!isLinux()) { + return facterData; + } + CommandLine commandLine = new CommandLine(PROGRAM_FACTER); + commandLine.addArgument("-j"); + String resultOutput; + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(4096);) { + boolean result = ProcessHelper.executeProgram(commandLine, false, 0, bos); + if (!result) { + return facterData; + } + resultOutput = new String(bos.toByteArray(), UTF_8); + facterData = mapper.readValue(resultOutput, FacterData.class); + } catch (UnsupportedEncodingException ex) { + log.error("Failed to parse program {} output", PROGRAM_FACTER, ex); + return facterData; + } catch (IOException e) { + e.printStackTrace(); + } + log.debug("Server status - facterData:{}", facterData); + return facterData; + } + + private boolean isLinux() { + String osName = System.getProperty("os.name"); + return !StringHelper.isEmpty(osName) && osName.toLowerCase().contains("linux"); + } + + @Produces + @RequestScoped + public StatsData getStatsData() { + return statsData; + } + +} diff --git a/jans-lock/service/src/main/java/io/jans/lock/service/status/cdi/event/StatusCheckerTimerEvent.java b/jans-lock/server/src/main/java/io/jans/lock/service/status/cdi/event/StatusCheckerTimerEvent.java similarity index 89% rename from jans-lock/service/src/main/java/io/jans/lock/service/status/cdi/event/StatusCheckerTimerEvent.java rename to jans-lock/server/src/main/java/io/jans/lock/service/status/cdi/event/StatusCheckerTimerEvent.java index d7705cd267b..3a6e64b29a6 100644 --- a/jans-lock/service/src/main/java/io/jans/lock/service/status/cdi/event/StatusCheckerTimerEvent.java +++ b/jans-lock/server/src/main/java/io/jans/lock/service/status/cdi/event/StatusCheckerTimerEvent.java @@ -13,7 +13,6 @@ */ public class StatusCheckerTimerEvent { - public StatusCheckerTimerEvent() { - } + public StatusCheckerTimerEvent() {} } diff --git a/jans-lock/server/src/main/java/io/jans/lock/ws/rs/HealthCheckController.java b/jans-lock/server/src/main/java/io/jans/lock/ws/rs/HealthCheckController.java index 3c0b4f0dca7..f15bdee7c3f 100644 --- a/jans-lock/server/src/main/java/io/jans/lock/ws/rs/HealthCheckController.java +++ b/jans-lock/server/src/main/java/io/jans/lock/ws/rs/HealthCheckController.java @@ -6,7 +6,15 @@ package io.jans.lock.ws.rs; +import org.slf4j.Logger; + +import io.jans.lock.model.status.StatsData; import io.jans.orm.PersistenceEntryManager; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.GET; @@ -14,6 +22,7 @@ import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; /** * Health check controller @@ -26,6 +35,31 @@ public class HealthCheckController { @Inject private PersistenceEntryManager persistenceEntryManager; + @Inject + Logger logger; + + @Inject + private StatsData statsData; + + @Operation(summary = "Returns application server status", description = "Returns application server status", operationId = "get-server-stat", tags = { + "Health - Check" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = StatsData.class))), + @ApiResponse(responseCode = "500", description = "InternalServerError") }) + @GET + @Path("/server-stat") + @Produces(MediaType.APPLICATION_JSON) + public Response getServerStat() { + logger.debug("Server Stat - statsData:{}", statsData); + + StatsData clonedStatsData = new StatsData(); + clonedStatsData.setDbType(statsData.getDbType()); + clonedStatsData.setFacterData(statsData.getFacterData()); + clonedStatsData.setLastUpdate(statsData.getLastUpdate()); + + return Response.ok(clonedStatsData).build(); + + } @GET @POST diff --git a/jans-lock/server/src/test/java/io/jans/lock/test/dev/TestPubSubRedis.java b/jans-lock/server/src/test/java/io/jans/lock/test/dev/TestPubSubRedis.java index 94b123f3150..5c2de12b06d 100644 --- a/jans-lock/server/src/test/java/io/jans/lock/test/dev/TestPubSubRedis.java +++ b/jans-lock/server/src/test/java/io/jans/lock/test/dev/TestPubSubRedis.java @@ -5,7 +5,6 @@ import java.util.Base64; import java.util.List; import java.util.Random; -import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; diff --git a/jans-lock/service/pom.xml b/jans-lock/service/pom.xml index bd69c089134..49bae597f14 100644 --- a/jans-lock/service/pom.xml +++ b/jans-lock/service/pom.xml @@ -48,12 +48,17 @@ io.jans jans-lock-model - + io.jans jans-core-service diff --git a/jans-lock/service/src/main/java/io/jans/lock/model/config/AppConfiguration.java b/jans-lock/service/src/main/java/io/jans/lock/model/config/AppConfiguration.java index 593edbcf6a9..a27d2b51959 100644 --- a/jans-lock/service/src/main/java/io/jans/lock/model/config/AppConfiguration.java +++ b/jans-lock/service/src/main/java/io/jans/lock/model/config/AppConfiguration.java @@ -6,6 +6,9 @@ package io.jans.lock.model.config; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.jans.doc.annotation.DocProperty; @@ -22,6 +25,8 @@ public class AppConfiguration implements Configuration { private String baseDN; + private List tokenChannels; + @DocProperty(description = "Choose whether to disable JDK loggers", defaultValue = "true") private Boolean disableJdkLogger = true; @@ -36,6 +41,8 @@ public class AppConfiguration implements Configuration { // Period in seconds private int cleanServiceInterval; + private String messageConsumerType; + public String getBaseDN() { return baseDN; } @@ -44,6 +51,18 @@ public void setBaseDN(String baseDN) { this.baseDN = baseDN; } + public List getTokenChannels() { + if (tokenChannels == null) { + tokenChannels = new ArrayList<>(); + } + + return tokenChannels; + } + + public void setTokenChannels(List tokenChannels) { + this.tokenChannels = tokenChannels; + } + public Boolean getDisableJdkLogger() { return disableJdkLogger; } @@ -108,4 +127,12 @@ public void setCleanServiceInterval(int cleanServiceInterval) { this.cleanServiceInterval = cleanServiceInterval; } + public String getMessageConsumerType() { + return messageConsumerType; + } + + public void setMessageConsumerType(String messageConsumerType) { + this.messageConsumerType = messageConsumerType; + } + } diff --git a/jans-lock/service/src/main/java/io/jans/lock/model/config/Conf.java b/jans-lock/service/src/main/java/io/jans/lock/model/config/Conf.java index 6983405dab7..e5389debc25 100644 --- a/jans-lock/service/src/main/java/io/jans/lock/model/config/Conf.java +++ b/jans-lock/service/src/main/java/io/jans/lock/model/config/Conf.java @@ -32,6 +32,10 @@ public class Conf { @AttributeName(name = "jansConfStatic") private StaticConfiguration statics; + @JsonObject + @AttributeName(name = "jansConfErrors") + private ErrorMessages errors; + @AttributeName(name = "jansRevision") private long revision; @@ -59,6 +63,14 @@ public void setStatics(StaticConfiguration statics) { this.statics = statics; } + public ErrorMessages getErrors() { + return errors; + } + + public void setErrors(ErrorMessages errors) { + this.errors = errors; + } + public long getRevision() { return revision; } diff --git a/jans-lock/service/src/main/java/io/jans/lock/model/config/ErrorMessages.java b/jans-lock/service/src/main/java/io/jans/lock/model/config/ErrorMessages.java new file mode 100644 index 00000000000..ecb7785729e --- /dev/null +++ b/jans-lock/service/src/main/java/io/jans/lock/model/config/ErrorMessages.java @@ -0,0 +1,42 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.lock.model.config; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.jans.model.error.ErrorMessage; +import jakarta.xml.bind.annotation.XmlAccessType; +import jakarta.xml.bind.annotation.XmlAccessorType; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementWrapper; +import jakarta.xml.bind.annotation.XmlRootElement; + +/** + * Base interface for all Jans Auth configurations + * + * @author Yuriy Movchan Date: 12/18/2023 + */ +@XmlRootElement(name = "errors") +@XmlAccessorType(XmlAccessType.FIELD) +@JsonIgnoreProperties(ignoreUnknown = true) +public class ErrorMessages implements Configuration { + + @XmlElementWrapper(name = "common") + @XmlElement(name = "error") + private List common; + + public List getCommon() { + return common; + } + + public void setCommon(List common) { + this.common = common; + } + +} diff --git a/jans-lock/service/src/main/java/io/jans/lock/service/ServiceInitializer.java b/jans-lock/service/src/main/java/io/jans/lock/service/ServiceInitializer.java new file mode 100644 index 00000000000..379494b1975 --- /dev/null +++ b/jans-lock/service/src/main/java/io/jans/lock/service/ServiceInitializer.java @@ -0,0 +1,45 @@ +/* + * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.lock.service; + +import org.slf4j.Logger; + +import io.jans.lock.service.config.ConfigurationFactory; +import io.jans.lock.service.message.TokenSubService; +import io.jans.service.cdi.event.ApplicationInitializedEvent; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; + +/** + * + * Lock services initializer + * + * @author Yuriy Movchan Date: 12/18/2023 + */ +@ApplicationScoped +public class ServiceInitializer { + + @Inject + private Logger log; + + @Inject + private ConfigurationFactory configurationFactory; + + @Inject + private TokenSubService tokenSubService; + + public void applicationInitialized(@Observes ApplicationInitializedEvent applicationInitializedEvent) { + log.info("Initializing Lock service module services"); + + configurationFactory.initTimer(); + tokenSubService.subscribe(); + + log.debug("Initializing Lock service module services comple"); + } + +} diff --git a/jans-lock/service/src/main/java/io/jans/lock/service/config/ConfigurationFactory.java b/jans-lock/service/src/main/java/io/jans/lock/service/config/ConfigurationFactory.java index bd86ff7c8b9..355c83c31a0 100644 --- a/jans-lock/service/src/main/java/io/jans/lock/service/config/ConfigurationFactory.java +++ b/jans-lock/service/src/main/java/io/jans/lock/service/config/ConfigurationFactory.java @@ -287,7 +287,7 @@ public void destroy(Class clazz) { private Conf loadConfigurationFromDB(String... returnAttributes) { final PersistenceEntryManager persistenceEntryManager = persistenceEntryManagerInstance.get(); - final String dn = this.baseConfiguration.getString("link_ConfigurationEntryDN"); + final String dn = this.baseConfiguration.getString("lock_ConfigurationEntryDN"); try { final Conf conf = persistenceEntryManager.find(dn, Conf.class, returnAttributes); diff --git a/jans-lock/service/src/main/java/io/jans/lock/service/consumer/MessageConsumerFactory.java b/jans-lock/service/src/main/java/io/jans/lock/service/consumer/MessageConsumerFactory.java new file mode 100644 index 00000000000..8a77dc9b074 --- /dev/null +++ b/jans-lock/service/src/main/java/io/jans/lock/service/consumer/MessageConsumerFactory.java @@ -0,0 +1,44 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.lock.service.consumer; + +import org.slf4j.Logger; + +import io.jans.service.message.consumer.MessageConsumer; +import io.jans.util.StringHelper; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Any; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +/** + * Message consumer factory + * + * @author Yuriy Movchan Date: 12/18/2023 + */ +@ApplicationScoped +public class MessageConsumerFactory { + + @Inject + private Logger log; + + @Inject + @Any + private Instance consumerProviderInstances; + + public MessageConsumer getMessageConsumer(String messageConsumerType) { + for (MessageConsumer consumerProvider : consumerProviderInstances) { + String serviceMessageConsumerType = consumerProvider.getMessageConsumerType(); + if (StringHelper.equalsIgnoreCase(serviceMessageConsumerType, messageConsumerType)) { + return consumerProvider; + } + } + + return consumerProviderInstances.select(NullMessageConsumer.class).get(); + } + +} diff --git a/jans-lock/service/src/main/java/io/jans/lock/service/consumer/NullMessageConsumer.java b/jans-lock/service/src/main/java/io/jans/lock/service/consumer/NullMessageConsumer.java new file mode 100644 index 00000000000..5cce44e63b1 --- /dev/null +++ b/jans-lock/service/src/main/java/io/jans/lock/service/consumer/NullMessageConsumer.java @@ -0,0 +1,39 @@ +package io.jans.lock.service.consumer; + +import org.slf4j.Logger; + +import io.jans.service.cdi.async.Asynchronous; +import io.jans.service.message.consumer.MessageConsumer; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class NullMessageConsumer extends MessageConsumer { + + public static String CONSUMER_TYPE = "NULL"; + + @Inject + private Logger log; + + @Override + @Asynchronous + public void onMessage(String channel, String message) { + log.info("onMessage {} : {} : {}", channel, message); + } + + @Override + public void onSubscribe(String channel, int subscribedChannels) { + log.debug("onSubscribe {} : {}", channel, subscribedChannels); + } + + @Override + public void onUnsubscribe(String channel, int subscribedChannels) { + log.debug("onUnsubscribe {} : {}", channel, subscribedChannels); + } + + @Override + public String getMessageConsumerType() { + return CONSUMER_TYPE; + } + +} diff --git a/jans-lock/service/src/main/java/io/jans/lock/service/message/TokenSubService.java b/jans-lock/service/src/main/java/io/jans/lock/service/message/TokenSubService.java new file mode 100644 index 00000000000..4af52032728 --- /dev/null +++ b/jans-lock/service/src/main/java/io/jans/lock/service/message/TokenSubService.java @@ -0,0 +1,45 @@ +/* + * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2023, Janssen Project + */ + +package io.jans.lock.service.message; + +import org.slf4j.Logger; + +import io.jans.lock.model.config.AppConfiguration; +import io.jans.lock.service.consumer.MessageConsumerFactory; +import io.jans.service.message.consumer.MessageConsumer; +import io.jans.service.message.provider.MessageProvider; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +/** + * @author Yuriy Movchan Date: 15/12/2023 + */ +@ApplicationScoped +public class TokenSubService { + + @Inject + protected Logger log; + + @Inject + private AppConfiguration appConfiguration; + + @Inject + private MessageProvider messageProvider; + + @Inject + private MessageConsumerFactory messageConsumerFactory; + + public void subscribe() { + log.info("Use message provider type: {}", messageProvider.getProviderType()); + + MessageConsumer messageConsumer = messageConsumerFactory.getMessageConsumer(appConfiguration.getMessageConsumerType()); + + messageProvider.subscribe(messageConsumer, appConfiguration.getTokenChannels().toArray(new String[0])); + + log.info("Subscribed to channels: {}", appConfiguration.getTokenChannels()); + } +} diff --git a/jans-orm/sql/src/main/java/io/jans/orm/sql/operation/impl/SqConnectionProviderPool.java b/jans-orm/sql/src/main/java/io/jans/orm/sql/operation/impl/SqConnectionProviderPool.java index e8cc387ca63..11532cc7487 100644 --- a/jans-orm/sql/src/main/java/io/jans/orm/sql/operation/impl/SqConnectionProviderPool.java +++ b/jans-orm/sql/src/main/java/io/jans/orm/sql/operation/impl/SqConnectionProviderPool.java @@ -172,13 +172,21 @@ private void openWithWaitImpl() throws Exception { } } - private void open() { + private void open() throws ClassNotFoundException { + preloadJdbcDriver(); + ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(connectionUri, connectionProperties); PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null); ObjectPool objectPool = new GenericObjectPool<>(poolableConnectionFactory, objectPoolConfig); + poolableConnectionFactory.setPool(objectPool); this.poolingDataSource = new PoolingDataSource<>(objectPool); - poolableConnectionFactory.setPool(objectPool); + } + + public void preloadJdbcDriver() throws ClassNotFoundException { + if (props.containsKey("jdbc.driver.class-name")) { + Class.forName(props.getProperty("jdbc.driver.class-name")); + } } public int getCreationResultCode() {