mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-13 13:03:11 +00:00
[CST-6152] Password add operation refactoring to include challenge in the value
This commit is contained in:
@@ -226,9 +226,12 @@ public interface AuthenticationMethod {
|
|||||||
public boolean isUsed(Context context, HttpServletRequest request);
|
public boolean isUsed(Context context, HttpServletRequest request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context The DSpace context
|
* Check if the given challenge is valid to change the password of the given
|
||||||
* @param challenge The current password of the user
|
* ePerson
|
||||||
* @return true if challenge matches with current password
|
* @param context The DSpace context
|
||||||
|
* @param ePerson the ePerson related to the password change
|
||||||
|
* @param challenge The challenge to check
|
||||||
|
* @return true if challenge matches with current password
|
||||||
*/
|
*/
|
||||||
public boolean canChangePassword(Context context, String challenge);
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge);
|
||||||
}
|
}
|
||||||
|
@@ -209,12 +209,14 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
|
|
||||||
for (AuthenticationMethod method : getAuthenticationMethodStack()) {
|
for (AuthenticationMethod method : getAuthenticationMethodStack()) {
|
||||||
if (method.canChangePassword(context, challenge)) {
|
if (method.getName().equals(context.getAuthenticationMethod())) {
|
||||||
return true;
|
return method.canChangePassword(context, ePerson, challenge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -280,7 +280,7 @@ public class IPAuthentication implements AuthenticationMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -754,7 +754,7 @@ public class LDAPAuthentication
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -87,7 +87,7 @@ public class OidcAuthentication implements AuthenticationMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -295,7 +295,7 @@ public class OidcAuthenticationBean implements AuthenticationMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -102,7 +102,7 @@ public class OrcidAuthentication implements AuthenticationMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -124,7 +124,7 @@ public class OrcidAuthenticationBean implements AuthenticationMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -269,11 +269,10 @@ public class PasswordAuthentication
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
EPerson ePerson = context.getCurrentUser();
|
if (context == null || ePerson == null) {
|
||||||
if (context != null && ePerson != null) {
|
return false;
|
||||||
return ePersonService.checkPassword(context, context.getCurrentUser(), challenge);
|
|
||||||
}
|
}
|
||||||
return false;
|
return ePersonService.checkPassword(context, ePerson, challenge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1278,7 +1278,7 @@ public class ShibAuthentication implements AuthenticationMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -610,7 +610,7 @@ public class X509Authentication implements AuthenticationMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canChangePassword(Context context, String challenge) {
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -182,6 +182,6 @@ public interface AuthenticationService {
|
|||||||
* @param challenge The current password of the user
|
* @param challenge The current password of the user
|
||||||
* @return true if challenge matches with current password
|
* @return true if challenge matches with current password
|
||||||
*/
|
*/
|
||||||
public boolean canChangePassword(Context context, String challenge);
|
public boolean canChangePassword(Context context, EPerson ePerson, String challenge);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -446,4 +446,8 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport {
|
|||||||
return previousActive;
|
return previousActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasPasswordSet() {
|
||||||
|
return StringUtils.isNotBlank(getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -190,7 +190,7 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
|||||||
HttpStatus.BAD_REQUEST.value());
|
HttpStatus.BAD_REQUEST.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler({InvalidPasswordException.class})
|
@ExceptionHandler({InvalidPasswordChallengeException.class})
|
||||||
protected void handleInvalidPasswordException(HttpServletRequest request, HttpServletResponse response,
|
protected void handleInvalidPasswordException(HttpServletRequest request, HttpServletResponse response,
|
||||||
Exception ex) throws IOException {
|
Exception ex) throws IOException {
|
||||||
sendErrorResponse(request, response, ex, "Current password is not valid", HttpServletResponse.SC_FORBIDDEN);
|
sendErrorResponse(request, response, ex, "Current password is not valid", HttpServletResponse.SC_FORBIDDEN);
|
||||||
|
@@ -8,17 +8,19 @@
|
|||||||
package org.dspace.app.rest.exception;
|
package org.dspace.app.rest.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This exception is thrown when the current password of user is invalid
|
* This exception is thrown when the password challenge of user is invalid.
|
||||||
*
|
*
|
||||||
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
|
* @author Mohamed Eskander (mohamed.eskander at 4science.it)
|
||||||
*/
|
*/
|
||||||
public class InvalidPasswordException extends RuntimeException {
|
public class InvalidPasswordChallengeException extends RuntimeException {
|
||||||
|
|
||||||
public InvalidPasswordException(String message) {
|
private static final long serialVersionUID = 7774965236190392985L;
|
||||||
|
|
||||||
|
public InvalidPasswordChallengeException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InvalidPasswordException(String message, Exception exception) {
|
public InvalidPasswordChallengeException(String message, Exception exception) {
|
||||||
super(message, exception);
|
super(message, exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -24,7 +24,6 @@ import org.dspace.app.rest.SearchRestMethod;
|
|||||||
import org.dspace.app.rest.authorization.AuthorizationFeatureService;
|
import org.dspace.app.rest.authorization.AuthorizationFeatureService;
|
||||||
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||||
import org.dspace.app.rest.exception.EPersonNameNotProvidedException;
|
import org.dspace.app.rest.exception.EPersonNameNotProvidedException;
|
||||||
import org.dspace.app.rest.exception.InvalidPasswordException;
|
|
||||||
import org.dspace.app.rest.exception.RESTEmptyWorkflowGroupException;
|
import org.dspace.app.rest.exception.RESTEmptyWorkflowGroupException;
|
||||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||||
import org.dspace.app.rest.model.EPersonRest;
|
import org.dspace.app.rest.model.EPersonRest;
|
||||||
@@ -33,7 +32,6 @@ import org.dspace.app.rest.model.MetadataValueRest;
|
|||||||
import org.dspace.app.rest.model.patch.Operation;
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
import org.dspace.app.rest.model.patch.Patch;
|
import org.dspace.app.rest.model.patch.Patch;
|
||||||
import org.dspace.app.util.AuthorizeUtil;
|
import org.dspace.app.util.AuthorizeUtil;
|
||||||
import org.dspace.authenticate.service.AuthenticationService;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.authorize.service.AuthorizeService;
|
import org.dspace.authorize.service.AuthorizeService;
|
||||||
import org.dspace.content.service.SiteService;
|
import org.dspace.content.service.SiteService;
|
||||||
@@ -84,9 +82,6 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
|||||||
@Autowired
|
@Autowired
|
||||||
private RegistrationDataService registrationDataService;
|
private RegistrationDataService registrationDataService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AuthenticationService authenticationService;
|
|
||||||
|
|
||||||
private final EPersonService es;
|
private final EPersonService es;
|
||||||
|
|
||||||
|
|
||||||
@@ -299,8 +294,6 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
|||||||
protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
|
protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
|
||||||
Patch patch) throws AuthorizeException, SQLException {
|
Patch patch) throws AuthorizeException, SQLException {
|
||||||
boolean passwordChangeFound = false;
|
boolean passwordChangeFound = false;
|
||||||
boolean challengeFound = false;
|
|
||||||
boolean canChangePassword;
|
|
||||||
for (Operation operation : patch.getOperations()) {
|
for (Operation operation : patch.getOperations()) {
|
||||||
if (StringUtils.equalsIgnoreCase(operation.getPath(), "/password")) {
|
if (StringUtils.equalsIgnoreCase(operation.getPath(), "/password")) {
|
||||||
passwordChangeFound = true;
|
passwordChangeFound = true;
|
||||||
@@ -315,21 +308,6 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
|
|||||||
if (passwordChangeFound && !StringUtils.equals(context.getAuthenticationMethod(), "password")) {
|
if (passwordChangeFound && !StringUtils.equals(context.getAuthenticationMethod(), "password")) {
|
||||||
throw new AccessDeniedException("Refused to perform the EPerson patch based to change the password " +
|
throw new AccessDeniedException("Refused to perform the EPerson patch based to change the password " +
|
||||||
"for non \"password\" authentication");
|
"for non \"password\" authentication");
|
||||||
} else if (passwordChangeFound) {
|
|
||||||
for (Operation operation : patch.getOperations()) {
|
|
||||||
if (StringUtils.equalsIgnoreCase(operation.getPath(), "/challenge")) {
|
|
||||||
challengeFound = true;
|
|
||||||
canChangePassword =
|
|
||||||
authenticationService.canChangePassword(context, String.valueOf(operation.getValue()));
|
|
||||||
if (!canChangePassword) {
|
|
||||||
throw new InvalidPasswordException("Current password is not valid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!challengeFound) {
|
|
||||||
throw new InvalidPasswordException("no challenge found");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
patchDSpaceObject(apiCategory, model, uuid, patch);
|
patchDSpaceObject(apiCategory, model, uuid, patch);
|
||||||
|
@@ -1,42 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.rest.repository.patch.operation;
|
|
||||||
|
|
||||||
import org.dspace.app.rest.model.patch.Operation;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.eperson.EPerson;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation for EPerson challenge patches.
|
|
||||||
*
|
|
||||||
* Example: <code>
|
|
||||||
* curl -X PATCH http://${dspace.server.url}/api/epersons/eperson/<:id-eperson> -H "
|
|
||||||
* Content-Type: application/json" -d '[{"op":"add","path":"/password","value":"newpassword"},
|
|
||||||
* { "op": "add", "path": /challenge", "value": "oldPassword"]'
|
|
||||||
* </code>
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class EPersonChallengeAddOperation<R> extends PatchOperation<R> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Path in json body of patch that uses this operation
|
|
||||||
*/
|
|
||||||
public static final String OPERATION_PASSWORD_CHANGE = "/challenge";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public R perform(Context context, R object, Operation operation) {
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Object objectToMatch, Operation operation) {
|
|
||||||
return (objectToMatch instanceof EPerson && operation.getOp().trim().equalsIgnoreCase(OPERATION_ADD)
|
|
||||||
&& operation.getPath().trim().equalsIgnoreCase(OPERATION_PASSWORD_CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -8,12 +8,17 @@
|
|||||||
package org.dspace.app.rest.repository.patch.operation;
|
package org.dspace.app.rest.repository.patch.operation;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||||
|
import org.dspace.app.rest.exception.InvalidPasswordChallengeException;
|
||||||
|
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||||
|
import org.dspace.app.rest.model.patch.JsonValueEvaluator;
|
||||||
import org.dspace.app.rest.model.patch.Operation;
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
import org.dspace.app.util.AuthorizeUtil;
|
import org.dspace.app.util.AuthorizeUtil;
|
||||||
|
import org.dspace.authenticate.service.AuthenticationService;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
@@ -32,7 +37,7 @@ import org.springframework.stereotype.Component;
|
|||||||
* Example: <code>
|
* Example: <code>
|
||||||
* curl -X PATCH http://${dspace.server.url}/api/epersons/eperson/<:id-eperson> -H "
|
* curl -X PATCH http://${dspace.server.url}/api/epersons/eperson/<:id-eperson> -H "
|
||||||
* Content-Type: application/json" -d '[{ "op": "add", "path": "
|
* Content-Type: application/json" -d '[{ "op": "add", "path": "
|
||||||
* /password", "value": "newpassword"]'
|
* /password", "value": {"password": "newpassword", "challenge": "currentpassword"}]'
|
||||||
* </code>
|
* </code>
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@@ -53,24 +58,51 @@ public class EPersonPasswordAddOperation<R> extends PatchOperation<R> {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AccountService accountService;
|
private AccountService accountService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationService authenticationService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R perform(Context context, R object, Operation operation) {
|
public R perform(Context context, R object, Operation operation) {
|
||||||
checkOperationValue(operation.getValue());
|
|
||||||
if (supports(object, operation)) {
|
if (!supports(object, operation)) {
|
||||||
EPerson eperson = (EPerson) object;
|
|
||||||
if (!AuthorizeUtil.authorizeUpdatePassword(context, eperson.getEmail())) {
|
|
||||||
throw new DSpaceBadRequestException("Password cannot be updated for the given EPerson with email: " +
|
|
||||||
eperson.getEmail());
|
|
||||||
}
|
|
||||||
String token = requestService.getCurrentRequest().getHttpServletRequest().getParameter("token");
|
|
||||||
if (StringUtils.isNotBlank(token)) {
|
|
||||||
verifyAndDeleteToken(context, eperson, token, operation);
|
|
||||||
}
|
|
||||||
ePersonService.setPassword(eperson, (String) operation.getValue());
|
|
||||||
return object;
|
|
||||||
} else {
|
|
||||||
throw new DSpaceBadRequestException(this.getClass().getName() + " does not support this operation");
|
throw new DSpaceBadRequestException(this.getClass().getName() + " does not support this operation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PasswordVO passwordVO = parseOperationValue(operation);
|
||||||
|
|
||||||
|
String newPassword = passwordVO.getPassword()
|
||||||
|
.orElseThrow(() -> new DSpaceBadRequestException("No password provided"));
|
||||||
|
|
||||||
|
EPerson eperson = (EPerson) object;
|
||||||
|
if (!AuthorizeUtil.authorizeUpdatePassword(context, eperson.getEmail())) {
|
||||||
|
throw new DSpaceBadRequestException("Password cannot be updated for the given EPerson with email: " +
|
||||||
|
eperson.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
String token = requestService.getCurrentRequest().getHttpServletRequest().getParameter("token");
|
||||||
|
if (StringUtils.isNotBlank(token)) {
|
||||||
|
verifyAndDeleteToken(context, eperson, token, operation);
|
||||||
|
} else if (eperson.hasPasswordSet()) {
|
||||||
|
verifyChallenge(context, eperson, passwordVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
ePersonService.setPassword(eperson, newPassword);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PasswordVO parseOperationValue(Operation operation) {
|
||||||
|
|
||||||
|
if (operation.getValue() == null) {
|
||||||
|
throw new UnprocessableEntityException("No value provided for operation " + operation.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (PasswordVO) ((JsonValueEvaluator) operation.getValue()).evaluate(PasswordVO.class);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new UnprocessableEntityException("Invalid value provided for operation " + operation.getPath(), ex);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyAndDeleteToken(Context context, EPerson eperson, String token, Operation operation) {
|
private void verifyAndDeleteToken(Context context, EPerson eperson, String token, Operation operation) {
|
||||||
@@ -91,9 +123,52 @@ public class EPersonPasswordAddOperation<R> extends PatchOperation<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verifyChallenge(Context context, EPerson eperson, PasswordVO passwordVO) {
|
||||||
|
|
||||||
|
String challenge = passwordVO.getChallenge()
|
||||||
|
.orElseThrow(() -> new InvalidPasswordChallengeException("No challenge provided"));
|
||||||
|
|
||||||
|
boolean canChangePassword = authenticationService.canChangePassword(context, eperson, challenge);
|
||||||
|
if (!canChangePassword) {
|
||||||
|
throw new InvalidPasswordChallengeException("The provided challenge is not valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(Object objectToMatch, Operation operation) {
|
public boolean supports(Object objectToMatch, Operation operation) {
|
||||||
return (objectToMatch instanceof EPerson && operation.getOp().trim().equalsIgnoreCase(OPERATION_ADD)
|
return (objectToMatch instanceof EPerson && operation.getOp().trim().equalsIgnoreCase(OPERATION_ADD)
|
||||||
&& operation.getPath().trim().equalsIgnoreCase(OPERATION_PASSWORD_CHANGE));
|
&& operation.getPath().trim().equalsIgnoreCase(OPERATION_PASSWORD_CHANGE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Value object that stores the new password to set and the challange to verify.
|
||||||
|
* This object models the value of the operation.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class PasswordVO {
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
private String challenge;
|
||||||
|
|
||||||
|
public Optional<String> getPassword() {
|
||||||
|
return Optional.ofNullable(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> getChallenge() {
|
||||||
|
return Optional.ofNullable(challenge);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChallenge(String challenge) {
|
||||||
|
this.challenge = challenge;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.dspace.app.rest.model.patch.Operation;
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
import org.dspace.app.rest.model.patch.Patch;
|
import org.dspace.app.rest.model.patch.Patch;
|
||||||
import org.dspace.app.rest.repository.patch.operation.DSpaceObjectMetadataPatchUtils;
|
import org.dspace.app.rest.repository.patch.operation.DSpaceObjectMetadataPatchUtils;
|
||||||
import org.dspace.app.rest.repository.patch.operation.EPersonChallengeAddOperation;
|
|
||||||
import org.dspace.app.rest.repository.patch.operation.EPersonPasswordAddOperation;
|
import org.dspace.app.rest.repository.patch.operation.EPersonPasswordAddOperation;
|
||||||
import org.dspace.app.rest.repository.patch.operation.PatchOperation;
|
import org.dspace.app.rest.repository.patch.operation.PatchOperation;
|
||||||
import org.dspace.app.rest.utils.ContextUtil;
|
import org.dspace.app.rest.utils.ContextUtil;
|
||||||
@@ -124,8 +123,7 @@ public class EPersonRestPermissionEvaluatorPlugin extends RestObjectPermissionEv
|
|||||||
*/
|
*/
|
||||||
for (Operation op: operations) {
|
for (Operation op: operations) {
|
||||||
if (!(op.getPath().contentEquals(EPersonPasswordAddOperation.OPERATION_PASSWORD_CHANGE)
|
if (!(op.getPath().contentEquals(EPersonPasswordAddOperation.OPERATION_PASSWORD_CHANGE)
|
||||||
|| (op.getPath().startsWith(DSpaceObjectMetadataPatchUtils.OPERATION_METADATA_PATH)
|
|| (op.getPath().startsWith(DSpaceObjectMetadataPatchUtils.OPERATION_METADATA_PATH)))) {
|
||||||
|| op.getPath().contentEquals(EPersonChallengeAddOperation.OPERATION_PASSWORD_CHANGE)))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,9 +36,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
@@ -1301,13 +1303,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
String newPassword = "newpassword";
|
||||||
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, password);
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
|
||||||
AddOperation addOperation2 = new AddOperation("/challenge", password);
|
|
||||||
ops.add(addOperation);
|
|
||||||
ops.add(addOperation2);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
@@ -1400,13 +1396,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
String newPassword = "newpassword";
|
||||||
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, password);
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
|
||||||
AddOperation addOperation2 = new AddOperation("/challenge", password);
|
|
||||||
ops.add(addOperation);
|
|
||||||
ops.add(addOperation2);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
String token = getAuthToken(ePerson.getEmail(), password);
|
String token = getAuthToken(ePerson.getEmail(), password);
|
||||||
|
|
||||||
@@ -1445,13 +1435,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
String newPassword = "newpassword";
|
||||||
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, password);
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
|
||||||
AddOperation addOperation2 = new AddOperation("/challenge", password);
|
|
||||||
ops.add(addOperation);
|
|
||||||
ops.add(addOperation2);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
@@ -1539,13 +1523,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
String patchBody = buildPasswordAddOperationPatchBody(null, password);
|
||||||
List<Operation> ops = new ArrayList<>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", null);
|
|
||||||
AddOperation addOperation2 = new AddOperation("/challenge", password);
|
|
||||||
ops.add(addOperation);
|
|
||||||
ops.add(addOperation2);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
// adding null pw should return bad request
|
// adding null pw should return bad request
|
||||||
getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID())
|
getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID())
|
||||||
@@ -1586,13 +1564,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
String newPassword = "newpass";
|
String newPassword = "newpass";
|
||||||
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, password);
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
|
||||||
AddOperation addOperation2 = new AddOperation("/challenge", password);
|
|
||||||
ops.add(addOperation);
|
|
||||||
ops.add(addOperation2);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
// initialize password with add operation, not set during creation
|
// initialize password with add operation, not set during creation
|
||||||
getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID())
|
getClient(token).perform(patch("/api/eperson/epersons/" + ePerson.getID())
|
||||||
@@ -2027,14 +1999,11 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
.withPassword(password)
|
.withPassword(password)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
String newPassword = "newpassword";
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, null);
|
||||||
ops.add(addOperation);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
accountService.sendRegistrationInfo(context, ePerson.getEmail());
|
accountService.sendRegistrationInfo(context, ePerson.getEmail());
|
||||||
String tokenForEPerson = registrationDataService.findByEmail(context, ePerson.getEmail()).getToken();
|
String tokenForEPerson = registrationDataService.findByEmail(context, ePerson.getEmail()).getToken();
|
||||||
PasswordHash oldPassword = ePersonService.getPasswordHash(ePerson);
|
PasswordHash oldPassword = ePersonService.getPasswordHash(ePerson);
|
||||||
@@ -2063,14 +2032,11 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
.withPassword(password)
|
.withPassword(password)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
String newPassword = "newpassword";
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, null);
|
||||||
ops.add(addOperation);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
accountService.sendRegistrationInfo(context, ePerson.getEmail());
|
accountService.sendRegistrationInfo(context, ePerson.getEmail());
|
||||||
String tokenForEPerson = registrationDataService.findByEmail(context, ePerson.getEmail()).getToken();
|
String tokenForEPerson = registrationDataService.findByEmail(context, ePerson.getEmail()).getToken();
|
||||||
PasswordHash oldPassword = ePersonService.getPasswordHash(ePerson);
|
PasswordHash oldPassword = ePersonService.getPasswordHash(ePerson);
|
||||||
@@ -2108,14 +2074,11 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
.withPassword(password)
|
.withPassword(password)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
String newPassword = "newpassword";
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, null);
|
||||||
ops.add(addOperation);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
accountService.sendRegistrationInfo(context, ePerson.getEmail());
|
accountService.sendRegistrationInfo(context, ePerson.getEmail());
|
||||||
accountService.sendRegistrationInfo(context, ePersonTwo.getEmail());
|
accountService.sendRegistrationInfo(context, ePersonTwo.getEmail());
|
||||||
String tokenForEPerson = registrationDataService.findByEmail(context, ePerson.getEmail()).getToken();
|
String tokenForEPerson = registrationDataService.findByEmail(context, ePerson.getEmail()).getToken();
|
||||||
@@ -2199,14 +2162,11 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
.withPassword(password)
|
.withPassword(password)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
String newPassword = "newpassword";
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, null);
|
||||||
ops.add(addOperation);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
accountService.sendRegistrationInfo(context, ePerson.getEmail());
|
accountService.sendRegistrationInfo(context, ePerson.getEmail());
|
||||||
String newRegisterToken = registrationDataService.findByEmail(context, newRegisterEmail).getToken();
|
String newRegisterToken = registrationDataService.findByEmail(context, newRegisterEmail).getToken();
|
||||||
PasswordHash oldPassword = ePersonService.getPasswordHash(ePerson);
|
PasswordHash oldPassword = ePersonService.getPasswordHash(ePerson);
|
||||||
@@ -3153,13 +3113,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
String newPassword = "newpassword";
|
||||||
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, password);
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
|
||||||
AddOperation addOperation2 = new AddOperation("/challenge", password);
|
|
||||||
ops.add(addOperation);
|
|
||||||
ops.add(addOperation2);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
@@ -3201,13 +3155,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
|
|
||||||
String newPassword = "newpassword";
|
String newPassword = "newpassword";
|
||||||
String wrongPassword = "wrong_password";
|
String wrongPassword = "wrong_password";
|
||||||
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, wrongPassword);
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
|
||||||
AddOperation addOperation2 = new AddOperation("/challenge", wrongPassword);
|
|
||||||
ops.add(addOperation);
|
|
||||||
ops.add(addOperation2);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
@@ -3231,11 +3179,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
String newPassword = "newpassword";
|
||||||
|
String patchBody = buildPasswordAddOperationPatchBody(newPassword, null);
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
|
||||||
ops.add(addOperation);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
@@ -3245,35 +3189,17 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
.andExpect(status().isForbidden());
|
.andExpect(status().isForbidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private String buildPasswordAddOperationPatchBody(String password, String challenge) {
|
||||||
public void patchChangePasswordWithIPAuthenticationMethod() throws Exception {
|
|
||||||
|
|
||||||
context.turnOffAuthorisationSystem();
|
Map<String, String> value = new HashMap<>();
|
||||||
|
if (password != null) {
|
||||||
|
value.put("password", password);
|
||||||
|
}
|
||||||
|
if (challenge != null) {
|
||||||
|
value.put("challenge", challenge);
|
||||||
|
}
|
||||||
|
|
||||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
return getPatchContent(List.of(new AddOperation("/password", value)));
|
||||||
.withNameInMetadata("John", "Doe")
|
|
||||||
.withEmail("Johndoe@example.com")
|
|
||||||
.withPassword(password)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
|
|
||||||
String newPassword = "newpassword";
|
|
||||||
|
|
||||||
List<Operation> ops = new ArrayList<Operation>();
|
|
||||||
AddOperation addOperation = new AddOperation("/password", newPassword);
|
|
||||||
AddOperation addOperation2 = new AddOperation("/challenge", password);
|
|
||||||
ops.add(addOperation);
|
|
||||||
ops.add(addOperation2);
|
|
||||||
String patchBody = getPatchContent(ops);
|
|
||||||
|
|
||||||
context.setAuthenticationMethod("ip");
|
|
||||||
|
|
||||||
getClient().perform(patch("/api/eperson/epersons/" + ePerson.getID())
|
|
||||||
.content(patchBody)
|
|
||||||
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON)
|
|
||||||
.with(ip("5.5.5.5")))
|
|
||||||
.andExpect(status().isUnauthorized());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user