Skip to content
Snippets Groups Projects
Commit 8ff50507 authored by Nicholas Blair's avatar Nicholas Blair
Browse files

Merge branch 'flexible-identifiers' into 'master'

Add IdentifiersFactory for more configurable UDS UserDetailsService

Defaults to same behavior (treat argument to loadUserByUsername as a NetID username), but allows for easy override with PVI and others.

Use case: consider STAR. star-war supports impersonation via 'On-Behalf-Of' header. Inside the `SwitchUserOnHeaderFilter` is a reference to a `UserDetailsService`. The user attribute value of the 'On-Behalf-Of' header is passed into that `UserDetailsService#loadUserByUsername(String)` method.
Prior to this contribution, `UdsPersonUserDetailsServiceImpl` could ONLY accept a NetID username. 

This contribution defaults to that same behavior. However, if one wants to use a different user attribute, they would simply add a `@Bean` to their Spring ApplicationContext:

```java
@Bean
public IdentifiersFactory pviIdentifiersFactory() {
  return new IdentifiersFactory.PVI();
}
```

With the magic of `@Autowired(required=false)`, the default Netid configuration is replaced, and one can now pass PVIs into the `SwitchUserOnHeaderFilter`.

A few other interested parties: @paul.erickson @ahoffmann @bjsousa 

See merge request !6
parents 3a37fe51 046ce483
No related branches found
No related tags found
No related merge requests found
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;
}
}
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();
}
}
}
/**
*
*/
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 {
......
......@@ -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");
......
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());
}
}
......@@ -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}
......
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