diff --git a/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java b/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java index dbe7b1b3a..506538bc6 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java @@ -22,7 +22,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.shiro.subject.Subject; import org.libreccm.core.AbstractEntityRepository; +import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.PermissionChecker; +import org.libreccm.security.RequiresPrivilege; import java.util.List; import java.util.Optional; @@ -45,10 +47,10 @@ public class CategoryRepository extends AbstractEntityRepository @Inject private DomainRepository domainRepo; - + @Inject private PermissionChecker permissionChecker; - + @Inject private Subject subject; @@ -160,16 +162,22 @@ public class CategoryRepository extends AbstractEntityRepository return current; } - - @Override + + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) - public void save(final Category category) { + @Override + public void save( + @RequiresPrivilege("manage_categories") final Category category) { super.save(category); } - - @Override + + @AuthorizationRequired + @RequiresPrivilege("manage_categories") @Transactional(Transactional.TxType.REQUIRED) + @Override public void delete(final Category category) { super.save(category); } + } diff --git a/ccm-core/src/main/java/org/libreccm/security/GroupRepository.java b/ccm-core/src/main/java/org/libreccm/security/GroupRepository.java index f04aa441a..f121f6d6f 100644 --- a/ccm-core/src/main/java/org/libreccm/security/GroupRepository.java +++ b/ccm-core/src/main/java/org/libreccm/security/GroupRepository.java @@ -85,28 +85,37 @@ public class GroupRepository extends AbstractEntityRepository { return query.getResultList(); } - - public List findAllOrderedByGroupName() { final TypedQuery query = getEntityManager().createNamedQuery( - "Group.findAllOrderedByGroupName", Group.class); + "Group.findAllOrderedByGroupName", Group.class); return query.getResultList(); } - - @Override + + @AuthorizationRequired + @RequiresPrivilege("admin") @Transactional(Transactional.TxType.REQUIRED) + @Override + public void save(final Group group) { + super.save(group); + } + + @AuthorizationRequired + @RequiresPrivilege("admin") + @Transactional(Transactional.TxType.REQUIRED) + @Override public void delete(final Group entity) { if (entity == null) { throw new IllegalArgumentException("Can't delete null"); } - - final Group delete = getEntityManager().find(Group.class, + + final Group delete = getEntityManager().find(Group.class, entity.getPartyId()); - + delete.getMemberships().forEach(m -> { getEntityManager().remove(m); }); - + getEntityManager().remove(delete); } + } diff --git a/ccm-core/src/main/java/org/libreccm/security/RoleRepository.java b/ccm-core/src/main/java/org/libreccm/security/RoleRepository.java index ad4bacc8b..c5c387362 100644 --- a/ccm-core/src/main/java/org/libreccm/security/RoleRepository.java +++ b/ccm-core/src/main/java/org/libreccm/security/RoleRepository.java @@ -81,6 +81,16 @@ public class RoleRepository extends AbstractEntityRepository { return query.getResultList(); } + @AuthorizationRequired + @RequiresPrivilege("admin") + @Transactional(Transactional.TxType.REQUIRED) + @Override + public void save(final Role role) { + super.save(role); + } + + @AuthorizationRequired + @RequiresPrivilege("admin") @Override @Transactional(Transactional.TxType.REQUIRED) public void delete(final Role role) { diff --git a/ccm-core/src/main/java/org/libreccm/web/ApplicationRepository.java b/ccm-core/src/main/java/org/libreccm/web/ApplicationRepository.java index 8ceaa5ff7..01e540e92 100644 --- a/ccm-core/src/main/java/org/libreccm/web/ApplicationRepository.java +++ b/ccm-core/src/main/java/org/libreccm/web/ApplicationRepository.java @@ -18,13 +18,17 @@ */ package org.libreccm.web; +import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.libreccm.core.AbstractEntityRepository; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.RequiresPrivilege; import java.util.List; import javax.enterprise.context.RequestScoped; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; +import javax.transaction.Transactional; /** * @@ -80,5 +84,21 @@ public class ApplicationRepository return query.getResultList(); } + + @AuthorizationRequired + @RequiresPrivilege("admin") + @Transactional(Transactional.TxType.REQUIRED) + @Override + public void save(final CcmApplication application) { + super.save(application); + } + + @AuthorizationRequired + @RequiresPrivilege("admin") + @Transactional(Transactional.TxType.REQUIRED) + @Override + public void delete(final CcmApplication application) { + super.delete(application); + } } diff --git a/ccm-core/src/test/java/org/libreccm/categorization/CategoryRepositoryTest.java b/ccm-core/src/test/java/org/libreccm/categorization/CategoryRepositoryTest.java index f9244e98c..1e0944bb4 100644 --- a/ccm-core/src/test/java/org/libreccm/categorization/CategoryRepositoryTest.java +++ b/ccm-core/src/test/java/org/libreccm/categorization/CategoryRepositoryTest.java @@ -18,6 +18,10 @@ */ package org.libreccm.categorization; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.authz.UnauthorizedException; +import org.apache.shiro.subject.Subject; + import java.io.File; import javax.inject.Inject; @@ -34,8 +38,8 @@ import org.jboss.arquillian.persistence.ShouldMatchDataSet; import org.jboss.arquillian.persistence.UsingDataSet; import org.jboss.arquillian.transaction.api.annotation.TransactionMode; import org.jboss.arquillian.transaction.api.annotation.Transactional; +import org.jboss.sasl.util.UsernamePasswordHashUtil; import org.jboss.shrinkwrap.api.ShrinkWrap; -import org.jboss.shrinkwrap.api.asset.EmptyAsset; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.shrinkwrap.resolver.api.maven.Maven; import org.jboss.shrinkwrap.resolver.api.maven.PomEquippedResolveStage; @@ -45,8 +49,11 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import org.libreccm.security.Shiro; import org.libreccm.tests.categories.IntegrationTest; +import javax.ws.rs.NotAuthorizedException; + import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; @@ -66,6 +73,12 @@ public class CategoryRepositoryTest { @Inject private DomainRepository domainRepo; + + @Inject + private Shiro shiro; + + @Inject + private Subject subject; @PersistenceContext(name = "LibreCCM") private EntityManager entityManager; @@ -117,16 +130,21 @@ public class CategoryRepositoryTest { .getPackage()) .addPackage(org.libreccm.l10n.LocalizedString.class.getPackage()) .addPackage(org.libreccm.security.Permission.class.getPackage()) - .addPackage(org.libreccm.testutils.EqualsVerifier.class.getPackage()) + .addPackage(org.libreccm.testutils.EqualsVerifier.class + .getPackage()) .addPackage(org.libreccm.tests.categories.IntegrationTest.class .getPackage()) .addPackage(org.libreccm.web.CcmApplication.class.getPackage()) .addPackage(org.libreccm.workflow.Workflow.class.getPackage()) + .addPackage(org.libreccm.cdi.utils.CdiUtil.class.getPackage()) + .addClass(com.arsdigita.kernel.KernelConfig.class) + .addClass(com.arsdigita.kernel.security.SecurityConfig.class) .addAsLibraries(libs) + .addAsResource("configs/shiro.ini", "shiro.ini") .addAsResource("test-persistence.xml", "META-INF/persistence.xml") - .addAsWebInfResource("test-web.xml", "WEB-INF/web.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml"); + .addAsWebInfResource("test-web.xml", "web.xml") + .addAsWebInfResource("META-INF/beans.xml", "beans.xml"); } @Test @@ -250,6 +268,44 @@ public class CategoryRepositoryTest { category.setName("new-category"); category.setUniqueId("new0001"); + shiro.getSystemUser().execute(() -> categoryRepo.save(category)); + } + + @Test + @UsingDataSet( + "datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml") + @ShouldMatchDataSet( + value = "datasets/org/libreccm/categorization/CategoryRepositoryTest/" + + "after-save-new-category.yml", + excludeColumns = {"object_id", "uuid"}) + @InSequence(3200) + public void saveNewCategoryGlobalAuth() { + final UsernamePasswordToken token = new UsernamePasswordToken( + "john.doe@example.org", "foo123"); + token.setRememberMe(true); + subject.login(token); + + final Category category = new Category(); + category.setDisplayName("new-category"); + category.setName("new-category"); + category.setUniqueId("new0001"); + + categoryRepo.save(category); + + subject.logout(); + } + + @Test(expected = UnauthorizedException.class) + @UsingDataSet( + "datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml") + @ShouldThrowException(UnauthorizedException.class) + @InSequence(3400) + public void saveNewCategoryNotAuthorized() { + final Category category = new Category(); + category.setDisplayName("new-category"); + category.setName("new-category"); + category.setUniqueId("new0001"); + categoryRepo.save(category); } diff --git a/ccm-core/src/test/java/org/libreccm/security/GroupRepositoryTest.java b/ccm-core/src/test/java/org/libreccm/security/GroupRepositoryTest.java index b0fda54da..13b8263df 100644 --- a/ccm-core/src/test/java/org/libreccm/security/GroupRepositoryTest.java +++ b/ccm-core/src/test/java/org/libreccm/security/GroupRepositoryTest.java @@ -126,14 +126,16 @@ public class GroupRepositoryTest { .getPackage()) .addPackage(org.libreccm.jpa.utils.MimeTypeConverter.class .getPackage()) - .addPackage(org.libreccm.testutils.EqualsVerifier.class.getPackage()) + .addPackage(org.libreccm.testutils.EqualsVerifier.class + .getPackage()) .addPackage(org.libreccm.tests.categories.IntegrationTest.class .getPackage()) .addAsLibraries(libs) + .addAsResource("configs/shiro.ini", "shiro.ini") .addAsResource("test-persistence.xml", "META-INF/persistence.xml") - .addAsWebInfResource("test-web.xml", "WEB-INF/web.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml"); + .addAsWebInfResource("test-web.xml", "web.xml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); } @Test diff --git a/ccm-core/src/test/java/org/libreccm/security/PartyRepositoryTest.java b/ccm-core/src/test/java/org/libreccm/security/PartyRepositoryTest.java index 9bbd9339a..f6b04eecc 100644 --- a/ccm-core/src/test/java/org/libreccm/security/PartyRepositoryTest.java +++ b/ccm-core/src/test/java/org/libreccm/security/PartyRepositoryTest.java @@ -18,6 +18,7 @@ */ package org.libreccm.security; +import org.apache.shiro.subject.Subject; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.ShouldThrowException; import org.jboss.arquillian.junit.Arquillian; @@ -29,7 +30,6 @@ import org.jboss.arquillian.persistence.UsingDataSet; import org.jboss.arquillian.transaction.api.annotation.TransactionMode; import org.jboss.arquillian.transaction.api.annotation.Transactional; import org.jboss.shrinkwrap.api.ShrinkWrap; -import org.jboss.shrinkwrap.api.asset.EmptyAsset; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.shrinkwrap.resolver.api.maven.Maven; import org.jboss.shrinkwrap.resolver.api.maven.PomEquippedResolveStage; @@ -72,6 +72,9 @@ public class PartyRepositoryTest { @Inject private PartyRepository partyRepository; + @Inject + private Shiro shiro; + @PersistenceContext private EntityManager entityManager; @@ -115,23 +118,30 @@ public class PartyRepositoryTest { .addPackage(org.libreccm.core.CcmObject.class.getPackage()) .addPackage(org.libreccm.categorization.Categorization.class .getPackage()) - .addPackage(org.libreccm.configuration.ConfigurationManager.class + .addPackage( + org.libreccm.configuration.ConfigurationManager.class + .getPackage()) + .addPackage(org.libreccm.l10n.LocalizedString.class .getPackage()) - .addPackage(org.libreccm.l10n.LocalizedString.class.getPackage()) .addPackage(org.libreccm.web.CcmApplication.class.getPackage()) .addPackage(org.libreccm.workflow.Workflow.class.getPackage()) .addPackage(org.libreccm.jpa.EntityManagerProducer.class .getPackage()) .addPackage(org.libreccm.jpa.utils.MimeTypeConverter.class .getPackage()) - .addPackage(org.libreccm.testutils.EqualsVerifier.class.getPackage()) + .addPackage(org.libreccm.testutils.EqualsVerifier.class. + getPackage()) .addPackage(org.libreccm.tests.categories.IntegrationTest.class .getPackage()) + .addClass(com.arsdigita.kernel.security.SecurityConfig.class) + .addClass(com.arsdigita.kernel.KernelConfig.class) + .addPackage(org.libreccm.cdi.utils.CdiUtil.class.getPackage()) .addAsLibraries(libs) + .addAsResource("configs/shiro.ini", "shiro.ini") .addAsResource("test-persistence.xml", "META-INF/persistence.xml") - .addAsWebInfResource("test-web.xml", "WEB-INF/web.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml"); + .addAsWebInfResource("test-web.xml", "web.xml") + .addAsWebInfResource("META-INF/beans.xml", "beans.xml"); } @Test @@ -218,12 +228,13 @@ public class PartyRepositoryTest { "$shiro1$SHA-512$500000$Y7CnccN1h25sR7KCElMOXg==$CVLWBhetodaEzzhDfGjRcCFZtSW02xOnjH7xhBx0lbxO66grKIt6LWmXoUhLEydce1JZ7cbzNLYOxIwwTeqi5Q=="); mmuster.setPasswordResetRequired(false); - partyRepository.save(mmuster); + final Subject system = shiro.getSystemUser(); + system.execute(() -> partyRepository.save(mmuster)); final Group users = new Group(); users.setName("users"); - partyRepository.save(users); + system.execute(() -> partyRepository.save(users)); } @Test @@ -240,15 +251,17 @@ public class PartyRepositoryTest { user.setName("johndoe"); group.setName("managers"); - partyRepository.save(user); - partyRepository.save(group); + shiro.getSystemUser().execute(() -> { + partyRepository.save(user); + partyRepository.save(group); + }); } @Test(expected = IllegalArgumentException.class) @ShouldThrowException(IllegalArgumentException.class) @InSequence(500) public void saveNullValue() { - partyRepository.save(null); + shiro.getSystemUser().execute(() -> partyRepository.save(null)); } @Test @@ -260,14 +273,14 @@ public class PartyRepositoryTest { public void deleteParty() { final Party user = partyRepository.findById(-10L); - partyRepository.delete(user); + shiro.getSystemUser().execute(() -> partyRepository.delete(user)); } @Test(expected = IllegalArgumentException.class) @ShouldThrowException(IllegalArgumentException.class) @InSequence(700) public void deleteNullValue() { - partyRepository.delete(null); + shiro.getSystemUser().execute(() -> partyRepository.delete(null)); } } diff --git a/ccm-core/src/test/java/org/libreccm/security/RoleRepositoryTest.java b/ccm-core/src/test/java/org/libreccm/security/RoleRepositoryTest.java index 3d6b52367..f597f8f07 100644 --- a/ccm-core/src/test/java/org/libreccm/security/RoleRepositoryTest.java +++ b/ccm-core/src/test/java/org/libreccm/security/RoleRepositoryTest.java @@ -53,7 +53,9 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; /** - * + * Tests for the {@link RoleRepository}. Note. We are not enabling the + * {@link AuthorizationInterceptor} for this test. + * * @author Jens Pelzetter */ @Category(IntegrationTest.class) @@ -126,10 +128,11 @@ public class RoleRepositoryTest { .addPackage(org.libreccm.tests.categories.IntegrationTest.class .getPackage()) .addAsLibraries(libs) + .addAsResource("configs/shiro.ini", "shiro.ini") .addAsResource("test-persistence.xml", "META-INF/persistence.xml") - .addAsWebInfResource("test-web.xml", "WEB-INF/web.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml"); + .addAsWebInfResource("test-web.xml", "web.xml") + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); } @Test diff --git a/ccm-core/src/test/java/org/libreccm/security/UserRepositoryTest.java b/ccm-core/src/test/java/org/libreccm/security/UserRepositoryTest.java index ae7f488e0..fb8064bc1 100644 --- a/ccm-core/src/test/java/org/libreccm/security/UserRepositoryTest.java +++ b/ccm-core/src/test/java/org/libreccm/security/UserRepositoryTest.java @@ -75,6 +75,9 @@ public class UserRepositoryTest { @Inject private UserRepository userRepository; + @Inject + private Shiro shiro; + @PersistenceContext private EntityManager entityManager; @@ -127,14 +130,19 @@ public class UserRepositoryTest { .getPackage()) .addPackage(org.libreccm.jpa.utils.MimeTypeConverter.class .getPackage()) - .addPackage(org.libreccm.testutils.EqualsVerifier.class.getPackage()) + .addPackage(org.libreccm.testutils.EqualsVerifier.class + .getPackage()) .addPackage(org.libreccm.tests.categories.IntegrationTest.class .getPackage()) + .addClass(com.arsdigita.kernel.security.SecurityConfig.class) + .addClass(com.arsdigita.kernel.KernelConfig.class) + .addPackage(org.libreccm.cdi.utils.CdiUtil.class.getPackage()) .addAsLibraries(libs) + .addAsResource("configs/shiro.ini", "shiro.ini") .addAsResource("test-persistence.xml", "META-INF/persistence.xml") - .addAsWebInfResource("test-web.xml", "WEB-INF/web.xml") - .addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml"); + .addAsWebInfResource("test-web.xml", "web.xml") + .addAsWebInfResource("META-INF/beans.xml", "beans.xml"); } @Test @@ -264,7 +272,7 @@ public class UserRepositoryTest { "$shiro1$SHA-512$500000$24lA090z7GKYr4VFlZ6t4A==$/heoTHPA5huT1UfJ8Q+waXEG6AjUKhFYLFrj7KW/l0/z9O+QkiZTtfPfbcPblgjcEvrROMEIoQY4Z65S7rFLQg=="); user.setPasswordResetRequired(false); - userRepository.save(user); + shiro.getSystemUser().execute(() -> userRepository.save(user)); } @Test @@ -286,14 +294,14 @@ public class UserRepositoryTest { emailAddress.setVerified(true); user.setPrimaryEmailAddress(emailAddress); - userRepository.save(user); + shiro.getSystemUser().execute(() -> userRepository.save(user)); } @Test(expected = IllegalArgumentException.class) @ShouldThrowException(IllegalArgumentException.class) @InSequence(700) public void saveNullValue() { - userRepository.save(null); + shiro.getSystemUser().execute(() -> userRepository.save(null)); } @Test @@ -305,14 +313,14 @@ public class UserRepositoryTest { public void deleteUser() { final User user = userRepository.findByName("mmuster"); - userRepository.delete(user); + shiro.getSystemUser().execute(() -> userRepository.delete(user)); } @Test(expected = IllegalArgumentException.class) @ShouldThrowException(IllegalArgumentException.class) @InSequence(900) public void deleteNullValue() { - userRepository.delete(null); + shiro.getSystemUser().execute(() -> userRepository.delete(null)); } } diff --git a/ccm-core/src/test/resources/datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml b/ccm-core/src/test/resources/datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml index 06f866094..605c3782b 100644 --- a/ccm-core/src/test/resources/datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml +++ b/ccm-core/src/test/resources/datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml @@ -43,4 +43,62 @@ ccm_core.category_domains: root_category_id: -2000 uri: http://libreccm.org/test version: 1.0 + +ccm_core.parties: + - party_id: -100 + name: public-user + - party_id: -200 + name: jdoe + - party_id: -300 + name: mmuster + +ccm_core.users: + - party_id: -100 + given_name: public + family_name: user + email_address: public-user@localhost + banned: false + bouncing: false + verified: true + password_reset_required: false + - party_id: -200 + given_name: John + family_name: Doe + email_address: john.doe@example.org + password: $shiro1$SHA-512$500000$Y7CnccN1h25sR7KCElMOXg==$CVLWBhetodaEzzhDfGjRcCFZtSW02xOnjH7xhBx0lbxO66grKIt6LWmXoUhLEydce1JZ7cbzNLYOxIwwTeqi5Q== + banned: false + bouncing: false + verified: true + password_reset_required: false + - party_id: -300 + given_name: Max + family_name: Mustermann + email_address: max.mustermann@example.org + password: $shiro1$SHA-512$500000$Y7CnccN1h25sR7KCElMOXg==$CVLWBhetodaEzzhDfGjRcCFZtSW02xOnjH7xhBx0lbxO66grKIt6LWmXoUhLEydce1JZ7cbzNLYOxIwwTeqi5Q== + banned: false + bouncing: false + verified: true + password_reset_required: false +ccm_core.ccm_roles: + - role_id: -500 + name: category_manager + - role_id: -510 + name: category_manager_domain_test + +ccm_core.role_memberships: + - membership_id: -600 + role_id: -500 + member_id: -200 + - membership_id: -610 + role_id: -510 + member_id: -300 + +ccm_core.permissions: + - permission_id: -700 + granted_privilege: manage_categories + grantee_id: -500 + - permission_id: -710 + granted_privilege: manage_categories + grantee_id: -510 + object_id: -1000