Skip to content
Snippets Groups Projects
Commit 3dd59973 authored by bhill6@wisc.edu's avatar bhill6@wisc.edu
Browse files

Removed deprecated property list format for local users, bumped version to 2.0

parent b6aa9a34
No related branches found
No related tags found
1 merge request!27Adding display name attribute, updated UDS libraries
Showing
with 125 additions and 261 deletions
......@@ -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>
......
......@@ -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>
......
......@@ -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;
}
}
......@@ -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.
*
......
......@@ -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>
......
/**
*
*/
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]);
}
}
}
}
......@@ -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;
}
/**
......
......@@ -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
*/
......
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
......@@ -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());
......
[
{
"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
---
- 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
......@@ -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>
......
......@@ -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>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment