From f91b19afcb1f6fe97b46aa694049db0a98d166a9 Mon Sep 17 00:00:00 2001 From: Mike McKay <mfmckay@wustl.edu> Date: Mon, 30 May 2016 15:29:22 -0500 Subject: [PATCH] A bunch of fixes to get password expiration working. --- .../xnat/configuration/SchedulerConfig.java | 1 + .../PasswordExpirationHandlerMethod.java | 53 +++++++++++++++++ .../security/XnatExpiredPasswordFilter.java | 58 ++++++++++++++----- .../xnat/spawner/site-admin-elements.yaml | 10 ++-- .../config/site/siteConfiguration.properties | 2 +- 5 files changed, 103 insertions(+), 21 deletions(-) create mode 100644 src/main/java/org/nrg/xnat/event/listeners/methods/PasswordExpirationHandlerMethod.java diff --git a/src/main/java/org/nrg/xnat/configuration/SchedulerConfig.java b/src/main/java/org/nrg/xnat/configuration/SchedulerConfig.java index f69f7691..efe99510 100644 --- a/src/main/java/org/nrg/xnat/configuration/SchedulerConfig.java +++ b/src/main/java/org/nrg/xnat/configuration/SchedulerConfig.java @@ -54,6 +54,7 @@ public class SchedulerConfig implements SchedulingConfigurer { _eventService.triggerEvent(new PreferenceEvent("host", String.valueOf(XDAT.getNotificationsPreferences().getHostname()))); _eventService.triggerEvent(new PreferenceEvent("requireLogin", String.valueOf(XDAT.getSiteConfigPreferences().getRequireLogin()))); _eventService.triggerEvent(new PreferenceEvent("security.channel", String.valueOf(XDAT.getSiteConfigPreferences().getSecurityChannel()))); + _eventService.triggerEvent(new PreferenceEvent("passwordExpirationType", String.valueOf(XDAT.getSiteConfigPreferences().getPasswordExpirationType()))); for (final TriggerTask triggerTask : _triggerTasks) { taskRegistrar.addTriggerTask(triggerTask); } diff --git a/src/main/java/org/nrg/xnat/event/listeners/methods/PasswordExpirationHandlerMethod.java b/src/main/java/org/nrg/xnat/event/listeners/methods/PasswordExpirationHandlerMethod.java new file mode 100644 index 00000000..cf5bafca --- /dev/null +++ b/src/main/java/org/nrg/xnat/event/listeners/methods/PasswordExpirationHandlerMethod.java @@ -0,0 +1,53 @@ +package org.nrg.xnat.event.listeners.methods; + +import com.google.common.collect.ImmutableList; +import org.nrg.xnat.security.XnatExpiredPasswordFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Lazy; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Component +public class PasswordExpirationHandlerMethod extends AbstractSiteConfigPreferenceHandlerMethod { + @Override + public List<String> getHandledPreferences() { + return PREFERENCES; + } + + @Override + public void handlePreferences(final Map<String, String> values) { + if (!Collections.disjoint(PREFERENCES, values.keySet())) { + updatePasswordExpiration(); + } + } + + @Override + public void handlePreference(final String preference, final String value) { + if (PREFERENCES.contains(preference)) { + updatePasswordExpiration(); + } + } + + private void updatePasswordExpiration() { + _filter.refreshFromSiteConfig(); + } + + private static final Logger _log = LoggerFactory.getLogger(PasswordExpirationHandlerMethod.class); + private static final List<String> PREFERENCES = ImmutableList.copyOf(Arrays.asList("passwordExpirationType", "passwordExpirationInterval", "passwordExpirationDate")); + + @Autowired + @Lazy + private JdbcTemplate _template; + + @Autowired + @Qualifier("expiredPasswordFilter") + private XnatExpiredPasswordFilter _filter; +} diff --git a/src/main/java/org/nrg/xnat/security/XnatExpiredPasswordFilter.java b/src/main/java/org/nrg/xnat/security/XnatExpiredPasswordFilter.java index 86f24801..90847a01 100644 --- a/src/main/java/org/nrg/xnat/security/XnatExpiredPasswordFilter.java +++ b/src/main/java/org/nrg/xnat/security/XnatExpiredPasswordFilter.java @@ -184,7 +184,7 @@ public class XnatExpiredPasswordFilter extends GenericFilterBean { } else if (user.isEnabled()) { boolean isExpired = checkForExpiredPassword(user); - if ((!isUserNonExpiring(user) && isExpired) || (_preferences.getRequireSaltedPasswords() && user.getSalt() == null)) { + if ((!isUserNonExpiring(user) && isExpired) || (_initializerPreferences.getRequireSaltedPasswords() && user.getSalt() == null)) { request.getSession().setAttribute("expired", isExpired); response.sendRedirect(TurbineUtils.GetFullServerPath() + changePasswordPath); } else { @@ -264,7 +264,7 @@ public class XnatExpiredPasswordFilter extends GenericFilterBean { return false; } if (isPasswordExpirationInterval()) { - List<Boolean> expired = (new JdbcTemplate(_dataSource)).query("SELECT ((now()-password_updated)> (Interval '" + passwordExpirationSetting + " days')) AS expired FROM xhbm_xdat_user_auth WHERE auth_user = ? AND auth_method = 'localdb'", new String[] {username}, new RowMapper<Boolean>() { + List<Boolean> expired = (new JdbcTemplate(_dataSource)).query("SELECT ((now()-password_updated)> (Interval '" + passwordExpirationSetting + "')) AS expired FROM xhbm_xdat_user_auth WHERE auth_user = ? AND auth_method = 'localdb'", new String[] {username}, new RowMapper<Boolean>() { public Boolean mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getBoolean(1); } @@ -288,20 +288,39 @@ public class XnatExpiredPasswordFilter extends GenericFilterBean { if (!passwordExpirationDirtied) { return passwordExpirationDisabled; } - final String type = _preferences.getPasswordExpirationType(); - if (StringUtils.isBlank(type)) { - passwordExpirationDisabled = true; - } else if (type.equals("Interval")) { - passwordExpirationInterval = true; - passwordExpirationSetting = Integer.toString(_preferences.getPasswordExpirationInterval()); - passwordExpirationDisabled = passwordExpirationSetting.equals("0"); - } else if (type.equals("Date")) { - passwordExpirationInterval = false; - passwordExpirationSetting = Long.toString(_preferences.getPasswordExpirationDate().getTime()); - passwordExpirationDisabled = passwordExpirationSetting.equals("0"); - } else { - passwordExpirationDisabled = true; + if(useSiteConfigPrefs){ + final String type = XDAT.getSiteConfigPreferences().getPasswordExpirationType(); + if (StringUtils.isBlank(type)) { + passwordExpirationDisabled = true; + } else if (type.equals("Interval")) { + passwordExpirationInterval = true; + passwordExpirationSetting = XDAT.getSiteConfigPreferences().getPasswordExpirationInterval(); + passwordExpirationDisabled = passwordExpirationSetting.equals("0"); + } else if (type.equals("Date")) { + passwordExpirationInterval = false; + passwordExpirationSetting = Long.toString((new Date(XDAT.getSiteConfigPreferences().getPasswordExpirationDate())).getTime()); + passwordExpirationDisabled = passwordExpirationSetting.equals("0"); + } else { + passwordExpirationDisabled = true; + } + } + else{ + final String type = _initializerPreferences.getPasswordExpirationType(); + if (StringUtils.isBlank(type)) { + passwordExpirationDisabled = true; + } else if (type.equals("Interval")) { + passwordExpirationInterval = true; + passwordExpirationSetting = _initializerPreferences.getPasswordExpirationInterval(); + passwordExpirationDisabled = StringUtils.equals(passwordExpirationSetting,"0"); + } else if (type.equals("Date")) { + passwordExpirationInterval = false; + passwordExpirationSetting = Long.toString((new Date(_initializerPreferences.getPasswordExpirationDate())).getTime()); + passwordExpirationDisabled = StringUtils.equals(passwordExpirationSetting,"0"); + } else { + passwordExpirationDisabled = true; + } } + passwordExpirationDirtied = false; return passwordExpirationDisabled; } @@ -337,9 +356,16 @@ public class XnatExpiredPasswordFilter extends GenericFilterBean { return _aliasTokenService; } + public void refreshFromSiteConfig(){ + useSiteConfigPrefs = true; + passwordExpirationDirtied = true; + } + + private boolean useSiteConfigPrefs = false; + @Autowired @Lazy - private InitializerSiteConfiguration _preferences; + private InitializerSiteConfiguration _initializerPreferences; @Autowired @Lazy diff --git a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml index 8f4b0533..2b5f0b38 100755 --- a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml +++ b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml @@ -398,17 +398,19 @@ passwords: label: Date value: Date passwordExpirationInterval: - kind: panel.input.number + kind: panel.input.text id: passwordExpirationInterval name: passwordExpirationInterval label: Password Expiration (Interval) - description: "-1 to disable" + description: > + Interval of time after which unchanged passwords expire and users have to change them. Enter "0" to disable. Uses + <a target="_blank" href="http://www.postgresql.org/docs/9.0/static/functions-datetime.html">PostgreSQL interval notation</a> passwordExpirationDate: kind: panel.input.text id: passwordExpirationDate name: passwordExpirationDate label: Password Expiration (Date) - description: Dates must be formatted MM/DD/YYYY + description: Expire passwords that were last changed before this date and require those users to change them. Enter "0" to disable. Dates must be formatted MM/DD/YYYY passwordReuseRestriction: kind: panel.select.single id: passwordReuseRestriction @@ -425,7 +427,7 @@ passwords: kind: panel.input.text id: passwordHistoryDuration name: passwordHistoryDuration - label: Password History (Duration) + label: Password History description: > Interval for which users cannot reuse an old password of theirs. Uses <a target="_blank" href="http://www.postgresql.org/docs/9.0/static/functions-datetime.html">PostgreSQL interval notation</a> diff --git a/src/main/resources/config/site/siteConfiguration.properties b/src/main/resources/config/site/siteConfiguration.properties index 30362515..28f57b9d 100644 --- a/src/main/resources/config/site/siteConfiguration.properties +++ b/src/main/resources/config/site/siteConfiguration.properties @@ -48,6 +48,6 @@ scanTypeMapping=true passwordExpirationType=Interval # Interval, in days, for expiring unchanged passwords (0 disables feature). Uses PostgreSQL interval notation: http://www.postgresql.org/docs/9.0/static/functions-datetime.html -passwordExpirationInterval=365 +passwordExpirationInterval=1 year # Date for expiring passwords. Generally null by default. passwordExpirationDate= \ No newline at end of file -- GitLab