diff --git a/ccm-cms-archetype-contenttype/src/main/resources/archetype-resources/src/main/java/__typeName__.java b/ccm-cms-archetype-contenttype/src/main/resources/archetype-resources/src/main/java/__typeName__.java index 2b66e9eaf..5d99732f2 100644 --- a/ccm-cms-archetype-contenttype/src/main/resources/archetype-resources/src/main/java/__typeName__.java +++ b/ccm-cms-archetype-contenttype/src/main/resources/archetype-resources/src/main/java/__typeName__.java @@ -7,7 +7,7 @@ import static ${package}.${typeName}Constants.*; import org.hibernate.envers.Audited; -import org.libreccm.cms.contentsection.ContentItem; +import org.libreccm.contentsection.ContentItem; import java.io.Serializable; diff --git a/ccm-cms-archetype-contenttype/src/main/resources/archetype-resources/src/main/java/__typeName__Module.java b/ccm-cms-archetype-contenttype/src/main/resources/archetype-resources/src/main/java/__typeName__Module.java index 7e839c91f..03624b7f4 100644 --- a/ccm-cms-archetype-contenttype/src/main/resources/archetype-resources/src/main/java/__typeName__Module.java +++ b/ccm-cms-archetype-contenttype/src/main/resources/archetype-resources/src/main/java/__typeName__Module.java @@ -12,7 +12,7 @@ import org.libreccm.modules.ShutdownEvent; import org.libreccm.modules.UnInstallEvent; @Module(packageName="${package}", - requiredModules = {@RequiredModule(module = org.libreccm.core.CcmCore)}) + requiredModules = {@RequiredModule(module = org.libreccm.core.CcmCore.class)}) public class ${typeName}Module implements CcmModule { @Override diff --git a/ccm-cms-types-externallink/src/main/java/org/librecms/contenttypes/externallink/Externallink.java b/ccm-cms-types-externallink/src/main/java/org/librecms/contenttypes/externallink/Externallink.java index 8231ca1e7..4bf1cc4be 100644 --- a/ccm-cms-types-externallink/src/main/java/org/librecms/contenttypes/externallink/Externallink.java +++ b/ccm-cms-types-externallink/src/main/java/org/librecms/contenttypes/externallink/Externallink.java @@ -7,7 +7,7 @@ import static org.librecms.contenttypes.externallink.ExternallinkConstants.*; import org.hibernate.envers.Audited; -import org.libreccm.cms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItem; import java.io.Serializable; diff --git a/ccm-cms-types-externallink/src/main/java/org/librecms/contenttypes/externallink/ExternallinkModule.java b/ccm-cms-types-externallink/src/main/java/org/librecms/contenttypes/externallink/ExternallinkModule.java index 5a3c72f13..698b5c0b0 100644 --- a/ccm-cms-types-externallink/src/main/java/org/librecms/contenttypes/externallink/ExternallinkModule.java +++ b/ccm-cms-types-externallink/src/main/java/org/librecms/contenttypes/externallink/ExternallinkModule.java @@ -11,8 +11,9 @@ import org.libreccm.modules.RequiredModule; import org.libreccm.modules.ShutdownEvent; import org.libreccm.modules.UnInstallEvent; -@Module(packageName="org.librecms.contenttypes.externallink", - requiredModules = {@RequiredModule(module = org.libreccm.core.CcmCore)}) +@Module(packageName = "org.librecms.contenttypes.externallink", + requiredModules = { + @RequiredModule(module = org.libreccm.core.CcmCore.class)}) public class ExternallinkModule implements CcmModule { @Override @@ -23,7 +24,7 @@ public class ExternallinkModule implements CcmModule { @Override public void init(final InitEvent event) { //ToDo Add initialisation logic necessary for your module - } + } @Override public void shutdown(final ShutdownEvent event) { @@ -35,5 +36,4 @@ public class ExternallinkModule implements CcmModule { //ToDo Remove module data } - } diff --git a/ccm-cms-types-faqitem/src/main/java/org/librecms/contenttypes/faqitem/FAQitem.java b/ccm-cms-types-faqitem/src/main/java/org/librecms/contenttypes/faqitem/FAQitem.java index 3e7104199..2515a6caf 100644 --- a/ccm-cms-types-faqitem/src/main/java/org/librecms/contenttypes/faqitem/FAQitem.java +++ b/ccm-cms-types-faqitem/src/main/java/org/librecms/contenttypes/faqitem/FAQitem.java @@ -3,17 +3,16 @@ */ package org.librecms.contenttypes.faqitem; -import static org.librecms.contenttypes.faqitem.FAQitemConstants.*; - import org.hibernate.envers.Audited; - -import org.libreccm.cms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItem; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.Table; +import static org.librecms.contenttypes.faqitem.FAQitemConstants.*; + @Entity @Audited @Table(name = "${type_name}", schema = DB_SCHEMA) diff --git a/ccm-cms-types-faqitem/src/main/java/org/librecms/contenttypes/faqitem/FAQitemModule.java b/ccm-cms-types-faqitem/src/main/java/org/librecms/contenttypes/faqitem/FAQitemModule.java index edfa0a57a..2d2fad4a5 100644 --- a/ccm-cms-types-faqitem/src/main/java/org/librecms/contenttypes/faqitem/FAQitemModule.java +++ b/ccm-cms-types-faqitem/src/main/java/org/librecms/contenttypes/faqitem/FAQitemModule.java @@ -11,8 +11,9 @@ import org.libreccm.modules.RequiredModule; import org.libreccm.modules.ShutdownEvent; import org.libreccm.modules.UnInstallEvent; -@Module(packageName="org.librecms.contenttypes.faqitem", - requiredModules = {@RequiredModule(module = org.libreccm.core.CcmCore)}) +@Module(packageName = "org.librecms.contenttypes.faqitem", + requiredModules = { + @RequiredModule(module = org.libreccm.core.CcmCore.class)}) public class FAQitemModule implements CcmModule { @Override @@ -23,7 +24,7 @@ public class FAQitemModule implements CcmModule { @Override public void init(final InitEvent event) { //ToDo Add initialisation logic necessary for your module - } + } @Override public void shutdown(final ShutdownEvent event) { @@ -35,5 +36,4 @@ public class FAQitemModule implements CcmModule { //ToDo Remove module data } - } diff --git a/ccm-cms-types-glossaryitem/src/main/java/org/librecms/contenttypes/glossaryitem/Glossaryitem.java b/ccm-cms-types-glossaryitem/src/main/java/org/librecms/contenttypes/glossaryitem/Glossaryitem.java index ba0c14ab3..2d6ce5a1f 100644 --- a/ccm-cms-types-glossaryitem/src/main/java/org/librecms/contenttypes/glossaryitem/Glossaryitem.java +++ b/ccm-cms-types-glossaryitem/src/main/java/org/librecms/contenttypes/glossaryitem/Glossaryitem.java @@ -6,8 +6,7 @@ package org.librecms.contenttypes.glossaryitem; import static org.librecms.contenttypes.glossaryitem.GlossaryitemConstants.*; import org.hibernate.envers.Audited; - -import org.libreccm.cms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItem; import java.io.Serializable; diff --git a/ccm-cms-types-glossaryitem/src/main/java/org/librecms/contenttypes/glossaryitem/GlossaryitemModule.java b/ccm-cms-types-glossaryitem/src/main/java/org/librecms/contenttypes/glossaryitem/GlossaryitemModule.java index af3e1a083..35a2e2454 100644 --- a/ccm-cms-types-glossaryitem/src/main/java/org/librecms/contenttypes/glossaryitem/GlossaryitemModule.java +++ b/ccm-cms-types-glossaryitem/src/main/java/org/librecms/contenttypes/glossaryitem/GlossaryitemModule.java @@ -12,7 +12,7 @@ import org.libreccm.modules.ShutdownEvent; import org.libreccm.modules.UnInstallEvent; @Module(packageName="org.librecms.contenttypes.glossaryitem", - requiredModules = {@RequiredModule(module = org.libreccm.core.CcmCore)}) + requiredModules = {@RequiredModule(module = org.libreccm.core.CcmCore.class)}) public class GlossaryitemModule implements CcmModule { @Override diff --git a/ccm-cms-types-newsitem/src/main/java/org/librecms/contenttypes/newsitem/Newsitem.java b/ccm-cms-types-newsitem/src/main/java/org/librecms/contenttypes/newsitem/Newsitem.java index 215e9027f..06c9ce067 100644 --- a/ccm-cms-types-newsitem/src/main/java/org/librecms/contenttypes/newsitem/Newsitem.java +++ b/ccm-cms-types-newsitem/src/main/java/org/librecms/contenttypes/newsitem/Newsitem.java @@ -7,7 +7,7 @@ import static org.librecms.contenttypes.newsitem.NewsitemConstants.*; import org.hibernate.envers.Audited; -import org.libreccm.cms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItem; import java.io.Serializable; diff --git a/ccm-cms-types-newsitem/src/main/java/org/librecms/contenttypes/newsitem/NewsitemModule.java b/ccm-cms-types-newsitem/src/main/java/org/librecms/contenttypes/newsitem/NewsitemModule.java index 600d29afd..0637c7a79 100644 --- a/ccm-cms-types-newsitem/src/main/java/org/librecms/contenttypes/newsitem/NewsitemModule.java +++ b/ccm-cms-types-newsitem/src/main/java/org/librecms/contenttypes/newsitem/NewsitemModule.java @@ -12,7 +12,7 @@ import org.libreccm.modules.ShutdownEvent; import org.libreccm.modules.UnInstallEvent; @Module(packageName="org.librecms.contenttypes.newsitem", - requiredModules = {@RequiredModule(module = org.libreccm.core.CcmCore)}) + requiredModules = {@RequiredModule(module = org.libreccm.core.CcmCore.class)}) public class NewsitemModule implements CcmModule { @Override diff --git a/ccm-core/src/main/java/org/libreccm/security/AuthorizationInterceptor.java b/ccm-core/src/main/java/org/libreccm/security/AuthorizationInterceptor.java new file mode 100644 index 000000000..9d80d2655 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/security/AuthorizationInterceptor.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.shiro.subject.Subject; +import org.libreccm.core.CcmObject; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import javax.inject.Inject; +import javax.interceptor.AroundInvoke; +import javax.interceptor.Interceptor; +import javax.interceptor.InvocationContext; + +import org.libreccm.security.PermissionChecker; + +/** + * + * @author Jens Pelzetter + */ +@AuthorizationRequired +@Interceptor +public class AuthorizationInterceptor { + + private static final Logger LOGGER = LogManager.getLogger( + AuthorizationInterceptor.class); + + @Inject + private Subject subject; + + @Inject + private PermissionChecker permissionChecker; + + @AroundInvoke + public Object intercept(final InvocationContext context) throws Exception { + LOGGER.debug("Intercepting method invocation"); + + final Method method = context.getMethod(); + if (method == null) { + throw new IllegalArgumentException( + "The authoriziation interceptor can only be used for method"); + } + + if (method.isAnnotationPresent(RequiresRole.class)) { + final String requiredRole = method.getAnnotation(RequiresRole.class) + .value(); + subject.checkRoles(requiredRole); + } + + if (method.isAnnotationPresent(RequiresPrivilege.class)) { + final String requiredPrivilege = method.getAnnotation( + RequiresPrivilege.class).value(); + permissionChecker.checkPermission(requiredPrivilege); + } + + final Annotation[][] annotations = method.getParameterAnnotations(); + final Object[] parameters = context.getParameters(); + if (parameters != null && parameters.length > 0 + && annotations != null && annotations.length > 0) { + for (int i = 0; i < parameters.length; i++) { + checkParameterPermission(parameters[i], annotations[i]); + } + } + + return context.proceed(); + } + + private void checkParameterPermission(final Object parameter, + final Annotation[] annotations) { + if (parameter instanceof CcmObject + && annotations != null + && annotations.length > 0) { + final CcmObject object = (CcmObject) parameter; + + String requiredPrivilege = null; + for(Annotation annotation : annotations) { + if (annotation instanceof RequiresPrivilege) { + requiredPrivilege = ((RequiresPrivilege) annotation).value(); + break; + } + } + + if (requiredPrivilege != null && !requiredPrivilege.isEmpty()) { + permissionChecker.checkPermission(requiredPrivilege, object); + } + } + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/security/AuthorizationRequired.java b/ccm-core/src/main/java/org/libreccm/security/AuthorizationRequired.java new file mode 100644 index 000000000..f456accfd --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/security/AuthorizationRequired.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.interceptor.InterceptorBinding; + +/** + * + * @author Jens Pelzetter + */ +@Inherited +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@InterceptorBinding +public @interface AuthorizationRequired { + +} diff --git a/ccm-core/src/main/java/org/libreccm/security/RequiresPrivilege.java b/ccm-core/src/main/java/org/libreccm/security/RequiresPrivilege.java new file mode 100644 index 000000000..8765b0321 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/security/RequiresPrivilege.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Jens Pelzetter + */ +@Inherited +@Target({ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequiresPrivilege { + + String value(); + +} diff --git a/ccm-core/src/main/java/org/libreccm/security/RequiresRole.java b/ccm-core/src/main/java/org/libreccm/security/RequiresRole.java new file mode 100644 index 000000000..6030f18f8 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/security/RequiresRole.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Jens Pelzetter + */ +@Inherited +@Target({ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequiresRole { + + String value(); + +} diff --git a/ccm-core/src/main/resources/META-INF/beans.xml b/ccm-core/src/main/resources/META-INF/beans.xml new file mode 100644 index 000000000..d45765d18 --- /dev/null +++ b/ccm-core/src/main/resources/META-INF/beans.xml @@ -0,0 +1,11 @@ + + + + org.libreccm.security.AuthorizationInterceptor + + + diff --git a/ccm-core/src/test/java/org/libreccm/security/AuthorizationInterceptorTest.java b/ccm-core/src/test/java/org/libreccm/security/AuthorizationInterceptorTest.java new file mode 100644 index 000000000..a847c52fa --- /dev/null +++ b/ccm-core/src/test/java/org/libreccm/security/AuthorizationInterceptorTest.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security; + +import com.arsdigita.kernel.KernelConfig; +import com.arsdigita.kernel.security.SecurityConfig; +import com.arsdigita.runtime.AbstractConfig; +import com.arsdigita.util.UncheckedWrapperException; +import com.arsdigita.util.parameter.AbstractParameterContext; +import com.arsdigita.web.CCMApplicationContextListener; +import com.arsdigita.xml.XML; +import com.arsdigita.xml.formatters.DateTimeFormatter; + +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.authz.AuthorizationException; +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; +import org.jboss.arquillian.junit.InSequence; +import org.jboss.arquillian.persistence.CreateSchema; +import org.jboss.arquillian.persistence.PersistenceTest; +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; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.libreccm.categorization.Categorization; +import org.libreccm.core.CcmObject; +import org.libreccm.core.CcmObjectRepository; +import org.libreccm.jpa.EntityManagerProducer; +import org.libreccm.jpa.utils.MimeTypeConverter; +import org.libreccm.l10n.LocalizedString; +import org.libreccm.security.authorization.LabBean; +import org.libreccm.tests.categories.IntegrationTest; + +import org.libreccm.testutils.EqualsVerifier; +import org.libreccm.web.CcmApplication; + +import java.io.File; + +import javax.inject.Inject; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * + * @author Jens Pelzetter + */ +@Category(IntegrationTest.class) +@RunWith(Arquillian.class) +@PersistenceTest +@Transactional(TransactionMode.COMMIT) +@CreateSchema({"create_ccm_core_schema.sql"}) +public class AuthorizationInterceptorTest { + + @Inject + private Subject subject; + + @Inject + private CcmObjectRepository objectRepository; + + @Inject + private LabBean labBean; + + public AuthorizationInterceptorTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Deployment + public static WebArchive createDeployment() { + final PomEquippedResolveStage pom = Maven + .resolver() + .loadPomFromFile("pom.xml"); + final PomEquippedResolveStage dependencies = pom. + importCompileAndRuntimeDependencies(); + final File[] libs = dependencies.resolve().withTransitivity().asFile(); + + for (File lib : libs) { + System.err.printf("Adding file '%s' to test archive...%n", + lib.getName()); + } + + return ShrinkWrap + .create(WebArchive.class, + "LibreCCM-org.libreccm.security.PermissionCheckerTest.war") + .addPackage(User.class.getPackage()) + .addPackage(CcmObject.class.getPackage()) + .addPackage(Categorization.class.getPackage()) + .addPackage(LocalizedString.class.getPackage()) + .addPackage(CcmApplication.class.getPackage()) + .addPackage(EntityManagerProducer.class.getPackage()) + .addPackage(MimeTypeConverter.class.getPackage()) + .addPackage(EqualsVerifier.class.getPackage()) + .addPackage(IntegrationTest.class.getPackage()) + .addPackage(KernelConfig.class.getPackage()) + .addPackage(SecurityConfig.class.getPackage()) + .addPackage(AbstractConfig.class.getPackage()) + .addPackage(AbstractParameterContext.class.getPackage()) + .addPackage(UncheckedWrapperException.class.getPackage()) + .addPackage(CCMApplicationContextListener.class.getPackage()) + .addPackage(XML.class.getPackage()) + .addPackage(DateTimeFormatter.class.getPackage()) + .addPackage(LabBean.class.getPackage()) + .addAsLibraries(libs) + .addAsResource("test-persistence.xml", + "META-INF/persistence.xml") + .addAsResource("com/arsdigita/kernel/" + + "KernelConfig_parameter.properties", + "com/arsdigita/kernel/" + + "KernelConfig_parameter.properties") + .addAsResource("com/arsdigita/kernel/security/" + + "SecurityConfig_parameter.properties", + "com/arsdigita/kernel/security/" + + "SecurityConfig_parameter.properties") + .addAsWebInfResource( + "configs/org/libreccm/security/UserManagerTest/" + + "registry.properties", + "conf/registry/registry.properties") + .addAsResource( + "configs/org/libreccm/security/UserManagerTest/ccm-core.config", + "ccm-core.config") + .addAsResource( + "configs/org/libreccm/security/ShiroTest/shiro.ini", + "shiro.ini") + .addAsResource( + "configs/org/libreccm/security/ShiroTest/log4j2.xml", + "log4j2.xml") + .addAsWebInfResource( + "configs/org/libreccm/security/ShiroTest/" + + "kernel.properties", + "conf/registry/ccm-core/kernel.properties") + .addAsWebInfResource( + "configs/org/libreccm//security/ShiroTest/" + + "security.properties", + "conf/registry/ccm-core/security.properties") + .addAsWebInfResource("test-web.xml", "web.xml") + .addAsWebInfResource("META-INF/beans.xml", "beans.xml"); + } + + @Test + @InSequence(10) + public void labBeanIsInjected() { + assertThat(labBean, is(not(nullValue()))); + } + + @Test + @UsingDataSet("datasets/org/libreccm/security/ShiroTest/data.yml") + @InSequence(100) + public void checkRequiresRoleAuthorized() { + final UsernamePasswordToken token = new UsernamePasswordToken("mmuster", + "foo123"); + token.setRememberMe(true); + subject.login(token); + + labBean.doSomethingWhichRequiresRole(); + } + + @Test(expected = AuthorizationException.class) + @UsingDataSet("datasets/org/libreccm/security/ShiroTest/data.yml") + @ShouldThrowException(AuthorizationException.class) + @InSequence(200) + public void checkRequiresRoleNotAuthorized() { + final UsernamePasswordToken token = new UsernamePasswordToken("jdoe", + "foo123"); + token.setRememberMe(true); + subject.login(token); + + labBean.doSomethingWhichRequiresRole(); + } + + @Test + @UsingDataSet("datasets/org/libreccm/security/ShiroTest/data.yml") + @InSequence(300) + public void checkRequiresPermissionAuthorized() { + final UsernamePasswordToken token = new UsernamePasswordToken("mmuster", + "foo123"); + token.setRememberMe(true); + subject.login(token); + + labBean.doSomethingWhichRequiresPermission(); + } + + @Test(expected = AuthorizationException.class) + @UsingDataSet("datasets/org/libreccm/security/ShiroTest/data.yml") + @ShouldThrowException(AuthorizationException.class) + @InSequence(400) + public void checkRequiresPermissionNotAuthorized() { + final UsernamePasswordToken token = new UsernamePasswordToken("jdoe", + "foo123"); + token.setRememberMe(true); + subject.login(token); + + labBean.doSomethingWhichRequiresPermission(); + } + + @Test + @UsingDataSet("datasets/org/libreccm/security/ShiroTest/data.yml") + @InSequence(500) + public void checkRequiresPermissionOnObjectAuthorized() { + final UsernamePasswordToken token = new UsernamePasswordToken("mmuster", + "foo123"); + token.setRememberMe(true); + subject.login(token); + + final CcmObject object1 = objectRepository.findById(-20001L); + + labBean.doSomethingWhichRequiresPermissionOnObject(object1); + } + + @Test(expected = AuthorizationException.class) + @UsingDataSet("datasets/org/libreccm/security/ShiroTest/data.yml") + @ShouldThrowException(AuthorizationException.class) + @InSequence(600) + public void checkRequiresPermissionOnObjectNotAuthorized() { + final UsernamePasswordToken token = new UsernamePasswordToken("jdoe", + "foo123"); + token.setRememberMe(true); + subject.login(token); + + final CcmObject object1 = objectRepository.findById(-20001L); + + labBean.doSomethingWhichRequiresPermissionOnObject(object1); + } + +} diff --git a/ccm-core/src/test/java/org/libreccm/security/authorization/LabBean.java b/ccm-core/src/test/java/org/libreccm/security/authorization/LabBean.java new file mode 100644 index 000000000..30ad99e7f --- /dev/null +++ b/ccm-core/src/test/java/org/libreccm/security/authorization/LabBean.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.security.authorization; + +import org.apache.shiro.subject.Subject; +import org.libreccm.core.CcmObject; +import org.libreccm.security.AuthorizationInterceptorTest; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.RequiresPrivilege; +import org.libreccm.security.RequiresRole; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * A simple bean used by the {@link AuthorizationInterceptorTest}. + * + * @author Jens Pelzetter + */ +@RequestScoped +public class LabBean { + + @Inject + private Subject subject; + + @AuthorizationRequired + @RequiresRole("role1") + public void doSomethingWhichRequiresRole() { + assertThat(subject.hasRole("role1"), is(true)); + } + + @AuthorizationRequired + @RequiresPrivilege("privilege1") + public void doSomethingWhichRequiresPermission() { + assertThat(subject.isPermitted("privilege1"), is(true)); + } + + @AuthorizationRequired + public void doSomethingWhichRequiresPermissionOnObject( + @RequiresPrivilege("privilege2") + final CcmObject object) { + assertThat(subject.isPermitted( + String.format("privilege2:%d", object.getObjectId())), + is(true)); + } +} diff --git a/pom.xml b/pom.xml index fc1a6efab..240b5d918 100644 --- a/pom.xml +++ b/pom.xml @@ -53,11 +53,11 @@ ccm-cms-types-event ccm-cms-types-minutes ccm-cms-types-decisiontree - ccm-cms-types-mparticle - ccm-cms-types-glossaryitem - ccm-cms-types-faqitem - ccm-cms-types-externallink - ccm-cms-types-newsitem + ccm-cms-types-mparticle + ccm-cms-types-glossaryitem + ccm-cms-types-faqitem + ccm-cms-types-externallink + ccm-cms-types-newsitem