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
No related merge requests found
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