diff --git a/scm-core/src/main/java/sonia/scm/ManagerDecorator.java b/scm-core/src/main/java/sonia/scm/ManagerDecorator.java index 7b3f03ee8c..ef20a374cb 100644 --- a/scm-core/src/main/java/sonia/scm/ManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/ManagerDecorator.java @@ -71,7 +71,7 @@ public class ManagerDecorator implements Manager { } @Override - public void delete(T object) throws NotFoundException { + public void delete(T object){ decorated.delete(object); } @@ -82,12 +82,12 @@ public class ManagerDecorator implements Manager { } @Override - public void modify(T object) throws NotFoundException { + public void modify(T object){ decorated.modify(object); } @Override - public void refresh(T object) throws NotFoundException { + public void refresh(T object){ decorated.refresh(object); } diff --git a/scm-core/src/main/java/sonia/scm/user/ChangePasswordNotAllowedException.java b/scm-core/src/main/java/sonia/scm/user/ChangePasswordNotAllowedException.java index 19c609ba30..caa0c918fc 100644 --- a/scm-core/src/main/java/sonia/scm/user/ChangePasswordNotAllowedException.java +++ b/scm-core/src/main/java/sonia/scm/user/ChangePasswordNotAllowedException.java @@ -3,6 +3,7 @@ package sonia.scm.user; public class ChangePasswordNotAllowedException extends RuntimeException { public static final String WRONG_USER_TYPE = "User of type {0} are not allowed to change password"; + public static final String OLD_PASSWORD_REQUIRED = "the old password is required."; public ChangePasswordNotAllowedException(String message) { super(message); diff --git a/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java b/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java index 27ca923902..93b0752766 100644 --- a/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java +++ b/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java @@ -154,7 +154,7 @@ public class SyncingRealmHelperTest { * Tests {@link SyncingRealmHelper#store(Group)} with an existing group. */ @Test - public void testStoreGroupModify() throws NotFoundException { + public void testStoreGroupModify(){ Group group = new Group("unit-test", "heartOfGold"); when(groupManager.get("heartOfGold")).thenReturn(group); @@ -191,7 +191,7 @@ public class SyncingRealmHelperTest { * Tests {@link SyncingRealmHelper#store(User)} with an existing user. */ @Test - public void testStoreUserModify() throws NotFoundException { + public void testStoreUserModify(){ when(userManager.contains("tricia")).thenReturn(Boolean.TRUE); User user = new User("tricia"); diff --git a/scm-it/src/test/java/sonia/scm/it/MeITCase.java b/scm-it/src/test/java/sonia/scm/it/MeITCase.java index 64f06765ea..203b748ade 100644 --- a/scm-it/src/test/java/sonia/scm/it/MeITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/MeITCase.java @@ -44,6 +44,35 @@ public class MeITCase { .assertStatusCode(204); } + @Test + public void nonAdminUserShouldChangeOwnPassword() { + String newPassword = "pass1"; + String username = "user1"; + String password = "pass"; + TestData.createUser(username, password,false,"xml"); + // user change the own password + ScmRequests.start() + .given() + .url(TestData.getMeUrl()) + .usernameAndPassword(username, password) + .getMeResource() + .assertStatusCode(200) + .usingMeResponse() + .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.FALSE)) + .assertPassword(Assert::assertNull) + .assertType(s -> assertThat(s).isEqualTo("xml")) + .requestChangePassword(password, newPassword) + .assertStatusCode(204); + // assert password is changed -> login with the new Password than undo changes + ScmRequests.start() + .given() + .url(TestData.getMeUrl()) + .usernameAndPassword(username, newPassword) + .getMeResource() + .assertStatusCode(200); + + } + @Test public void shouldHidePasswordLinkIfUserTypeIsNotXML() { String newUser = "user"; diff --git a/scm-it/src/test/java/sonia/scm/it/UserITCase.java b/scm-it/src/test/java/sonia/scm/it/UserITCase.java index 7e7ceae4f7..2860d2f3fa 100644 --- a/scm-it/src/test/java/sonia/scm/it/UserITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/UserITCase.java @@ -31,7 +31,7 @@ public class UserITCase { .usingUserResponse() .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE)) .assertPassword(Assert::assertNull) - .requestChangePassword(newPassword) // the oldPassword is not needed in the user resource + .requestChangePassword(password, newPassword) // the oldPassword is needed when the own password should be changed .assertStatusCode(204); // assert password is changed -> login with the new Password ScmRequests.start() @@ -60,7 +60,7 @@ public class UserITCase { .getUserResource() .assertStatusCode(200) .usingUserResponse() - .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE)) // the user anonymous is not an admin + .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.TRUE)) .assertPassword(Assert::assertNull) .requestChangePassword(newPassword) // the oldPassword is not needed in the user resource .assertStatusCode(204); @@ -75,6 +75,21 @@ public class UserITCase { } @Test + public void nonAdminUserShouldNotChangePasswordOfOtherUser() { + String user = "user"; + String password = "pass"; + TestData.createUser(user, password, false, "xml"); + String user2 = "user2"; + TestData.createUser(user2, password, false, "xml"); + ScmRequests.start() + .given() + .url(TestData.getUserUrl(user2)) + .usernameAndPassword(user, password) + .getUserResource() + .assertStatusCode(403); + } + + @Test public void nonAdminUserShouldChangeOwnPassword() { String newUser = "user"; String password = "pass"; @@ -88,7 +103,7 @@ public class UserITCase { .assertStatusCode(200) .usingUserResponse() .assertAdmin(aBoolean -> assertThat(aBoolean).isEqualTo(Boolean.FALSE)) - .requestChangePassword(newPassword) // the oldPassword is not needed in the user resource + .requestChangePassword(password, newPassword) // the oldPassword is needed when the own password should be changed .assertStatusCode(204); // assert password is changed -> login with the new Password ScmRequests.start() diff --git a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java index 41fd9a1290..d93b223404 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/ScmRequests.java @@ -406,6 +406,10 @@ public class ScmRequests { return new AppliedChangePasswordRequest(applyPUTRequestFromLink(super.response, LINKS_PASSWORD_HREF, VndMediaType.PASSWORD_CHANGE, createPasswordChangeJson(null, newPassword))); } + public AppliedChangePasswordRequest requestChangePassword(String oldPassword , String newPassword) { + return new AppliedChangePasswordRequest(applyPUTRequestFromLink(super.response, LINKS_PASSWORD_HREF, VndMediaType.PASSWORD_CHANGE, createPasswordChangeJson(oldPassword, newPassword))); + } + } diff --git a/scm-test/src/main/java/sonia/scm/user/UserManagerTestBase.java b/scm-test/src/main/java/sonia/scm/user/UserManagerTestBase.java index 9f1c50c797..dddce344ce 100644 --- a/scm-test/src/main/java/sonia/scm/user/UserManagerTestBase.java +++ b/scm-test/src/main/java/sonia/scm/user/UserManagerTestBase.java @@ -196,7 +196,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase { } @Test(expected = NotFoundException.class) - public void testModifyNotExisting() throws NotFoundException, ConcurrentModificationException { + public void testModifyNotExisting() { manager.modify(UserTestData.createZaphod()); } @@ -249,7 +249,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase { } @Test(expected = NotFoundException.class) - public void testRefreshNotFound() throws NotFoundException { + public void testRefreshNotFound(){ manager.refresh(UserTestData.createDent()); } diff --git a/scm-webapp/src/main/java/sonia/scm/ManagerDaoAdapter.java b/scm-webapp/src/main/java/sonia/scm/ManagerDaoAdapter.java index e2a1f29a33..7979eca0e7 100644 --- a/scm-webapp/src/main/java/sonia/scm/ManagerDaoAdapter.java +++ b/scm-webapp/src/main/java/sonia/scm/ManagerDaoAdapter.java @@ -15,7 +15,7 @@ public class ManagerDaoAdapter { this.dao = dao; } - public void modify(T object, Function permissionCheck, AroundHandler beforeUpdate, AroundHandler afterUpdate) throws NotFoundException { + public void modify(T object, Function permissionCheck, AroundHandler beforeUpdate, AroundHandler afterUpdate) { T notModified = dao.get(object.getId()); if (notModified != null) { permissionCheck.apply(notModified).check(); @@ -51,7 +51,7 @@ public class ManagerDaoAdapter { return newObject; } - public void delete(T toDelete, Supplier permissionCheck, AroundHandler beforeDelete, AroundHandler afterDelete) throws NotFoundException { + public void delete(T toDelete, Supplier permissionCheck, AroundHandler beforeDelete, AroundHandler afterDelete) { permissionCheck.get().check(); if (dao.contains(toDelete)) { beforeDelete.handle(toDelete); diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java index 95f729c2a3..6592bfab8b 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/ChangePasswordResource.java @@ -109,7 +109,7 @@ public class ChangePasswordResource @ResponseCode(code = 500, condition = "internal server error") }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response changePassword(@FormParam("old-password") String oldPassword, @FormParam("new-password") String newPassword) throws NotFoundException, ConcurrentModificationException { + public Response changePassword(@FormParam("old-password") String oldPassword, @FormParam("new-password") String newPassword) { AssertUtil.assertIsNotEmpty(oldPassword); AssertUtil.assertIsNotEmpty(newPassword); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DiffRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DiffRootResource.java index 99a996b02f..cb78c961a2 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DiffRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/DiffRootResource.java @@ -50,7 +50,7 @@ public class DiffRootResource { @ResponseCode(code = 404, condition = "not found, no revision with the specified param for the repository available or repository not found"), @ResponseCode(code = 500, condition = "internal server error") }) - public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision) throws NotFoundException { + public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision){ HttpUtil.checkForCRLFInjection(revision); try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) { StreamingOutput responseEntry = output -> { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupResource.java index ffa9a9ec08..789a9847cb 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupResource.java @@ -53,7 +53,7 @@ public class GroupResource { @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), @ResponseCode(code = 500, condition = "internal server error") }) - public Response get(@PathParam("id") String id) throws NotFoundException { + public Response get(@PathParam("id") String id){ return adapter.get(id, groupToGroupDtoMapper::map); } @@ -98,7 +98,7 @@ public class GroupResource { @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - public Response update(@PathParam("id") String name, @Valid GroupDto groupDto) throws NotFoundException, ConcurrentModificationException { + public Response update(@PathParam("id") String name, @Valid GroupDto groupDto) throws ConcurrentModificationException { return adapter.update(name, existing -> dtoToGroupMapper.map(groupDto)); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IdResourceManagerAdapter.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IdResourceManagerAdapter.java index f3ff20b010..197d089eb1 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IdResourceManagerAdapter.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/IdResourceManagerAdapter.java @@ -39,7 +39,7 @@ class IdResourceManagerAdapter(manager, type); } - Response get(String id, Function mapToDto) throws NotFoundException { + Response get(String id, Function mapToDto) { return singleAdapter.get(loadBy(id), mapToDto); } @@ -62,7 +62,7 @@ class IdResourceManagerAdapter applyChanges, Consumer checker ) throws NotFoundException, ConcurrentModificationException { + public Response changePassword(String id, Function applyChanges, Consumer checker ) throws ConcurrentModificationException { return singleAdapter.changePassword( loadBy(id), applyChanges, @@ -71,7 +71,7 @@ class IdResourceManagerAdapter applyChanges) throws NotFoundException, ConcurrentModificationException { + public Response update(String id, Function applyChanges) throws ConcurrentModificationException { return singleAdapter.update( loadBy(id), applyChanges, diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeResource.java index 7ebbf7ebb2..b4fa21feaa 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeResource.java @@ -6,11 +6,10 @@ import com.webcohesion.enunciate.metadata.rs.TypeHint; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.credential.PasswordService; import sonia.scm.ConcurrentModificationException; -import sonia.scm.NotFoundException; +import sonia.scm.user.ChangePasswordNotAllowedException; import sonia.scm.user.InvalidPasswordException; import sonia.scm.user.User; import sonia.scm.user.UserManager; -import sonia.scm.user.UserPermissions; import sonia.scm.web.VndMediaType; import javax.inject.Inject; @@ -61,7 +60,7 @@ public class MeResource { @ResponseCode(code = 401, condition = "not authenticated / invalid credentials"), @ResponseCode(code = 500, condition = "internal server error") }) - public Response get(@Context Request request, @Context UriInfo uriInfo) throws NotFoundException { + public Response get(@Context Request request, @Context UriInfo uriInfo) { String id = (String) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal(); return adapter.get(id, meToUserDtoMapper::map); @@ -79,8 +78,11 @@ public class MeResource { }) @TypeHint(TypeHint.NO_CONTENT.class) @Consumes(VndMediaType.PASSWORD_CHANGE) - public Response changePassword(PasswordChangeDto passwordChangeDto) throws NotFoundException, ConcurrentModificationException { + public Response changePassword(PasswordChangeDto passwordChangeDto) throws ConcurrentModificationException { String name = (String) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal(); + if (passwordChangeDto.getOldPassword() == null){ + throw new ChangePasswordNotAllowedException(ChangePasswordNotAllowedException.OLD_PASSWORD_REQUIRED); + } return adapter.changePassword(name, user -> user.clone().changePassword(passwordService.encryptPassword(passwordChangeDto.getNewPassword())), userManager.getChangePasswordChecker().andThen(getOldOriginalPasswordChecker(passwordChangeDto.getOldPassword()))); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java index af1ba3bf64..b1ea912acf 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java @@ -100,7 +100,7 @@ public class PermissionRootResource { @Produces(VndMediaType.PERMISSION) @TypeHint(PermissionDto.class) @Path("{permission-name}") - public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("permission-name") String permissionName) throws NotFoundException { + public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("permission-name") String permissionName) { Repository repository = load(namespace, name); RepositoryPermissions.permissionRead(repository).check(); return Response.ok( @@ -158,7 +158,7 @@ public class PermissionRootResource { public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("permission-name") String permissionName, - @Valid PermissionDto permission) throws NotFoundException, AlreadyExistsException { + @Valid PermissionDto permission) throws AlreadyExistsException { log.info("try to update the permission with name: {}. the modified permission is: {}", permissionName, permission); Repository repository = load(namespace, name); RepositoryPermissions.permissionWrite(repository).check(); @@ -198,7 +198,7 @@ public class PermissionRootResource { @Path("{permission-name}") public Response delete(@PathParam("namespace") String namespace, @PathParam("name") String name, - @PathParam("permission-name") String permissionName) throws NotFoundException { + @PathParam("permission-name") String permissionName) { log.info("try to delete the permission with name: {}.", permissionName); Repository repository = load(namespace, name); RepositoryPermissions.modify(repository).check(); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java index f9328525a9..56bb50d4e6 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java @@ -91,7 +91,7 @@ public class RepositoryResource { @ResponseCode(code = 404, condition = "not found, no repository with the specified name available in the namespace"), @ResponseCode(code = 500, condition = "internal server error") }) - public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name) throws NotFoundException { + public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name){ return adapter.get(loadBy(namespace, name), repositoryToDtoMapper::map); } @@ -138,7 +138,7 @@ public class RepositoryResource { @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryDto repositoryDto) throws NotFoundException, ConcurrentModificationException { + public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryDto repositoryDto) throws ConcurrentModificationException { return adapter.update( loadBy(namespace, name), existing -> processUpdate(repositoryDto, existing), diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java index 743d9f9710..b5763c4ff0 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java @@ -46,14 +46,14 @@ class SingleResourceManagerAdapter> reader, Function mapToDto) throws NotFoundException { + Response get(Supplier> reader, Function mapToDto) { return reader.get() .map(mapToDto) .map(Response::ok) .map(Response.ResponseBuilder::build) .orElseThrow(NotFoundException::new); } - public Response changePassword(Supplier> reader, Function applyChanges, Predicate hasSameKey, Consumer checker, Function permissionCheck) throws NotFoundException, ConcurrentModificationException { + public Response changePassword(Supplier> reader, Function applyChanges, Predicate hasSameKey, Consumer checker, Function permissionCheck) throws ConcurrentModificationException { MODEL_OBJECT existingModelObject = reader.get().orElseThrow(NotFoundException::new); MODEL_OBJECT changedModelObject = applyChanges.apply(existingModelObject); checkForUpdate(hasSameKey, existingModelObject, changedModelObject); @@ -65,7 +65,7 @@ class SingleResourceManagerAdapter> reader, Function applyChanges, Predicate hasSameKey) throws NotFoundException, ConcurrentModificationException { + public Response update(Supplier> reader, Function applyChanges, Predicate hasSameKey) throws ConcurrentModificationException { MODEL_OBJECT existingModelObject = reader.get().orElseThrow(NotFoundException::new); MODEL_OBJECT changedModelObject = applyChanges.apply(existingModelObject); checkForUpdate(hasSameKey, existingModelObject, changedModelObject); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java index 874ce4f568..e3cf17d3a4 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java @@ -47,7 +47,7 @@ public class SourceRootResource { @GET @Produces(VndMediaType.SOURCE) @Path("{revision}/{path: .*}") - public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision, @PathParam("path") String path) throws NotFoundException, IOException { + public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision, @PathParam("path") String path) throws IOException { return getSource(namespace, name, path, revision); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserResource.java index 8c87d1b2d7..e8d2b8617d 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserResource.java @@ -3,9 +3,10 @@ package sonia.scm.api.v2.resources; import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.TypeHint; +import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.credential.PasswordService; import sonia.scm.ConcurrentModificationException; -import sonia.scm.NotFoundException; +import sonia.scm.user.ChangePasswordNotAllowedException; import sonia.scm.user.User; import sonia.scm.user.UserManager; import sonia.scm.web.VndMediaType; @@ -57,7 +58,7 @@ public class UserResource { @ResponseCode(code = 404, condition = "not found, no user with the specified id/name available"), @ResponseCode(code = 500, condition = "internal server error") }) - public Response get(@PathParam("id") String id) throws NotFoundException { + public Response get(@PathParam("id") String id) { return adapter.get(id, userToDtoMapper::map); } @@ -102,7 +103,7 @@ public class UserResource { @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - public Response update(@PathParam("id") String name, @Valid UserDto userDto) throws NotFoundException, ConcurrentModificationException { + public Response update(@PathParam("id") String name, @Valid UserDto userDto) throws ConcurrentModificationException { return adapter.update(name, existing -> dtoToUserMapper.map(userDto, existing.getPassword())); } @@ -129,7 +130,11 @@ public class UserResource { @ResponseCode(code = 500, condition = "internal server error") }) @TypeHint(TypeHint.NO_CONTENT.class) - public Response changePassword(@PathParam("id") String name, @Valid PasswordChangeDto passwordChangeDto) throws NotFoundException, ConcurrentModificationException { + public Response changePassword(@PathParam("id") String name, @Valid PasswordChangeDto passwordChangeDto) throws ConcurrentModificationException { + String currentUserName = (String) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal(); + if (currentUserName.equals(name) && passwordChangeDto.getOldPassword() == null){ + throw new ChangePasswordNotAllowedException(ChangePasswordNotAllowedException.OLD_PASSWORD_REQUIRED); + } return adapter.changePassword(name, user -> user.changePassword(passwordService.encryptPassword(passwordChangeDto.getNewPassword())), userManager.getChangePasswordChecker()); } diff --git a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java index 327415ec22..a0ef2dbad5 100644 --- a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java +++ b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupManager.java @@ -125,7 +125,7 @@ public class DefaultGroupManager extends AbstractGroupManager } @Override - public void delete(Group group) throws NotFoundException { + public void delete(Group group){ logger.info("delete group {} of type {}", group.getName(), group.getType()); managerDaoAdapter.delete( group, @@ -145,7 +145,7 @@ public class DefaultGroupManager extends AbstractGroupManager public void init(SCMContextProvider context) {} @Override - public void modify(Group group) throws NotFoundException { + public void modify(Group group){ logger.info("modify group {} of type {}", group.getName(), group.getType()); managerDaoAdapter.modify( @@ -160,7 +160,7 @@ public class DefaultGroupManager extends AbstractGroupManager } @Override - public void refresh(Group group) throws NotFoundException { + public void refresh(Group group){ String name = group.getName(); if (logger.isInfoEnabled()) { diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java index 8cb325b818..c2e8bc3ad8 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java @@ -151,7 +151,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { } @Override - public void delete(Repository repository) throws NotFoundException { + public void delete(Repository repository){ logger.info("delete repository {}/{} of type {}", repository.getNamespace(), repository.getName(), repository.getType()); managerDaoAdapter.delete( repository, @@ -179,7 +179,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { } @Override - public void modify(Repository repository) throws NotFoundException { + public void modify(Repository repository){ logger.info("modify repository {}/{} of type {}", repository.getNamespace(), repository.getName(), repository.getType()); managerDaoAdapter.modify( diff --git a/scm-webapp/src/main/java/sonia/scm/repository/HealthChecker.java b/scm-webapp/src/main/java/sonia/scm/repository/HealthChecker.java index 52dea4223b..f943cc7151 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/HealthChecker.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/HealthChecker.java @@ -55,7 +55,7 @@ public final class HealthChecker { this.repositoryManager = repositoryManager; } - public void check(String id) throws NotFoundException { + public void check(String id){ RepositoryPermissions.healthCheck(id).check(); Repository repository = repositoryManager.get(id); @@ -68,7 +68,7 @@ public final class HealthChecker { } public void check(Repository repository) - throws NotFoundException, ConcurrentModificationException { + { RepositoryPermissions.healthCheck(repository).check(); doCheck(repository); @@ -94,7 +94,7 @@ public final class HealthChecker { } } - private void doCheck(Repository repository) throws NotFoundException { + private void doCheck(Repository repository){ logger.info("start health check for repository {}", repository.getName()); HealthCheckResult result = HealthCheckResult.healthy(); diff --git a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java index c9821575d2..9c9d89d341 100644 --- a/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java +++ b/scm-webapp/src/main/java/sonia/scm/user/DefaultUserManager.java @@ -159,7 +159,7 @@ public class DefaultUserManager extends AbstractUserManager } @Override - public void delete(User user) throws NotFoundException { + public void delete(User user) { logger.info("delete user {} of type {}", user.getName(), user.getType()); managerDaoAdapter.delete( user, @@ -195,12 +195,12 @@ public class DefaultUserManager extends AbstractUserManager * @throws IOException */ @Override - public void modify(User user) throws NotFoundException { + public void modify(User user) { modify(user,UserPermissions::modify); } @Override - public void modify(User user, Function permissionChecker) throws NotFoundException { + public void modify(User user, Function permissionChecker) { logger.info("modify user {} of type {}", user.getName(), user.getType()); managerDaoAdapter.modify( user, @@ -218,7 +218,7 @@ public class DefaultUserManager extends AbstractUserManager * @throws IOException */ @Override - public void refresh(User user) throws NotFoundException { + public void refresh(User user) { if (logger.isInfoEnabled()) { logger.info("refresh user {} of type {}", user.getName(), user.getType()); diff --git a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java index a67c275bc0..4a28c3bc83 100644 --- a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java @@ -152,7 +152,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { } @Test(expected = NotFoundException.class) - public void testDeleteNotFound() throws NotFoundException { + public void testDeleteNotFound(){ manager.delete(createRepositoryWithId()); } @@ -304,7 +304,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { } @Test - public void testModify() throws NotFoundException, AlreadyExistsException { + public void testModify() throws AlreadyExistsException { Repository heartOfGold = createTestRepository(); heartOfGold.setDescription("prototype ship"); @@ -328,12 +328,12 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { } @Test(expected = NotFoundException.class) - public void testModifyNotFound() throws NotFoundException { + public void testModifyNotFound(){ manager.modify(createRepositoryWithId()); } @Test - public void testRefresh() throws NotFoundException, AlreadyExistsException { + public void testRefresh() throws AlreadyExistsException { Repository heartOfGold = createTestRepository(); String description = heartOfGold.getDescription(); @@ -354,7 +354,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { } @Test(expected = RepositoryNotFoundException.class) - public void testRefreshNotFound() throws NotFoundException { + public void testRefreshNotFound(){ manager.refresh(createRepositoryWithId()); } @@ -495,7 +495,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { return createRepository(RepositoryTestData.createHeartOfGold()); } - private void delete(Manager manager, Repository repository) throws NotFoundException { + private void delete(Manager manager, Repository repository){ String id = repository.getId();