From 2f46105958dce60b6495beb23e4ef143c30f32d5 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Mon, 21 Nov 2016 16:31:21 -0500 Subject: [PATCH] add API endpoint to convert OAuth users to local #3338 --- .../edu/harvard/iq/dataverse/api/Admin.java | 186 +++++++++++++++++- .../AuthenticationServiceBean.java | 68 ++++++- .../providers/shib/ShibServiceBean.java | 5 +- .../edu/harvard/iq/dataverse/api/AdminIT.java | 118 ++++++++++- .../edu/harvard/iq/dataverse/api/UtilIT.java | 16 ++ 5 files changed, 383 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 85afa0b6003..c71b7bfcae5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -284,9 +284,14 @@ public Response listAuthenticatedUsers() { /** * curl -X PUT -d "shib@mailinator.com" * http://localhost:8080/api/admin/authenticatedUsers/id/11/convertShibToBuiltIn + * + * @deprecated We have documented this API endpoint so we'll keep in around + * for a while but we should encourage everyone to switch to the + * "convertRemoteToBuiltIn" endpoint and then remove this Shib-specfic one. */ @PUT @Path("authenticatedUsers/id/{id}/convertShibToBuiltIn") + @Deprecated public Response convertShibUserToBuiltin(@PathParam("id") Long id, String newEmailAddress) { try { AuthenticatedUser user = findAuthenticatedUserOrDie(); @@ -297,7 +302,7 @@ public Response convertShibUserToBuiltin(@PathParam("id") Long id, String newEma return error(Response.Status.FORBIDDEN, "Superusers only."); } try { - BuiltinUser builtinUser = authSvc.convertShibToBuiltIn(id, newEmailAddress); + BuiltinUser builtinUser = authSvc.convertRemoteToBuiltIn(id, newEmailAddress); if (builtinUser == null) { return error(Response.Status.BAD_REQUEST, "User id " + id + " could not be converted from Shibboleth to BuiltIn. An Exception was not thrown."); } @@ -318,6 +323,39 @@ public Response convertShibUserToBuiltin(@PathParam("id") Long id, String newEma } } + @PUT + @Path("authenticatedUsers/id/{id}/convertRemoteToBuiltIn") + public Response convertOAuthUserToBuiltin(@PathParam("id") Long id, String newEmailAddress) { + try { + AuthenticatedUser user = findAuthenticatedUserOrDie(); + if (!user.isSuperuser()) { + return error(Response.Status.FORBIDDEN, "Superusers only."); + } + } catch (WrappedResponse ex) { + return error(Response.Status.FORBIDDEN, "Superusers only."); + } + try { + BuiltinUser builtinUser = authSvc.convertRemoteToBuiltIn(id, newEmailAddress); + if (builtinUser == null) { + return error(Response.Status.BAD_REQUEST, "User id " + id + " could not be converted from remote to BuiltIn. An Exception was not thrown."); + } + JsonObjectBuilder output = Json.createObjectBuilder(); + output.add("email", builtinUser.getEmail()); + output.add("username", builtinUser.getUserName()); + return ok(output); + } catch (Throwable ex) { + StringBuilder sb = new StringBuilder(); + sb.append(ex + " "); + while (ex.getCause() != null) { + ex = ex.getCause(); + sb.append(ex + " "); + } + String msg = "User id " + id + " could not be converted from remote to BuiltIn. Details from Exception: " + sb; + logger.info(msg); + return error(Response.Status.BAD_REQUEST, msg); + } + } + /** * This is used in testing via AdminIT.java but we don't expect sysadmins to * use this. @@ -457,6 +495,152 @@ public Response builtin2shib(String content) { return ok(response); } + /** + * This is used in testing via AdminIT.java but we don't expect sysadmins to + * use this. + */ + @Path("authenticatedUsers/convert/builtin2oauth") + @PUT + public Response builtin2oauth(String content) { + logger.info("entering builtin2oauth..."); + try { + AuthenticatedUser userToRunThisMethod = findAuthenticatedUserOrDie(); + if (!userToRunThisMethod.isSuperuser()) { + return error(Response.Status.FORBIDDEN, "Superusers only."); + } + } catch (WrappedResponse ex) { + return error(Response.Status.FORBIDDEN, "Superusers only."); + } + boolean disabled = false; + if (disabled) { + return error(Response.Status.BAD_REQUEST, "API endpoint disabled."); + } + AuthenticatedUser builtInUserToConvert = null; + String emailToFind; + String password; + String authuserId = "0"; // could let people specify id on authuser table. probably better to let them tell us their + String newEmailAddressToUse; + String newProviderId; + String newPersistentUserIdInLookupTable; + logger.info("content: " + content); + try { + String[] args = content.split(":"); + emailToFind = args[0]; + password = args[1]; + newEmailAddressToUse = args[2]; + newProviderId = args[3]; + newPersistentUserIdInLookupTable = args[4]; +// authuserId = args[666]; + } catch (ArrayIndexOutOfBoundsException ex) { + return error(Response.Status.BAD_REQUEST, "Problem with content <<<" + content + ">>>: " + ex.toString()); + } + AuthenticatedUser existingAuthUserFoundByEmail = shibService.findAuthUserByEmail(emailToFind); + String existing = "NOT FOUND"; + if (existingAuthUserFoundByEmail != null) { + builtInUserToConvert = existingAuthUserFoundByEmail; + existing = existingAuthUserFoundByEmail.getIdentifier(); + } else { + long longToLookup = Long.parseLong(authuserId); + AuthenticatedUser specifiedUserToConvert = authSvc.findByID(longToLookup); + if (specifiedUserToConvert != null) { + builtInUserToConvert = specifiedUserToConvert; + } else { + return error(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); + } + } +// String shibProviderId = ShibAuthenticationProvider.PROVIDER_ID; + Map randomUser = shibService.getRandomUser(); +// String eppn = UUID.randomUUID().toString().substring(0, 8); + String eppn = randomUser.get("eppn"); + String idPEntityId = randomUser.get("idp"); + String notUsed = null; + String separator = "|"; +// UserIdentifier newUserIdentifierInLookupTable = new UserIdentifier(idPEntityId + separator + eppn, notUsed); + UserIdentifier newUserIdentifierInLookupTable = new UserIdentifier(newPersistentUserIdInLookupTable, notUsed); + String overwriteFirstName = randomUser.get("firstName"); + String overwriteLastName = randomUser.get("lastName"); + String overwriteEmail = randomUser.get("email"); + overwriteEmail = newEmailAddressToUse; + logger.info("overwriteEmail: " + overwriteEmail); + boolean validEmail = EMailValidator.isEmailValid(overwriteEmail, null); + if (!validEmail) { + // See https://github.com/IQSS/dataverse/issues/2998 + return error(Response.Status.BAD_REQUEST, "invalid email: " + overwriteEmail); + } + /** + * @todo If affiliation is not null, put it in RoleAssigneeDisplayInfo + * constructor. + */ + /** + * Here we are exercising (via an API test) shibService.getAffiliation + * with the TestShib IdP and a non-production DevShibAccountType. + */ +// idPEntityId = ShibUtil.testShibIdpEntityId; +// String overwriteAffiliation = shibService.getAffiliation(idPEntityId, ShibServiceBean.DevShibAccountType.RANDOM); + String overwriteAffiliation = null; + logger.info("overwriteAffiliation: " + overwriteAffiliation); + /** + * @todo Find a place to put "position" in the authenticateduser table: + * https://github.com/IQSS/dataverse/issues/1444#issuecomment-74134694 + */ + String overwritePosition = "staff;student"; + AuthenticatedUserDisplayInfo displayInfo = new AuthenticatedUserDisplayInfo(overwriteFirstName, overwriteLastName, overwriteEmail, overwriteAffiliation, overwritePosition); + JsonObjectBuilder response = Json.createObjectBuilder(); + JsonArrayBuilder problems = Json.createArrayBuilder(); + if (password != null) { + response.add("password supplied", password); + boolean knowsExistingPassword = false; + BuiltinUser oldBuiltInUser = builtinUserService.findByUserName(builtInUserToConvert.getUserIdentifier()); + if (oldBuiltInUser != null) { + String usernameOfBuiltinAccountToConvert = oldBuiltInUser.getUserName(); + response.add("old username", usernameOfBuiltinAccountToConvert); + AuthenticatedUser authenticatedUser = shibService.canLogInAsBuiltinUser(usernameOfBuiltinAccountToConvert, password); + if (authenticatedUser != null) { + knowsExistingPassword = true; + AuthenticatedUser convertedUser = authSvc.convertBuiltInUserToRemoteUser(builtInUserToConvert, newProviderId, newUserIdentifierInLookupTable); + if (convertedUser != null) { + /** + * @todo Display name is not being overwritten. Logic + * must be in Shib backing bean + */ + AuthenticatedUser updatedInfoUser = authSvc.updateAuthenticatedUser(convertedUser, displayInfo); + if (updatedInfoUser != null) { + response.add("display name overwritten with", updatedInfoUser.getName()); + } else { + problems.add("couldn't update display info"); + } + } else { + problems.add("unable to convert user"); + } + } + } else { + problems.add("couldn't find old username"); + } + if (!knowsExistingPassword) { + String message = "User doesn't know password."; + problems.add(message); + /** + * @todo Someday we should make a errorResponse method that + * takes JSON arrays and objects. + */ + return error(Status.BAD_REQUEST, problems.build().toString()); + } +// response.add("knows existing password", knowsExistingPassword); + } + + response.add("user to convert", builtInUserToConvert.getIdentifier()); + response.add("existing user found by email (prompt to convert)", existing); + response.add("changing to this provider", newProviderId); + response.add("value to overwrite old first name", overwriteFirstName); + response.add("value to overwrite old last name", overwriteLastName); + response.add("value to overwrite old email address", overwriteEmail); + if (overwriteAffiliation != null) { + response.add("affiliation", overwriteAffiliation); + } + response.add("problems", problems); + return ok(response); + } + @DELETE @Path("authenticatedUsers/id/{id}/") public Response deleteAuthenticatedUserById(@PathParam("id") Long id) { diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java index 779c756b5c7..9319966a8fc 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java @@ -586,6 +586,11 @@ public Timestamp getCurrentTimestamp() { // TODO should probably be moved to the Shib provider - this is a classic Shib-specific // use case. This class should deal with general autnetications. + @Deprecated + /** + * @deprecated. Switch to convertBuiltInUserToRemoteUser instead. + * @todo. Switch to convertBuiltInUserToRemoteUser instead. + */ public AuthenticatedUser convertBuiltInToShib(AuthenticatedUser builtInUserToConvert, String shibProviderId, UserIdentifier newUserIdentifierInLookupTable) { logger.info("converting user " + builtInUserToConvert.getId() + " from builtin to shib"); String builtInUserIdentifier = builtInUserToConvert.getIdentifier(); @@ -635,6 +640,55 @@ public AuthenticatedUser convertBuiltInToShib(AuthenticatedUser builtInUserToCon return null; } + public AuthenticatedUser convertBuiltInUserToRemoteUser(AuthenticatedUser builtInUserToConvert, String newProviderId, UserIdentifier newUserIdentifierInLookupTable) { + logger.info("converting user " + builtInUserToConvert.getId() + " from builtin to remote"); + String builtInUserIdentifier = builtInUserToConvert.getIdentifier(); + logger.info("builtin user identifier: " + builtInUserIdentifier); + TypedQuery typedQuery = em.createQuery("SELECT OBJECT(o) FROM AuthenticatedUserLookup AS o WHERE o.authenticatedUser = :auid", AuthenticatedUserLookup.class); + typedQuery.setParameter("auid", builtInUserToConvert); + AuthenticatedUserLookup authuserLookup; + try { + authuserLookup = typedQuery.getSingleResult(); + } catch (NoResultException | NonUniqueResultException ex) { + logger.info("exception caught: " + ex); + return null; + } + if (authuserLookup == null) { + return null; + } + + String oldProviderId = authuserLookup.getAuthenticationProviderId(); + logger.info("we expect this to be 'builtin': " + oldProviderId); + authuserLookup.setAuthenticationProviderId(newProviderId); + String oldUserLookupIdentifier = authuserLookup.getPersistentUserId(); + logger.info("this should be 'pete' or whatever the old builtin username was: " + oldUserLookupIdentifier); + String perUserShibIdentifier = newUserIdentifierInLookupTable.getLookupStringPerAuthProvider(); + authuserLookup.setPersistentUserId(perUserShibIdentifier); + /** + * @todo this should be a transaction of some kind. We want to update + * the authenticateduserlookup and also delete the row from the + * builtinuser table in a single transaction. + */ + em.persist(authuserLookup); + String builtinUsername = builtInUserIdentifier.replaceFirst(AuthenticatedUser.IDENTIFIER_PREFIX, ""); + BuiltinUser builtin = builtinUserServiceBean.findByUserName(builtinUsername); + if (builtin != null) { + // These were created by AuthenticationResponse.Status.BREAKOUT in ShibServiceBean.canLogInAsBuiltinUser + List oldTokens = passwordResetServiceBean.findPasswordResetDataByDataverseUser(builtin); + for (PasswordResetData oldToken : oldTokens) { + em.remove(oldToken); + } + em.remove(builtin); + } else { + logger.info("Couldn't delete builtin user because could find it based on username " + builtinUsername); + } + AuthenticatedUser nonBuiltinUser = lookupUser(newProviderId, perUserShibIdentifier); + if (nonBuiltinUser != null) { + return nonBuiltinUser; + } + return null; + } + /** * @param idOfAuthUserToConvert The id of the AuthenticatedUser (Shibboleth * user) to convert to a BuiltinUser. @@ -644,14 +698,14 @@ public AuthenticatedUser convertBuiltInToShib(AuthenticatedUser builtInUserToCon * @throws java.lang.Exception You must catch and report back to the user (a * superuser) any Exceptions. */ - public BuiltinUser convertShibToBuiltIn(Long idOfAuthUserToConvert, String newEmailAddress) throws Exception { + public BuiltinUser convertRemoteToBuiltIn(Long idOfAuthUserToConvert, String newEmailAddress) throws Exception { AuthenticatedUser authenticatedUser = findByID(idOfAuthUserToConvert); if (authenticatedUser == null) { throw new Exception("User id " + idOfAuthUserToConvert + " not found."); } AuthenticatedUser existingUserWithSameEmail = getAuthenticatedUserByEmail(newEmailAddress); if (existingUserWithSameEmail != null) { - throw new Exception("User id " + idOfAuthUserToConvert + " (" + authenticatedUser.getIdentifier() + ") cannot be converted from Shibboleth to BuiltIn because the email address " + newEmailAddress + " is already in use by user id " + existingUserWithSameEmail.getId() + " (" + existingUserWithSameEmail.getIdentifier() + ")."); + throw new Exception("User id " + idOfAuthUserToConvert + " (" + authenticatedUser.getIdentifier() + ") cannot be converted from remote to BuiltIn because the email address " + newEmailAddress + " is already in use by user id " + existingUserWithSameEmail.getId() + " (" + existingUserWithSameEmail.getIdentifier() + ")."); } BuiltinUser builtinUser = new BuiltinUser(); builtinUser.setUserName(authenticatedUser.getUserIdentifier()); @@ -668,12 +722,12 @@ public BuiltinUser convertShibToBuiltIn(Long idOfAuthUserToConvert, String newEm for (ConstraintViolation violation : violations) { logMsg.append(" Invalid value: <<<").append(violation.getInvalidValue()).append(">>> for ").append(violation.getPropertyPath()).append(" at ").append(violation.getLeafBean()).append(" - ").append(violation.getMessage()); } - throw new Exception("User id " + idOfAuthUserToConvert + " cannot be converted from Shibboleth to BuiltIn because of constraint violations on the BuiltIn user that would be created: " + numViolations + ". Details: " + logMsg); + throw new Exception("User id " + idOfAuthUserToConvert + " cannot be converted from remote to BuiltIn because of constraint violations on the BuiltIn user that would be created: " + numViolations + ". Details: " + logMsg); } try { builtinUser = builtinUserServiceBean.save(builtinUser); } catch (IllegalArgumentException ex) { - throw new Exception("User id " + idOfAuthUserToConvert + " cannot be converted from Shibboleth to BuiltIn because of an IllegalArgumentException creating the row in the builtinuser table: " + ex); + throw new Exception("User id " + idOfAuthUserToConvert + " cannot be converted from remote to BuiltIn because of an IllegalArgumentException creating the row in the builtinuser table: " + ex); } AuthenticatedUserLookup lookup = authenticatedUser.getAuthenticatedUserLookup(); if (lookup == null) { @@ -683,9 +737,9 @@ public BuiltinUser convertShibToBuiltIn(Long idOfAuthUserToConvert, String newEm if (providerId == null) { throw new Exception("User id " + idOfAuthUserToConvert + " provider id is null."); } - String shibProviderId = ShibAuthenticationProvider.PROVIDER_ID; - if (!providerId.equals(shibProviderId)) { - throw new Exception("User id " + idOfAuthUserToConvert + " cannot be converted from Shibboleth to BuiltIn because current provider id is '" + providerId + "' rather than '" + shibProviderId + "'."); + String builtinProviderId = BuiltinAuthenticationProvider.PROVIDER_ID; + if (providerId.equals(builtinProviderId)) { + throw new Exception("User id " + idOfAuthUserToConvert + " cannot be converted from remote to BuiltIn because current provider id is '" + providerId + "' which is the same as '" + builtinProviderId + "'. This user is already a BuiltIn user."); } lookup.setAuthenticationProviderId(BuiltinAuthenticationProvider.PROVIDER_ID); lookup.setPersistentUserId(authenticatedUser.getUserIdentifier()); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibServiceBean.java index 246ec5856f8..58f81d95cb6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibServiceBean.java @@ -325,10 +325,13 @@ private void mutateRequestForDevRandom(HttpServletRequest request) { /** * For testing, don't expect this to work well. + * + * @todo Move this method to somewhere that makes more sense for OAuth as + * well as Shib. */ public Map getRandomUser() throws JsonSyntaxException, JsonIOException { Map fakeUser = new HashMap<>(); - String sURL = "http://api.randomuser.me/0.8"; + String sURL = "https://api.randomuser.me/0.8"; URL url = null; try { url = new URL(sURL); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java b/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java index 716b74a6274..bae21a09510 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java @@ -3,6 +3,7 @@ import com.jayway.restassured.RestAssured; import com.jayway.restassured.path.json.JsonPath; import com.jayway.restassured.response.Response; +import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.GitHubOAuth2AP; import static javax.ws.rs.core.Response.Status.FORBIDDEN; import static javax.ws.rs.core.Response.Status.OK; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; @@ -11,6 +12,7 @@ import java.util.UUID; import static javax.ws.rs.core.Response.Status.CREATED; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; import static org.junit.Assert.assertEquals; public class AdminIT { @@ -109,7 +111,14 @@ public void testConvertShibUserToBuiltin() throws Exception { String existingEmailAddress = "dataverse@mailinator.com"; Response existingEmailFail = UtilIT.migrateShibToBuiltin(idOfUserToConvert, existingEmailAddress, superuserApiToken); existingEmailFail.prettyPrint(); - existingEmailFail.then().assertThat().statusCode(BAD_REQUEST.getStatusCode()); + existingEmailFail.then().assertThat() + .body("status", equalTo("ERROR")) + .body("message", equalTo("User id " + idOfUserToConvert + + " could not be converted from Shibboleth to BuiltIn. Details from Exception: java.lang.Exception: User id " + + idOfUserToConvert + " (@" + + usernameOfUserToConvert + + ") cannot be converted from remote to BuiltIn because the email address dataverse@mailinator.com is already in use by user id 1 (@dataverseAdmin). ")) + .statusCode(BAD_REQUEST.getStatusCode()); String newEmailAddress = UUID.randomUUID().toString().substring(0, 8) + "@mailinator.com"; Response shouldWork = UtilIT.migrateShibToBuiltin(idOfUserToConvert, newEmailAddress, superuserApiToken); @@ -124,6 +133,113 @@ public void testConvertShibUserToBuiltin() throws Exception { } + @Test + public void testConvertOAuthUserToBuiltin() throws Exception { + + System.out.println("BEGIN testConvertOAuthUserToBuiltin"); + + Response createUserToConvert = UtilIT.createRandomUser(); + createUserToConvert.prettyPrint(); + + long idOfUserToConvert = createUserToConvert.body().jsonPath().getLong("data.authenticatedUser.id"); + String emailOfUserToConvert = createUserToConvert.body().jsonPath().getString("data.user.email"); + String usernameOfUserToConvert = UtilIT.getUsernameFromResponse(createUserToConvert); + + String password = usernameOfUserToConvert; + String newEmailAddressToUse = "builtin2shib." + UUID.randomUUID().toString().substring(0, 8) + "@mailinator.com"; + + GitHubOAuth2AP github = new GitHubOAuth2AP(null, null); + String providerIdToConvertTo = github.getId(); + String newPersistentUserIdInLookupTable = UUID.randomUUID().toString().substring(0, 8); + String data = emailOfUserToConvert + ":" + password + ":" + newEmailAddressToUse + ":" + providerIdToConvertTo + ":" + newPersistentUserIdInLookupTable; + + System.out.println("data: " + data); + Response builtinToShibAnon = UtilIT.migrateBuiltinToOAuth(data, ""); + builtinToShibAnon.prettyPrint(); + builtinToShibAnon.then().assertThat().statusCode(FORBIDDEN.getStatusCode()); + + Response createSuperuser = UtilIT.createRandomUser(); + String superuserUsername = UtilIT.getUsernameFromResponse(createSuperuser); + String superuserApiToken = UtilIT.getApiTokenFromResponse(createSuperuser); + Response toggleSuperuser = UtilIT.makeSuperUser(superuserUsername); + toggleSuperuser.then().assertThat() + .statusCode(OK.getStatusCode()); + + Response makeShibUser = UtilIT.migrateBuiltinToOAuth(data, superuserApiToken); + makeShibUser.prettyPrint(); + makeShibUser.then().assertThat() + .statusCode(OK.getStatusCode()) + // .body("data.affiliation", equalTo("TestShib Test IdP")) + .body("data.'changing to this provider'", equalTo("github")) + .body("data.'password supplied'", equalTo(password)); + + /** + * @todo Write more failing tests such as expecting a non-OK response if + * the OAuth user has an invalid email address: + * https://github.com/IQSS/dataverse/issues/2998 + */ + Response oauthToBuiltinAnon = UtilIT.migrateOAuthToBuiltin(Long.MAX_VALUE, "", ""); + oauthToBuiltinAnon.prettyPrint(); + oauthToBuiltinAnon.then().assertThat().statusCode(FORBIDDEN.getStatusCode()); + + Response nonSuperuser = UtilIT.migrateOAuthToBuiltin(Long.MAX_VALUE, "", ""); + nonSuperuser.prettyPrint(); + nonSuperuser.then().assertThat().statusCode(FORBIDDEN.getStatusCode()); + + Response infoOfUserToConvert = UtilIT.getAuthenticatedUser(usernameOfUserToConvert, superuserApiToken); + infoOfUserToConvert.prettyPrint(); + infoOfUserToConvert.then().assertThat() + .body("data.id", equalTo(Long.valueOf(idOfUserToConvert).intValue())) + .body("data.identifier", equalTo("@" + usernameOfUserToConvert)) + .body("data.persistentUserId", equalTo(newPersistentUserIdInLookupTable)) + .body("data.authenticationProviderId", equalTo("github")) + .statusCode(OK.getStatusCode()); + + String invalidEmailAddress = "invalidEmailAddress"; + Response invalidEmailFail = UtilIT.migrateOAuthToBuiltin(idOfUserToConvert, invalidEmailAddress, superuserApiToken); + invalidEmailFail.prettyPrint(); + invalidEmailFail.then().assertThat() + .body("status", equalTo("ERROR")) + .statusCode(BAD_REQUEST.getStatusCode()); + + String existingEmailAddress = "dataverse@mailinator.com"; + Response existingEmailFail = UtilIT.migrateOAuthToBuiltin(idOfUserToConvert, existingEmailAddress, superuserApiToken); + existingEmailFail.prettyPrint(); + existingEmailFail.then().assertThat() + .body("status", equalTo("ERROR")) + .body("message", equalTo("User id " + idOfUserToConvert + + " could not be converted from remote to BuiltIn. Details from Exception: java.lang.Exception: User id " + + idOfUserToConvert + " (@" + + usernameOfUserToConvert + + ") cannot be converted from remote to BuiltIn because the email address dataverse@mailinator.com is already in use by user id 1 (@dataverseAdmin). ")) + .statusCode(BAD_REQUEST.getStatusCode()); + + String newEmailAddress = UUID.randomUUID().toString().substring(0, 8) + "@mailinator.com"; + Response shouldWork = UtilIT.migrateOAuthToBuiltin(idOfUserToConvert, newEmailAddress, superuserApiToken); + shouldWork.prettyPrint(); + shouldWork.then().assertThat() + .body("data.username", notNullValue()) + .body("data.email", equalTo(newEmailAddress)) + .statusCode(OK.getStatusCode()); + + Response infoForUserConvertedToBuiltin = UtilIT.getAuthenticatedUser(usernameOfUserToConvert, superuserApiToken); + infoForUserConvertedToBuiltin.prettyPrint(); + infoForUserConvertedToBuiltin.then().assertThat() + .body("data.id", equalTo(Long.valueOf(idOfUserToConvert).intValue())) + .body("data.identifier", equalTo("@" + usernameOfUserToConvert)) + .body("data.persistentUserId", equalTo(usernameOfUserToConvert)) + .body("data.authenticationProviderId", equalTo("builtin")) + .body("data.email", equalTo(newEmailAddress)) + .statusCode(OK.getStatusCode()); + + Response deleteUserToConvert = UtilIT.deleteUser(usernameOfUserToConvert); + assertEquals(200, deleteUserToConvert.getStatusCode()); + + Response deleteSuperuser = UtilIT.deleteUser(superuserUsername); + assertEquals(200, deleteSuperuser.getStatusCode()); + + } + @Test public void testFindPermissonsOn() { Response createUser = UtilIT.createRandomUser(); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index ee651ecab64..e617e6eea05 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -487,6 +487,14 @@ static Response migrateShibToBuiltin(Long userIdToConvert, String newEmailAddres return response; } + static Response migrateOAuthToBuiltin(Long userIdToConvert, String newEmailAddress, String apiToken) { + Response response = given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .body(newEmailAddress) + .put("/api/admin/authenticatedUsers/id/" + userIdToConvert + "/convertRemoteToBuiltIn"); + return response; + } + static Response migrateBuiltinToShib(String data, String apiToken) { Response response = given() .header(API_TOKEN_HTTP_HEADER, apiToken) @@ -495,6 +503,14 @@ static Response migrateBuiltinToShib(String data, String apiToken) { return response; } + static Response migrateBuiltinToOAuth(String data, String apiToken) { + Response response = given() + .header(API_TOKEN_HTTP_HEADER, apiToken) + .body(data) + .put("/api/admin/authenticatedUsers/convert/builtin2oauth"); + return response; + } + static Response nativeGet(Integer datasetId, String apiToken) { Response response = given() .header(API_TOKEN_HTTP_HEADER, apiToken)