From b2152d6a8603239735854dc48189c46f9826d790 Mon Sep 17 00:00:00 2001 From: Dan Galdi Date: Thu, 22 Aug 2024 13:58:37 -0400 Subject: [PATCH] Fix date postgres and make SMTP port configurable (#105) --- Model/lib/rng/wdkModel-config.rng | 11 ++++++ .../java/org/gusdb/wdk/model/Utilities.java | 16 ++++++-- .../gusdb/wdk/model/config/ModelConfig.java | 38 +++++++++++++++---- .../wdk/model/config/ModelConfigBuilder.java | 14 +++++++ .../wdk/model/user/UserPasswordEmailer.java | 4 +- .../wdk/model/user/UserReferenceFactory.java | 12 +++--- 6 files changed, 77 insertions(+), 18 deletions(-) diff --git a/Model/lib/rng/wdkModel-config.rng b/Model/lib/rng/wdkModel-config.rng index 6bdd9e4c7..ea400562e 100644 --- a/Model/lib/rng/wdkModel-config.rng +++ b/Model/lib/rng/wdkModel-config.rng @@ -13,6 +13,17 @@ + + + + + + + + + + + diff --git a/Model/src/main/java/org/gusdb/wdk/model/Utilities.java b/Model/src/main/java/org/gusdb/wdk/model/Utilities.java index ab6b8e2b1..48fcce356 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/Utilities.java +++ b/Model/src/main/java/org/gusdb/wdk/model/Utilities.java @@ -217,18 +217,18 @@ public static void sendEmail(String smtpServer, String sendTos, String reply, String subject, String content, String ccAddresses, Attachment[] attachments) throws WdkModelException { // call the 8 parameter one - sendEmail(smtpServer, null, null, sendTos, reply, subject, content, ccAddresses, null, attachments); + sendEmail(smtpServer, null, null, sendTos, reply, subject, content, ccAddresses, null, attachments, 25, false); } public static void sendEmail(String smtpServer, String sendTos, String reply, String subject, String content, String ccAddresses, String bccAddresses, Attachment[] attachments) throws WdkModelException { - sendEmail(smtpServer, null, null, sendTos, reply, subject, content, ccAddresses, bccAddresses, attachments); + sendEmail(smtpServer, null, null, sendTos, reply, subject, content, ccAddresses, bccAddresses, attachments, 25, false); } - // sendEmail() all 10 parameters + // sendEmail() all 12 parameters public static void sendEmail(String smtpServer, String username, String password, String sendTos, String reply, - String subject, String content, String ccAddresses, String bccAddresses, Attachment[] attachments) throws WdkModelException { + String subject, String content, String ccAddresses, String bccAddresses, Attachment[] attachments, int smtpPort, boolean tlsEnabled) throws WdkModelException { LOG.debug("Sending message to: " + sendTos + ", bcc to: " + bccAddresses + ",reply: " + reply + ", using SMPT: " + smtpServer); @@ -237,6 +237,14 @@ public static void sendEmail(String smtpServer, String username, String password Properties props = new Properties(); props.put("mail.smtp.host", smtpServer); props.put("mail.debug", "true"); + props.put("mail.smtp.port", smtpPort); + + if (tlsEnabled) { + props.put("mail.smtp.starttls.enable","true"); + props.put("mail.smtp.ssl.protocols", "TLSv1.2"); + props.put("mail.smtp.ssl.trust", smtpServer); + } + Authenticator auth = null; if (username != null && password != null) { diff --git a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java index feea6767a..a25a4c18c 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java +++ b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java @@ -14,7 +14,7 @@ /** * An object representation of the {@code model-config.xml} file. It holds all the configuration information * for the WDK system. - * + * * @author Jerric */ public class ModelConfig implements OAuthConfig, KeyStoreConfig { @@ -53,6 +53,17 @@ public String getName() { private final Optional _smtpPassword; + /** + * the SMTP port to connect to on SMTP server. + */ + private final int _smtpPort; + + /** + * Determines whether to use TLS when connecting to SMTP server. + */ + private final boolean _smtpTlsEnabled; + + /** * the reply of the registration & recover password emails. */ @@ -155,8 +166,8 @@ public String getName() { public ModelConfig(String modelName, String projectId, Path gusHome, boolean caching, boolean useWeights, String paramRegex, Optional secretKeyFile, String secretKey, Path wdkTempDir, String webServiceUrl, String assetsUrl, - String smtpServer, Optional smtpUser, Optional smtpPassword, String supportEmail, List adminEmails, String emailSubject, - String emailContent, ModelConfigUserDB userDB, ModelConfigAppDB appDB, + String smtpServer, Optional smtpUser, Optional smtpPassword, Integer smtpPort, boolean smtpTlsEnabled, String supportEmail, + List adminEmails, String emailSubject, String emailContent, ModelConfigUserDB userDB, ModelConfigAppDB appDB, ModelConfigUserDatasetStore userDatasetStoreConfig, QueryMonitor queryMonitor, boolean monitorBlockedThreads, int blockedThreshold, AuthenticationMethod authenticationMethod, String oauthUrl, String oauthClientId, String oauthClientSecret, String changePasswordUrl, @@ -185,6 +196,9 @@ public ModelConfig(String modelName, String projectId, Path gusHome, boolean cac _smtpServer = smtpServer; _smtpUserName = smtpUser; _smtpPassword = smtpPassword; + _smtpPort = smtpPort; + _smtpTlsEnabled = smtpTlsEnabled; + _supportEmail = supportEmail; _adminEmails = adminEmails; _emailSubject = emailSubject; @@ -221,7 +235,7 @@ public ModelConfig(String modelName, String projectId, Path gusHome, boolean cac /** * If it returns true, a monitoring thread will be turned on when webapp is initialized. - * + * * @return */ public boolean isMonitorBlockedThreads() { @@ -230,7 +244,7 @@ public boolean isMonitorBlockedThreads() { /** * An report will be fired when the number of blocked threads reaches the threshold. - * + * * @return */ public int getBlockedThreshold() { @@ -277,6 +291,14 @@ public Optional getSmtpPassword() { return _smtpPassword; } + public int getSmtpPort() { + return _smtpPort; + } + + public boolean isSmtpTlsEnabled() { + return _smtpTlsEnabled; + } + /** * @return Returns the emailContent. */ @@ -317,9 +339,9 @@ public ModelConfigAppDB getAppDB() { * Returns a cached secret key, generated by encrypting the value in the * configured secret key file. If the configured filename is null or the contents * of the file cannot be read for any reason, null is returned. - * + * * Note: as of 8/12/24, you can alternatively directly set the secretKey in model-config.xml - * + * * @return secret key */ public String getSecretKey() { @@ -444,7 +466,7 @@ public QueryMonitor getQueryMonitor() { * own cache behavior. if global caching is disabled, then caching on sqlQuery will always be disabled, * regardless of the individual setting on the query. Please note that this flag has no effect on * processQueries, which is always cached. - * + * * @return whether global caching is turned on or not. */ public boolean isCaching() { diff --git a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java index c5ea41243..e9d93f467 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java +++ b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java @@ -16,6 +16,7 @@ public class ModelConfigBuilder { private static final Logger LOG = Logger.getLogger(ModelConfigBuilder.class); + private static final int DEFAULT_SMTP_PORT = 25; // basic model information private String _modelName; @@ -40,6 +41,8 @@ public class ModelConfigBuilder { private String _smtpServer; private String _smtpUsername; private String _smtpPassword; + private Integer _smtpPort; + private boolean _smtpTlsEnabled; private String _supportEmail; private List _adminEmails = Collections.emptyList(); private String _emailSubject = ""; @@ -98,6 +101,7 @@ public ModelConfig build() throws WdkModelException { Optional smtpUsername = Optional.ofNullable(_smtpUsername).filter(s -> !s.isBlank()); Optional smtpPassword = Optional.ofNullable(_smtpPassword).filter(s -> !s.isBlank()); String smtpServer = _smtpServer == null ? "localhost" : _smtpServer; + int smtpPort = _smtpPort == null ? DEFAULT_SMTP_PORT : _smtpPort; return new ModelConfig( @@ -124,6 +128,8 @@ public ModelConfig build() throws WdkModelException { smtpServer, smtpUsername, smtpPassword, + smtpPort, + _smtpTlsEnabled, _supportEmail, _adminEmails, _emailSubject, @@ -214,6 +220,14 @@ public void setSmtpPassword(String smtpPassword) { _smtpPassword = smtpPassword; } + public void setSmtpPort(int smtpPort) { + _smtpPort = smtpPort; + } + + public void setSmtpTlsEnabled(boolean smtpTlsEnabled) { + _smtpTlsEnabled = smtpTlsEnabled; + } + /** * @param emailContent * The emailContent to set. diff --git a/Model/src/main/java/org/gusdb/wdk/model/user/UserPasswordEmailer.java b/Model/src/main/java/org/gusdb/wdk/model/user/UserPasswordEmailer.java index 6a1373721..8806d2d42 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/user/UserPasswordEmailer.java +++ b/Model/src/main/java/org/gusdb/wdk/model/user/UserPasswordEmailer.java @@ -42,6 +42,8 @@ public void emailTemporaryPassword(User user, String password) throws WdkModelEx // Unwrap optionals here to maintain consistency with nullable arguments in Utilities.sendEmail method. String smtpUser = wdkModelConfig.getSmtpUserName().orElse(null); String smtpPass = wdkModelConfig.getSmtpPassword().orElse(null); + int smtpPort = wdkModelConfig.getSmtpPort(); + boolean smtpTlsEnabled = wdkModelConfig.isSmtpTlsEnabled(); // populate email content macros with user data String emailContent = wdkModelConfig.getEmailContent() @@ -52,6 +54,6 @@ public void emailTemporaryPassword(User user, String password) throws WdkModelEx .replaceAll("\\$\\$" + EMAIL_MACRO_PASSWORD + "\\$\\$", Matcher.quoteReplacement(password)); - Utilities.sendEmail(smtpServer, smtpUser, smtpPass, user.getEmail(), supportEmail, emailSubject, emailContent, null, null, new Attachment[]{}); + Utilities.sendEmail(smtpServer, smtpUser, smtpPass, user.getEmail(), supportEmail, emailSubject, emailContent, null, null, new Attachment[]{}, smtpPort, smtpTlsEnabled); } } diff --git a/Model/src/main/java/org/gusdb/wdk/model/user/UserReferenceFactory.java b/Model/src/main/java/org/gusdb/wdk/model/user/UserReferenceFactory.java index 9197d2e8f..5c6ec3d24 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/user/UserReferenceFactory.java +++ b/Model/src/main/java/org/gusdb/wdk/model/user/UserReferenceFactory.java @@ -29,9 +29,10 @@ class UserReferenceFactory { public static final String USER_SCHEMA_MACRO = "$$USER_SCHEMA$$"; private static final String IS_GUEST_VALUE_MACRO = "$$IS_GUEST$$"; + private static final String FIRST_ACCESS_MACRO = "$$FIRST_ACCESS$$"; // types used by SQL returned by getInsertUserRefSql() below - private static final Integer[] INSERT_USER_REF_PARAM_TYPES = { Types.BIGINT, Types.TIMESTAMP }; + private static final Integer[] INSERT_USER_REF_PARAM_TYPES = { Types.BIGINT }; // SQL and types to select user ref by ID private static final String SELECT_USER_REF_BY_ID_SQL = @@ -72,12 +73,13 @@ public int addUserReference(User user) throws WdkModelException { try { long userId = user.getUserId(); boolean isGuest = user.isGuest(); - Timestamp insertedOn = new Timestamp(new Date().getTime()); + Date insertedOn = new Date(); String sql = getInsertUserRefSql() .replace(USER_SCHEMA_MACRO, _userSchema) - .replace(IS_GUEST_VALUE_MACRO, _userDb.getPlatform().convertBoolean(isGuest).toString()); + .replace(IS_GUEST_VALUE_MACRO, _userDb.getPlatform().convertBoolean(isGuest).toString()) + .replace(FIRST_ACCESS_MACRO, _userDb.getPlatform().toDbDateSqlValue(insertedOn)); return new SQLRunner(_userDb.getDataSource(), sql, "insert-user-ref") - .executeUpdate(new Object[]{ userId, insertedOn }, INSERT_USER_REF_PARAM_TYPES); + .executeUpdate(new Object[]{userId}, INSERT_USER_REF_PARAM_TYPES); } catch (SQLRunnerException e) { throw WdkModelException.translateFrom(e); @@ -86,7 +88,7 @@ public int addUserReference(User user) throws WdkModelException { private String getInsertUserRefSql() { return "MERGE INTO " + USER_SCHEMA_MACRO + TABLE_USERS + " tgt " + - "USING (SELECT ? AS user_id, ? AS first_access, " + IS_GUEST_VALUE_MACRO + " AS is_guest" + _userDb.getPlatform().getDummyTable() + ") src " + + "USING (SELECT ? AS user_id, " + FIRST_ACCESS_MACRO + " AS first_access, " + IS_GUEST_VALUE_MACRO + " AS is_guest" + _userDb.getPlatform().getDummyTable() + ") src " + "ON (tgt." + COL_USER_ID + " = src.user_id) " + "WHEN NOT MATCHED THEN " + "INSERT (" + COL_USER_ID + ", " + COL_IS_GUEST + ", " + COL_FIRST_ACCESS + ") " +