From a5d2cfc7b14ba15c485003649e8b7bf5ce08d91f Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 30 Sep 2016 19:42:54 +0200 Subject: [PATCH] unit test and javadoc for RepositoryPermissions --- pom.xml | 3 + .../scm/repository/RepositoryPermissions.java | 135 +++++------ .../repository/RepositoryPermissionsTest.java | 224 ++++++++++++++++++ .../scm/repository/repository-permissions.ini | 6 + 4 files changed, 294 insertions(+), 74 deletions(-) create mode 100644 scm-core/src/test/java/sonia/scm/repository/RepositoryPermissionsTest.java create mode 100644 scm-core/src/test/resources/sonia/scm/repository/repository-permissions.ini diff --git a/pom.xml b/pom.xml index 712e47fde9..652e4ef2c0 100644 --- a/pom.xml +++ b/pom.xml @@ -198,6 +198,8 @@ true ${project.build.javaLevel} ${project.build.javaLevel} + ${project.test.javaLevel} + ${project.test.javaLevel} ${project.build.sourceEncoding} 1.7 + 1.8 UTF-8 SCM-BSD diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermissions.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermissions.java index 001034f606..a0cf08cdc1 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermissions.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermissions.java @@ -37,6 +37,7 @@ import sonia.scm.security.PermissionActionCheck; import sonia.scm.security.PermissionCheck; /** + * Permission checks for repository related permissions. * * @author Sebastian Sdorra * @since 2.0.0 @@ -44,30 +45,31 @@ import sonia.scm.security.PermissionCheck; public final class RepositoryPermissions { - /** Field description */ + /** create permission */ public static final String ACTION_CREATE = "create"; - /** Field description */ + /** delete permission */ public static final String ACTION_DELETE = "delete"; - /** Field description */ + /** modify permission */ public static final String ACTION_MODIFY = "modify"; - /** Field description */ + /** health check permission implies modify permission */ public static final String ACTION_HC = "hc,".concat(ACTION_MODIFY); - /** Field description */ + /** read permission */ public static final String ACTION_READ = "read"; - /** Field description */ + /** write permission */ public static final String ACTION_WRITE = "write"; - /** Field description */ - public static final String SEPERATOR = ":"; + /** permission separator */ + public static final String SEPARATOR = ":"; + /** permission action separator */ public static final String SEPERATOR_ACTION = ","; - /** Field description */ + /** permission main type */ public static final String TYPE = "repository"; //~--- constructors --------------------------------------------------------- @@ -77,10 +79,9 @@ public final class RepositoryPermissions //~--- methods -------------------------------------------------------------- /** - * Method description + * Returns permission check for create action. * - * - * @return + * @return permission check for create action */ public static PermissionCheck create() { @@ -88,12 +89,11 @@ public final class RepositoryPermissions } /** - * Method description + * Returns permission check for delete action. * + * @param r repository for permission check * - * @param r - * - * @return + * @return permission check for delete action */ public static PermissionCheck delete(Repository r) { @@ -101,23 +101,21 @@ public final class RepositoryPermissions } /** - * Method description + * Returns permission check for delete action. * + * @param id id of repository for permission check * - * @param id - * - * @return + * @return permission check for delete action */ public static PermissionCheck delete(String id) { - return check(ACTION_DELETE.concat(SEPERATOR).concat(id)); + return check(ACTION_DELETE.concat(SEPARATOR).concat(id)); } /** - * Method description + * Returns permission action check for delete action. * - * - * @return + * @return permission action check for delete action */ public static PermissionActionCheck delete() { @@ -125,37 +123,34 @@ public final class RepositoryPermissions } /** - * Method description + * Returns permission check for health check action. * + * @param id id of repository for permission check * - * @param id - * - * @return + * @return permission check for health check action */ public static PermissionCheck healthCheck(String id) { - return check(ACTION_HC.concat(SEPERATOR).concat(id)); + return check(ACTION_HC.concat(SEPARATOR).concat(id)); } /** - * Method description + * Returns permission action check for health check action. * - * - * @return + * @return permission action check for health check action. */ public static PermissionActionCheck healthCheck() { return new PermissionActionCheck<>( - TYPE.concat(SEPERATOR).concat(ACTION_HC)); + TYPE.concat(SEPARATOR).concat(ACTION_HC)); } /** - * Method description + * Returns permission check for health check action. * + * @param r repository for permission check * - * @param r - * - * @return + * @return permission check for health check action */ public static PermissionCheck healthCheck(Repository r) { @@ -163,12 +158,11 @@ public final class RepositoryPermissions } /** - * Method description + * Returns permission action check for modify action. * + * @param r repository for permission check * - * @param r - * - * @return + * @return permission action check for modify action */ public static PermissionCheck modify(Repository r) { @@ -176,23 +170,22 @@ public final class RepositoryPermissions } /** - * Method description + * Returns permission action check for modify action. * * - * @param id + * @param id id of repository for permission check * - * @return + * @return permission action check for modify action */ public static PermissionCheck modify(String id) { - return check(ACTION_MODIFY.concat(SEPERATOR).concat(id)); + return check(ACTION_MODIFY.concat(SEPARATOR).concat(id)); } /** - * Method description + * Returns permission action check for modify action. * - * - * @return + * @return permission action check for modify action */ public static PermissionActionCheck modify() { @@ -200,25 +193,23 @@ public final class RepositoryPermissions } /** - * Method description + * Returns permission check for read action. * + * @param id id of repository for permission check * - * @param id - * - * @return + * @return permission check for read action */ public static PermissionCheck read(String id) { - return check(ACTION_READ.concat(SEPERATOR).concat(id)); + return check(ACTION_READ.concat(SEPARATOR).concat(id)); } /** - * Method description + * Returns permission check for read action. * + * @param r repository for permission check * - * @param r - * - * @return + * @return permission check for read action */ public static PermissionCheck read(Repository r) { @@ -226,10 +217,9 @@ public final class RepositoryPermissions } /** - * Method description + * Returns permission action check for read action. * - * - * @return + * @return permission action check for read action */ public static PermissionActionCheck read() { @@ -237,25 +227,23 @@ public final class RepositoryPermissions } /** - * Method description + * Returns permission check for write action. * + * @param id id of repository for permission check * - * @param id - * - * @return + * @return permission check for write action */ public static PermissionCheck write(String id) { - return check(ACTION_WRITE.concat(SEPERATOR).concat(id)); + return check(ACTION_WRITE.concat(SEPARATOR).concat(id)); } /** - * Method description + * Returns permission check for write action. * + * @param r repository for permission check * - * @param r - * - * @return + * @return permission check for write action */ public static PermissionCheck write(Repository r) { @@ -263,10 +251,9 @@ public final class RepositoryPermissions } /** - * Method description + * Return permission action check for write action. * - * - * @return + * @return permission action check for write action */ public static PermissionActionCheck write() { @@ -275,11 +262,11 @@ public final class RepositoryPermissions private static PermissionActionCheck actionCheck(String action) { - return new PermissionActionCheck<>(TYPE.concat(SEPERATOR).concat(action)); + return new PermissionActionCheck<>(TYPE.concat(SEPARATOR).concat(action)); } private static PermissionCheck check(String permission) { - return new PermissionCheck(TYPE.concat(SEPERATOR).concat(permission)); + return new PermissionCheck(TYPE.concat(SEPARATOR).concat(permission)); } } diff --git a/scm-core/src/test/java/sonia/scm/repository/RepositoryPermissionsTest.java b/scm-core/src/test/java/sonia/scm/repository/RepositoryPermissionsTest.java new file mode 100644 index 0000000000..4457941c52 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/RepositoryPermissionsTest.java @@ -0,0 +1,224 @@ +/** + * Copyright (c) 2014, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ +package sonia.scm.repository; + +import com.github.sdorra.shiro.ShiroRule; +import com.github.sdorra.shiro.SubjectAware; +import java.util.function.Supplier; +import org.apache.shiro.authz.UnauthorizedException; +import org.junit.Test; +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.*; +import org.mockito.runners.MockitoJUnitRunner; +import sonia.scm.security.PermissionActionCheck; +import sonia.scm.security.PermissionCheck; + +/** + * Unit tests for {@link RepositoryPermissions}. + * + * @author Sebastian Sdorra + */ +@RunWith(MockitoJUnitRunner.class) +@SubjectAware(configuration = "classpath:sonia/scm/repository/repository-permissions.ini") +public class RepositoryPermissionsTest { + + @Mock + private Repository repository; + + /** + * Shiro rule. + */ + @Rule + public ShiroRule shiro = new ShiroRule(); + + /** + * Test permission checks with id successful. + */ + @Test + @SubjectAware(username = "permitted", password = "secret") + public void testPermissionCheckWithId() { + assertPermissionCheckId(RepositoryPermissions::read); + assertPermissionCheckId(RepositoryPermissions::write); + assertPermissionCheckId(RepositoryPermissions::delete); + assertPermissionCheckId(RepositoryPermissions::modify); + assertPermissionCheckId(RepositoryPermissions::healthCheck); + } + + /** + * Test permission checks with id successful. + */ + @Test + @SubjectAware(username = "permitted", password = "secret") + public void testPermissionActionCheck() { + assertPermissionActionCheck(RepositoryPermissions::read); + assertPermissionActionCheck(RepositoryPermissions::write); + assertPermissionActionCheck(RepositoryPermissions::delete); + assertPermissionActionCheck(RepositoryPermissions::modify); + assertPermissionActionCheck(RepositoryPermissions::healthCheck); + } + + @Test + @SubjectAware(username = "notpermitted", password = "secret") + public void testPermissionActionCheckWithoutRequired() { + assertFailedPermissionActionCheck(RepositoryPermissions::read); + assertFailedPermissionActionCheck(RepositoryPermissions::write); + assertFailedPermissionActionCheck(RepositoryPermissions::delete); + assertFailedPermissionActionCheck(RepositoryPermissions::modify); + assertFailedPermissionActionCheck(RepositoryPermissions::healthCheck); + } + + /** + * Test permission checks with repository successful. + */ + @Test + @SubjectAware(username = "permitted", password = "secret") + public void testPermissionCheckWithRepository() { + assertPermissionCheckRepository(RepositoryPermissions::read); + assertPermissionCheckRepository(RepositoryPermissions::write); + assertPermissionCheckRepository(RepositoryPermissions::delete); + assertPermissionCheckRepository(RepositoryPermissions::modify); + assertPermissionCheckRepository(RepositoryPermissions::healthCheck); + } + + /** + * Test permission checks with id and without the required permissions. + */ + @Test + @SubjectAware(username = "notpermitted", password = "secret") + public void testPermissionCheckWithIdAndWithoutRequiredPermissions() { + assertFailedPermissionCheckId(RepositoryPermissions::read); + assertFailedPermissionCheckId(RepositoryPermissions::write); + assertFailedPermissionCheckId(RepositoryPermissions::delete); + assertFailedPermissionCheckId(RepositoryPermissions::modify); + assertFailedPermissionCheckId(RepositoryPermissions::healthCheck); + } + + /** + * Tests permission checks with repository and without the required permissions. + */ + @Test + @SubjectAware(username = "notpermitted", password = "secret") + public void testPermissionCheckWithRepositoryAndWithoutRequiredPermissions() { + assertFailedPermissionCheckRepository(RepositoryPermissions::read); + assertFailedPermissionCheckRepository(RepositoryPermissions::write); + assertFailedPermissionCheckRepository(RepositoryPermissions::delete); + assertFailedPermissionCheckRepository(RepositoryPermissions::modify); + assertFailedPermissionCheckRepository(RepositoryPermissions::healthCheck); + } + + private void assertFailedPermissionCheckRepository(RepositoryPermissionChecker checker) { + when(repository.getId()).thenReturn("abc"); + assertFailedPermissionCheck(checker.get(repository)); + } + + private void assertFailedPermissionCheckId(RepositoryPermissionChecker checker) { + assertFailedPermissionCheck(checker.get("abc")); + } + + private void assertFailedPermissionCheck(PermissionCheck check) { + assertNotNull(check); + assertFalse(check.isPermitted()); + boolean fail = false; + try { + check.check(); + } + catch (UnauthorizedException ex) { + fail = true; + } + assertTrue(fail); + } + + private void assertPermissionCheckRepository(RepositoryPermissionChecker checker) { + when(repository.getId()).thenReturn("abc"); + assertPermissionCheck(checker.get(repository)); + } + + private void assertPermissionCheckId(RepositoryPermissionChecker checker) { + assertPermissionCheck(checker.get("abc")); + } + + private void assertPermissionCheck(PermissionCheck check) { + assertNotNull(check); + assertTrue(check.isPermitted()); + check.check(); + } + + private void assertPermissionActionCheck(Supplier> supplier) { + assertPermissionActionCheck(supplier.get()); + } + + private void assertFailedPermissionActionCheck(Supplier> supplier) { + assertFailedPermissionActionCheck(supplier.get()); + } + + private void assertFailedPermissionActionCheck(PermissionActionCheck check) { + assertNotNull(check); + assertFalse(check.isPermitted("abc")); + boolean fail = false; + try { + check.check("abc"); + } + catch (UnauthorizedException ex) { + fail = true; + } + assertTrue(fail); + fail = false; + when(repository.getId()).thenReturn("abc"); + assertFalse(check.isPermitted(repository)); + try { + check.check(repository); + } + catch (UnauthorizedException ex) { + fail = true; + } + assertTrue(fail); + } + + private void assertPermissionActionCheck(PermissionActionCheck check) { + assertNotNull(check); + assertTrue(check.isPermitted("abc")); + check.check("abc"); + when(repository.getId()).thenReturn("abc"); + assertTrue(check.isPermitted(repository)); + check.check(repository); + } + + @FunctionalInterface + private static interface RepositoryPermissionChecker { + + public PermissionCheck get(T type); + + } + +} diff --git a/scm-core/src/test/resources/sonia/scm/repository/repository-permissions.ini b/scm-core/src/test/resources/sonia/scm/repository/repository-permissions.ini new file mode 100644 index 0000000000..e148e48f14 --- /dev/null +++ b/scm-core/src/test/resources/sonia/scm/repository/repository-permissions.ini @@ -0,0 +1,6 @@ +[users] +notpermitted = secret +permitted = secret, permitted + +[roles] +permitted = repository:*:abc \ No newline at end of file