Skip to content

Commit

Permalink
added institution-wide Shibboleth groups #1401
Browse files Browse the repository at this point in the history
  • Loading branch information
pdurbin committed Jan 31, 2015
1 parent f29ec7b commit 4a4310b
Show file tree
Hide file tree
Showing 21 changed files with 551 additions and 65 deletions.
6 changes: 6 additions & 0 deletions scripts/api/data/ipGroup3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"alias":"ipGroup3",
"name":"IP group to match all IPv4 and IPv6 addresses",
"ranges" : [["0.0.0.0", "255.255.255.255"],
["::", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]]
}
5 changes: 5 additions & 0 deletions scripts/api/data/shibGroupHarvard.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "All Harvard PIN/Shibboleth Users",
"attribute": "Shib-Identity-Provider",
"pattern": "https://fed.huit.harvard.edu/idp/shibboleth"
}
5 changes: 5 additions & 0 deletions scripts/api/data/shibGroupTestShib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "All testshib.org Shibboleth Users",
"attribute": "Shib-Identity-Provider",
"pattern": "https://idp.testshib.org/idp/shibboleth"
}
4 changes: 4 additions & 0 deletions scripts/api/setup-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,9 @@ echo "Set the metadata block for Root"
curl -s -X POST -H "Content-type:application/json" -d "[\"citation\"]" $SERVER/dvs/:root/metadatablocks/?key=$adminKey
echo

echo "Setting up a sample Shibboleth institutional group"
curl -s -X POST -H 'Content-type:application/json' --upload-file data/shibGroupTestShib.json "$SERVER/groups/shib?key=$adminKey"
echo

# OPTIONAL USERS AND DATAVERSES
#./setup-optional.sh
7 changes: 7 additions & 0 deletions scripts/search/dbbuiltin2shib
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash -x
psql -c "select id,name,useridentifier from authenticateduser;" dataverse_db
psql -c "select * from authenticateduserlookup;" dataverse_db
psql -c "select id,encryptedpassword,firstname,lastname,username from builtinuser;" dataverse_db
psql -c "select * from roleassignment;" dataverse_db
psql -c "select datasetversionid,useridentifier from datasetversion_dataverseuser;" dataverse_db
psql -c "select * from explicitgroup;" dataverse_db
5 changes: 5 additions & 0 deletions scripts/search/dbshibgroups
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash -x
psql -c "select * from shibgroup;" dataverse_db
psql -c "select * from authenticateduser;" dataverse_db
psql -c "select * from persistedglobalgroup;" dataverse_db
psql -c "select * from roleassignment;" dataverse_db
5 changes: 5 additions & 0 deletions scripts/search/tests/grant-ipgroup3-add-on-root
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
. scripts/search/export-keys
OUTPUT=`curl -s -X POST -H "Content-type:application/json" -d "{\"assignee\": \"&ip/ipGroup3\",\"role\": \"dvContributor\"}" "http://localhost:8080/api/dvs/root/assignments?key=$ADMINKEY"`
echo $OUTPUT
echo $OUTPUT | jq ' .data | {assignee,_roleAlias}'
6 changes: 6 additions & 0 deletions scripts/search/tests/grant-shibgroup1-add-on-root
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
. scripts/search/export-keys
OUTPUT=`curl -s -X POST -H "Content-type:application/json" -d "{\"assignee\": \"&shib/1\",\"role\": \"dvContributor\"}" "http://localhost:8080/api/dvs/root/assignments?key=$ADMINKEY"`
echo $OUTPUT
echo $OUTPUT | jq .
#echo $OUTPUT | jq ' .data | {assignee,_roleAlias}'
5 changes: 5 additions & 0 deletions scripts/search/tests/ipgroup-add
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
. scripts/search/export-keys
OUTPUT=`curl -s -X POST -d @scripts/api/data/ipGroup3.json http://localhost:8080/api/groups/ip -H "Content-type:application/json"`
echo $OUTPUT
echo $OUTPUT | jq .
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
*/
package edu.harvard.iq.dataverse;

import edu.harvard.iq.dataverse.authorization.Permission;
import edu.harvard.iq.dataverse.authorization.groups.Group;
import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean;
import edu.harvard.iq.dataverse.authorization.users.User;
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
Expand All @@ -15,6 +19,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
Expand Down Expand Up @@ -43,6 +48,12 @@ public class DataverseHeaderFragment implements java.io.Serializable {
@EJB
SettingsServiceBean settingsService;

@EJB
GroupServiceBean groupService;

@EJB
PermissionServiceBean permissionService;

@Inject
DataverseSession dataverseSession;

Expand Down Expand Up @@ -214,4 +225,27 @@ public DvObject getDvObject() {
}

}

public boolean isDebugShibboleth() {
// curl -X PUT -d yes http://localhost:8080/api/s/settings/:ShibEnabled
boolean safeDefaultIfKeyNotFound = false;
return settingsService.isTrueForKey(SettingsServiceBean.Key.ShibEnabled, safeDefaultIfKeyNotFound);
}

public List<String> getGroups(User user) {
List<String> groups = new ArrayList<>();
Set<Group> groupsForUser = groupService.groupsFor(user);
for (Group group : groupsForUser) {
groups.add(group.getDisplayName() + " (" + group.getIdentifier() + ")");
}
return groups;
}

public List<String> getPermissions(User user, Dataverse dataverse) {
List<String> permissions = new ArrayList<>();
for (Permission permission : permissionService.permissionsForUser(user, dataverse)) {
permissions.add(permission.name());
}
return permissions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,12 @@ public List<RoleAssignmentRow> getRoleAssignments() {
for (RoleAssignment roleAssignment : ras) {
// for files, only show role assignments which can download
if (!(dvObject instanceof DataFile) || roleAssignment.getRole().permissions().contains(Permission.DownloadFile)) {
raList.add(new RoleAssignmentRow(roleAssignment,
roleAssigneeService.getRoleAssignee(roleAssignment.getAssigneeIdentifier()).getDisplayInfo()));
RoleAssignee roleAssignee = roleAssigneeService.getRoleAssignee(roleAssignment.getAssigneeIdentifier());
if (roleAssignee != null) {
raList.add(new RoleAssignmentRow(roleAssignment, roleAssignee.getDisplayInfo()));
} else {
logger.info("Could not find role assignee based on role assignment id " + roleAssignment.getId());
}
}
}
}
Expand Down
62 changes: 46 additions & 16 deletions src/main/java/edu/harvard/iq/dataverse/Shib.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.google.gson.JsonSyntaxException;
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
import edu.harvard.iq.dataverse.authorization.RoleAssigneeDisplayInfo;
import edu.harvard.iq.dataverse.authorization.groups.impl.shib.ShibGroupServiceBean;
import edu.harvard.iq.dataverse.authorization.providers.shib.ShibAuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import java.io.IOException;
Expand Down Expand Up @@ -43,6 +44,9 @@ public class Shib implements java.io.Serializable {
@EJB
AuthenticationServiceBean authSvc;

@EJB
ShibGroupServiceBean shibGroupService;

HttpServletRequest request;

/**
Expand Down Expand Up @@ -142,6 +146,12 @@ public class Shib implements java.io.Serializable {
*/
private String persistentUserIdSeparator = "|";

/**
* The Shibboleth Identity Provider (IdP), an "entityId" which often but not
* always looks like a URL.
*/
String shibIdp;

private boolean debug = false;

public void init() {
Expand All @@ -150,15 +160,18 @@ public void init() {

// set one of these to true in dev to avoid needing Shibboleth set up locally
boolean devRandom = false;
boolean devConstant = false;
boolean devConstantTestShib = false;
boolean devConstantHarvard = false;
if (devRandom) {
mutateRequestForDevRandom();
}
if (devConstant) {
mutateRequestForDevConstant();
if (devConstantTestShib) {
mutateRequestForDevConstantTestShib();
}
if (devConstantHarvard) {
mutateRequestForDevConstantHarvard();
}

String shibIdp;
try {
shibIdp = getRequiredValueFromAttribute(shibIdpAttribute);
} catch (Exception ex) {
Expand Down Expand Up @@ -201,7 +214,7 @@ public void init() {
logger.info("Found user based on " + userPersistentId + ". Logging in.");
logger.info("Updating display info for " + au.getName());
authSvc.updateAuthenticatedUser(au, displayInfo);
session.setUser(au);
logInUserAndSetShibAttributes(au);
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(homepage);
} catch (IOException ex) {
Expand All @@ -217,13 +230,22 @@ public void init() {
}

public String confirm() {
logger.info("confirm called...");
ShibAuthenticationProvider shibAuthProvider = new ShibAuthenticationProvider();
AuthenticatedUser au = authSvc.createAuthenticatedUser(shibAuthProvider.getId(), userPersistentId, displayInfo);
session.setUser(au);
if (au != null) {
logger.info("created user " + au.getIdentifier());
} else {
logger.info("couldn't create user " + userPersistentId);
}
logInUserAndSetShibAttributes(au);
return homepage + "?faces-redirect=true";
}

private void logInUserAndSetShibAttributes(AuthenticatedUser au) {
au.setShibIdentityProvider(shibIdp);
session.setUser(au);
}

public List<String> getShibValues() {
return shibValues;
}
Expand Down Expand Up @@ -323,8 +345,6 @@ private void mutateRequestForDevRandom() throws JsonSyntaxException, JsonIOExcep
// in dev we don't care if a new, random user is created each time
request.setAttribute(attr, UUID.randomUUID().toString().substring(0, 8));
}
// let's pretent TestShib is the IDP
request.setAttribute(shibIdpAttribute, "https://idp.testshib.org/idp/shibboleth");

String sURL = "http://api.randomuser.me";
URL url = null;
Expand Down Expand Up @@ -352,26 +372,36 @@ private void mutateRequestForDevRandom() throws JsonSyntaxException, JsonIOExcep
} catch (IOException ex) {
Logger.getLogger(Shib.class.getName()).log(Level.SEVERE, null, ex);
}
JsonObject foo = root.getAsJsonObject();
logger.info(foo.toString());
JsonElement results = foo.get("results");
logger.info(results.toString());
JsonObject rootObject = root.getAsJsonObject();
logger.fine(rootObject.toString());
JsonElement results = rootObject.get("results");
logger.fine(results.toString());
JsonElement firstResult = results.getAsJsonArray().get(0);
logger.info(firstResult.toString());
logger.fine(firstResult.toString());
JsonElement user = firstResult.getAsJsonObject().get("user");
JsonElement email = user.getAsJsonObject().get("email");
JsonElement password = user.getAsJsonObject().get("password");
JsonElement name = user.getAsJsonObject().get("name");
JsonElement firstName = name.getAsJsonObject().get("first");
JsonElement lastName = name.getAsJsonObject().get("last");
request.setAttribute(displayNameAttribute, StringUtils.capitalise(firstName.getAsString()) + " " + StringUtils.capitalise(lastName.getAsString()));
request.setAttribute(emailAttribute, email.getAsString());
// random IDP
request.setAttribute(shibIdpAttribute, "https://idp." + password.getAsString() + ".com/idp/shibboleth");
}

private void mutateRequestForDevConstant() {
private void mutateRequestForDevConstantTestShib() {
request.setAttribute(shibIdpAttribute, "https://idp.testshib.org/idp/shibboleth");
request.setAttribute(uniquePersistentIdentifier, "constant");
request.setAttribute(uniquePersistentIdentifier, "constantTestShib");
request.setAttribute(displayNameAttribute, "Sam El");
request.setAttribute(emailAttribute, "saml@mailinator.com");
}

private void mutateRequestForDevConstantHarvard() {
request.setAttribute(shibIdpAttribute, "https://fed.huit.harvard.edu/idp/shibboleth");
request.setAttribute(uniquePersistentIdentifier, "constantHarvard");
request.setAttribute(displayNameAttribute, "John Harvard");
request.setAttribute(emailAttribute, "jharvard@mailinator.com");
}

}
84 changes: 83 additions & 1 deletion src/main/java/edu/harvard/iq/dataverse/api/Groups.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import edu.harvard.iq.dataverse.authorization.groups.impl.ipaddress.IpGroup;
import edu.harvard.iq.dataverse.authorization.groups.impl.ipaddress.IpGroupProvider;
import edu.harvard.iq.dataverse.authorization.groups.impl.shib.ShibGroup;
import edu.harvard.iq.dataverse.authorization.groups.impl.shib.ShibGroupProvider;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.util.json.JsonParser;
import javax.ejb.Stateless;
import javax.ws.rs.GET;
Expand All @@ -14,9 +17,12 @@
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonString;
import javax.json.JsonValue;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
/**
*
* @author michael
Expand All @@ -27,10 +33,12 @@ public class Groups extends AbstractApiBean {
private static final Logger logger = Logger.getLogger(Groups.class.getName());

private IpGroupProvider ipGroupPrv;
private ShibGroupProvider shibGroupPrv;

@PostConstruct
void postConstruct() {
ipGroupPrv = groupSvc.getIpGroupProvider();
shibGroupPrv = groupSvc.getShibGroupProvider();
}

@POST
Expand Down Expand Up @@ -99,6 +107,80 @@ public Response deleteIpGroup( @PathParam("groupIdtf") String groupIdtf ) {
}
}


@GET
@Path("shib")
public Response listShibGroups() {
JsonArrayBuilder arrBld = Json.createArrayBuilder();
for (ShibGroup g : shibGroupPrv.findAll()) {
arrBld.add(json(g));
}
return okResponse(arrBld);
}

@POST
@Path("shib")
public Response createShibGroup(JsonObject shibGroupInput, @QueryParam("key") String apiKey) {
try {
findSuperUserKeyorDie(apiKey);
} catch (Exception ex) {
return errorResponse(Response.Status.BAD_REQUEST, "Problem with API token: " + ex.getMessage());
}
String expectedNameKey = "name";
JsonString name = shibGroupInput.getJsonString(expectedNameKey);
if (name == null) {
return errorResponse(Response.Status.BAD_REQUEST, "required field missing: " + expectedNameKey);
}
String expectedAttributeKey = "attribute";
JsonString attribute = shibGroupInput.getJsonString(expectedAttributeKey);
if (attribute == null) {
return errorResponse(Response.Status.BAD_REQUEST, "required field missing: " + expectedAttributeKey);
}
String expectedPatternKey = "pattern";
JsonString pattern = shibGroupInput.getJsonString(expectedPatternKey);
if (pattern == null) {
return errorResponse(Response.Status.BAD_REQUEST, "required field missing: " + expectedPatternKey);
}
ShibGroup shibGroupToPersist = new ShibGroup(name.getString(), attribute.getString(), pattern.getString());
ShibGroup persitedShibGroup = shibGroupPrv.persist(shibGroupToPersist);
if (persitedShibGroup != null) {
return okResponse("Shibboleth group persisted: " + persitedShibGroup);
} else {
return errorResponse(Response.Status.BAD_REQUEST, "Could not persist Shibboleth group");
}
}

@DELETE
@Path("shib/{primaryKey}")
public Response deleteShibGroup(@PathParam("primaryKey") String id, @QueryParam("key") String apiKey) {
try {
findSuperUserKeyorDie(apiKey);
} catch (Exception ex) {
return errorResponse(Response.Status.BAD_REQUEST, "Problem with API token: " + ex.getMessage());
}
ShibGroup doomed = shibGroupPrv.get(id);
if (doomed != null) {
boolean deleted = shibGroupPrv.delete(doomed);
if (deleted) {
return okResponse("Shibboleth group " + id + " deleted");
} else {
return errorResponse(Response.Status.BAD_REQUEST, "Could not delete Shibboleth group with a id of " + id);
}
} else {
return errorResponse(Response.Status.BAD_REQUEST, "Could not find Shibboleth group with a id of " + id);
}
}

private void findSuperUserKeyorDie(String apiKey) throws Exception {
AuthenticatedUser authenticatedUser = findUserByApiToken(apiKey);
if (authenticatedUser != null) {
if (authenticatedUser.isSuperuser()) {
return;
} else {
throw new Exception("User " + authenticatedUser.getIdentifier() + " has insufficient permission.");
}
} else {
throw new Exception("Could not find user from API token.");
}
}

}
Loading

0 comments on commit 4a4310b

Please sign in to comment.