diff --git a/src/main/java/org/nrg/pipeline/XnatPipelineLauncher.java b/src/main/java/org/nrg/pipeline/XnatPipelineLauncher.java
index e88d15ba45848bc0f9db1244a01339fd0d4acdc8..30b6785406ae1a527c369b805ac817d65c8e0600 100644
--- a/src/main/java/org/nrg/pipeline/XnatPipelineLauncher.java
+++ b/src/main/java/org/nrg/pipeline/XnatPipelineLauncher.java
@@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.Paths;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -190,7 +191,7 @@ public class XnatPipelineLauncher {
      */
 
     public boolean launch() {
-        return launch(XDAT.getSiteConfigPreferences().getPipelinePath() + "bin" + File.separator + SCHEDULE);
+        return launch(Paths.get(XDAT.getSiteConfigPreferences().getPipelinePath(), "bin", SCHEDULE).toString());
     }
 
     /*
@@ -303,7 +304,7 @@ public class XnatPipelineLauncher {
             command = "";
         }
 
-        command += XDAT.getSiteConfigPreferences().getAdminEmail() + "bin" + File.separator + "XnatPipelineLauncher";
+        command += Paths.get(XDAT.getSiteConfigPreferences().getPipelinePath(), "bin", "XnatPipelineLauncher").toString();
 
         if (System.getProperty("os.name").toUpperCase().startsWith("WINDOWS")) {
             command += ".bat";
@@ -330,7 +331,7 @@ public class XnatPipelineLauncher {
     private List<String> getPipelineConfigurationArguments() {
         List<String> arguments = new ArrayList<>();
         try {
-            String pipelinePath = new File(XDAT.getSiteConfigPreferences().getAdminEmail()).getCanonicalPath();
+            String pipelinePath = new File(XDAT.getSiteConfigPreferences().getPipelinePath()).getCanonicalPath();
             boolean requiresQuotes = pipelinePath.contains(" ");
             arguments.add("-config");
             String configPath = pipelinePath + File.separator + "pipeline.config";
diff --git a/src/main/java/org/nrg/pipeline/utils/PipelineFileUtils.java b/src/main/java/org/nrg/pipeline/utils/PipelineFileUtils.java
index 4165fa6172bfbf241f497af456af81c1eb0b972b..a6c647efe8b82f6e5278b90acb3445435dcab12c 100644
--- a/src/main/java/org/nrg/pipeline/utils/PipelineFileUtils.java
+++ b/src/main/java/org/nrg/pipeline/utils/PipelineFileUtils.java
@@ -92,7 +92,7 @@ public class PipelineFileUtils {
 
 	public static String getBuildDir(String project,  boolean postfixTimestamp) {
 		ArcProject arcProject = ArcSpecManager.GetFreshInstance().getProjectArc(project);
-		String buildPath = XDAT.getSiteConfigPreferences().getAdminEmail()  ;
+		String buildPath = XDAT.getSiteConfigPreferences().getBuildPath()  ;
 		if (arcProject != null) {
 			buildPath = arcProject.getPaths().getBuildpath();
 		}
diff --git a/src/main/java/org/nrg/xnat/archive/DicomZipImporter.java b/src/main/java/org/nrg/xnat/archive/DicomZipImporter.java
index b2267f4daba7e4e24acb41108842c813381d0758..32621fb5337f54cee03b31e606a5fcad64925dbb 100644
--- a/src/main/java/org/nrg/xnat/archive/DicomZipImporter.java
+++ b/src/main/java/org/nrg/xnat/archive/DicomZipImporter.java
@@ -32,7 +32,7 @@ import org.nrg.xnat.restlet.util.FileWriterWrapperI;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
-@ImporterHandler(handler = "DICOM-zip", allowCallsWithoutFiles = false)
+@ImporterHandler(handler = ImporterHandlerA.DICOM_ZIP_IMPORTER)
 public final class DicomZipImporter extends ImporterHandlerA {
     private final InputStream in;
     private final Object listenerControl;
diff --git a/src/main/java/org/nrg/xnat/archive/GradualDicomImporter.java b/src/main/java/org/nrg/xnat/archive/GradualDicomImporter.java
index ffa912bfcf1ec1ec0c0670886e663a05ef1d9f26..236379e3a87f060a03d53f7e6fed6754044ec497 100644
--- a/src/main/java/org/nrg/xnat/archive/GradualDicomImporter.java
+++ b/src/main/java/org/nrg/xnat/archive/GradualDicomImporter.java
@@ -64,7 +64,7 @@ import java.util.concurrent.Callable;
 
 @SuppressWarnings("ThrowFromFinallyBlock")
 @Service
-@ImporterHandler(handler = "DICOM-zip", allowCallsWithoutFiles = false)
+@ImporterHandler(handler = ImporterHandlerA.GRADUAL_DICOM_IMPORTER)
 public class GradualDicomImporter extends ImporterHandlerA {
     public static final String SENDER_AE_TITLE_PARAM = "Sender-AE-Title";
     public static final String SENDER_ID_PARAM = "Sender-ID";
diff --git a/src/main/java/org/nrg/xnat/configuration/SchedulerConfig.java b/src/main/java/org/nrg/xnat/configuration/SchedulerConfig.java
index 540fee3185bed97d169f4659a442c05f070545c7..36d36973c68278dc3d2f6cf52aa4a8dc0613d6cc 100644
--- a/src/main/java/org/nrg/xnat/configuration/SchedulerConfig.java
+++ b/src/main/java/org/nrg/xnat/configuration/SchedulerConfig.java
@@ -1,8 +1,11 @@
 package org.nrg.xnat.configuration;
 
 import org.nrg.config.exceptions.SiteConfigurationException;
+import org.nrg.framework.exceptions.NrgServiceError;
+import org.nrg.framework.exceptions.NrgServiceRuntimeException;
 import org.nrg.mail.services.EmailRequestLogService;
 import org.nrg.xdat.preferences.InitializerSiteConfiguration;
+import org.nrg.xdat.preferences.SiteConfigPreferences;
 import org.nrg.xnat.helpers.prearchive.SessionXMLRebuilder;
 import org.nrg.xnat.security.DisableInactiveUsers;
 import org.nrg.xnat.security.ResetEmailRequests;
@@ -24,6 +27,7 @@ import org.springframework.scheduling.support.CronTrigger;
 import org.springframework.scheduling.support.PeriodicTrigger;
 
 import javax.inject.Inject;
+import java.sql.SQLException;
 import java.util.List;
 
 @Configuration
@@ -31,7 +35,13 @@ import java.util.List;
 public class SchedulerConfig implements SchedulingConfigurer {
     @Bean
     public TriggerTask disableInactiveUsers() throws SiteConfigurationException {
-        return new TriggerTask(new DisableInactiveUsers(_preferences.getInactivityBeforeLockout()), new CronTrigger(_preferences.getInactivityBeforeLockoutSchedule()));
+        try {
+            final DisableInactiveUsers task = new DisableInactiveUsers(_preferences.getInactivityBeforeLockout(), (int) SiteConfigPreferences.convertPGIntervalToSeconds(_preferences.getMaxFailedLoginsLockoutDuration()));
+            return new TriggerTask(task, new CronTrigger(_preferences.getInactivityBeforeLockoutSchedule()));
+        } catch (SQLException e) {
+            // This isn't a real thing: PGInterval doesn't actually access the database. But just to make everyone happy...
+            throw new NrgServiceRuntimeException(NrgServiceError.Unknown, "This really shouldn't happen.", e);
+        }
     }
 
     @Bean
diff --git a/src/main/java/org/nrg/xnat/initialization/PropertiesConfig.java b/src/main/java/org/nrg/xnat/initialization/PropertiesConfig.java
index af431c4d4b811fcb4b303a706a3f8f99cb9ee664..c6a5fd961bfa9e6a510d9f983d9f2ec0b930eee2 100644
--- a/src/main/java/org/nrg/xnat/initialization/PropertiesConfig.java
+++ b/src/main/java/org/nrg/xnat/initialization/PropertiesConfig.java
@@ -160,7 +160,7 @@ public class PropertiesConfig {
                 // Then cool, just return that.
                 return candidate;
             } else {
-                // If it's a file, then the parent is probably a config folder, so if this is services.properties (the default) or the specific file identified by xnat.config...
+                // If it's a file, then the parent is probably a config folder, so if this is xnat-conf.properties (the default) or the specific file identified by xnat.config...
                 if (file.getName().equals(XNAT_CONF_FILE) || StringUtils.equals(candidate.toString(), environment.getProperty(JAVA_XNAT_CONFIG))) {
                     // So its parent is a config folder, QED.
                     return candidate.getParent();
diff --git a/src/main/java/org/nrg/xnat/initialization/RootConfig.java b/src/main/java/org/nrg/xnat/initialization/RootConfig.java
index 79de8d9aa243ea03af84f5dfb2cfe267a4cba09d..9ac4540a0f4318b3cfd13eeef944bbec57900d0a 100644
--- a/src/main/java/org/nrg/xnat/initialization/RootConfig.java
+++ b/src/main/java/org/nrg/xnat/initialization/RootConfig.java
@@ -20,7 +20,6 @@ import org.nrg.xnat.services.XnatAppInfo;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
-import org.springframework.context.annotation.ImportResource;
 import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
@@ -29,10 +28,8 @@ import org.springframework.oxm.jaxb.Jaxb2Marshaller;
 import javax.servlet.ServletContext;
 import javax.xml.bind.Marshaller;
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.jar.Manifest;
 
 /**
  * Configuration for the XNAT root application context. This contains all of the basic infrastructure for initializing
@@ -43,8 +40,7 @@ import java.util.jar.Manifest;
  * for standard XNAT components should be added in the {@link ApplicationConfig application configuration class}.
  */
 @Configuration
-@Import({PropertiesConfig.class, DatabaseConfig.class})
-@ImportResource("WEB-INF/conf/xnat-security.xml")
+@Import({PropertiesConfig.class, DatabaseConfig.class, SecurityConfig.class})
 public class RootConfig {
     @Bean
     public XnatAppInfo appInfo(final ServletContext context) throws IOException {
diff --git a/src/main/java/org/nrg/xnat/initialization/SecurityConfig.java b/src/main/java/org/nrg/xnat/initialization/SecurityConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..771b24c2d94d61e046ae40d1c9f6c301c7c684aa
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/initialization/SecurityConfig.java
@@ -0,0 +1,225 @@
+package org.nrg.xnat.initialization;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.nrg.config.exceptions.SiteConfigurationException;
+import org.nrg.framework.services.SerializerService;
+import org.nrg.xdat.preferences.InitializerSiteConfiguration;
+import org.nrg.xnat.security.*;
+import org.nrg.xnat.security.alias.AliasTokenAuthenticationProvider;
+import org.nrg.xnat.security.config.AuthenticationProviderAggregator;
+import org.nrg.xnat.security.config.AuthenticationProviderConfigurator;
+import org.nrg.xnat.security.config.DatabaseAuthenticationProviderConfigurator;
+import org.nrg.xnat.security.config.LdapAuthenticationProviderConfigurator;
+import org.nrg.xnat.security.userdetailsservices.XnatDatabaseUserDetailsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportResource;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.security.access.AccessDecisionVoter;
+import org.springframework.security.access.vote.AuthenticatedVoter;
+import org.springframework.security.access.vote.RoleVoter;
+import org.springframework.security.access.vote.UnanimousBased;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
+import org.springframework.security.web.access.channel.InsecureChannelProcessor;
+import org.springframework.security.web.access.channel.SecureChannelProcessor;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.logout.LogoutFilter;
+import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
+import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
+import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+import org.springframework.security.web.session.ConcurrentSessionFilter;
+
+import javax.sql.DataSource;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+@Configuration
+@ImportResource("WEB-INF/conf/xnat-security.xml")
+public class SecurityConfig {
+    @Bean
+    public UnanimousBased unanimousBased() {
+        final RoleVoter voter = new RoleVoter();
+        voter.setRolePrefix("ROLE_");
+        final List<AccessDecisionVoter<?>> voters = new ArrayList<>();
+        voters.add(voter);
+        voters.add(new AuthenticatedVoter());
+        return new UnanimousBased(voters);
+    }
+
+    @Bean
+    public OnXnatLogin logUserLogin() {
+        return new OnXnatLogin();
+    }
+
+    @Bean
+    public AuthenticationFailureHandler authFailure() {
+        return new XnatUrlAuthenticationFailureHandler("/app/template/Login.vm?failed=true", "/app/template/PostRegister.vm");
+    }
+
+    @Bean
+    public XnatAuthenticationEntryPoint loginUrlAuthenticationEntryPoint() {
+        final XnatAuthenticationEntryPoint entryPoint = new XnatAuthenticationEntryPoint("/app/template/Login.vm");
+        entryPoint.setDataPaths(Arrays.asList("/data/**", "/REST/**", "/fs/**"));
+        entryPoint.setInteractiveAgents(Arrays.asList(".*MSIE.*", ".*Mozilla.*", ".*AppleWebKit.*", ".*Opera.*"));
+        return entryPoint;
+    }
+
+    @Bean
+    public SessionRegistry sessionRegistry() {
+        return new SessionRegistryImpl();
+    }
+
+    @Bean
+    public ConcurrentSessionFilter concurrencyFilter(final SessionRegistry sessionRegistry) {
+        return new ConcurrentSessionFilter(sessionRegistry, "/app/template/Login.vm");
+    }
+
+    @Bean
+    public ConcurrentSessionControlAuthenticationStrategy sas(final SessionRegistry sessionRegistry) throws SiteConfigurationException {
+        final ConcurrentSessionControlAuthenticationStrategy strategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
+        strategy.setMaximumSessions(_configuration.getConcurrentMaxSessions());
+        strategy.setExceptionIfMaximumExceeded(true);
+        return strategy;
+    }
+
+    @Bean
+    public LogoutFilter logoutFilter() {
+        final XnatLogoutSuccessHandler logoutSuccessHandler = new XnatLogoutSuccessHandler();
+        logoutSuccessHandler.setOpenXnatLogoutSuccessUrl("/");
+        logoutSuccessHandler.setSecuredXnatLogoutSuccessUrl("/app/template/Login.vm");
+        final SecurityContextLogoutHandler securityContextLogoutHandler = new SecurityContextLogoutHandler();
+        securityContextLogoutHandler.setInvalidateHttpSession(true);
+        final XnatLogoutHandler xnatLogoutHandler = new XnatLogoutHandler();
+        final LogoutFilter      filter            = new LogoutFilter(logoutSuccessHandler, securityContextLogoutHandler, xnatLogoutHandler);
+        filter.setFilterProcessesUrl("/app/action/LogoutUser");
+        return filter;
+    }
+
+    @Bean
+    public FilterSecurityInterceptorBeanPostProcessor filterSecurityInterceptorBeanPostProcessor() throws IOException {
+        final Resource resource = RESOURCE_LOADER.getResource("classpath:META-INF/xnat/security/configured-urls.yaml");
+        try (final InputStream inputStream = resource.getInputStream()) {
+            final HashMap<String, ArrayList<String>>         urlMap        = _serializer.deserializeYaml(inputStream, TYPE_REFERENCE);
+            final FilterSecurityInterceptorBeanPostProcessor postProcessor = new FilterSecurityInterceptorBeanPostProcessor();
+            postProcessor.setOpenUrls(urlMap.get("openUrls"));
+            postProcessor.setAdminUrls(urlMap.get("adminUrls"));
+            return postProcessor;
+        }
+    }
+
+    @Bean
+    public TranslatingChannelProcessingFilter channelProcessingFilter() throws SiteConfigurationException {
+        final ChannelDecisionManagerImpl decisionManager = new ChannelDecisionManagerImpl();
+        decisionManager.setChannelProcessors(Arrays.asList(new SecureChannelProcessor(), new InsecureChannelProcessor()));
+        final TranslatingChannelProcessingFilter filter = new TranslatingChannelProcessingFilter();
+        filter.setChannelDecisionManager(decisionManager);
+        filter.setRequiredChannel(_configuration.getSecurityChannel());
+        return filter;
+    }
+
+    @Bean
+    public AliasTokenAuthenticationProvider aliasTokenAuthenticationProvider() {
+        return new AliasTokenAuthenticationProvider();
+    }
+
+    @Bean
+    public DatabaseAuthenticationProviderConfigurator dbConfigurator() {
+        return new DatabaseAuthenticationProviderConfigurator();
+    }
+
+    @Bean
+    public LdapAuthenticationProviderConfigurator ldapConfigurator() {
+        return new LdapAuthenticationProviderConfigurator();
+    }
+
+    @Bean
+    public AuthenticationProviderAggregator providerAggregator(final List<AuthenticationProvider> providers, final List<AuthenticationProviderConfigurator> configurators) {
+        final Map<String, AuthenticationProviderConfigurator> configuratorMap = new HashMap<>();
+        for (final AuthenticationProviderConfigurator configurator : configurators) {
+            configuratorMap.put(configurator.getConfiguratorId(), configurator);
+        }
+
+        return new AuthenticationProviderAggregator(providers, configuratorMap);
+    }
+
+    @Bean(name = {"org.springframework.security.authenticationManager", "customAuthenticationManager"})
+    public XnatProviderManager customAuthenticationManager(final AuthenticationProviderAggregator aggregator) {
+        return new XnatProviderManager(aggregator);
+    }
+
+    @Bean
+    public XnatAuthenticationFilter customAuthenticationFilter(final XnatProviderManager providerManager,
+                                                               final AuthenticationSuccessHandler successHandler,
+                                                               final AuthenticationFailureHandler failureHandler,
+                                                               final SessionAuthenticationStrategy sas) {
+        final XnatAuthenticationFilter filter = new XnatAuthenticationFilter();
+        filter.setAuthenticationManager(providerManager);
+        filter.setAuthenticationSuccessHandler(successHandler);
+        filter.setAuthenticationFailureHandler(failureHandler);
+        filter.setSessionAuthenticationStrategy(sas);
+        return filter;
+    }
+
+    @Bean
+    public XnatBasicAuthenticationFilter customBasicAuthenticationFilter(final XnatProviderManager providerManager,
+                                                                         final AuthenticationEntryPoint entryPoint,
+                                                                         final SessionAuthenticationStrategy sas) {
+        final XnatBasicAuthenticationFilter filter = new XnatBasicAuthenticationFilter(providerManager, entryPoint);
+        filter.setSessionAuthenticationStrategy(sas);
+        return filter;
+    }
+
+    @Bean
+    public XnatExpiredPasswordFilter expiredPasswordFilter() {
+        final XnatExpiredPasswordFilter filter = new XnatExpiredPasswordFilter();
+        filter.setChangePasswordPath("/app/template/XDATScreen_UpdateUser.vm");
+        filter.setChangePasswordDestination("/app/action/ModifyPassword");
+        filter.setLogoutDestination("/app/action/LogoutUser");
+        filter.setLoginPath("/app/template/Login.vm");
+        filter.setLoginDestination("/app/action/XDATLoginUser");
+        filter.setInactiveAccountPath("/app/template/InactiveAccount.vm");
+        filter.setInactiveAccountDestination("/app/action/XnatInactiveAccount");
+        filter.setEmailVerificationPath("/app/template/VerifyEmail.vm");
+        filter.setEmailVerificationDestination("/data/services/sendEmailVerification");
+        return filter;
+    }
+
+    @Bean
+    public XnatInitCheckFilter xnatInitCheckFilter() {
+        final XnatInitCheckFilter filter = new XnatInitCheckFilter();
+        filter.setInitializationPaths(Arrays.asList("/xapi/siteConfig/batch", "/xapi/notifications/smtp"));
+        filter.setConfigurationPath("/setup");
+        filter.setNonAdminErrorPath("/app/template/Unconfigured.vm");
+        filter.setExemptedPaths(Arrays.asList("/app/template/XDATScreen_UpdateUser.vm", "/app/action/ModifyPassword", "/app/template/Login.vm", "/style/app.css", "/login"));
+        return filter;
+    }
+
+    @Bean
+    public XnatDatabaseUserDetailsService customDatabaseService(final DataSource dataSource) {
+        final XnatDatabaseUserDetailsService service = new XnatDatabaseUserDetailsService();
+        service.setDataSource(dataSource);
+        return service;
+    }
+
+    private static final ResourceLoader                                    RESOURCE_LOADER = new DefaultResourceLoader();
+    private static final TypeReference<HashMap<String, ArrayList<String>>> TYPE_REFERENCE  = new TypeReference<HashMap<String, ArrayList<String>>>() {
+    };
+
+    @Autowired
+    @Lazy
+    private InitializerSiteConfiguration _configuration;
+
+    @Autowired
+    @Lazy
+    private SerializerService _serializer;
+}
\ No newline at end of file
diff --git a/src/main/java/org/nrg/xnat/restlet/actions/SessionImporter.java b/src/main/java/org/nrg/xnat/restlet/actions/SessionImporter.java
index 415d80201bd8795fe7a4097fb37a2190ab7e4128..adb4a73788ae5e46376e7060b936c8ff39cb9e54 100644
--- a/src/main/java/org/nrg/xnat/restlet/actions/SessionImporter.java
+++ b/src/main/java/org/nrg/xnat/restlet/actions/SessionImporter.java
@@ -46,7 +46,7 @@ import org.nrg.xnat.turbine.utils.XNATSessionPopulater;
 import org.restlet.data.Status;
 import org.xml.sax.SAXException;
 
-@ImporterHandler(handler = "SI", allowCallsWithoutFiles = false)
+@ImporterHandler(handler = ImporterHandlerA.SESSION_IMPORTER)
 public class SessionImporter extends ImporterHandlerA implements Callable<List<String>> {
 
 	static Logger logger = Logger.getLogger(SessionImporter.class);
diff --git a/src/main/java/org/nrg/xnat/restlet/actions/XarImporter.java b/src/main/java/org/nrg/xnat/restlet/actions/XarImporter.java
index 33cc7c759f0c7e948e836a012a3bdc71e067edbc..dde32a013556040efae1496a8a442435767beadf 100644
--- a/src/main/java/org/nrg/xnat/restlet/actions/XarImporter.java
+++ b/src/main/java/org/nrg/xnat/restlet/actions/XarImporter.java
@@ -52,12 +52,12 @@ import org.nrg.xnat.turbine.utils.ArcSpecManager;
 import org.nrg.xnat.utils.WorkflowUtils;
 import org.xml.sax.SAXException;
 
-@ImporterHandler(handler = "XAR", allowCallsWithoutFiles = false)
+@ImporterHandler(handler = ImporterHandlerA.XAR_IMPORTER)
 public class XarImporter extends ImporterHandlerA implements Callable<List<String>> {
 
-	static final String[] zipExtensions={".zip",".jar",".rar",".ear",".gar",".xar"};
+	private static final String[] zipExtensions={".zip",".jar",".rar",".ear",".gar",".xar"};
 
-	static Logger logger = Logger.getLogger(XarImporter.class);
+	private static final Logger logger = Logger.getLogger(XarImporter.class);
 
 	private final FileWriterWrapperI fw;
 	private final UserI user;
@@ -66,19 +66,19 @@ public class XarImporter extends ImporterHandlerA implements Callable<List<Strin
 	
 	/**
 	 * 
-	 * @param listenerControl
-	 * @param u
-	 * @param session
-	 * @param overwrite:   'append' means overwrite, but preserve un-modified content (don't delete anything)
-	 *                      'delete' means delete the pre-existing content.
-	 * @param additionalValues: should include project, subject_ID and label (if session is null)
+	 * @param listenerControl     The listener.
+	 * @param u                   The user.
+     * @param fw                  The file writer wrapper.
+     * @param params              Parameters to the operation, including overwrite, 'append' means overwrite, but
+     *                            preserve un-modified content (don't delete anything), 'delete' means delete the
+     *                            pre-existing content. Should include project, subject_ID and label if session is null.
 	 */
 	public XarImporter(final Object listenerControl, final UserI u, final FileWriterWrapperI fw, final Map<String,Object> params) {
 		super(listenerControl, u, fw, params);
 		this.user=u;
 		this.fw=fw;
 		this.params=params;
-		this.urlList=new ArrayList<String>();
+		this.urlList= new ArrayList<>();
 	}
 	
 	//@SuppressWarnings("serial")
diff --git a/src/main/java/org/nrg/xnat/restlet/actions/importer/ImporterHandlerA.java b/src/main/java/org/nrg/xnat/restlet/actions/importer/ImporterHandlerA.java
index e84358d0321293205465d50341d80025182e6a35..5b3237b4f84d2cff377995d75f5e71c2d0a5e4ac 100644
--- a/src/main/java/org/nrg/xnat/restlet/actions/importer/ImporterHandlerA.java
+++ b/src/main/java/org/nrg/xnat/restlet/actions/importer/ImporterHandlerA.java
@@ -47,18 +47,18 @@ public abstract class ImporterHandlerA  extends StatusProducer implements Callab
 
     public abstract List<String> call() throws ClientException, ServerException;
 
-    static Logger logger = Logger.getLogger(ImporterHandlerA.class);
+    private static final Logger logger = Logger.getLogger(ImporterHandlerA.class);
 
     public static final String IMPORT_HANDLER_ATTR = "import-handler";
 
-    public static String SESSION_IMPORTER="SI";
-    public static String XAR_IMPORTER="XAR";
-    public static String GRADUAL_DICOM_IMPORTER="gradual-DICOM";
-    public static String DICOM_ZIP_IMPORTER="DICOM-zip";
-    public static String BLANK_PREARCHIVE_ENTRY="blank";
+    public static final String SESSION_IMPORTER="SI";
+    public static final String XAR_IMPORTER="XAR";
+    public static final String GRADUAL_DICOM_IMPORTER="gradual-DICOM";
+    public static final String DICOM_ZIP_IMPORTER="DICOM-zip";
+    public static final String BLANK_PREARCHIVE_ENTRY="blank";
 
     static String DEFAULT_HANDLER=SESSION_IMPORTER;
-    final static Map<String,Class<? extends ImporterHandlerA>> IMPORTERS=new HashMap<String,Class<? extends ImporterHandlerA>>();
+    final static Map<String,Class<? extends ImporterHandlerA>> IMPORTERS= new HashMap<>();
 
     private static final String PROP_OBJECT_IDENTIFIER = "org.nrg.import.handler.impl";
     private static final String IMPORTER_PROPERTIES = "importer.properties";
diff --git a/src/main/java/org/nrg/xnat/security/DisableInactiveUsers.java b/src/main/java/org/nrg/xnat/security/DisableInactiveUsers.java
index 33132ad86f2c5f3b645913075df9b277794f4dda..d3fa49b87e03b5ee355ae3688453d139619c1189 100644
--- a/src/main/java/org/nrg/xnat/security/DisableInactiveUsers.java
+++ b/src/main/java/org/nrg/xnat/security/DisableInactiveUsers.java
@@ -18,7 +18,6 @@ import org.nrg.xft.XFTTable;
 import org.nrg.xft.event.EventUtils;
 import org.nrg.xft.exception.DBPoolException;
 import org.nrg.xft.security.UserI;
-import org.nrg.xft.utils.AuthUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,8 +28,9 @@ import java.util.GregorianCalendar;
 
 public class DisableInactiveUsers implements Runnable {
 
-    public DisableInactiveUsers(final int inactivityBeforeLockout) {
+    public DisableInactiveUsers(final int inactivityBeforeLockout, final int lockoutDuration) {
         _inactivityBeforeLockout = inactivityBeforeLockout;
+        _lockoutDuration = lockoutDuration;
     }
 
     /**
@@ -62,7 +62,7 @@ public class DisableInactiveUsers implements Runnable {
                         u.setVerified("0");
                         Users.save(u, u, false, EventUtils.newEventInstance(EventUtils.CATEGORY.SIDE_ADMIN, EventUtils.TYPE.PROCESS, "Disabled due to inactivity"));
 
-                        String expiration = TurbineUtils.getDateTimeFormatter().format(DateUtils.addMilliseconds(GregorianCalendar.getInstance().getTime(), -(AuthUtils.LOCKOUT_DURATION)));
+                        String expiration = TurbineUtils.getDateTimeFormatter().format(DateUtils.addMilliseconds(GregorianCalendar.getInstance().getTime(), _lockoutDuration));
                         System.out.println("Locked out " + u.getLogin() + " user account until " + expiration);
                         AdminUtils.sendAdminEmail(u.getLogin() + " account disabled due to inactivity.", "User " + u.getLogin() + " has been automatically disabled due to inactivity.");
                     }
@@ -98,6 +98,7 @@ public class DisableInactiveUsers implements Runnable {
 
     private static final Logger logger = LoggerFactory.getLogger(DisableInactiveUsers.class);
 
-    private int _inactivityBeforeLockout;
+    private final int _inactivityBeforeLockout;
+    private final int _lockoutDuration;
 }
 
diff --git a/src/main/java/org/nrg/xnat/security/XnatAuthenticationFilter.java b/src/main/java/org/nrg/xnat/security/XnatAuthenticationFilter.java
index dfb1c279d4fcf688fb55e839c0a243016625f35c..dad3fd4f943d0b9ccfcc879b888f5c84b250a0e6 100644
--- a/src/main/java/org/nrg/xnat/security/XnatAuthenticationFilter.java
+++ b/src/main/java/org/nrg/xnat/security/XnatAuthenticationFilter.java
@@ -27,7 +27,6 @@ import org.springframework.security.crypto.codec.Base64;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 
 import javax.inject.Inject;
-import javax.inject.Named;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.UnsupportedEncodingException;
@@ -135,6 +134,5 @@ public class XnatAuthenticationFilter extends UsernamePasswordAuthenticationFilt
     private static final Map<String, Integer> checked = Maps.newHashMap();
 
     @Inject
-    @Named("customAuthenticationManager")
     private XnatProviderManager _providerManager;
 }
diff --git a/src/main/java/org/nrg/xnat/security/XnatExpiredPasswordFilter.java b/src/main/java/org/nrg/xnat/security/XnatExpiredPasswordFilter.java
index 2dbbd4764751b1176cadf75154d5e6b34ad0ef07..94b242ea479f8ad9c92d820505d045cef51c6366 100644
--- a/src/main/java/org/nrg/xnat/security/XnatExpiredPasswordFilter.java
+++ b/src/main/java/org/nrg/xnat/security/XnatExpiredPasswordFilter.java
@@ -1,340 +1,364 @@
-/*
- * org.nrg.xnat.security.XnatExpiredPasswordFilter
- * XNAT http://www.xnat.org
- * Copyright (c) 2014, Washington University School of Medicine
- * All Rights Reserved
- *
- * Released under the Simplified BSD.
- *
- * Last modified 12/11/13 3:33 PM
- */
-package org.nrg.xnat.security;
-
-import org.apache.commons.lang3.StringUtils;
-import org.nrg.config.exceptions.SiteConfigurationException;
-import org.nrg.xdat.XDAT;
-import org.nrg.xdat.entities.AliasToken;
-import org.nrg.xdat.entities.UserRole;
-import org.nrg.xdat.om.ArcArchivespecification;
-import org.nrg.xdat.preferences.InitializerSiteConfiguration;
-import org.nrg.xdat.security.helpers.Roles;
-import org.nrg.xdat.services.AliasTokenService;
-import org.nrg.xdat.services.XdatUserAuthService;
-import org.nrg.xdat.turbine.utils.TurbineUtils;
-import org.nrg.xft.security.UserI;
-import org.nrg.xnat.turbine.utils.ArcSpecManager;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.security.crypto.codec.Base64;
-import org.springframework.web.filter.GenericFilterBean;
-
-import javax.inject.Inject;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.sql.DataSource;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-
-@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection"})
-public class XnatExpiredPasswordFilter extends GenericFilterBean {
-    private String changePasswordPath = "";
-    private String changePasswordDestination = "";
-    private String logoutDestination = "";
-    private String loginPath = "";
-    private String loginDestination = "";
-    private String inactiveAccountPath;
-    private String inactiveAccountDestination;
-    private String emailVerificationDestination;
-    private String emailVerificationPath;
-    private boolean passwordExpirationDirtied = true;
-    private boolean passwordExpirationDisabled;
-    private boolean passwordExpirationInterval;
-    private String passwordExpirationSetting;
-
-    @Override
-    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
-        final HttpServletRequest request = (HttpServletRequest) req;
-        final HttpServletResponse response = (HttpServletResponse) res;
-        UserI user = XDAT.getUserDetails();
-        Object passwordExpired = request.getSession().getAttribute("expired");
-        // MIGRATION: Need to remove arcspec.
-        ArcArchivespecification _arcSpec = ArcSpecManager.GetInstance();
-        final String referer = request.getHeader("Referer");
-        if (request.getSession() != null && request.getSession().getAttribute("forcePasswordChange") != null && (Boolean) request.getSession().getAttribute("forcePasswordChange")) {
-            try {
-                String refererPath = null;
-                String uri = new URI(request.getRequestURI()).getPath();
-                if (!StringUtils.isBlank(referer)) {
-                    refererPath = new URI(referer).getPath();
-                }
-                if (uri.endsWith(changePasswordPath) || uri.endsWith(changePasswordDestination) || uri.endsWith(logoutDestination) || uri.endsWith(loginPath) || uri.endsWith(loginDestination)) {
-                    //If you're already on the change password page, continue on without redirect.
-                    chain.doFilter(req, res);
-                } else if (!StringUtils.isBlank(refererPath) && (changePasswordPath.equals(refererPath) || changePasswordDestination.equals(refererPath) || logoutDestination.equals(refererPath))) {
-                    //If you're on a request within the change password page, continue on without redirect.
-                    chain.doFilter(req, res);
-                } else {
-                    response.sendRedirect(TurbineUtils.GetFullServerPath() + changePasswordPath);
-                }
-            } catch (URISyntaxException ignored) {
-                //
-            }
-        } else if (passwordExpired != null && !(Boolean) passwordExpired) {
-            //If the date of password change was checked earlier in the session and found to be not expired, do not send them to the expired password page.
-            chain.doFilter(request, response);
-        } else if (_arcSpec == null || !_arcSpec.isComplete()) {
-            //If the arc spec has not yet been set, have the user configure the arc spec before changing their password. This prevents a negative interaction with the arc spec filter.
-            chain.doFilter(request, response);
-        } else {
-            if (user == null) {
-                //If the user is not logged in, do not send them to the expired password page.
-
-                String header = request.getHeader("Authorization");
-                if (header != null && header.startsWith("Basic ")) {
-                    //For users that authenticated using basic authentication, check whether their password is expired, and if so give them a 403 and a message that they need to change their password.
-
-                    String token = new String(Base64.decode(header.substring(6).getBytes("UTF-8")), "UTF-8");
-                    String username = "";
-                    int delim = token.indexOf(":");
-                    if (delim != -1) {
-                        username = token.substring(0, delim);
-                    }
-                    if (AliasToken.isAliasFormat(username)) {
-                        AliasToken alias = _aliasTokenService.locateToken(username);
-                        if (alias == null) {
-                            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Your security token has expired. Please try again after updating your session.");
-                            return;
-                        }
-                        username = alias.getXdatUserId();
-                    }
-                    // Check whether the user is connected to an active role for non_expiring.
-                    try {
-                        List<Integer> roles = (new JdbcTemplate(_dataSource)).query("SELECT COUNT(*) FROM xhbm_user_role where username = ? and role = ? and enabled = 't'", new String[]{username, UserRole.ROLE_NON_EXPIRING}, new RowMapper<Integer>() {
-                            public Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
-                                return rs.getInt(1);
-                            }
-                        });
-                        if (roles.get(0) > 0) {
-                            chain.doFilter(request, response);
-                        }
-                    } catch (Exception e) {
-                        logger.error(e);
-                    }
-
-                    try {
-                        passwordExpirationDisabled = isPasswordExpirationDisabled();
-                    } catch (SiteConfigurationException e) {
-                        logger.error("An error occurred trying to check for expired passwords, continuing processing.", e);
-                    }
-                    if (passwordExpirationDisabled) {
-                        chain.doFilter(request, response);
-                    } else {
-                        final boolean isExpired = checkForExpiredPassword(username);
-                        request.getSession().setAttribute("expired", isExpired);
-                        if (username != null && isExpired && !username.equals("guest")) {
-                            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Your password has expired. Please try again after changing your password.");
-                        } else {
-                            chain.doFilter(request, response);
-                        }
-                    }
-                } else {
-                    checkUserChangePassword(request, response);
-                    //User is not authenticated through basic authentication either.
-                    chain.doFilter(req, res);
-                }
-            } else {
-                String uri = request.getRequestURI();
-
-                if (user.isGuest()) {
-                    //If you're a guest and you try to access the change password page, you get sent to the login page since there's no password on the guest account to change.
-                    checkUserChangePassword(request, response);
-                }
-                if (user.isGuest() ||
-                        //If you're logging in or out, or going to the login page itself
-                        (uri.endsWith(logoutDestination) || uri.endsWith(loginPath) || uri.endsWith(loginDestination)) ||
-                        //If you're already on the change password page, continue on without redirect.
-                        (user.isEnabled() && (uri.endsWith(changePasswordPath) || uri.endsWith(changePasswordDestination))) ||
-                        //If you're already on the inactive account page or reactivating an account, continue on without redirect.
-                        (!user.isEnabled() && (uri.endsWith(inactiveAccountPath) || uri.endsWith(inactiveAccountDestination) ||
-                                uri.endsWith(emailVerificationPath) || uri.endsWith(emailVerificationDestination) ||
-                                (referer != null && (referer.endsWith(inactiveAccountPath) || referer.endsWith(inactiveAccountDestination))))) ||
-                        //If you're on a request within the change password page, continue on without redirect.
-                        (referer != null && (referer.endsWith(changePasswordPath) || referer.endsWith(changePasswordDestination) ||
-                                referer.endsWith(logoutDestination)))) {
-                    chain.doFilter(req, res);
-                } else {
-                    if (
-                            user.getAuthorization() != null && user.getAuthorization().getAuthMethod().equals(XdatUserAuthService.LDAP)
-                            ) {
-                        // Shouldn't check for a localdb expired password if user is coming in through LDAP
-                        chain.doFilter(req, res);
-                    } else if (user.isEnabled()) {
-                        boolean isExpired = checkForExpiredPassword(user);
-
-                        if ((!isUserNonExpiring(user) && isExpired) || (_preferences.getRequireSaltedPasswords() && user.getSalt() == null)) {
-                            request.getSession().setAttribute("expired", isExpired);
-                            response.sendRedirect(TurbineUtils.GetFullServerPath() + changePasswordPath);
-                        } else {
-                            chain.doFilter(request, response);
-                        }
-                    } else {
-                        response.sendRedirect(TurbineUtils.GetFullServerPath() + inactiveAccountPath);
-                    }
-                }
-            }
-        }
-    }
-
-    public void setChangePasswordPath(String path) {
-        this.changePasswordPath = path;
-    }
-
-    public void setChangePasswordDestination(String path) {
-        this.changePasswordDestination = path;
-    }
-
-    public void setLogoutDestination(String path) {
-        this.logoutDestination = path;
-    }
-
-    public void setLoginPath(String path) {
-        this.loginPath = path;
-    }
-
-    public void setLoginDestination(String loginDestination) {
-        this.loginDestination = loginDestination;
-    }
-
-    public void setInactiveAccountPath(String inactiveAccountPath) {
-        this.inactiveAccountPath = inactiveAccountPath;
-    }
-
-    public String getInactiveAccountPath() {
-        return inactiveAccountPath;
-    }
-
-    public void setInactiveAccountDestination(String inactiveAccountDestination) {
-        this.inactiveAccountDestination = inactiveAccountDestination;
-    }
-
-    public String getInactiveAccountDestination() {
-        return inactiveAccountDestination;
-    }
-
-    public void setEmailVerificationDestination(String emailVerificationDestination) {
-        this.emailVerificationDestination = emailVerificationDestination;
-    }
-
-    public String getEmailVerificationDestination() {
-        return emailVerificationDestination;
-    }
-
-    public void setEmailVerificationPath(String emailVerificationPath) {
-        this.emailVerificationPath = emailVerificationPath;
-    }
-
-    public String getEmailVerificationPath() {
-        return emailVerificationPath;
-    }
-
-    public void setPasswordExpirationDirtied(final boolean passwordExpirationDirtied) {
-        this.passwordExpirationDirtied = passwordExpirationDirtied;
-    }
-
-    private boolean checkForExpiredPassword(final UserI user) {
-        return checkForExpiredPassword(user.getUsername());
-    }
-
-    private boolean checkForExpiredPassword(final String username) {
-        try {
-            if (isPasswordExpirationDisabled()) {
-                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>() {
-                    public Boolean mapRow(ResultSet rs, int rowNum) throws SQLException {
-                        return rs.getBoolean(1);
-                    }
-                });
-                return expired.get(0);
-            } else {
-                List<Boolean> expired = (new JdbcTemplate(_dataSource)).query("SELECT (to_date('" + new SimpleDateFormat("MM/dd/yyyy").format(new Date(Long.parseLong(passwordExpirationSetting))) + "', 'MM/DD/YYYY') BETWEEN password_updated AND now()) 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);
-                    }
-                });
-                return expired.get(0);
-            }
-        } catch (Throwable e) { // ldap authentication can throw an exception during these queriess
-            logger.error(e.getMessage(), e);
-        }
-        return false;
-    }
-
-    private boolean isPasswordExpirationDisabled() throws SiteConfigurationException {
-        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;
-        }
-        passwordExpirationDirtied = false;
-        return passwordExpirationDisabled;
-    }
-
-    private boolean isPasswordExpirationInterval() {
-        return passwordExpirationInterval;
-    }
-
-    private boolean isUserNonExpiring(UserI user) {
-        try {
-            return Roles.checkRole(user, UserRole.ROLE_NON_EXPIRING);
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-    private void checkUserChangePassword(HttpServletRequest request, HttpServletResponse response) throws IOException {
-        try {
-            String uri = new URI(request.getRequestURI()).getPath();
-            if (uri.endsWith("XDATScreen_UpdateUser.vm") && request.getParameterMap().isEmpty()) {
-                response.sendRedirect(TurbineUtils.GetFullServerPath() + "/app/template/Login.vm");
-            }
-        } catch (URISyntaxException ignored) {
-        }
-    }
-
-    @Autowired
-    @Lazy
-    private InitializerSiteConfiguration _preferences;
-
-    @Autowired
-    @Lazy
-    private AliasTokenService _aliasTokenService;
-
-    @Inject
-    private DataSource _dataSource;
-}
+/*
+ * org.nrg.xnat.security.XnatExpiredPasswordFilter
+ * XNAT http://www.xnat.org
+ * Copyright (c) 2014, Washington University School of Medicine
+ * All Rights Reserved
+ *
+ * Released under the Simplified BSD.
+ *
+ * Last modified 12/11/13 3:33 PM
+ */
+package org.nrg.xnat.security;
+
+import org.apache.commons.lang3.StringUtils;
+import org.nrg.config.exceptions.SiteConfigurationException;
+import org.nrg.framework.services.ContextService;
+import org.nrg.xdat.XDAT;
+import org.nrg.xdat.entities.AliasToken;
+import org.nrg.xdat.entities.UserRole;
+import org.nrg.xdat.om.ArcArchivespecification;
+import org.nrg.xdat.preferences.InitializerSiteConfiguration;
+import org.nrg.xdat.security.helpers.Roles;
+import org.nrg.xdat.services.AliasTokenService;
+import org.nrg.xdat.services.XdatUserAuthService;
+import org.nrg.xdat.turbine.utils.TurbineUtils;
+import org.nrg.xft.security.UserI;
+import org.nrg.xnat.turbine.utils.ArcSpecManager;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.inject.Inject;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection"})
+public class XnatExpiredPasswordFilter extends GenericFilterBean implements ApplicationContextAware {
+    private String changePasswordPath        = "";
+    private String changePasswordDestination = "";
+    private String logoutDestination         = "";
+    private String loginPath                 = "";
+    private String loginDestination          = "";
+    private String inactiveAccountPath;
+    private String inactiveAccountDestination;
+    private String emailVerificationDestination;
+    private String emailVerificationPath;
+    private boolean passwordExpirationDirtied = true;
+    private boolean passwordExpirationDisabled;
+    private boolean passwordExpirationInterval;
+    private String  passwordExpirationSetting;
+
+    @Override
+    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
+        final HttpServletRequest  request         = (HttpServletRequest) req;
+        final HttpServletResponse response        = (HttpServletResponse) res;
+        UserI                     user            = XDAT.getUserDetails();
+        Object                    passwordExpired = request.getSession().getAttribute("expired");
+        // MIGRATION: Need to remove arcspec.
+        ArcArchivespecification _arcSpec = ArcSpecManager.GetInstance();
+        final String            referer  = request.getHeader("Referer");
+        if (request.getSession() != null && request.getSession().getAttribute("forcePasswordChange") != null && (Boolean) request.getSession().getAttribute("forcePasswordChange")) {
+            try {
+                String refererPath = null;
+                String uri         = new URI(request.getRequestURI()).getPath();
+                if (!StringUtils.isBlank(referer)) {
+                    refererPath = new URI(referer).getPath();
+                }
+                if (uri.endsWith(changePasswordPath) || uri.endsWith(changePasswordDestination) || uri.endsWith(logoutDestination) || uri.endsWith(loginPath) || uri.endsWith(loginDestination)) {
+                    //If you're already on the change password page, continue on without redirect.
+                    chain.doFilter(req, res);
+                } else if (!StringUtils.isBlank(refererPath) && (changePasswordPath.equals(refererPath) || changePasswordDestination.equals(refererPath) || logoutDestination.equals(refererPath))) {
+                    //If you're on a request within the change password page, continue on without redirect.
+                    chain.doFilter(req, res);
+                } else {
+                    response.sendRedirect(TurbineUtils.GetFullServerPath() + changePasswordPath);
+                }
+            } catch (URISyntaxException ignored) {
+                //
+            }
+        } else if (passwordExpired != null && !(Boolean) passwordExpired) {
+            //If the date of password change was checked earlier in the session and found to be not expired, do not send them to the expired password page.
+            chain.doFilter(request, response);
+        } else if (_arcSpec == null || !_arcSpec.isComplete()) {
+            //If the arc spec has not yet been set, have the user configure the arc spec before changing their password. This prevents a negative interaction with the arc spec filter.
+            chain.doFilter(request, response);
+        } else {
+            if (user == null) {
+                //If the user is not logged in, do not send them to the expired password page.
+
+                String header = request.getHeader("Authorization");
+                if (header != null && header.startsWith("Basic ")) {
+                    //For users that authenticated using basic authentication, check whether their password is expired, and if so give them a 403 and a message that they need to change their password.
+
+                    String token    = new String(Base64.decode(header.substring(6).getBytes("UTF-8")), "UTF-8");
+                    String username = "";
+                    int    delim    = token.indexOf(":");
+                    if (delim != -1) {
+                        username = token.substring(0, delim);
+                    }
+                    if (AliasToken.isAliasFormat(username)) {
+                        AliasToken alias = getAliasTokenService().locateToken(username);
+                        if (alias == null) {
+                            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Your security token has expired. Please try again after updating your session.");
+                            return;
+                        }
+                        username = alias.getXdatUserId();
+                    }
+                    // Check whether the user is connected to an active role for non_expiring.
+                    try {
+                        List<Integer> roles = (new JdbcTemplate(_dataSource)).query("SELECT COUNT(*) FROM xhbm_user_role where username = ? and role = ? and enabled = 't'", new String[] {username, UserRole.ROLE_NON_EXPIRING}, new RowMapper<Integer>() {
+                            public Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
+                                return rs.getInt(1);
+                            }
+                        });
+                        if (roles.get(0) > 0) {
+                            chain.doFilter(request, response);
+                        }
+                    } catch (Exception e) {
+                        logger.error(e);
+                    }
+
+                    try {
+                        passwordExpirationDisabled = isPasswordExpirationDisabled();
+                    } catch (SiteConfigurationException e) {
+                        logger.error("An error occurred trying to check for expired passwords, continuing processing.", e);
+                    }
+                    if (passwordExpirationDisabled) {
+                        chain.doFilter(request, response);
+                    } else {
+                        final boolean isExpired = checkForExpiredPassword(username);
+                        request.getSession().setAttribute("expired", isExpired);
+                        if (username != null && isExpired && !username.equals("guest")) {
+                            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Your password has expired. Please try again after changing your password.");
+                        } else {
+                            chain.doFilter(request, response);
+                        }
+                    }
+                } else {
+                    checkUserChangePassword(request, response);
+                    //User is not authenticated through basic authentication either.
+                    chain.doFilter(req, res);
+                }
+            } else {
+                String uri = request.getRequestURI();
+
+                if (user.isGuest()) {
+                    //If you're a guest and you try to access the change password page, you get sent to the login page since there's no password on the guest account to change.
+                    checkUserChangePassword(request, response);
+                }
+                if (user.isGuest() ||
+                    //If you're logging in or out, or going to the login page itself
+                    (uri.endsWith(logoutDestination) || uri.endsWith(loginPath) || uri.endsWith(loginDestination)) ||
+                    //If you're already on the change password page, continue on without redirect.
+                    (user.isEnabled() && (uri.endsWith(changePasswordPath) || uri.endsWith(changePasswordDestination))) ||
+                    //If you're already on the inactive account page or reactivating an account, continue on without redirect.
+                    (!user.isEnabled() && (uri.endsWith(inactiveAccountPath) || uri.endsWith(inactiveAccountDestination) ||
+                                           uri.endsWith(emailVerificationPath) || uri.endsWith(emailVerificationDestination) ||
+                                           (referer != null && (referer.endsWith(inactiveAccountPath) || referer.endsWith(inactiveAccountDestination))))) ||
+                    //If you're on a request within the change password page, continue on without redirect.
+                    (referer != null && (referer.endsWith(changePasswordPath) || referer.endsWith(changePasswordDestination) ||
+                                         referer.endsWith(logoutDestination)))) {
+                    chain.doFilter(req, res);
+                } else {
+                    if (
+                            user.getAuthorization() != null && user.getAuthorization().getAuthMethod().equals(XdatUserAuthService.LDAP)
+                            ) {
+                        // Shouldn't check for a localdb expired password if user is coming in through LDAP
+                        chain.doFilter(req, res);
+                    } else if (user.isEnabled()) {
+                        boolean isExpired = checkForExpiredPassword(user);
+
+                        if ((!isUserNonExpiring(user) && isExpired) || (_preferences.getRequireSaltedPasswords() && user.getSalt() == null)) {
+                            request.getSession().setAttribute("expired", isExpired);
+                            response.sendRedirect(TurbineUtils.GetFullServerPath() + changePasswordPath);
+                        } else {
+                            chain.doFilter(request, response);
+                        }
+                    } else {
+                        response.sendRedirect(TurbineUtils.GetFullServerPath() + inactiveAccountPath);
+                    }
+                }
+            }
+        }
+    }
+
+    public void setChangePasswordPath(String path) {
+        this.changePasswordPath = path;
+    }
+
+    public void setChangePasswordDestination(String path) {
+        this.changePasswordDestination = path;
+    }
+
+    public void setLogoutDestination(String path) {
+        this.logoutDestination = path;
+    }
+
+    public void setLoginPath(String path) {
+        this.loginPath = path;
+    }
+
+    public void setLoginDestination(String loginDestination) {
+        this.loginDestination = loginDestination;
+    }
+
+    public void setInactiveAccountPath(String inactiveAccountPath) {
+        this.inactiveAccountPath = inactiveAccountPath;
+    }
+
+    public String getInactiveAccountPath() {
+        return inactiveAccountPath;
+    }
+
+    public void setInactiveAccountDestination(String inactiveAccountDestination) {
+        this.inactiveAccountDestination = inactiveAccountDestination;
+    }
+
+    public String getInactiveAccountDestination() {
+        return inactiveAccountDestination;
+    }
+
+    public void setEmailVerificationDestination(String emailVerificationDestination) {
+        this.emailVerificationDestination = emailVerificationDestination;
+    }
+
+    public String getEmailVerificationDestination() {
+        return emailVerificationDestination;
+    }
+
+    public void setEmailVerificationPath(String emailVerificationPath) {
+        this.emailVerificationPath = emailVerificationPath;
+    }
+
+    public String getEmailVerificationPath() {
+        return emailVerificationPath;
+    }
+
+    public void setPasswordExpirationDirtied(final boolean passwordExpirationDirtied) {
+        this.passwordExpirationDirtied = passwordExpirationDirtied;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setApplicationContext(final ApplicationContext context) throws BeansException {
+        _context = context;
+    }
+
+    private boolean checkForExpiredPassword(final UserI user) {
+        return checkForExpiredPassword(user.getUsername());
+    }
+
+    private boolean checkForExpiredPassword(final String username) {
+        try {
+            if (isPasswordExpirationDisabled()) {
+                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>() {
+                    public Boolean mapRow(ResultSet rs, int rowNum) throws SQLException {
+                        return rs.getBoolean(1);
+                    }
+                });
+                return expired.get(0);
+            } else {
+                List<Boolean> expired = (new JdbcTemplate(_dataSource)).query("SELECT (to_date('" + new SimpleDateFormat("MM/dd/yyyy").format(new Date(Long.parseLong(passwordExpirationSetting))) + "', 'MM/DD/YYYY') BETWEEN password_updated AND now()) 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);
+                    }
+                });
+                return expired.get(0);
+            }
+        } catch (Throwable e) { // ldap authentication can throw an exception during these queriess
+            logger.error(e.getMessage(), e);
+        }
+        return false;
+    }
+
+    private boolean isPasswordExpirationDisabled() throws SiteConfigurationException {
+        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;
+        }
+        passwordExpirationDirtied = false;
+        return passwordExpirationDisabled;
+    }
+
+    private boolean isPasswordExpirationInterval() {
+        return passwordExpirationInterval;
+    }
+
+    private boolean isUserNonExpiring(UserI user) {
+        try {
+            return Roles.checkRole(user, UserRole.ROLE_NON_EXPIRING);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    private void checkUserChangePassword(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        try {
+            String uri = new URI(request.getRequestURI()).getPath();
+            if (uri.endsWith("XDATScreen_UpdateUser.vm") && request.getParameterMap().isEmpty()) {
+                response.sendRedirect(TurbineUtils.GetFullServerPath() + "/app/template/Login.vm");
+            }
+        } catch (URISyntaxException ignored) {
+        }
+    }
+
+    // We have to do this because the filter must be created in the root context, but the token service must be created
+    // in the application context. We use the context service to cheat across these boundaries.
+    private AliasTokenService getAliasTokenService() {
+        if (_aliasTokenService == null) {
+            _aliasTokenService = _contextService.getBean(AliasTokenService.class);
+        }
+        return _aliasTokenService;
+    }
+
+    @Autowired
+    @Lazy
+    private InitializerSiteConfiguration _preferences;
+
+    @Autowired
+    @Lazy
+    private ContextService _contextService;
+
+    @Inject
+    private DataSource _dataSource;
+
+    private ApplicationContext _context;
+    private AliasTokenService  _aliasTokenService;
+}
diff --git a/src/main/java/org/nrg/xnat/security/XnatProviderManager.java b/src/main/java/org/nrg/xnat/security/XnatProviderManager.java
index 6e1e149f311b4cbbbeb9f1497d978b26eefb99ab..a762ed38c82c8f42c952299f7e83012e7b0a073c 100644
--- a/src/main/java/org/nrg/xnat/security/XnatProviderManager.java
+++ b/src/main/java/org/nrg/xnat/security/XnatProviderManager.java
@@ -1,429 +1,408 @@
-/*
- * org.nrg.xnat.security.XnatProviderManager
- * XNAT http://www.xnat.org
- * Copyright (c) 2014, Washington University School of Medicine
- * All Rights Reserved
- *
- * Released under the Simplified BSD.
- *
- * Last modified 12/13/13 2:19 PM
- */
-package org.nrg.xnat.security;
-
-import com.google.common.collect.Maps;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.DateUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.velocity.VelocityContext;
-import org.hibernate.exception.DataException;
-import org.nrg.framework.services.ContextService;
-import org.nrg.xdat.XDAT;
-import org.nrg.xdat.entities.AliasToken;
-import org.nrg.xdat.entities.UserAuthI;
-import org.nrg.xdat.entities.XdatUserAuth;
-import org.nrg.xdat.security.helpers.Users;
-import org.nrg.xdat.services.XdatUserAuthService;
-import org.nrg.xdat.turbine.utils.AdminUtils;
-import org.nrg.xdat.turbine.utils.TurbineUtils;
-import org.nrg.xft.security.UserI;
-import org.nrg.xft.utils.AuthUtils;
-import org.nrg.xnat.security.alias.AliasTokenAuthenticationProvider;
-import org.nrg.xnat.security.alias.AliasTokenAuthenticationToken;
-import org.nrg.xnat.security.provider.XnatAuthenticationProvider;
-import org.nrg.xnat.security.provider.XnatDatabaseAuthenticationProvider;
-import org.nrg.xnat.security.provider.XnatLdapAuthenticationProvider;
-import org.nrg.xnat.security.tokens.XnatDatabaseUsernamePasswordAuthenticationToken;
-import org.nrg.xnat.security.tokens.XnatLdapUsernamePasswordAuthenticationToken;
-import org.nrg.xnat.security.userdetailsservices.XnatDatabaseUserDetailsService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.context.support.MessageSourceAccessor;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.security.authentication.*;
-import org.springframework.security.core.*;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-
-import javax.inject.Inject;
-import javax.sql.DataSource;
-import java.io.IOException;
-import java.net.URL;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.*;
-
-public class XnatProviderManager extends ProviderManager {
-
-    public XnatProviderManager(final List<AuthenticationProvider> providers, final Properties properties) {
-
-        super(providers);
-
-        if (properties == null) {
-            throw new IllegalArgumentException("The list of authentication providers cannot be set to null.");
-        }
-
-        _properties = properties;
-
-        if(!StringUtils.isBlank(properties.getProperty(SECURITY_MAX_FAILED_LOGINS_PROPERTY))) {
-            AuthUtils.MAX_FAILED_LOGIN_ATTEMPTS=Integer.valueOf(properties.getProperty(SECURITY_MAX_FAILED_LOGINS_PROPERTY));
-        }
-
-        if(!StringUtils.isBlank(properties.getProperty(SECURITY_MAX_FAILED_LOGINS_LOCKOUT_DURATION_PROPERTY))) {
-            AuthUtils.LOCKOUT_DURATION=Integer.valueOf(properties.getProperty(SECURITY_MAX_FAILED_LOGINS_LOCKOUT_DURATION_PROPERTY));
-            if(AuthUtils.LOCKOUT_DURATION>0)AuthUtils.LOCKOUT_DURATION=-(AuthUtils.LOCKOUT_DURATION); //LOCKOUT must be negative for date comparison to work
-        }
-    }
-
-    @Override
-    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
-        Class<? extends Authentication> toTest = authentication.getClass();
-        AuthenticationException lastException = null;
-        Authentication result = null;
-        List<AuthenticationProvider> providers = new ArrayList<>();
-
-        // HACK: This is a hack to work around open XNAT auth issue. If this is a bare un/pw auth token, use anon auth.
-        if (authentication.getClass() == UsernamePasswordAuthenticationToken.class && authentication.getName().equalsIgnoreCase("guest")) {
-            providers.add(getAnonymousAuthenticationProvider());
-            authentication = new AnonymousAuthenticationToken(getAnonymousAuthenticationProvider().getKey(), authentication.getPrincipal(), Collections.<GrantedAuthority>singletonList(new SimpleGrantedAuthority("ROLE_ANONYMOUS")));
-        } else {
-            for (AuthenticationProvider candidate : getProviders()) {
-                if (!candidate.supports(toTest)) {
-                    continue;
-                }
-                if(authentication instanceof XnatLdapUsernamePasswordAuthenticationToken){
-                    if (!(candidate instanceof XnatLdapAuthenticationProvider)) {
-                        continue;
-                    }
-                    XnatLdapAuthenticationProvider ldapCandidate = (XnatLdapAuthenticationProvider) candidate;
-                    if (!((XnatLdapUsernamePasswordAuthenticationToken) authentication).getProviderId().equalsIgnoreCase(ldapCandidate.getProviderId())) {
-                        //This is a different LDAP provider than the one that was selected.
-                        continue;
-                    }
-                }
-                try {
-                    if (((XnatDatabaseAuthenticationProvider)candidate).isPlainText()) {
-                        String username = authentication.getPrincipal().toString();
-                        Boolean encrypted = new JdbcTemplate(_dataSource).query("SELECT primary_password_encrypt<>0 OR (primary_password_encrypt IS NULL AND CHAR_LENGTH(primary_password)=64) FROM xdat_user WHERE login=? LIMIT 1", new String[] {username}, new RowMapper<Boolean>() {
-                            public Boolean mapRow(ResultSet rs, int rowNum) throws SQLException {
-                                return rs.getBoolean(1);
-                            }
-                        }).get(0);
-
-                        if (encrypted) continue;
-                    }
-                } catch (Exception e) {/*casting exceptions can be safely ignored*/}
-                providers.add(candidate);
-            }
-        }
-
-        assert providers.size() > 0: "No provider found for authentication of type " + authentication.getClass().getSimpleName();
-
-        for (AuthenticationProvider provider : providers) {
-            _log.debug("Authentication attempt using " + provider.getClass().getName());
-
-            try {
-                result = provider.authenticate(authentication);
-                if (result != null) {
-                    if (_log.isDebugEnabled()) {
-                        _log.debug("Found a provider that worked for " + authentication.getName() + ": " + provider.getClass().getSimpleName());
-                    }
-
-                    copyDetails(authentication, result);
-                    break;
-                }
-            } catch (AccountStatusException exception) {
-                _log.warn("Error occurred authenticating login request", exception);
-                lastException = exception;
-            } catch(NewLdapAccountNotAutoEnabledException e) {
-                try {
-                    AdminUtils.sendNewUserNotification(e.getUserDetails(), "", "", "", new VelocityContext());
-                } catch (Exception exception) {
-                    _log.error("Error occurred sending new user request email", exception);
-                }
-                lastException = e;
-
-            } catch (AuthenticationException e) {
-                lastException = e;
-            }
-        }
-
-        if (result != null) {
-            boolean eraseCredentialsAfterAuthentication = false;
-            if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
-                // Authentication is complete. Remove credentials and other secret data from authentication
-                ((CredentialsContainer)result).eraseCredentials();
-            }
-
-            eventPublisher.publishAuthenticationSuccess(authentication);
-
-            return result;
-            
-        } else {
-            // Parent was null, or didn't authenticate (or throw an exception).
-            if (lastException == null) {
-                lastException = new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound",
-                        new Object[] {toTest.getName()}, "No AuthenticationProvider found for {0}"));
-            }
-
-            eventPublisher.publishAuthenticationFailure(lastException, authentication);
-            throw lastException;
-        }
-    }
-
-    private AnonymousAuthenticationProvider getAnonymousAuthenticationProvider() {
-        return _contextService.getBean(AnonymousAuthenticationProvider.class);
-    }
-
-    public void setProperties(List<String> fileNames) {
-        _properties = new Properties();
-        for (String filename : fileNames) {
-            String path = "../../../../../../" + filename;
-            URL url = getClass().getResource(path);
-            if (url != null) {
-                try {
-                    _properties.load(url.openStream());
-                } catch (IOException e) {
-                    _log.error(e);
-                }
-            }
-        }
-    }
-
-    public XdatUserAuth getUserByAuth(Authentication authentication) {
-        if(authentication==null){
-            return null;
-        }
-
-        final String u;
-        if(authentication.getPrincipal() instanceof String){
-            u=(String)authentication.getPrincipal();
-        }else{
-            u=((UserI)authentication.getPrincipal()).getLogin();
-        }
-        final String method;
-        final String provider;
-        if(authentication instanceof XnatLdapUsernamePasswordAuthenticationToken){
-            provider=((XnatLdapUsernamePasswordAuthenticationToken)authentication).getProviderId();
-            method=XdatUserAuthService.LDAP;
-        }else{
-            provider=XnatDatabaseUserDetailsService.DB_PROVIDER;
-            method=XdatUserAuthService.LOCALDB;
-        }
-
-        try {
-            return getUserAuthService().getUserByNameAndAuth(u, method, provider);
-        } catch (DataException exception) {
-            _log.error("An error occurred trying to retrieve the auth method", exception);
-            throw new RuntimeException("An error occurred trying to validate the given information. Please check your username and password. If this problem persists, please contact your system administrator.");
-        }
-    }
-
-    public UsernamePasswordAuthenticationToken buildUPTokenForAuthMethod(String authMethod, String username, String password){
-        XnatAuthenticationProvider chosenProvider = findAuthenticationProviderByAuthMethod(authMethod);
-        return buildUPToken(chosenProvider, username, password);
-    }
-
-    public UsernamePasswordAuthenticationToken buildUPTokenForProviderName(String providerName, String username, String password){
-        XnatAuthenticationProvider chosenProvider = findAuthenticationProviderByProviderName(providerName);
-        return buildUPToken(chosenProvider, username, password);
-    }
-
-    public String retrieveAuthMethod(final String username) {
-        String auth = cached_methods.get(username);
-        if (auth == null) {
-            try {
-                List<XdatUserAuth> userAuths = getUserAuthService().getUsersByName(username);
-                if (userAuths.size() == 1) {
-                    auth = userAuths.get(0).getAuthMethod();
-                    cached_methods.put(username.intern(), auth.intern());
-                    // The list may contain localdb auth method even when password is empty and LDAP authentication is used (MRH)
-                } else if (userAuths.size() > 1) {
-                    for (UserAuthI userAuth : userAuths) {
-                        auth = userAuth.getAuthMethod();
-                        cached_methods.put(username.intern(), auth.intern());
-                        if (!userAuth.getAuthMethod().equalsIgnoreCase(XdatUserAuthService.LOCALDB)) {
-                            break;
-                        }
-                    }
-                } else if (AliasToken.isAliasFormat(username)) {
-                    auth = XdatUserAuthService.TOKEN;
-                    cached_methods.put(username.intern(), auth.intern());
-                }
-            } catch (DataException exception) {
-                _log.error("An error occurred trying to retrieve the auth method", exception);
-                throw new RuntimeException("An error occurred trying to validate the given information. Please check your username and password. If this problem persists, please contact your system administrator.");
-            }
-        }
-        return auth;
-    }
-
-    private XdatUserAuthService getUserAuthService() {
-        if (_userAuthService == null) {
-            _userAuthService = _contextService.getBean(XdatUserAuthService.class);
-        }
-        return _userAuthService;
-    }
-
-    private static UsernamePasswordAuthenticationToken buildUPToken(XnatAuthenticationProvider provider, String username, String password){
-        if (provider instanceof XnatLdapAuthenticationProvider) {
-            return new XnatLdapUsernamePasswordAuthenticationToken(username, password, provider.getProviderId());
-        } else  if (provider instanceof AliasTokenAuthenticationProvider) {
-            return new AliasTokenAuthenticationToken(username, Long.parseLong(password));
-        } else {
-            return new XnatDatabaseUsernamePasswordAuthenticationToken(username, password);
-        }
-    }
-
-    private XnatAuthenticationProvider findAuthenticationProviderByAuthMethod(final String authMethod){
-        return findAuthenticationProvider(new XnatAuthenticationProviderMatcher() {
-            @Override
-            public boolean matches(XnatAuthenticationProvider provider) {
-                return provider.getAuthMethod().equalsIgnoreCase(authMethod);
-            }
-        });
-    }
-
-    private XnatAuthenticationProvider findAuthenticationProviderByProviderName(final String providerName){
-        return findAuthenticationProvider(new XnatAuthenticationProviderMatcher() {
-            @Override
-            public boolean matches(XnatAuthenticationProvider provider) {
-                return provider.getName().equalsIgnoreCase(providerName);
-            }
-        });
-    }
-
-    private XnatAuthenticationProvider findAuthenticationProvider(XnatAuthenticationProviderMatcher matcher){
-        List<AuthenticationProvider> prov = getProviders();
-        for(AuthenticationProvider ap : prov){
-            XnatAuthenticationProvider xap = (XnatAuthenticationProvider) ap;
-            if(matcher.matches(xap)){
-                return xap;
-            }
-        }
-        return null;
-    }
-
-    private void copyDetails(Authentication source, Authentication destination) {
-        if ((destination instanceof AbstractAuthenticationToken) && (destination.getDetails() == null)) {
-            AbstractAuthenticationToken token = (AbstractAuthenticationToken) destination;
-
-            token.setDetails(source.getDetails());
-}
-    }
-
-    private static final class AuthenticationAttemptEventPublisher implements AuthenticationEventPublisher {
-
-        private final FailedAttemptsManager failedAttemptsManager;
-        private final LastSuccessfulLoginManager lastSuccessfulLoginManager;
-
-        private AuthenticationAttemptEventPublisher(final XnatProviderManager manager) {
-            failedAttemptsManager = new FailedAttemptsManager(manager);
-            lastSuccessfulLoginManager = new LastSuccessfulLoginManager(manager);
-        }
-
-        public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
-            //increment failed login attempt
-            failedAttemptsManager.addFailedLoginAttempt(authentication);
-        }
-
-        public void publishAuthenticationSuccess(Authentication authentication) {
-            failedAttemptsManager.clearCount(authentication);
-            lastSuccessfulLoginManager.updateLastSuccessfulLogin(authentication);
-        }
-    }
-
-    private static final class LastSuccessfulLoginManager {
-        private final XnatProviderManager _manager;
-
-        public LastSuccessfulLoginManager(final XnatProviderManager manager) {
-            _manager = manager;
-        }
-
-        private void updateLastSuccessfulLogin(Authentication auth) {
-            XdatUserAuth ua = _manager.getUserByAuth(auth);
-            if (ua != null) {
-                Date now = java.util.Calendar.getInstance(TimeZone.getDefault()).getTime();
-                ua.setLastSuccessfulLogin(now);
-                ua.setLastLoginAttempt(now);
-                XDAT.getXdatUserAuthService().update(ua);
-            }
-        }
-    }
-
-    private static final class FailedAttemptsManager {
-        private final XnatProviderManager _manager;
-
-        public FailedAttemptsManager(final XnatProviderManager manager) {
-            _manager = manager;
-        }
-
-        /**
-         * Increments failed Login count
-         *
-         * @param auth The authentication that failed.
-         */
-        private synchronized void addFailedLoginAttempt(final Authentication auth) {
-            XdatUserAuth ua = _manager.getUserByAuth(auth);
-            if (ua != null) {
-                if (AuthUtils.MAX_FAILED_LOGIN_ATTEMPTS > 0) {
-                    ua.setFailedLoginAttempts(ua.getFailedLoginAttempts() + 1);
-                    ua.setLastLoginAttempt(new Date());
-                    XDAT.getXdatUserAuthService().update(ua);
-                }
-
-                if (StringUtils.isNotEmpty(ua.getXdatUsername())) {
-                    Integer uid = Users.getUserid(ua.getXdatUsername());
-                    if (uid != null) {
-                        try {
-                            if (ua.getFailedLoginAttempts().equals(AuthUtils.MAX_FAILED_LOGIN_ATTEMPTS)) {
-                                String expiration = TurbineUtils.getDateTimeFormatter().format(DateUtils.addMilliseconds(GregorianCalendar.getInstance().getTime(), -(AuthUtils.LOCKOUT_DURATION)));
-                                System.out.println("Locked out " + ua.getXdatUsername() + " user account until " + expiration);
-                                AdminUtils.sendAdminEmail(ua.getXdatUsername() + " account temporarily disabled.", "User " + ua.getXdatUsername() + " has been temporarily disabled due to excessive failed login attempts. The user's account will be automatically enabled at " + expiration + ".");
-                            }
-                        } catch (Exception e) {
-                            //ignore
-                        }
-                    }
-                }
-            }
-        }
-
-        public void clearCount(final Authentication auth) {
-            if (AuthUtils.MAX_FAILED_LOGIN_ATTEMPTS > 0) {
-                XdatUserAuth ua = _manager.getUserByAuth(auth);
-                if (ua != null) {
-                    ua.setFailedLoginAttempts(0);
-                    XDAT.getXdatUserAuthService().update(ua);
-                }
-            }
-        }
-    }
-
-    private interface XnatAuthenticationProviderMatcher  {
-        boolean matches(XnatAuthenticationProvider provider);
-    }
-
-    private static final String SECURITY_MAX_FAILED_LOGINS_LOCKOUT_DURATION_PROPERTY = "security.max_failed_logins_lockout_duration";
-    private static final String SECURITY_MAX_FAILED_LOGINS_PROPERTY = "security.max_failed_logins";
-
-    private static final Log _log = LogFactory.getLog(XnatProviderManager.class);
-
-    private static Map<String,String> cached_methods= Maps.newConcurrentMap();//this will prevent 20,000 curl scripts from hitting the db everytime
-
-    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
-
-    @Inject
-    private DataSource _dataSource;
-
-    @Autowired
-    @Qualifier("rootContextService")
-    @Lazy
-    private ContextService _contextService;
-
-    private XdatUserAuthService _userAuthService;
-
-    private final AuthenticationEventPublisher eventPublisher = new AuthenticationAttemptEventPublisher(this);
-    private Properties _properties;
-}
+/*
+ * org.nrg.xnat.security.XnatProviderManager
+ * XNAT http://www.xnat.org
+ * Copyright (c) 2014, Washington University School of Medicine
+ * All Rights Reserved
+ *
+ * Released under the Simplified BSD.
+ *
+ * Last modified 12/13/13 2:19 PM
+ */
+package org.nrg.xnat.security;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.velocity.VelocityContext;
+import org.hibernate.exception.DataException;
+import org.nrg.config.exceptions.SiteConfigurationException;
+import org.nrg.framework.services.ContextService;
+import org.nrg.xdat.XDAT;
+import org.nrg.xdat.entities.AliasToken;
+import org.nrg.xdat.entities.UserAuthI;
+import org.nrg.xdat.entities.XdatUserAuth;
+import org.nrg.xdat.preferences.InitializerSiteConfiguration;
+import org.nrg.xdat.preferences.SiteConfigPreferences;
+import org.nrg.xdat.security.helpers.Users;
+import org.nrg.xdat.services.XdatUserAuthService;
+import org.nrg.xdat.turbine.utils.AdminUtils;
+import org.nrg.xdat.turbine.utils.TurbineUtils;
+import org.nrg.xft.security.UserI;
+import org.nrg.xnat.security.alias.AliasTokenAuthenticationProvider;
+import org.nrg.xnat.security.alias.AliasTokenAuthenticationToken;
+import org.nrg.xnat.security.provider.XnatAuthenticationProvider;
+import org.nrg.xnat.security.provider.XnatDatabaseAuthenticationProvider;
+import org.nrg.xnat.security.provider.XnatLdapAuthenticationProvider;
+import org.nrg.xnat.security.tokens.XnatDatabaseUsernamePasswordAuthenticationToken;
+import org.nrg.xnat.security.tokens.XnatLdapUsernamePasswordAuthenticationToken;
+import org.nrg.xnat.security.userdetailsservices.XnatDatabaseUserDetailsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.context.support.MessageSourceAccessor;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.security.authentication.*;
+import org.springframework.security.core.*;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import javax.inject.Inject;
+import javax.sql.DataSource;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+
+public class XnatProviderManager extends ProviderManager {
+    public XnatProviderManager(final List<AuthenticationProvider> providers) {
+        super(providers);
+    }
+
+    @Override
+    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+        Class<? extends Authentication> toTest        = authentication.getClass();
+        AuthenticationException         lastException = null;
+        Authentication                  result        = null;
+        List<AuthenticationProvider>    providers     = new ArrayList<>();
+
+        // HACK: This is a hack to work around open XNAT auth issue. If this is a bare un/pw auth token, use anon auth.
+        if (authentication.getClass() == UsernamePasswordAuthenticationToken.class && authentication.getName().equalsIgnoreCase("guest")) {
+            providers.add(getAnonymousAuthenticationProvider());
+            authentication = new AnonymousAuthenticationToken(getAnonymousAuthenticationProvider().getKey(), authentication.getPrincipal(), Collections.<GrantedAuthority> singletonList(new SimpleGrantedAuthority("ROLE_ANONYMOUS")));
+        } else {
+            for (AuthenticationProvider candidate : getProviders()) {
+                if (!candidate.supports(toTest)) {
+                    continue;
+                }
+                if (authentication instanceof XnatLdapUsernamePasswordAuthenticationToken) {
+                    if (!(candidate instanceof XnatLdapAuthenticationProvider)) {
+                        continue;
+                    }
+                    XnatLdapAuthenticationProvider ldapCandidate = (XnatLdapAuthenticationProvider) candidate;
+                    if (!((XnatLdapUsernamePasswordAuthenticationToken) authentication).getProviderId().equalsIgnoreCase(ldapCandidate.getProviderId())) {
+                        //This is a different LDAP provider than the one that was selected.
+                        continue;
+                    }
+                }
+                try {
+                    if (((XnatDatabaseAuthenticationProvider) candidate).isPlainText()) {
+                        String username = authentication.getPrincipal().toString();
+                        @SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection"})
+                        final Boolean encrypted = new JdbcTemplate(_dataSource).query("SELECT primary_password_encrypt<>0 OR (primary_password_encrypt IS NULL AND CHAR_LENGTH(primary_password)=64) FROM xdat_user WHERE login=? LIMIT 1", new String[] {username}, new RowMapper<Boolean>() {
+                            public Boolean mapRow(ResultSet rs, int rowNum) throws SQLException {
+                                return rs.getBoolean(1);
+                            }
+                        }).get(0);
+
+                        if (encrypted) {
+                            continue;
+                        }
+                    }
+                } catch (Exception e) {/*casting exceptions can be safely ignored*/}
+                providers.add(candidate);
+            }
+        }
+
+        assert providers.size() > 0 : "No provider found for authentication of type " + authentication.getClass().getSimpleName();
+
+        for (AuthenticationProvider provider : providers) {
+            _log.debug("Authentication attempt using " + provider.getClass().getName());
+
+            try {
+                result = provider.authenticate(authentication);
+                if (result != null) {
+                    if (_log.isDebugEnabled()) {
+                        _log.debug("Found a provider that worked for " + authentication.getName() + ": " + provider.getClass().getSimpleName());
+                    }
+
+                    copyDetails(authentication, result);
+                    break;
+                }
+            } catch (AccountStatusException exception) {
+                _log.warn("Error occurred authenticating login request", exception);
+                lastException = exception;
+            } catch (NewLdapAccountNotAutoEnabledException e) {
+                try {
+                    AdminUtils.sendNewUserNotification(e.getUserDetails(), "", "", "", new VelocityContext());
+                } catch (Exception exception) {
+                    _log.error("Error occurred sending new user request email", exception);
+                }
+                lastException = e;
+
+            } catch (AuthenticationException e) {
+                lastException = e;
+            }
+        }
+
+        if (result != null) {
+            boolean eraseCredentialsAfterAuthentication = false;
+            if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
+                // Authentication is complete. Remove credentials and other secret data from authentication
+                ((CredentialsContainer) result).eraseCredentials();
+            }
+
+            eventPublisher.publishAuthenticationSuccess(authentication);
+
+            return result;
+
+        } else {
+            // Parent was null, or didn't authenticate (or throw an exception).
+            if (lastException == null) {
+                lastException = new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound",
+                                                                                  new Object[] {toTest.getName()}, "No AuthenticationProvider found for {0}"));
+            }
+
+            eventPublisher.publishAuthenticationFailure(lastException, authentication);
+            throw lastException;
+        }
+    }
+
+    private AnonymousAuthenticationProvider getAnonymousAuthenticationProvider() {
+        return _contextService.getBean(AnonymousAuthenticationProvider.class);
+    }
+
+    public XdatUserAuth getUserByAuth(Authentication authentication) {
+        if (authentication == null) {
+            return null;
+        }
+
+        final String u;
+        if (authentication.getPrincipal() instanceof String) {
+            u = (String) authentication.getPrincipal();
+        } else {
+            u = ((UserI) authentication.getPrincipal()).getLogin();
+        }
+        final String method;
+        final String provider;
+        if (authentication instanceof XnatLdapUsernamePasswordAuthenticationToken) {
+            provider = ((XnatLdapUsernamePasswordAuthenticationToken) authentication).getProviderId();
+            method = XdatUserAuthService.LDAP;
+        } else {
+            provider = XnatDatabaseUserDetailsService.DB_PROVIDER;
+            method = XdatUserAuthService.LOCALDB;
+        }
+
+        try {
+            return getUserAuthService().getUserByNameAndAuth(u, method, provider);
+        } catch (DataException exception) {
+            _log.error("An error occurred trying to retrieve the auth method", exception);
+            throw new RuntimeException("An error occurred trying to validate the given information. Please check your username and password. If this problem persists, please contact your system administrator.");
+        }
+    }
+
+    public UsernamePasswordAuthenticationToken buildUPTokenForAuthMethod(String authMethod, String username, String password) {
+        XnatAuthenticationProvider chosenProvider = findAuthenticationProviderByAuthMethod(authMethod);
+        return buildUPToken(chosenProvider, username, password);
+    }
+
+    public UsernamePasswordAuthenticationToken buildUPTokenForProviderName(String providerName, String username, String password) {
+        XnatAuthenticationProvider chosenProvider = findAuthenticationProviderByProviderName(providerName);
+        return buildUPToken(chosenProvider, username, password);
+    }
+
+    public String retrieveAuthMethod(final String username) {
+        String auth = cached_methods.get(username);
+        if (auth == null) {
+            try {
+                List<XdatUserAuth> userAuths = getUserAuthService().getUsersByName(username);
+                if (userAuths.size() == 1) {
+                    auth = userAuths.get(0).getAuthMethod();
+                    cached_methods.put(username.intern(), auth.intern());
+                    // The list may contain localdb auth method even when password is empty and LDAP authentication is used (MRH)
+                } else if (userAuths.size() > 1) {
+                    for (UserAuthI userAuth : userAuths) {
+                        auth = userAuth.getAuthMethod();
+                        cached_methods.put(username.intern(), auth.intern());
+                        if (!userAuth.getAuthMethod().equalsIgnoreCase(XdatUserAuthService.LOCALDB)) {
+                            break;
+                        }
+                    }
+                } else if (AliasToken.isAliasFormat(username)) {
+                    auth = XdatUserAuthService.TOKEN;
+                    cached_methods.put(username.intern(), auth.intern());
+                }
+            } catch (DataException exception) {
+                _log.error("An error occurred trying to retrieve the auth method", exception);
+                throw new RuntimeException("An error occurred trying to validate the given information. Please check your username and password. If this problem persists, please contact your system administrator.");
+            }
+        }
+        return auth;
+    }
+
+    private XdatUserAuthService getUserAuthService() {
+        if (_userAuthService == null) {
+            _userAuthService = _contextService.getBean(XdatUserAuthService.class);
+        }
+        return _userAuthService;
+    }
+
+    private static UsernamePasswordAuthenticationToken buildUPToken(XnatAuthenticationProvider provider, String username, String password) {
+        if (provider instanceof XnatLdapAuthenticationProvider) {
+            return new XnatLdapUsernamePasswordAuthenticationToken(username, password, provider.getProviderId());
+        } else if (provider instanceof AliasTokenAuthenticationProvider) {
+            return new AliasTokenAuthenticationToken(username, password);
+        } else {
+            return new XnatDatabaseUsernamePasswordAuthenticationToken(username, password);
+        }
+    }
+
+    private XnatAuthenticationProvider findAuthenticationProviderByAuthMethod(final String authMethod) {
+        return findAuthenticationProvider(new XnatAuthenticationProviderMatcher() {
+            @Override
+            public boolean matches(XnatAuthenticationProvider provider) {
+                return provider.getAuthMethod().equalsIgnoreCase(authMethod);
+            }
+        });
+    }
+
+    private XnatAuthenticationProvider findAuthenticationProviderByProviderName(final String providerName) {
+        return findAuthenticationProvider(new XnatAuthenticationProviderMatcher() {
+            @Override
+            public boolean matches(XnatAuthenticationProvider provider) {
+                return provider.getName().equalsIgnoreCase(providerName);
+            }
+        });
+    }
+
+    private XnatAuthenticationProvider findAuthenticationProvider(XnatAuthenticationProviderMatcher matcher) {
+        List<AuthenticationProvider> prov = getProviders();
+        for (AuthenticationProvider ap : prov) {
+            XnatAuthenticationProvider xap = (XnatAuthenticationProvider) ap;
+            if (matcher.matches(xap)) {
+                return xap;
+            }
+        }
+        return null;
+    }
+
+    private void copyDetails(Authentication source, Authentication destination) {
+        if ((destination instanceof AbstractAuthenticationToken) && (destination.getDetails() == null)) {
+            AbstractAuthenticationToken token = (AbstractAuthenticationToken) destination;
+
+            token.setDetails(source.getDetails());
+        }
+    }
+
+    private static final class AuthenticationAttemptEventPublisher implements AuthenticationEventPublisher {
+
+        private final FailedAttemptsManager      failedAttemptsManager;
+        private final LastSuccessfulLoginManager lastSuccessfulLoginManager;
+
+        private AuthenticationAttemptEventPublisher(final XnatProviderManager manager) {
+            failedAttemptsManager = new FailedAttemptsManager(manager);
+            lastSuccessfulLoginManager = new LastSuccessfulLoginManager(manager);
+        }
+
+        public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
+            //increment failed login attempt
+            try {
+                failedAttemptsManager.addFailedLoginAttempt(authentication);
+            } catch (SiteConfigurationException e) {
+                _log.error("An error occurred accessing the site configuration", e);
+            }
+        }
+
+        public void publishAuthenticationSuccess(Authentication authentication) {
+            try {
+                failedAttemptsManager.clearCount(authentication);
+                lastSuccessfulLoginManager.updateLastSuccessfulLogin(authentication);
+            } catch (SiteConfigurationException e) {
+                _log.error("An error occurred accessing the site configuration", e);
+            }
+        }
+    }
+
+    private static final class LastSuccessfulLoginManager {
+        private final XnatProviderManager _manager;
+
+        public LastSuccessfulLoginManager(final XnatProviderManager manager) {
+            _manager = manager;
+        }
+
+        private void updateLastSuccessfulLogin(Authentication auth) {
+            XdatUserAuth ua = _manager.getUserByAuth(auth);
+            if (ua != null) {
+                Date now = java.util.Calendar.getInstance(TimeZone.getDefault()).getTime();
+                ua.setLastSuccessfulLogin(now);
+                ua.setLastLoginAttempt(now);
+                XDAT.getXdatUserAuthService().update(ua);
+            }
+        }
+    }
+
+    private static final class FailedAttemptsManager {
+        private final XnatProviderManager _manager;
+
+        public FailedAttemptsManager(final XnatProviderManager manager) {
+            _manager = manager;
+        }
+
+        /**
+         * Increments failed Login count
+         *
+         * @param auth The authentication that failed.
+         */
+        private synchronized void addFailedLoginAttempt(final Authentication auth) throws SiteConfigurationException {
+            XdatUserAuth ua = _manager.getUserByAuth(auth);
+            if (ua != null) {
+                if (_manager._preferences.getMaxFailedLogins() > 0) {
+                    ua.setFailedLoginAttempts(ua.getFailedLoginAttempts() + 1);
+                    ua.setLastLoginAttempt(new Date());
+                    XDAT.getXdatUserAuthService().update(ua);
+                }
+
+                if (StringUtils.isNotEmpty(ua.getXdatUsername())) {
+                    Integer uid = Users.getUserid(ua.getXdatUsername());
+                    if (uid != null) {
+                        try {
+                            if (ua.getFailedLoginAttempts().equals(_manager._preferences.getMaxFailedLogins())) {
+                                String expiration = TurbineUtils.getDateTimeFormatter().format(DateUtils.addMilliseconds(GregorianCalendar.getInstance().getTime(), (int) SiteConfigPreferences.convertPGIntervalToSeconds(_manager._preferences.getMaxFailedLoginsLockoutDuration())));
+                                _log.info("Locked out " + ua.getXdatUsername() + " user account until " + expiration);
+                                AdminUtils.sendAdminEmail(ua.getXdatUsername() + " account temporarily disabled.", "User " + ua.getXdatUsername() + " has been temporarily disabled due to excessive failed login attempts. The user's account will be automatically enabled at " + expiration + ".");
+                            }
+                        } catch (Exception e) {
+                            //ignore
+                        }
+                    }
+                }
+            }
+        }
+
+        public void clearCount(final Authentication auth) throws SiteConfigurationException {
+            if (_manager._preferences.getMaxFailedLogins() > 0) {
+                XdatUserAuth ua = _manager.getUserByAuth(auth);
+                if (ua != null) {
+                    ua.setFailedLoginAttempts(0);
+                    XDAT.getXdatUserAuthService().update(ua);
+                }
+            }
+        }
+    }
+
+    private interface XnatAuthenticationProviderMatcher {
+        boolean matches(XnatAuthenticationProvider provider);
+    }
+
+    private static final Log _log = LogFactory.getLog(XnatProviderManager.class);
+
+    private static Map<String, String> cached_methods = Maps.newConcurrentMap();//this will prevent 20,000 curl scripts from hitting the db everytime
+
+    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
+
+    @Inject
+    private DataSource _dataSource;
+
+    @Autowired
+    @Qualifier("rootContextService")
+    @Lazy
+    private ContextService _contextService;
+
+    @Autowired
+    @Lazy
+    private InitializerSiteConfiguration _preferences;
+
+    private XdatUserAuthService _userAuthService;
+
+    private final AuthenticationEventPublisher eventPublisher = new AuthenticationAttemptEventPublisher(this);
+}
diff --git a/src/main/java/org/nrg/xnat/security/alias/AliasTokenAuthenticationProvider.java b/src/main/java/org/nrg/xnat/security/alias/AliasTokenAuthenticationProvider.java
index 39672b61f57e608ea37b3198b06e87c7af0f9e5e..e8a9a051dfac89496088429d4da8aeab0f8a7550 100644
--- a/src/main/java/org/nrg/xnat/security/alias/AliasTokenAuthenticationProvider.java
+++ b/src/main/java/org/nrg/xnat/security/alias/AliasTokenAuthenticationProvider.java
@@ -33,6 +33,14 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
 
 public class AliasTokenAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider implements XnatAuthenticationProvider {
 
+    public AliasTokenAuthenticationProvider() {
+        this("token");
+    }
+
+    public AliasTokenAuthenticationProvider(final String name) {
+        _name = name;
+    }
+
     /**
      * Performs authentication with the same contract as {@link
      * org.springframework.security.authentication.AuthenticationManager#authenticate(org.springframework.security.core.Authentication)}.
@@ -94,10 +102,6 @@ public class AliasTokenAuthenticationProvider extends AbstractUserDetailsAuthent
         return StringUtils.isBlank(_name) ? getClass().toString() : _name;
     }
 
-    public void setName(final String name) {
-        _name = name;
-    }
-
     @Override
     public String getProviderId() {
         return _providerId;
@@ -202,6 +206,6 @@ public class AliasTokenAuthenticationProvider extends AbstractUserDetailsAuthent
 
     private XdatUserAuthService _userAuthService;
 
-    private String _name;
+    private final String _name;
     private String _providerId;
 }
diff --git a/src/main/java/org/nrg/xnat/security/config/AuthenticationProviderAggregator.java b/src/main/java/org/nrg/xnat/security/config/AuthenticationProviderAggregator.java
index abda2cd2e0878d5d94960bdecd5a4b6dae111b2a..6990368e825463d43f11210b3534c5b69b015cc4 100644
--- a/src/main/java/org/nrg/xnat/security/config/AuthenticationProviderAggregator.java
+++ b/src/main/java/org/nrg/xnat/security/config/AuthenticationProviderAggregator.java
@@ -4,80 +4,48 @@ import org.apache.commons.lang3.StringUtils;
 import org.nrg.framework.utilities.BasicXnatResourceLocator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.core.io.Resource;
 import org.springframework.core.io.support.PropertiesLoaderUtils;
 import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.core.io.Resource;
 
 import java.util.*;
 
 public class AuthenticationProviderAggregator extends ArrayList<AuthenticationProvider> {
 
-    public AuthenticationProviderAggregator(List<AuthenticationProvider> standaloneProviders, Map<String, AuthenticationProviderConfigurator> configurators, Properties properties) {
-        if (properties == null) {
-            throw new IllegalArgumentException("The list of authentication providers cannot be set to null.");
-        }
-
-//        String commaDelineatedProviders = properties.getProperty("provider.providers.enabled");
-//        assert !StringUtils.isBlank(commaDelineatedProviders) : "You must specify at least one authentication provider configuration.";
-//        ArrayList<String> providerArray=new ArrayList<String>(Arrays.asList(commaDelineatedProviders.split("[\\s,]+")));
-//        HashMap<String, HashMap<String, String>> providerMap = new HashMap<>();
-//        for(String prov : providerArray){
-//            providerMap.put(prov, new HashMap<String, String>());
-//        }
-
-        ArrayList<String> providerArray=new ArrayList<String>();
-        String dbName = "Database";
-        String dbId = "localdb";
-        String dbType = "db";
+    public AuthenticationProviderAggregator(List<AuthenticationProvider> standaloneProviders, Map<String, AuthenticationProviderConfigurator> configurators) {
+        ArrayList<String> providerArray = new ArrayList<>();
+        String            dbName        = "Database";
+        String            dbId          = "localdb";
+        String            dbType        = "db";
         providerArray.add(dbType);
         HashMap<String, HashMap<String, String>> providerMap = new HashMap<>();
         providerMap.put(dbType, new HashMap<String, String>());
-        providerMap.get(dbType).put("name",dbName);
-        providerMap.get(dbType).put("id",dbId);
-        providerMap.get(dbType).put("type",dbType);
+        providerMap.get(dbType).put("name", dbName);
+        providerMap.get(dbType).put("id", dbId);
+        providerMap.get(dbType).put("type", dbType);
 
         // Populate map of properties
         try {
-            String filnameEnd = "-provider.properties";
-            final List<Resource> resources = BasicXnatResourceLocator.getResources("classpath*:META-INF/xnat/auth/**/*" + filnameEnd);
+            String               filenameEnd = "-provider.properties";
+            final List<Resource> resources   = BasicXnatResourceLocator.getResources("classpath*:META-INF/xnat/auth/**/*" + filenameEnd);
             for (final Resource resource : resources) {
                 String filename = resource.getFilename();
-                String id = filename.substring(0, (filename.length() - filnameEnd.length()));
+                String id       = filename.substring(0, (filename.length() - filenameEnd.length()));
                 providerMap.put(id, new HashMap<String, String>());
                 providerArray.add(id);
                 final Properties provider = PropertiesLoaderUtils.loadProperties(resource);
                 for (Map.Entry<Object, Object> providerProperty : provider.entrySet()) {
                     providerMap.get(id).put(providerProperty.getKey().toString(), providerProperty.getValue().toString());
                 }
-
             }
-        }catch(Exception e){
-            _log.error("",e);
+        } catch (Exception e) {
+            _log.error("", e);
         }
-//
-//        for(Map.Entry<Object, Object> entry : properties.entrySet()) {
-//            String key = (String) entry.getKey();
-//            StringTokenizer st = new StringTokenizer(key, ".");
-//            String provider = st.nextToken();
-//            if (provider.equals("provider")) {
-//                String name = st.nextToken();
-//                if(providerMap.containsKey(name)) {
-//                    StringBuilder providerProperty = new StringBuilder();
-//                    while (st.hasMoreTokens()) {
-//                        if (providerProperty.length() > 0) {
-//                            providerProperty.append(".");
-//                        }
-//                        providerProperty.append(st.nextToken());
-//                    }
-//                    providerMap.get(name).put(providerProperty.toString(), (String) entry.getValue());
-//                }
-//            }
-//        }
 
         // Create providers
-        for(String prov: providerArray){
+        for (String prov : providerArray) {
             String name = providerMap.get(prov).get("name");
-            String id = providerMap.get(prov).get("id");
+            String id   = providerMap.get(prov).get("id");
             String type = providerMap.get(prov).get("type");
 
             assert !StringUtils.isBlank(name) : "You must provide a name for all authentication provider configurations";
diff --git a/src/main/java/org/nrg/xnat/security/config/DatabaseAuthenticationProviderConfigurator.java b/src/main/java/org/nrg/xnat/security/config/DatabaseAuthenticationProviderConfigurator.java
index 532d085649bb3fba094c28cf9ac72a7c779ae191..0857caa31dba50c47e834af3cc7d217a7c3ab4d1 100644
--- a/src/main/java/org/nrg/xnat/security/config/DatabaseAuthenticationProviderConfigurator.java
+++ b/src/main/java/org/nrg/xnat/security/config/DatabaseAuthenticationProviderConfigurator.java
@@ -24,6 +24,10 @@ import java.util.List;
 import java.util.Map;
 
 public class DatabaseAuthenticationProviderConfigurator extends AbstractAuthenticationProviderConfigurator {
+    public DatabaseAuthenticationProviderConfigurator() {
+        setConfiguratorId("db");
+    }
+
     @Override
     public List<AuthenticationProvider> getAuthenticationProviders(String id, String name) {
         List<AuthenticationProvider> providers = new ArrayList<>();
diff --git a/src/main/java/org/nrg/xnat/security/config/LdapAuthenticationProviderConfigurator.java b/src/main/java/org/nrg/xnat/security/config/LdapAuthenticationProviderConfigurator.java
index b0e535b1de65b3993de6782497ecf6687c5ab890..a23300a67337716d01073f5c1c0cc419cc5799ab 100644
--- a/src/main/java/org/nrg/xnat/security/config/LdapAuthenticationProviderConfigurator.java
+++ b/src/main/java/org/nrg/xnat/security/config/LdapAuthenticationProviderConfigurator.java
@@ -30,6 +30,10 @@ import java.util.List;
 import java.util.Map;
 
 public class LdapAuthenticationProviderConfigurator extends AbstractAuthenticationProviderConfigurator {
+    public LdapAuthenticationProviderConfigurator() {
+        setConfiguratorId("ldap");
+    }
+
     @Override
     public List<AuthenticationProvider> getAuthenticationProviders(String id, String name) {
         throw new NotImplementedException("You must provide LDAP properties in order to configure an LDAP connection.");
diff --git a/src/main/java/org/nrg/xnat/turbine/utils/ArcSpecManager.java b/src/main/java/org/nrg/xnat/turbine/utils/ArcSpecManager.java
index 17c17ad8b2c50559b95059beefd1d7256f1dfbd8..77aa42932f5e5539c8a07d2e791d2513b2cbcfe3 100644
--- a/src/main/java/org/nrg/xnat/turbine/utils/ArcSpecManager.java
+++ b/src/main/java/org/nrg/xnat/turbine/utils/ArcSpecManager.java
@@ -239,7 +239,8 @@ public class ArcSpecManager {
         arcSpec.setEnableNewRegistrations(preferences.getUserRegistration());
 
         arcSpec.setRequireLogin(preferences.getRequireLogin());
-        if (StringUtils.isNotBlank(preferences.getAdminEmail())) {
+
+        if (StringUtils.isNotBlank(preferences.getPipelinePath())) {
             arcSpec.setProperty("globalPaths/pipelinePath", preferences.getPipelinePath());
         }
 
diff --git a/src/main/resources/META-INF/xnat/security/configured-urls.yaml b/src/main/resources/META-INF/xnat/security/configured-urls.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b968bd4b3b05964b88e7aaa0a12b41bb34f49786
--- /dev/null
+++ b/src/main/resources/META-INF/xnat/security/configured-urls.yaml
@@ -0,0 +1,51 @@
+openUrls:
+  - /app/action/AcceptProjectAccess/par/*
+  - /app/action/ModifyPassword*
+  - /app/action/XDATForgotLogin*
+  - /app/action/XDATRegisterUser*
+  - /app/action/InactiveAccountEmail*
+  - /app/template/XDATScreen_UpdateUser.vm*
+  - /app/template/Error.vm*
+  - /app/template/ForgotLogin.vm*
+  - /app/template/Login.vm*
+  - /app/template/PostRegister.vm*
+  - /app/template/InactiveAccount.vm*
+  - /app/template/Register.vm*
+  - /app/template/ResendEmail.vm*
+  - /app/template/ResendVerification.vm*
+  - /app/template/VerificationSent.vm*
+  - /app/template/VerifyEmail.vm*
+  - /favicon.ico
+  - /data/JSESSION
+  - /REST/JSESSION
+  - /data/services/auth*
+  - /REST/services/auth*
+  - /data/services/sendemailverification*
+  - /REST/services/sendemailverification*
+  - /images/**
+  - /scripts/**
+  - /style/**
+  - /themes/**
+  - /files/**
+  - /pages/**
+  - /page/**
+  - /applet/**
+
+adminUrls:
+  - /app/template/AdminSummary.vm*
+  - /app/template/XDATScreen_EditScript.vm/user/Test*
+  - /app/template/XDATScreen_active_sessions.vm*
+  - /app/template/XDATScreen_admin.vm*
+  - /app/template/XDATScreen_admin_options.vm*
+  - /app/template/XDATScreen_admin_projectAccess.vm*
+  - /app/template/XDATScreen_bundles.vm*
+  - /app/template/XDATScreen_dataTypes.vm*
+  - /app/template/XDATScreen_email.vm*
+  - /app/template/XDATScreen_emailSpecifications.vm*
+  - /app/template/XDATScreen_groups.vm*
+  - /app/template/XDATScreen_manage_info.vm*
+  - /app/template/XDATScreen_manage_news.vm*
+  - /app/template/XDATScreen_manage_pipeline.vm*
+  - /app/template/XDATScreen_roles.vm*
+  - /monitoring*
+  - /setup/**