Skip to content

Commit

Permalink
Shib: stub out migrate to builtin account #2915 #2939
Browse files Browse the repository at this point in the history
The basics are in place but code should be cleaned up more and
refactored. Started working a bit on user management. Added PROVIDER_ID
static field for Shib provider.
  • Loading branch information
pdurbin committed Feb 12, 2016
1 parent f37fdbd commit 7ea6a01
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 3 deletions.
121 changes: 121 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/api/Admin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
import edu.harvard.iq.dataverse.Dataverse;
import edu.harvard.iq.dataverse.actionlogging.ActionLogRecord;
import edu.harvard.iq.dataverse.api.dto.RoleDTO;
import edu.harvard.iq.dataverse.authorization.AuthenticatedUserLookup;
import edu.harvard.iq.dataverse.authorization.AuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.exceptions.AuthenticationProviderFactoryNotFoundException;
import edu.harvard.iq.dataverse.authorization.exceptions.AuthorizationSetupException;
import edu.harvard.iq.dataverse.authorization.providers.AuthenticationProviderFactory;
import edu.harvard.iq.dataverse.authorization.providers.AuthenticationProviderRow;
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUser;
import edu.harvard.iq.dataverse.authorization.providers.shib.ShibAuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.engine.command.impl.PublishDataverseCommand;
import edu.harvard.iq.dataverse.settings.Setting;
Expand All @@ -24,6 +28,7 @@

import static edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder.jsonObjectBuilder;
import static edu.harvard.iq.dataverse.util.json.JsonPrinter.*;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateless;
Expand Down Expand Up @@ -228,6 +233,122 @@ public Response publishDataverseAsCreator(@PathParam("id") long id) {
}
}

/**
* Experimental: Used for testing Shibboleth account conversions and the
* start of having any sort of user management.
*/
@GET
@Path("authenticatedUsers")
public Response listAuthenticatedUsersExperimental() {
try {
AuthenticatedUser user = findAuthenticatedUserOrDie();
if (!user.isSuperuser()) {
return errorResponse(Response.Status.FORBIDDEN, "Superusers only.");
}
} catch (WrappedResponse ex) {
return errorResponse(Response.Status.FORBIDDEN, "Superusers only.");
}
JsonArrayBuilder userArray = Json.createArrayBuilder();
authSvc.findAllAuthenticatedUsers().stream().forEach((user) -> {
userArray.add(user.getId() + ":" + user.getIdentifier() + ":" + user.getAuthenticatedUserLookup().getAuthenticationProviderId());
});
return okResponse(userArray);
}

/**
* @todo Document this in the guides once it has stabilized.
*
* @todo Refactor more of this business logic into ShibServiceBean in case
* we want to build a superuser GUI around this some day.
*
* curl -X PUT -d "shib@mailinator.com"
* http://localhost:8080/api/admin/authenticatedUsers/id/11/convertShibToBuiltIn
*/
@PUT
@Path("authenticatedUsers/id/{id}/convertShibToBuiltIn")
public Response convertShibUserToBuiltin(@PathParam("id") Long id, String newEmailAddress) {
try {
AuthenticatedUser user = findAuthenticatedUserOrDie();
if (!user.isSuperuser()) {
return errorResponse(Response.Status.FORBIDDEN, "Superusers only.");
}
} catch (WrappedResponse ex) {
return errorResponse(Response.Status.FORBIDDEN, "Superusers only.");
}
AuthenticatedUser userToConvert = authSvc.findByID(id);
if (userToConvert == null) {
return errorResponse(Response.Status.BAD_REQUEST, "User id " + id + " not found.");
}
AuthenticatedUserLookup lookup = userToConvert.getAuthenticatedUserLookup();
if (lookup == null) {
return errorResponse(Response.Status.BAD_REQUEST, "User id " + id + " does not have an 'authenticateduserlookup' row");
}
String providerId = lookup.getAuthenticationProviderId();
if (providerId == null) {
return errorResponse(Response.Status.BAD_REQUEST, "User id " + id + " provider id is null.");
}
String shibProviderId = ShibAuthenticationProvider.PROVIDER_ID;
if (!providerId.equals(shibProviderId)) {
return errorResponse(Response.Status.BAD_REQUEST, "User id " + id + " cannot be converted because current provider id is '" + providerId + "' rather than '" + shibProviderId + "'.");
}
BuiltinUser builtinUser = null;
try {
/**
* @todo Refactor more of the logic and error checking into this
* convertShibToBuiltIn method.
*/
builtinUser = authSvc.convertShibToBuiltIn(userToConvert, newEmailAddress);
} catch (Throwable ex) {
while (ex.getCause() != null) {
ex = ex.getCause();
}
if (ex instanceof ConstraintViolationException) {
ConstraintViolationException constraintViolationException = (ConstraintViolationException) ex;
StringBuilder userMsg = new StringBuilder();
StringBuilder logMsg = new StringBuilder();
logMsg.append("User id " + id + " cannot be converted from Shibboleth to BuiltIn. ");
for (ConstraintViolation<?> violation : constraintViolationException.getConstraintViolations()) {
logMsg.append(" Invalid value: <<<").append(violation.getInvalidValue()).append(">>> for ").append(violation.getPropertyPath()).append(" at ").append(violation.getLeafBean()).append(" - ").append(violation.getMessage());
userMsg.append(" Invalid value: <<<").append(violation.getInvalidValue()).append(">>> for ").append(violation.getPropertyPath()).append(" - ").append(violation.getMessage());
}
logger.warning(logMsg.toString());
return errorResponse(Response.Status.BAD_REQUEST, "User id " + id + " could not be converted from Shibboleth to BuiltIn: " + userMsg.toString());
} else {
return errorResponse(Response.Status.INTERNAL_SERVER_ERROR, "User id " + id + " cannot be converted due to unexpected exception: " + ex);
}
}
if (builtinUser == null) {
return errorResponse(Response.Status.BAD_REQUEST, "User id " + id + " could not be converted from Shibboleth to BuiltIn");
}
try {
/**
* @todo Should this logic be moved to the
* authSvc.convertShibToBuiltIn() method?
*/
lookup.setAuthenticationProviderId(BuiltinAuthenticationProvider.PROVIDER_ID);
lookup.setPersistentUserId(userToConvert.getUserIdentifier());
em.persist(lookup);
userToConvert.setEmail(newEmailAddress);
em.persist(userToConvert);
em.flush();
} catch (Throwable ex) {
while (ex.getCause() != null) {
ex = ex.getCause();
}
if (ex instanceof SQLException) {
String msg = "User id " + id + " only half converted from Shibboleth to BuiltIn and may not be able to log in. Manual changes may be necessary on 'authenticationproviderid' and 'authenticationproviderid' on 'authenticateduserlookup' table and 'email' on 'authenticateduser' table.";
logger.warning(msg);
return errorResponse(Response.Status.BAD_REQUEST, msg);
} else {
return errorResponse(Response.Status.INTERNAL_SERVER_ERROR, "User id " + id + " only half converted from Shibboleth to BuiltIn and may not be able to log in due to unexpected exception: " + ex.getClass().getName());
}
}
JsonObjectBuilder output = Json.createObjectBuilder();
output.add("email", builtinUser.getEmail());
output.add("username", builtinUser.getUserName());
return okResponse(output);
}

@DELETE
@Path("authenticatedUsers/id/{id}/")
public Response deleteAuthenticatedUserById(@PathParam("id") Long id) {
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/edu/harvard/iq/dataverse/api/TestApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ public String test( @PathParam("w1") String w1 ) {
@Path("user/convert/builtin2shib")
@PUT
public Response builtin2shib(String content) {
try {
AuthenticatedUser userToRunThisMethod = findAuthenticatedUserOrDie();
if (!userToRunThisMethod.isSuperuser()) {
return errorResponse(Response.Status.FORBIDDEN, "Superusers only.");
}
} catch (WrappedResponse ex) {
return errorResponse(Response.Status.FORBIDDEN, "Superusers only.");
}
boolean disabled = false;
if (disabled) {
return errorResponse(Response.Status.BAD_REQUEST, "API endpoint disabled.");
Expand Down Expand Up @@ -130,8 +138,7 @@ public Response builtin2shib(String content) {
return errorResponse(Response.Status.BAD_REQUEST, "No user to convert. We couldn't find a *single* existing user account based on " + emailToFind + " and no user was found using specified id " + longToLookup);
}
}
ShibAuthenticationProvider shibProvider = new ShibAuthenticationProvider();
String shibProviderId = shibProvider.getId();
String shibProviderId = ShibAuthenticationProvider.PROVIDER_ID;
Map<String, String> randomUser = shibService.getRandomUser();
// String eppn = UUID.randomUUID().toString().substring(0, 8);
String eppn = randomUser.get("eppn");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import edu.harvard.iq.dataverse.authorization.exceptions.AuthorizationSetupException;
import edu.harvard.iq.dataverse.authorization.providers.AuthenticationProviderFactory;
import edu.harvard.iq.dataverse.authorization.providers.AuthenticationProviderRow;
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProviderFactory;
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUser;
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean;
Expand All @@ -36,6 +37,10 @@
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

/**
* The AuthenticationManager is responsible for registering and listing
Expand Down Expand Up @@ -498,4 +503,32 @@ public AuthenticatedUser convertBuiltInToShib(AuthenticatedUser builtInUserToCon
return null;
}

/**
* @param authenticatedUser The AuthenticatedUser (Shibboleth user) to
* convert to a BuiltinUser.
* @param newEmailAddress The new email address that will be used instead of
* the user's old email address from the institution that they have left.
* @return BuiltinUser
* @throws java.lang.Exception You must catch a potential
* ConstraintViolationException due to Bean Validation (non-null, etc.) on
* the entities. Report these back to the superuser.
*/
public BuiltinUser convertShibToBuiltIn(AuthenticatedUser authenticatedUser, String newEmailAddress) throws Exception {
BuiltinUser builtinUser = new BuiltinUser();
builtinUser.setUserName(authenticatedUser.getUserIdentifier());
builtinUser.setFirstName(authenticatedUser.getFirstName());
builtinUser.setLastName(authenticatedUser.getLastName());
builtinUser.setEmail(newEmailAddress);
/**
* @todo If there are violations, don't even try to persist the user.
* Report the violations. Write tests around this.
*/
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<BuiltinUser>> violations = validator.validate(builtinUser);
logger.fine("constraint violation count: " + violations.size());
builtinUser = builtinUserServiceBean.save(builtinUser);
return builtinUser;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

public class ShibAuthenticationProvider implements AuthenticationProvider {

public static final String PROVIDER_ID = "shib";

@Override
public String getId() {
return "shib";
return PROVIDER_ID;
}

@Override
Expand Down
Loading

0 comments on commit 7ea6a01

Please sign in to comment.