Merge pull request #75 from hapifhir/ks-20200113-mailtls

Preparing for email TLS support
This commit is contained in:
Sean McIlvenna
2020-01-14 11:01:47 -08:00
committed by GitHub
2 changed files with 156 additions and 140 deletions

View File

@@ -26,168 +26,178 @@ import java.sql.Driver;
@EnableTransactionManagement() @EnableTransactionManagement()
public class FhirServerConfigCommon { public class FhirServerConfigCommon {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirServerConfigCommon.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirServerConfigCommon.class);
private Boolean enableIndexMissingFields = HapiProperties.getEnableIndexMissingFields(); private Boolean enableIndexMissingFields = HapiProperties.getEnableIndexMissingFields();
private Boolean autoCreatePlaceholderReferenceTargets = HapiProperties.getAutoCreatePlaceholderReferenceTargets(); private Boolean autoCreatePlaceholderReferenceTargets = HapiProperties.getAutoCreatePlaceholderReferenceTargets();
private Boolean enforceReferentialIntegrityOnWrite = HapiProperties.getEnforceReferentialIntegrityOnWrite(); private Boolean enforceReferentialIntegrityOnWrite = HapiProperties.getEnforceReferentialIntegrityOnWrite();
private Boolean enforceReferentialIntegrityOnDelete = HapiProperties.getEnforceReferentialIntegrityOnDelete(); private Boolean enforceReferentialIntegrityOnDelete = HapiProperties.getEnforceReferentialIntegrityOnDelete();
private Boolean allowContainsSearches = HapiProperties.getAllowContainsSearches(); private Boolean allowContainsSearches = HapiProperties.getAllowContainsSearches();
private Boolean allowMultipleDelete = HapiProperties.getAllowMultipleDelete(); private Boolean allowMultipleDelete = HapiProperties.getAllowMultipleDelete();
private Boolean allowExternalReferences = HapiProperties.getAllowExternalReferences(); private Boolean allowExternalReferences = HapiProperties.getAllowExternalReferences();
private Boolean expungeEnabled = HapiProperties.getExpungeEnabled(); private Boolean expungeEnabled = HapiProperties.getExpungeEnabled();
private Boolean allowPlaceholderReferences = HapiProperties.getAllowPlaceholderReferences(); private Boolean allowPlaceholderReferences = HapiProperties.getAllowPlaceholderReferences();
private Boolean subscriptionRestHookEnabled = HapiProperties.getSubscriptionRestHookEnabled(); private Boolean subscriptionRestHookEnabled = HapiProperties.getSubscriptionRestHookEnabled();
private Boolean subscriptionEmailEnabled = HapiProperties.getSubscriptionEmailEnabled(); private Boolean subscriptionEmailEnabled = HapiProperties.getSubscriptionEmailEnabled();
private Boolean allowOverrideDefaultSearchParams = HapiProperties.getAllowOverrideDefaultSearchParams(); private Boolean allowOverrideDefaultSearchParams = HapiProperties.getAllowOverrideDefaultSearchParams();
private String emailFrom = HapiProperties.getEmailFrom(); private String emailFrom = HapiProperties.getEmailFrom();
private Boolean emailEnabled = HapiProperties.getEmailEnabled(); private Boolean emailEnabled = HapiProperties.getEmailEnabled();
private String emailHost = HapiProperties.getEmailHost(); private String emailHost = HapiProperties.getEmailHost();
private Integer emailPort = HapiProperties.getEmailPort(); private Integer emailPort = HapiProperties.getEmailPort();
private String emailUsername = HapiProperties.getEmailUsername(); private String emailUsername = HapiProperties.getEmailUsername();
private String emailPassword = HapiProperties.getEmailPassword(); private String emailPassword = HapiProperties.getEmailPassword();
@Autowired private Boolean emailAuth = HapiProperties.getEmailAuth();
private SubscriptionDeliveryHandlerFactory mySubscriptionDeliveryHandlerFactory; private Boolean emailStartTlsEnable = HapiProperties.getEmailStartTlsEnable();
private Boolean emailStartTlsRequired = HapiProperties.getEmailStartTlsRequired();
private Boolean emailQuitWait = HapiProperties.getEmailQuitWait();
public FhirServerConfigCommon() { @Autowired
ourLog.info("Server configured to " + (this.allowContainsSearches ? "allow" : "deny") + " contains searches"); private SubscriptionDeliveryHandlerFactory mySubscriptionDeliveryHandlerFactory;
ourLog.info("Server configured to " + (this.allowMultipleDelete ? "allow" : "deny") + " multiple deletes");
ourLog.info("Server configured to " + (this.allowExternalReferences ? "allow" : "deny") + " external references");
ourLog.info("Server configured to " + (this.expungeEnabled ? "enable" : "disable") + " expunges");
ourLog.info("Server configured to " + (this.allowPlaceholderReferences ? "allow" : "deny") + " placeholder references");
ourLog.info("Server configured to " + (this.allowOverrideDefaultSearchParams ? "allow" : "deny") + " overriding default search params");
if (this.emailEnabled) { public FhirServerConfigCommon() {
ourLog.info("Server is configured to enable email with host '" + this.emailHost + "' and port " + this.emailPort.toString()); ourLog.info("Server configured to " + (this.allowContainsSearches ? "allow" : "deny") + " contains searches");
ourLog.info("Server will use '" + this.emailFrom + "' as the from email address"); ourLog.info("Server configured to " + (this.allowMultipleDelete ? "allow" : "deny") + " multiple deletes");
ourLog.info("Server configured to " + (this.allowExternalReferences ? "allow" : "deny") + " external references");
ourLog.info("Server configured to " + (this.expungeEnabled ? "enable" : "disable") + " expunges");
ourLog.info("Server configured to " + (this.allowPlaceholderReferences ? "allow" : "deny") + " placeholder references");
ourLog.info("Server configured to " + (this.allowOverrideDefaultSearchParams ? "allow" : "deny") + " overriding default search params");
if (this.emailUsername != null && this.emailUsername.length() > 0) { if (this.emailEnabled) {
ourLog.info("Server is configured to use username '" + this.emailUsername + "' for email"); ourLog.info("Server is configured to enable email with host '" + this.emailHost + "' and port " + this.emailPort.toString());
} ourLog.info("Server will use '" + this.emailFrom + "' as the from email address");
if (this.emailPassword != null && this.emailPassword.length() > 0) { if (this.emailUsername != null && this.emailUsername.length() > 0) {
ourLog.info("Server is configured to use a password for email"); ourLog.info("Server is configured to use username '" + this.emailUsername + "' for email");
} }
}
if (this.subscriptionRestHookEnabled) { if (this.emailPassword != null && this.emailPassword.length() > 0) {
ourLog.info("REST-hook subscriptions enabled"); ourLog.info("Server is configured to use a password for email");
} }
if (this.subscriptionEmailEnabled) {
ourLog.info("Email subscriptions enabled");
}
} }
/** if (this.subscriptionRestHookEnabled) {
* Configure FHIR properties around the the JPA server via this bean ourLog.info("REST-hook subscriptions enabled");
*/
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setIndexMissingFields(this.enableIndexMissingFields ? DaoConfig.IndexEnabledEnum.ENABLED : DaoConfig.IndexEnabledEnum.DISABLED);
retVal.setAutoCreatePlaceholderReferenceTargets(this.autoCreatePlaceholderReferenceTargets);
retVal.setEnforceReferentialIntegrityOnWrite(this.enforceReferentialIntegrityOnWrite);
retVal.setEnforceReferentialIntegrityOnDelete(this.enforceReferentialIntegrityOnDelete);
retVal.setAllowContainsSearches(this.allowContainsSearches);
retVal.setAllowMultipleDelete(this.allowMultipleDelete);
retVal.setAllowExternalReferences(this.allowExternalReferences);
retVal.setExpungeEnabled(this.expungeEnabled);
retVal.setAutoCreatePlaceholderReferenceTargets(this.allowPlaceholderReferences);
retVal.setEmailFromAddress(this.emailFrom);
Integer maxFetchSize = HapiProperties.getMaximumFetchSize();
retVal.setFetchSizeDefaultMaximum(maxFetchSize);
ourLog.info("Server configured to have a maximum fetch size of " + (maxFetchSize == Integer.MAX_VALUE ? "'unlimited'" : maxFetchSize));
Long reuseCachedSearchResultsMillis = HapiProperties.getReuseCachedSearchResultsMillis();
retVal.setReuseCachedSearchResultsForMillis(reuseCachedSearchResultsMillis);
ourLog.info("Server configured to cache search results for {} milliseconds", reuseCachedSearchResultsMillis);
Long retainCachedSearchesMinutes = HapiProperties.getExpireSearchResultsAfterMins();
retVal.setExpireSearchResultsAfterMillis(retainCachedSearchesMinutes * 60 * 1000);
// Subscriptions are enabled by channel type
if (HapiProperties.getSubscriptionRestHookEnabled()) {
ourLog.info("Enabling REST-hook subscriptions");
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.RESTHOOK);
}
if (HapiProperties.getSubscriptionEmailEnabled()) {
ourLog.info("Enabling email subscriptions");
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.EMAIL);
}
if (HapiProperties.getSubscriptionWebsocketEnabled()) {
ourLog.info("Enabling websocket subscriptions");
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.WEBSOCKET);
}
retVal.setFilterParameterEnabled(HapiProperties.getFilterSearchEnabled());
return retVal;
} }
@Bean if (this.subscriptionEmailEnabled) {
public ModelConfig modelConfig() { ourLog.info("Email subscriptions enabled");
ModelConfig modelConfig = new ModelConfig(); }
modelConfig.setAllowContainsSearches(this.allowContainsSearches); }
modelConfig.setAllowExternalReferences(this.allowExternalReferences);
modelConfig.setDefaultSearchParamsCanBeOverridden(this.allowOverrideDefaultSearchParams);
modelConfig.setEmailFromAddress(this.emailFrom);
// You can enable these if you want to support Subscriptions from your server /**
if (this.subscriptionRestHookEnabled) { * Configure FHIR properties around the the JPA server via this bean
modelConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.RESTHOOK); */
} @Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
if (this.subscriptionEmailEnabled) { retVal.setIndexMissingFields(this.enableIndexMissingFields ? DaoConfig.IndexEnabledEnum.ENABLED : DaoConfig.IndexEnabledEnum.DISABLED);
modelConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.EMAIL); retVal.setAutoCreatePlaceholderReferenceTargets(this.autoCreatePlaceholderReferenceTargets);
} retVal.setEnforceReferentialIntegrityOnWrite(this.enforceReferentialIntegrityOnWrite);
retVal.setEnforceReferentialIntegrityOnDelete(this.enforceReferentialIntegrityOnDelete);
retVal.setAllowContainsSearches(this.allowContainsSearches);
retVal.setAllowMultipleDelete(this.allowMultipleDelete);
retVal.setAllowExternalReferences(this.allowExternalReferences);
retVal.setExpungeEnabled(this.expungeEnabled);
retVal.setAutoCreatePlaceholderReferenceTargets(this.allowPlaceholderReferences);
retVal.setEmailFromAddress(this.emailFrom);
return modelConfig; Integer maxFetchSize = HapiProperties.getMaximumFetchSize();
retVal.setFetchSizeDefaultMaximum(maxFetchSize);
ourLog.info("Server configured to have a maximum fetch size of " + (maxFetchSize == Integer.MAX_VALUE ? "'unlimited'" : maxFetchSize));
Long reuseCachedSearchResultsMillis = HapiProperties.getReuseCachedSearchResultsMillis();
retVal.setReuseCachedSearchResultsForMillis(reuseCachedSearchResultsMillis);
ourLog.info("Server configured to cache search results for {} milliseconds", reuseCachedSearchResultsMillis);
Long retainCachedSearchesMinutes = HapiProperties.getExpireSearchResultsAfterMins();
retVal.setExpireSearchResultsAfterMillis(retainCachedSearchesMinutes * 60 * 1000);
// Subscriptions are enabled by channel type
if (HapiProperties.getSubscriptionRestHookEnabled()) {
ourLog.info("Enabling REST-hook subscriptions");
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.RESTHOOK);
}
if (HapiProperties.getSubscriptionEmailEnabled()) {
ourLog.info("Enabling email subscriptions");
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.EMAIL);
}
if (HapiProperties.getSubscriptionWebsocketEnabled()) {
ourLog.info("Enabling websocket subscriptions");
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.WEBSOCKET);
} }
/** retVal.setFilterParameterEnabled(HapiProperties.getFilterSearchEnabled());
* The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
* directory called "jpaserver_derby_files". return retVal;
* <p> }
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
*/ @Bean
@Bean(destroyMethod = "close") public ModelConfig modelConfig() {
public BasicDataSource dataSource() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { ModelConfig modelConfig = new ModelConfig();
BasicDataSource retVal = new BasicDataSource(); modelConfig.setAllowContainsSearches(this.allowContainsSearches);
Driver driver = (Driver) Class.forName(HapiProperties.getDataSourceDriver()).getConstructor().newInstance(); modelConfig.setAllowExternalReferences(this.allowExternalReferences);
retVal.setDriver(driver); modelConfig.setDefaultSearchParamsCanBeOverridden(this.allowOverrideDefaultSearchParams);
retVal.setUrl(HapiProperties.getDataSourceUrl()); modelConfig.setEmailFromAddress(this.emailFrom);
retVal.setUsername(HapiProperties.getDataSourceUsername());
retVal.setPassword(HapiProperties.getDataSourcePassword()); // You can enable these if you want to support Subscriptions from your server
retVal.setMaxTotal(HapiProperties.getDataSourceMaxPoolSize()); if (this.subscriptionRestHookEnabled) {
return retVal; modelConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.RESTHOOK);
} }
@Lazy if (this.subscriptionEmailEnabled) {
@Bean modelConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.EMAIL);
public IBinaryStorageSvc binaryStorageSvc() {
return new DatabaseBlobBinaryStorageSvcImpl();
} }
@Bean() return modelConfig;
public IEmailSender emailSender() { }
if (this.emailEnabled) {
JavaMailEmailSender retVal = new JavaMailEmailSender();
retVal.setSmtpServerHostname(this.emailHost); /**
retVal.setSmtpServerPort(this.emailPort); * The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
retVal.setSmtpServerUsername(this.emailUsername); * directory called "jpaserver_derby_files".
retVal.setSmtpServerPassword(this.emailPassword); * <p>
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
*/
@Bean(destroyMethod = "close")
public BasicDataSource dataSource() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
BasicDataSource retVal = new BasicDataSource();
Driver driver = (Driver) Class.forName(HapiProperties.getDataSourceDriver()).getConstructor().newInstance();
retVal.setDriver(driver);
retVal.setUrl(HapiProperties.getDataSourceUrl());
retVal.setUsername(HapiProperties.getDataSourceUsername());
retVal.setPassword(HapiProperties.getDataSourcePassword());
retVal.setMaxTotal(HapiProperties.getDataSourceMaxPoolSize());
return retVal;
}
Validate.notNull(mySubscriptionDeliveryHandlerFactory, "No subscription delivery handler"); @Lazy
mySubscriptionDeliveryHandlerFactory.setEmailSender(retVal); @Bean
public IBinaryStorageSvc binaryStorageSvc() {
return new DatabaseBlobBinaryStorageSvcImpl();
}
@Bean()
public IEmailSender emailSender() {
if (this.emailEnabled) {
JavaMailEmailSender retVal = new JavaMailEmailSender();
retVal.setSmtpServerHostname(this.emailHost);
retVal.setSmtpServerPort(this.emailPort);
retVal.setSmtpServerUsername(this.emailUsername);
retVal.setSmtpServerPassword(this.emailPassword);
// TODO KHS add these when HAPI 4.2.0 is released
// retVal.setAuth(this.emailAuth);
// retVal.setStartTlsEnable(this.emailStartTlsEnable);
// retVal.setStartTlsRequired(this.emailStartTlsRequired);
// retVal.setQuitWait(this.emailQuitWait);
Validate.notNull(mySubscriptionDeliveryHandlerFactory, "No subscription delivery handler");
mySubscriptionDeliveryHandlerFactory.setEmailSender(retVal);
return retVal; return retVal;
}
return null;
} }
return null;
}
} }

View File

@@ -406,6 +406,12 @@ public class HapiProperties {
return HapiProperties.getProperty("email.password"); return HapiProperties.getProperty("email.password");
} }
// Defaults from https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html
public static Boolean getEmailAuth() { return HapiProperties.getBooleanProperty("email.auth", false); }
public static Boolean getEmailStartTlsEnable() { return HapiProperties.getBooleanProperty("email.starttls.enable", false); }
public static Boolean getEmailStartTlsRequired() { return HapiProperties.getBooleanProperty("email.starttls.required", false); }
public static Boolean getEmailQuitWait() { return HapiProperties.getBooleanProperty("email.quitwait", true); }
public static Long getReuseCachedSearchResultsMillis() { public static Long getReuseCachedSearchResultsMillis() {
String value = HapiProperties.getProperty(REUSE_CACHED_SEARCH_RESULTS_MILLIS, "60000"); String value = HapiProperties.getProperty(REUSE_CACHED_SEARCH_RESULTS_MILLIS, "60000");
return Long.valueOf(value); return Long.valueOf(value);