From 3dd59973e87732ec0888688a1c499dea8a8a678a Mon Sep 17 00:00:00 2001
From: "bhill6@wisc.edu" <bhill6@wisc.edu>
Date: Mon, 6 Mar 2017 13:00:37 -0600
Subject: [PATCH] Removed deprecated property list format for local users,
 bumped version to 2.0

---
 pom.xml                                       |   2 +-
 uw-spring-security-config/pom.xml             |   2 +-
 ...alAuthenticationSecurityConfiguration.java |  21 +--
 .../local/LocalConfigurationTest.java         |   2 +
 uw-spring-security-core/pom.xml               |   2 +-
 .../LocalUserDetailsAttributesMapper.java     |  98 --------------
 .../local/LocalUserDetailsManagerImpl.java    |  38 +-----
 ...calUsersAuthenticationAttemptCallback.java |   2 +-
 .../wisc/uwss/local/local-users.properties    |   4 -
 .../LocalUserDetailsManagerImplTest.java      | 125 ++++--------------
 .../src/test/resources/test-users.json        |  24 ++++
 .../src/test/resources/test-users.yaml        |  62 +++++++++
 uw-spring-security-sample-war/pom.xml         |   2 +-
 uw-spring-security-web/pom.xml                |   2 +-
 14 files changed, 125 insertions(+), 261 deletions(-)
 delete mode 100644 uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsAttributesMapper.java
 delete mode 100644 uw-spring-security-core/src/main/resources/edu/wisc/uwss/local/local-users.properties
 create mode 100644 uw-spring-security-core/src/test/resources/test-users.json
 create mode 100644 uw-spring-security-core/src/test/resources/test-users.yaml

diff --git a/pom.xml b/pom.xml
index b6ffba4..9bca073 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>edu.wisc.uwss</groupId>
 	<artifactId>uw-spring-security</artifactId>
-	<version>1.8.0-SNAPSHOT</version>
+	<version>2.0.0-SNAPSHOT</version>
 	<packaging>pom</packaging>
 	<name>UW Spring Security Parent</name>
 	<description>Parent project for module to integrate Spring Security with UW authentication mechanism.</description>
diff --git a/uw-spring-security-config/pom.xml b/uw-spring-security-config/pom.xml
index 1a97f83..058dda0 100644
--- a/uw-spring-security-config/pom.xml
+++ b/uw-spring-security-config/pom.xml
@@ -3,7 +3,7 @@
 	<parent>
 		<groupId>edu.wisc.uwss</groupId>
 		<artifactId>uw-spring-security</artifactId>
-		<version>1.8.0-SNAPSHOT</version>
+		<version>2.0.0-SNAPSHOT</version>
 	</parent>
 	<artifactId>uw-spring-security-config</artifactId>
 	<name>UW Spring Security Configuration</name>
diff --git a/uw-spring-security-config/src/main/java/edu/wisc/uwss/configuration/local/LocalAuthenticationSecurityConfiguration.java b/uw-spring-security-config/src/main/java/edu/wisc/uwss/configuration/local/LocalAuthenticationSecurityConfiguration.java
index 0880a29..384f95f 100644
--- a/uw-spring-security-config/src/main/java/edu/wisc/uwss/configuration/local/LocalAuthenticationSecurityConfiguration.java
+++ b/uw-spring-security-config/src/main/java/edu/wisc/uwss/configuration/local/LocalAuthenticationSecurityConfiguration.java
@@ -55,24 +55,7 @@ public class LocalAuthenticationSecurityConfiguration extends GlobalMethodSecuri
   public UserDetailsManager localUserDetailsManager() {
     return new LocalUserDetailsManagerImpl();
   }
-  /**
-   * 
-   * @return a {@link Properties} instance containing all local user accounts.
-   */
-  @Bean @Qualifier("demo-users") @Value("${edu.wisc.uwss.local.userdetails.resource:classpath:/edu/wisc/uwss/local/local-users.properties}")
-  public Properties demoUserProperties(String resourcePath) {
-    logger.info("local-users loading demo users from {}", resourcePath);
-      Resource resource = this.resourceLoader.getResource(resourcePath);
-      PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
-      propertiesFactoryBean.setLocation(resource);
-      Properties properties = null;
-      try {
-          propertiesFactoryBean.afterPropertiesSet();
-          properties = propertiesFactoryBean.getObject();
-      } catch (IOException e) {
-          throw new IllegalStateException("unable to load demo users from resource path: "+resourcePath, e);
-      }
-      return properties;
-  }
+
+
 
 }
diff --git a/uw-spring-security-config/src/test/java/edu/wisc/uwss/configuration/local/LocalConfigurationTest.java b/uw-spring-security-config/src/test/java/edu/wisc/uwss/configuration/local/LocalConfigurationTest.java
index ee428ed..2530b48 100644
--- a/uw-spring-security-config/src/test/java/edu/wisc/uwss/configuration/local/LocalConfigurationTest.java
+++ b/uw-spring-security-config/src/test/java/edu/wisc/uwss/configuration/local/LocalConfigurationTest.java
@@ -15,6 +15,8 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
 
 import edu.wisc.uwss.local.LocalUserDetailsManagerImpl;
 
+import java.util.Properties;
+
 /**
  * A unit test that activates the {@link Configuration} classes in the "edu.wisc.uwss.configuration.local" package.
  * 
diff --git a/uw-spring-security-core/pom.xml b/uw-spring-security-core/pom.xml
index ab0c202..cb4b566 100644
--- a/uw-spring-security-core/pom.xml
+++ b/uw-spring-security-core/pom.xml
@@ -3,7 +3,7 @@
 	<parent>
 		<groupId>edu.wisc.uwss</groupId>
 		<artifactId>uw-spring-security</artifactId>
-		<version>1.8.0-SNAPSHOT</version>
+		<version>2.0.0-SNAPSHOT</version>
 	</parent>
 	<artifactId>uw-spring-security-core</artifactId>
 	<name>UW Spring Security Core</name>
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsAttributesMapper.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsAttributesMapper.java
deleted file mode 100644
index 8e85c68..0000000
--- a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsAttributesMapper.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * 
- */
-package edu.wisc.uwss.local;
-
-import edu.wisc.uwss.UWUserDetails;
-import edu.wisc.uwss.UWUserDetailsImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Interface providing a mechanism to bind a row from the local users properties
- * file to a {@link UWUserDetails} instance.
- *
- * This interface is used during application initialization - not during
- * authentication attempts. Since it is executed during Spring ApplicationContext initialization,
- * implementations should avoid injecting other service or dao interfaces, as it may be
- * affected by a race condition.
- *
- * If you have custom {@link UWUserDetails} that depend on services/daos to complete the model,
- * you may want to consider implementing a {@link LocalUsersAuthenticationAttemptCallback}; that interface
- * participates in the authentication attempt itself, not during application initialization.
- *
- * @deprecated use {@link LocalUserDetailsLoader} instead, to be removed in 2.0
- * @author Nicholas Blair
- */
-@Deprecated
-public interface LocalUserDetailsAttributesMapper {
-
-  /**
-   * Map a list of attributes to a {@link UWUserDetails}.
-   * 
-   * @param username the value to use from {@link UWUserDetails#getUsername()} 
-   * @param row the values from a row in the properties file, in order
-   * @return a {@link UWUserDetails} instance (never null)
-   * @throws IllegalArgumentException if the row is malformed
-   */
-  UWUserDetails mapUser(String username, String [] row);
-
-  /**
-   * Default {@link LocalUserDetailsAttributesMapper} implementation.
-   * 
-   * @author Nicholas Blair
-   */
-  public static class Default implements LocalUserDetailsAttributesMapper {
-
-    private static final Logger logger = LoggerFactory.getLogger(LocalUserDetailsAttributesMapper.class);
-
-    /**
-     * {@inheritDoc}
-     * 
-     * The format of the properties is as follows (key=value):
-     * <pre>
-     * username=password,fullName,firstName,lastName,emailAddress[,membership1,[membership2...]]
-     * </pre>
-     * 
-     * Membership can be 1 or more UDDS values, comma separated.
-     */
-    @Override
-    public UWUserDetails mapUser(String username, String[] values) {
-      if (values.length > 6) {
-        String[] uddsValues = Arrays.copyOfRange(values, 6, values.length);
-        List<String> membership = new ArrayList<>();
-        Collections.addAll(membership, uddsValues);
-        // pvi, username, password, email,
-        return new UWUserDetailsImpl(values[1], username, values[0], values[2], values[5], membership)
-                .setFirstName(values[3])
-                .setLastName(values[4]);
-      } else if (values.length == 6) {
-        // String pvi, String username, String password, String fullName, String emailAddress
-        return new UWUserDetailsImpl(values[1], username, values[0], values[2], values[5])
-                .setFirstName(values[3])
-                .setLastName(values[4]);
-      }
-      return mapUserDeprecatedFormat(username, values);
-
-    }
-
-    @Deprecated
-    UWUserDetails mapUserDeprecatedFormat(String username, String[] values) {
-      if (values.length == 5) {
-        logger.warn("Mapping deprecated in UWSS 1.2. Expected: username=password,fullName,firstName,lastName,emailAddress[,membership1,[membership2...]]");
-        List<String> membership = new ArrayList<>();
-        membership.add(values[4]);
-        return new UWUserDetailsImpl(values[1], username, values[0], values[2], values[3], membership);
-      } else {
-        //length must equal 4
-        logger.warn("Mapping deprecated in UWSS 1.2. Expected: username=password,fullName,firstName,lastName,emailAddress[,membership1,[membership2...]]");
-        return new UWUserDetailsImpl(values[1], username, values[0], values[2], values[3]);
-      }
-    }
-  }
-}
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsManagerImpl.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsManagerImpl.java
index 3e3683b..03d4c41 100644
--- a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsManagerImpl.java
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUserDetailsManagerImpl.java
@@ -46,26 +46,15 @@ public class LocalUserDetailsManagerImpl implements UserDetailsManager {
   @Autowired(required=false)
   private List<LocalUsersAuthenticationAttemptCallback> callbacks = new ArrayList<>();
   @Autowired(required=false)
-  private LocalUserDetailsAttributesMapper localUserDetailsAttributeMapper = new LocalUserDetailsAttributesMapper.Default();
-  @Autowired(required=false)
   private LocalUserDetailsLoader localUserDetailsLoader = new LocalUserDetailsLoader.Default();
   @Value("#{environment['edu.wisc.uwss.local.userDetailsLoader.resource'] ?: 'classpath:/edu/wisc/uwss/local/local-users.json' }")
   private Resource localUserResource;
-  @Value("#{environment['edu.wisc.uwss.local.userDetailsLoader.enabled'] ?: false }")
+  @Value("#{environment['edu.wisc.uwss.local.userDetailsLoader.enabled'] ?: true }")
   private boolean loaderEnabled;
 
   private Properties properties = new Properties();
 
-  /**
-   * Visible for testing.
-   *
-   * @param loaderEnabled whether or not to enable the {@link LocalUserDetailsLoader}
-   * @return a reference to this instance
-   */
-  LocalUserDetailsManagerImpl setLoaderEnabled(boolean loaderEnabled) {
-    this.loaderEnabled = loaderEnabled;
-    return this;
-  }
+
   /**
    * Visible for testing.
    *
@@ -91,33 +80,12 @@ public class LocalUserDetailsManagerImpl implements UserDetailsManager {
    */
   @PostConstruct
   public void init() {
-    if(loaderEnabled) {
       logger.debug("LocalUserDetailsLoader of type {} enabled, processing resource {}", localUserDetailsLoader.getClass(), localUserResource);
       List<UWUserDetails> users = localUserDetailsLoader.loadUsers(localUserResource);
       for(UWUserDetails u : users) {
         addDemoUser(u);
       }
-    } else {
-      logger.debug("LocalUserDetailsAttributesMapper of type {} enabled, processing properties file of size {}", localUserDetailsAttributeMapper.getClass(), properties.size());
-      for (Entry<Object, Object> entry : properties.entrySet()) {
-        String[] values = ((String) entry.getValue()).split(",");
-        String username = (String) entry.getKey();
-
-        final UWUserDetails user = localUserDetailsAttributeMapper.mapUser(username, values);
-        addDemoUser(user);
-      }
-    }
-  }
-  /**
-   * Populate the internal map of {@link UWUserDetailsImpl} via the entries in the
-   * injected {@link Properties}.
-   * 
-   * @see LocalUserDetailsAttributesMapper
-   * @param properties
-   */
-  @Autowired
-  public void setDemoUsers(@Qualifier("demo-users") Properties properties) {
-   this.properties = properties;
+
   }
 
   /**
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUsersAuthenticationAttemptCallback.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUsersAuthenticationAttemptCallback.java
index f862109..8ed1aa5 100644
--- a/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUsersAuthenticationAttemptCallback.java
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/local/LocalUsersAuthenticationAttemptCallback.java
@@ -24,7 +24,7 @@ import edu.wisc.uwss.UWUserDetails;
  * if you need a particular order of execution.
  *
  * If instead you need to modify {@link UWUserDetails} instances during application initialization only,
- * see {@link LocalUserDetailsAttributesMapper}.
+ * see {@link LocalUserDetailsLoader}.
  *
  * @author Nicholas Blair
  */
diff --git a/uw-spring-security-core/src/main/resources/edu/wisc/uwss/local/local-users.properties b/uw-spring-security-core/src/main/resources/edu/wisc/uwss/local/local-users.properties
deleted file mode 100644
index 8df9dbe..0000000
--- a/uw-spring-security-core/src/main/resources/edu/wisc/uwss/local/local-users.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-admin=admin,UW000A000,Amy Administrator,Amy,Administrator,amy.administrator@demo.wisc.edu,A535900
-jane=jane,UW000A001,Jane Doe,Jane,Doe,jane.doe@demo.wisc.edu,A535005
-john=john,UW000A002,John Doe,John,Doe,john.doe@demo.wisc.edu,A535005
-jim=jim,UW000A003,Jim Doe,Jim,Doe,jim.doe@demo.wisc.edu
\ No newline at end of file
diff --git a/uw-spring-security-core/src/test/java/edu/wisc/uwss/local/LocalUserDetailsManagerImplTest.java b/uw-spring-security-core/src/test/java/edu/wisc/uwss/local/LocalUserDetailsManagerImplTest.java
index 4a4c972..c7b07a4 100644
--- a/uw-spring-security-core/src/test/java/edu/wisc/uwss/local/LocalUserDetailsManagerImplTest.java
+++ b/uw-spring-security-core/src/test/java/edu/wisc/uwss/local/LocalUserDetailsManagerImplTest.java
@@ -65,11 +65,8 @@ public class LocalUserDetailsManagerImplTest {
    */
   @Test
   public void init_demoUsers_control() throws IOException {
-      Properties properties = new Properties();
-      properties.load(new ClassPathResource("edu/wisc/uwss/local/local-users.properties").getInputStream());
-      
       LocalUserDetailsManagerImpl service = new LocalUserDetailsManagerImpl();
-      service.setDemoUsers(properties);
+      service.setLocalUserResource(new ClassPathResource("test-users.yaml"));
       service.init();
       
       UWUserDetails userDetails = service.loadUserByUsername("admin");
@@ -80,92 +77,29 @@ public class LocalUserDetailsManagerImplTest {
       UWUserDetails jane = service.loadUserByUsername("jane");
       assertEquals("UW000A001", jane.getPvi());
       assertEquals("Jane Doe", jane.getFullName());
-     
+      assertEquals("Loretta Doe", jane.getDisplayName());
+
       UWUserDetails john = service.loadUserByUsername("john");
-      assertEquals("UW000A002", john.getPvi());
+      assertEquals("UW000A004", john.getPvi());
       assertEquals("John Doe", john.getFullName());
+      assertEquals("Jack Doe", john.getDisplayName());
 
       assertTrue(john.getUddsMembership().contains("A535005"));
   }
-  /**
-   * Confirm that {@link LocalUserDetailsManagerImpl} with {@link LocalUserDetailsManagerImpl#setLoaderEnabled(boolean)}
-   * of true results in equivalent {@link UWUserDetails} instances being loaded from JSON.
-   *
-   * Note: As of 1.5.x, this test passes, but potentially should not, as the {@link UWUserDetails}
-   * provided by the default {@link LocalUserDetailsAttributesMapper} do not have any
-   * {@link GrantedAuthority}, where the {@link UWUserDetails} provided by the
-   * {@link LocalUserDetailsLoader} do. See https://git.doit.wisc.edu/adi-ia/uw-spring-security/issues/5.
-   *
-   * @throws IOException
-   */
-  @Test
-  public void init_compare_default_loader_vs_attributesmapper() throws IOException {
-    Properties properties = new Properties();
-    properties.load(new ClassPathResource("edu/wisc/uwss/local/local-users.properties").getInputStream());
-
-    LocalUserDetailsManagerImpl withAttributesMapper = new LocalUserDetailsManagerImpl();
-    withAttributesMapper.setDemoUsers(properties);
-    withAttributesMapper.init();
-
-    LocalUserDetailsManagerImpl withLoader = new LocalUserDetailsManagerImpl()
-            .setLocalUserResource(new ClassPathResource("edu/wisc/uwss/local/local-users.json"))
-            .setLoaderEnabled(true);
-    withLoader.init();
-
-    assertEquals(withAttributesMapper.getUserCount(), withLoader.getUserCount());
-    assertEquals(withAttributesMapper.loadUserByUsername("admin"), withLoader.loadUserByUsername("admin"));
-    assertEquals(withAttributesMapper.loadUserByUsername("jane"), withLoader.loadUserByUsername("jane"));
-    assertEquals(withAttributesMapper.loadUserByUsername("john"), withLoader.loadUserByUsername("john"));
-    assertEquals(withAttributesMapper.loadUserByUsername("jim"), withLoader.loadUserByUsername("jim"));
-
-  }
-  /**
-   * Confirm that {@link LocalUserDetailsManagerImpl} with {@link LocalUserDetailsManagerImpl#setLoaderEnabled(boolean)}
-   * of true results in equivalent {@link UWUserDetails} instances being loaded from YAML.
-   *
-   * Note: As of 1.5.x, this test passes, but potentially should not, as the {@link UWUserDetails}
-   * provided by the default {@link LocalUserDetailsAttributesMapper} do not have any
-   * {@link GrantedAuthority}, where the {@link UWUserDetails} provided by the
-   * {@link LocalUserDetailsLoader} do. See https://git.doit.wisc.edu/adi-ia/uw-spring-security/issues/5.
-   *
-   * @throws IOException
-   */
-  @Test
-  public void init_compare_yaml_loader_vs_attributesmapper() throws IOException {
-    Properties properties = new Properties();
-    properties.load(new ClassPathResource("edu/wisc/uwss/local/local-users.properties").getInputStream());
-
-    LocalUserDetailsManagerImpl withAttributesMapper = new LocalUserDetailsManagerImpl();
-    withAttributesMapper.setDemoUsers(properties);
-    withAttributesMapper.init();
-
-    LocalUserDetailsManagerImpl withLoader = new LocalUserDetailsManagerImpl()
-            .setLocalUserResource(new ClassPathResource("edu/wisc/uwss/local/local-users.yaml"))
-            .setLoaderEnabled(true);
-    withLoader.init();
 
-    assertEquals(withAttributesMapper.getUserCount(), withLoader.getUserCount());
-    assertEquals(withAttributesMapper.loadUserByUsername("admin"), withLoader.loadUserByUsername("admin"));
-    assertEquals(withAttributesMapper.loadUserByUsername("jane"), withLoader.loadUserByUsername("jane"));
-    assertEquals(withAttributesMapper.loadUserByUsername("john"), withLoader.loadUserByUsername("john"));
-    assertEquals(withAttributesMapper.loadUserByUsername("jim"), withLoader.loadUserByUsername("jim"));
-  }
   /**
    * Set up a properties instance including a user with a single UDDS.
    * Verify that value properly set in {@link UWUserDetails#getUddsMembership()}.
    */
   @Test
   public void init_demoUsers_with_no_udds_and_no_control() {
-      Properties properties = new Properties();
-      properties.put("test", "test,UW000A000,Nothing,Nothing,,foo@foo.wisc.edu");
-      
       LocalUserDetailsManagerImpl service = new LocalUserDetailsManagerImpl();
-      service.setDemoUsers(properties);
+      service.setLocalUserResource(new ClassPathResource("test-users.yaml"));
       service.init();
       
-      UWUserDetails userDetails = service.loadUserByUsername("test");
+      UWUserDetails userDetails = service.loadUserByUsername("testnoudds");
       assertNotNull(userDetails);
-      assertEquals("UW000A000", userDetails.getPvi());
+      assertEquals("UW000A003", userDetails.getPvi());
       assertEquals("Nothing", userDetails.getFullName());
       assertTrue(userDetails.getUddsMembership().isEmpty());
   }
@@ -175,18 +109,15 @@ public class LocalUserDetailsManagerImplTest {
    */
   @Test
   public void init_demoUsers_with_single_udds() {
-      Properties properties = new Properties();
-      properties.put("test", "test,UW000A000,Single UDDS,Single,UDDS,foo@foo.wisc.edu,A061234");
-      
       LocalUserDetailsManagerImpl service = new LocalUserDetailsManagerImpl();
-      service.setDemoUsers(properties);
+      service.setLocalUserResource(new ClassPathResource("test-users.yaml"));
       service.init();
       
-      UWUserDetails userDetails = service.loadUserByUsername("test");
+      UWUserDetails userDetails = service.loadUserByUsername("testsingleudds");
       assertNotNull(userDetails);
-      assertEquals("UW000A000", userDetails.getPvi());
-      assertEquals("Single UDDS", ((UWUserDetails) userDetails).getFullName());
-      assertTrue(((UWUserDetails) userDetails).getUddsMembership().contains("A061234"));
+      assertEquals("UW000A002", userDetails.getPvi());
+      assertEquals("Single UDDS", userDetails.getFullName());
+      assertTrue(userDetails.getUddsMembership().contains("A535005"));
   }
   /**
    * Set up a properties instance including a user with multiple UDDS values.
@@ -194,19 +125,16 @@ public class LocalUserDetailsManagerImplTest {
    */
   @Test
   public void setDemoUsers_with_multiple_udds() {
-      Properties properties = new Properties();
-      properties.put("test", "test,UW000A000,Multiple UDDS,Multiple,UDDS,foo@foo.wisc.edu,A061234,A061235,A061236");
-      
       LocalUserDetailsManagerImpl service = new LocalUserDetailsManagerImpl();
-      service.setDemoUsers(properties);
+      service.setLocalUserResource(new ClassPathResource("test-users.yaml"));
       service.init();
       
-      UWUserDetails userDetails = service.loadUserByUsername("test");
+      UWUserDetails userDetails = service.loadUserByUsername("testmultiudds");
       assertNotNull(userDetails);
-      assertEquals("UW000A000", userDetails.getPvi());
+      assertEquals("UW000B003", userDetails.getPvi());
       assertEquals("Multiple UDDS", userDetails.getFullName());
-      assertTrue(userDetails.getUddsMembership().contains("A061234"));
-      assertTrue(userDetails.getUddsMembership().contains("A061235"));
+      assertTrue(userDetails.getUddsMembership().contains("A535005"));
+      assertTrue(userDetails.getUddsMembership().contains("A535900"));
       assertTrue(userDetails.getUddsMembership().contains("A061236"));
   }
   
@@ -368,13 +296,13 @@ public class LocalUserDetailsManagerImplTest {
 
   @Test
   public void unsupportedFormatWithUDDS() {
-    LocalUserDetailsAttributesMapper attributesMapper = new LocalUserDetailsAttributesMapper.Default();
+    LocalUserDetailsLoader attributesMapper = new LocalUserDetailsLoader.Default();
+    List<UWUserDetails> users = attributesMapper.loadUsers(new ClassPathResource("test-users.json"));
+
     //demo STAR user with UDDS:
-    String row = "aalpaca,UW123D455,Amy Alpaca,amy.alpaca@demo.wisc.edu,A064079";
-    String[] values = row.split(",");
     String username = "aalpaca";
 
-    UWUserDetails uwUserDetails = attributesMapper.mapUser(username, values);
+    UWUserDetails uwUserDetails = users.get(0);
     assertEquals(username, uwUserDetails.getUsername());
     assertEquals("aalpaca", uwUserDetails.getPassword());
     assertEquals("UW123D455", uwUserDetails.getPvi());
@@ -386,13 +314,12 @@ public class LocalUserDetailsManagerImplTest {
 
   @Test
   public void unsupportedFormatWithoutUDDS() {
-    LocalUserDetailsAttributesMapper attributesMapper = new LocalUserDetailsAttributesMapper.Default();
+    LocalUserDetailsLoader attributesMapper = new LocalUserDetailsLoader.Default();
+    List<UWUserDetails> users = attributesMapper.loadUsers(new ClassPathResource("test-users.json"));
     //demo STAR user without UDDS:
-    String row = "jim,UW000A003,Jim Doe,jim.doe@demo.wisc.edu";
-    String[] values = row.split(",");
-    String username = "aalpaca";
+    String username = "jim";
 
-    UWUserDetails uwUserDetails = attributesMapper.mapUser(username, values);
+    UWUserDetails uwUserDetails = users.get(1);
     assertEquals(username, uwUserDetails.getUsername());
     assertEquals("jim", uwUserDetails.getPassword());
     assertEquals("UW000A003", uwUserDetails.getPvi());
diff --git a/uw-spring-security-core/src/test/resources/test-users.json b/uw-spring-security-core/src/test/resources/test-users.json
new file mode 100644
index 0000000..e929927
--- /dev/null
+++ b/uw-spring-security-core/src/test/resources/test-users.json
@@ -0,0 +1,24 @@
+[
+  {
+    "username": "aalpaca",
+    "password": "aalpaca",
+    "fullName": "Amy Alpaca",
+    "firstName": "Amy",
+    "lastName": "Alpaca",
+    "emailAddress": "amy.alpaca@demo.wisc.edu",
+    "pvi": "UW123D455",
+    "uddsMembership": [ "A064079" ],
+    "authorities": []
+  },
+  {
+    "username": "jim",
+    "password": "jim",
+    "fullName": "Jim Doe",
+    "firstName": "Jim",
+    "lastName": "Doe",
+    "emailAddress": "jim.doe@demo.wisc.edu",
+    "pvi": "UW000A003",
+    "uddsMembership": [ ],
+    "authorities": []
+  }
+]
\ No newline at end of file
diff --git a/uw-spring-security-core/src/test/resources/test-users.yaml b/uw-spring-security-core/src/test/resources/test-users.yaml
new file mode 100644
index 0000000..df94f2e
--- /dev/null
+++ b/uw-spring-security-core/src/test/resources/test-users.yaml
@@ -0,0 +1,62 @@
+---
+- pvi: "UW000A000"
+  username: "admin"
+  password: "admin"
+  fullName: "Amy Administrator"
+  emailAddress: "amy.administrator@demo.wisc.edu"
+  uddsMembership:
+  - "A535900"
+  authorities:
+  - "edu.wisc.uwss.local.administrator"
+  firstName: "Amy"
+  lastName: "Administrator"
+- pvi: "UW000A001"
+  username: "jane"
+  password: "jane"
+  fullName: "Jane Doe"
+  displayName: "Loretta Doe"
+  emailAddress: "jane.doe@demo.wisc.edu"
+  uddsMembership:
+  - "A535005"
+  authorities: []
+  firstName: "John"
+  lastName: "Doe"
+- pvi: "UW000A004"
+  username: "john"
+  password: "john"
+  fullName: "John Doe"
+  displayName: "Jack Doe"
+  emailAddress: "john.doe@demo.wisc.edu"
+  uddsMembership:
+  - "A535005"
+  authorities: []
+  firstName: "John"
+  lastName: "Doe"
+- pvi: "UW000A002"
+  username: "testsingleudds"
+  password: "john"
+  fullName: "Single UDDS"
+  emailAddress: "john.doe@demo.wisc.edu"
+  uddsMembership:
+  - "A535005"
+  authorities: []
+  firstName: "John"
+  lastName: "Doe"
+- pvi: "UW000A003"
+  username: "testnoudds"
+  password: "jim123"
+  fullName: "Nothing"
+  emailAddress: "jim.doe@demo.wisc.edu"
+  uddsMembership: []
+  authorities: []
+  firstName: "Jim"
+  lastName: "Doe"
+- pvi: "UW000B003"
+  username: "testmultiudds"
+  password: "udds1"
+  fullName: "Multiple UDDS"
+  emailAddress: "multi.udds@demo.wisc.edu"
+  uddsMembership: ["A535005","A535900","A061236"]
+  authorities: []
+  firstName: "Test"
+  lastName: "Multi"
\ No newline at end of file
diff --git a/uw-spring-security-sample-war/pom.xml b/uw-spring-security-sample-war/pom.xml
index a2c3867..44a82e3 100644
--- a/uw-spring-security-sample-war/pom.xml
+++ b/uw-spring-security-sample-war/pom.xml
@@ -3,7 +3,7 @@
 	<parent>
 		<groupId>edu.wisc.uwss</groupId>
 		<artifactId>uw-spring-security</artifactId>
-		<version>1.8.0-SNAPSHOT</version>
+		<version>2.0.0-SNAPSHOT</version>
 	</parent>
 	<artifactId>uw-spring-security-sample-war</artifactId>
 	<name>UW Spring Security Sample War</name>
diff --git a/uw-spring-security-web/pom.xml b/uw-spring-security-web/pom.xml
index 1061bfa..4c6eedf 100644
--- a/uw-spring-security-web/pom.xml
+++ b/uw-spring-security-web/pom.xml
@@ -3,7 +3,7 @@
 	<parent>
 		<groupId>edu.wisc.uwss</groupId>
 		<artifactId>uw-spring-security</artifactId>
-		<version>1.8.0-SNAPSHOT</version>
+		<version>2.0.0-SNAPSHOT</version>
 	</parent>
 	<artifactId>uw-spring-security-web</artifactId>
 	<name>UW Spring Security Web</name>
-- 
GitLab