diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/IdentifiersBuilder.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/IdentifiersBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..d015c2ab0f100d77cf52ebc2bb3b9553d294583a
--- /dev/null
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/IdentifiersBuilder.java
@@ -0,0 +1,122 @@
+package edu.wisc.uwss.uds;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import edu.wisc.services.uds.person.v1_1.Identifier;
+import edu.wisc.services.uds.person.v1_1.Identifiers;
+
+/**
+ * Builder pattern for constructing {@link IdentifiersBuilder}.
+ *
+ * This class is not thread safe and is intended for use as a prototype.
+ *
+ * Example usage:
+ * <pre>
+    new IdentifiersBuilder()
+      .withNetid("bbadger")
+      .withPvi("UW000A000)
+      .toIdentifiers();
+ * </pre>
+ *
+ * Will return:
+ *
+ * <pre>
+ <uds:Identifiers>
+ <uds:Identifier>
+ <uds:Source>UWMSNSUDS</uds:Source>
+ <uds:IdName>NETID</uds:IdName>
+ <uds:Value>bbadger</uds:Value>
+ </uds:Identifier>
+ <uds:Identifier>
+ <uds:Source>UWMSNSUDS</uds:Source>
+ <uds:IdName>PVI</uds:IdName>
+ <uds:Value>UW111Z000</uds:Value>
+ </uds:Identifier>
+ </uds:Identifiers>
+ * </pre>
+ *
+ * @author Nicholas Blair
+ */
+public class IdentifiersBuilder {
+  private final Identifiers identifiers = new Identifiers();
+  public static final String EMPLID = "EMPLID";
+  public static final String UWHRS = "UWHRS";
+  public static final String UWMSNSUDS = "UWMSNSUDS";
+  public static final String NETID = "NETID";
+  public static final String PHOTOID = "PHOTOID";
+  public static final String PVI = "PVI";
+  /**
+   *
+   * @return the accumulated {@link Identifiers}
+   */
+  public Identifiers toIdentifiers() {
+    return identifiers;
+  }
+  /**
+   * Add an {@link Identifier} for a NetID.
+   *
+   * @param value the NetID value
+   * @return this
+   */
+  public IdentifiersBuilder withNetid(String value) {
+    return with(NETID, UWMSNSUDS, value);
+  }
+  /**
+   * Add an {@link Identifier} for a PVI.
+   *
+   * @param value the PVI value
+   * @return this
+   */
+  public IdentifiersBuilder withPvi(String value) {
+    return with(PVI, UWMSNSUDS, value);
+  }
+  /**
+   * Add an {@link Identifier} for an HRS emplid.
+   * Note: the source on this Identifier is {@link #UWHRS}.
+   *
+   * @param value the emplid value
+   * @return this
+   */
+  public IdentifiersBuilder withHrsEmplid(String value) {
+    return with(EMPLID, UWHRS, value);
+  }
+  /**
+   * Add an {@link Identifier} for a Photoid.
+   *
+   * @param value the photoid value
+   * @return this
+   */
+  public IdentifiersBuilder withPhotoid(String value) {
+    return with(PHOTOID, UWMSNSUDS, value);
+  }
+
+  /**
+   * Add an {@link Identifier}.
+   *
+   * @param idName {@link Identifier#getIdName()}
+   * @param source {@link Identifier#getSource()}
+   * @param value {@link Identifier#getValue()}
+   * @return this
+   */
+  public IdentifiersBuilder with(String idName, String source, String value) {
+    identifiers.getIdentifiers().add(makeIdentifier(idName, source, value));
+    return this;
+  }
+  /**
+   * Utility method to construct a new {@link Identifier}
+   *
+   * @param idName {@link Identifier#getIdName()}
+   * @param source {@link Identifier#getSource()}
+   * @param value {@link Identifier#getValue()}
+   * @return a new {@link Identifier}
+   */
+  protected Identifier makeIdentifier(String idName, String source, String value) {
+    Identifier identifier = new Identifier();
+    identifier.setIdName(idName);
+    identifier.setSource(source);
+    identifier.setValue(value);
+    return identifier;
+  }
+
+}
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/IdentifiersFactory.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/IdentifiersFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..d09a0ccf24a9377c8b0f73cf981480fab175efb1
--- /dev/null
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/IdentifiersFactory.java
@@ -0,0 +1,46 @@
+package edu.wisc.uwss.uds;
+
+import edu.wisc.services.uds.person.v1_1.Identifiers;
+
+/**
+ * Factory interface for constructing {@link Identifiers} for use with {@link UdsPersonUserDetailsServiceImpl}.
+ *
+ * @author Nicholas Blair
+ */
+public interface IdentifiersFactory {
+
+  /**
+   *
+   * @param value
+   * @return an {@link Identifiers}
+   */
+  Identifiers withValue(String value);
+
+  /**
+   * {@link IdentifiersFactory} that returns "PVI" {@link Identifiers}.
+   */
+  public static class PVI implements IdentifiersFactory {
+    @Override
+    public Identifiers withValue(String value) {
+      return new IdentifiersBuilder().withPvi(value).toIdentifiers();
+    }
+  }
+  /**
+   * {@link IdentifiersFactory} that returns "NetID" {@link Identifiers}.
+   */
+  public static class NetID implements IdentifiersFactory {
+    @Override
+    public Identifiers withValue(String value) {
+      return new IdentifiersBuilder().withNetid(value).toIdentifiers();
+    }
+  }
+  /**
+   * {@link IdentifiersFactory} that returns PhotoID {@link Identifiers}.
+   */
+  public static class PhotoID implements IdentifiersFactory {
+    @Override
+    public Identifiers withValue(String value) {
+      return new IdentifiersBuilder().withPhotoid(value).toIdentifiers();
+    }
+  }
+}
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/UdsPersonUserDetailsImpl.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/UdsPersonUserDetailsImpl.java
similarity index 98%
rename from uw-spring-security-core/src/main/java/edu/wisc/uwss/UdsPersonUserDetailsImpl.java
rename to uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/UdsPersonUserDetailsImpl.java
index db52c8d1b1e0d6d7e79d221e45dc2d0611d6272c..2356f9f685670f1b22411e7ffc3a3d3f250c0d6a 100644
--- a/uw-spring-security-core/src/main/java/edu/wisc/uwss/UdsPersonUserDetailsImpl.java
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/UdsPersonUserDetailsImpl.java
@@ -1,7 +1,7 @@
 /**
  * 
  */
-package edu.wisc.uwss;
+package edu.wisc.uwss.uds;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -18,13 +18,12 @@ import edu.wisc.services.uds.person.v1_1.Employee;
 import edu.wisc.services.uds.person.v1_1.Identifier;
 import edu.wisc.services.uds.person.v1_1.Name;
 import edu.wisc.services.uds.person.v1_1.Person;
+import edu.wisc.uwss.UWUserDetails;
 
 /**
  * {@link UWUserDetails} backed by a {@link Person}.
  * Most fields are computed fields, transforming equivalents from {@link Person}.
  * 
- * TODO: this class should move to the edu.wisc.uwss.uds package.
- * 
  * @author ctcudd
  */
 public class UdsPersonUserDetailsImpl implements UWUserDetails {
diff --git a/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/UdsPersonUserDetailsServiceImpl.java b/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/UdsPersonUserDetailsServiceImpl.java
index ad7c6e71f761fec7577a070df0725c1f16feee5d..285c7ef64ac4844f3fabb1972a6843489113b648 100644
--- a/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/UdsPersonUserDetailsServiceImpl.java
+++ b/uw-spring-security-core/src/main/java/edu/wisc/uwss/uds/UdsPersonUserDetailsServiceImpl.java
@@ -12,24 +12,25 @@ import edu.wisc.services.uds.person.v1_1.Identifiers;
 import edu.wisc.services.uds.person.v1_1.Person;
 import edu.wisc.uds.UdsPersonService;
 import edu.wisc.uwss.UWUserDetails;
-import edu.wisc.uwss.UdsPersonUserDetailsImpl;
 
 /**
- * @author Collin Cudd
+ * Implementation of {@link UserDetailsService} backed by a {@link UdsPersonService} (required).
+ *
+ * An {@link IdentifiersFactory} can optionally be provided in order to control the "idName" and
+ * "source" used for the {@link Identifiers} passed to the {@link UdsPersonService}.
+ * The default {@link IdentifiersFactory} is to treat the value as a UW-Madison NetID.
  *
+ * @see IdentifiersFactory
+ * @author Collin Cudd
  */
 public class UdsPersonUserDetailsServiceImpl implements UserDetailsService{
   
   @Autowired UdsPersonService personService;
-  
+  @Autowired(required=false) IdentifiersFactory identifiersFactory = new IdentifiersFactory.NetID();
+
   @Override
   public UWUserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
-    Identifiers identifiers = new Identifiers();
-    Identifier identifier = new Identifier();
-    identifier.setIdName(UdsPersonUserDetailsImpl.NETID_IDNAME);
-    identifier.setSource(UdsPersonUserDetailsImpl.UWMSNSUDS_SOURCE);
-    identifier.setValue(username);
-    identifiers.getIdentifiers().add(identifier);
+    Identifiers identifiers = identifiersFactory.withValue(username);
     Person person = personService.getPerson(identifiers);
     if(person == null) {
       throw new UsernameNotFoundException("no person found for " + username + " via UDS Person");
diff --git a/uw-spring-security-core/src/test/java/edu/wisc/uwss/uds/IdentifiersBuilderTest.java b/uw-spring-security-core/src/test/java/edu/wisc/uwss/uds/IdentifiersBuilderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc4a782707a8a2b38ae1d7f8d407cccaaf2a0f3c
--- /dev/null
+++ b/uw-spring-security-core/src/test/java/edu/wisc/uwss/uds/IdentifiersBuilderTest.java
@@ -0,0 +1,89 @@
+package edu.wisc.uwss.uds;
+
+import org.junit.Test;
+
+import edu.wisc.services.uds.person.v1_1.Identifier;
+import edu.wisc.services.uds.person.v1_1.Identifiers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Unit tests for {@link IdentifiersBuilder}.
+ *
+ * Examples provided from uds-person-client-java:
+ *
+ <pre>
+ <uds:Identifier>
+ <uds:Source>UWHRS</uds:Source>
+ <uds:IdName>EMPLID</uds:IdName>
+ <uds:Value>00000123</uds:Value>
+ </uds:Identifier>
+ <uds:Identifier>
+ <uds:Source>UWMSNSUDS</uds:Source>
+ <uds:IdName>NETID</uds:IdName>
+ <uds:Value>bbadger</uds:Value>
+ </uds:Identifier>
+ <uds:Identifier>
+ <uds:Source>UWMSNSUDS</uds:Source>
+ <uds:IdName>PHOTOID</uds:IdName>
+ <uds:Value>90212345671</uds:Value>
+ </uds:Identifier>
+ <uds:Identifier>
+ <uds:Source>UWMSNSUDS</uds:Source>
+ <uds:IdName>PVI</uds:IdName>
+ <uds:Value>UW111Z000</uds:Value>
+ </uds:Identifier>
+ </pre>
+ *
+ * @author Nicholas Blair
+ */
+public class IdentifiersBuilderTest {
+
+  /**
+   * Confirm stable behavior when no identifiers added.
+   */
+  @Test
+  public void toIdentifiers_empty() {
+    assertEquals(new Identifiers(), new IdentifiersBuilder().toIdentifiers());
+  }
+  /**
+   * Confirm behavior of withNetid.
+   */
+  @Test
+  public void toIdentifiers_netid() {
+    Identifiers identifiers = new IdentifiersBuilder().withNetid("bbadger").toIdentifiers();
+    assertFalse(identifiers.getIdentifiers().isEmpty());
+    Identifier id = identifiers.getIdentifiers().get(0);
+    assertIdentifier(id, IdentifiersBuilder.NETID, IdentifiersBuilder.UWMSNSUDS, "bbadger");
+
+  }
+  /**
+   * Confirm behavior of withPvi.
+   */
+  @Test
+  public void toIdentifiers_pvi() {
+    Identifiers identifiers = new IdentifiersBuilder().withPvi("UW111Z000").toIdentifiers();
+    assertFalse(identifiers.getIdentifiers().isEmpty());
+    Identifier id = identifiers.getIdentifiers().get(0);
+    assertIdentifier(id, IdentifiersBuilder.PVI, IdentifiersBuilder.UWMSNSUDS, "UW111Z000");
+  }
+
+  /**
+   * Confirm we can add multiple identifiers.
+   */
+  @Test
+  public void toIdentifiers_both() {
+    Identifiers identifiers = new IdentifiersBuilder()
+            .withNetid("bbadger").withPvi("UW111Z000").toIdentifiers();
+    assertFalse(identifiers.getIdentifiers().isEmpty());
+    Identifier id = identifiers.getIdentifiers().get(0);
+    assertIdentifier(identifiers.getIdentifiers().get(0), IdentifiersBuilder.NETID, IdentifiersBuilder.UWMSNSUDS, "bbadger");
+    assertIdentifier(identifiers.getIdentifiers().get(1), IdentifiersBuilder.PVI, IdentifiersBuilder.UWMSNSUDS, "UW111Z000");
+  }
+  protected void assertIdentifier(Identifier id, String idName, String source, String value) {
+    assertEquals(idName, id.getIdName());
+    assertEquals(source, id.getSource());
+    assertEquals(value, id.getValue());
+  }
+}
diff --git a/uw-spring-security-core/src/test/java/edu/wisc/uwss/uds/UdsPersonUserDetailsImplTest.java b/uw-spring-security-core/src/test/java/edu/wisc/uwss/uds/UdsPersonUserDetailsImplTest.java
index 9a8645eb68be846bfeb85f094f28833ff724872c..56eda990296164740dab5bb39ddd66d52d179ee1 100644
--- a/uw-spring-security-core/src/test/java/edu/wisc/uwss/uds/UdsPersonUserDetailsImplTest.java
+++ b/uw-spring-security-core/src/test/java/edu/wisc/uwss/uds/UdsPersonUserDetailsImplTest.java
@@ -14,7 +14,6 @@ import edu.wisc.services.uds.person.v1_1.Identifier;
 import edu.wisc.services.uds.person.v1_1.Identifiers;
 import edu.wisc.services.uds.person.v1_1.Name;
 import edu.wisc.services.uds.person.v1_1.Person;
-import edu.wisc.uwss.UdsPersonUserDetailsImpl;
 
 /**
  * Tests for {@link UdsPersonUserDetailsImpl}