From 402d2cfdb7396326d4b8a3546be73607e7c7156b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sun, 26 Feb 2017 14:28:00 +0100 Subject: [PATCH] #781 added missing unit tests for authentication related classes --- .../sonia/scm/security/AdminDetector.java | 2 +- .../security/LocalDatabaseSynchronizer.java | 1 - .../sonia/scm/security/AdminDetectorTest.java | 121 ++++++++++++++++++ .../AuthenticationInfoCollectorTest.java | 110 ++++++++++++++++ .../scm/security/GroupCollectorTest.java | 107 ++++++++++++++++ .../LocalDatabaseSynchronizerTest.java | 106 +++++++++++++++ 6 files changed, 445 insertions(+), 2 deletions(-) create mode 100644 scm-webapp/src/test/java/sonia/scm/security/AdminDetectorTest.java create mode 100644 scm-webapp/src/test/java/sonia/scm/security/AuthenticationInfoCollectorTest.java create mode 100644 scm-webapp/src/test/java/sonia/scm/security/GroupCollectorTest.java create mode 100644 scm-webapp/src/test/java/sonia/scm/security/LocalDatabaseSynchronizerTest.java diff --git a/scm-webapp/src/main/java/sonia/scm/security/AdminDetector.java b/scm-webapp/src/main/java/sonia/scm/security/AdminDetector.java index ddc43d8b0a..ec1e4bd711 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/AdminDetector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/AdminDetector.java @@ -85,8 +85,8 @@ public class AdminDetector { private boolean isAdminByConfiguration(User user, Collection groups) { boolean result = false; + Set adminUsers = configuration.getAdminUsers(); - if (adminUsers != null) { result = adminUsers.contains(user.getName()); } diff --git a/scm-webapp/src/main/java/sonia/scm/security/LocalDatabaseSynchronizer.java b/scm-webapp/src/main/java/sonia/scm/security/LocalDatabaseSynchronizer.java index af99ce5609..e37e31709b 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/LocalDatabaseSynchronizer.java +++ b/scm-webapp/src/main/java/sonia/scm/security/LocalDatabaseSynchronizer.java @@ -32,7 +32,6 @@ package sonia.scm.security; import com.google.inject.Inject; import java.util.Set; -import org.apache.shiro.authc.DisabledAccountException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.HandlerEvent; diff --git a/scm-webapp/src/test/java/sonia/scm/security/AdminDetectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/AdminDetectorTest.java new file mode 100644 index 0000000000..253375caff --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/security/AdminDetectorTest.java @@ -0,0 +1,121 @@ +/** + * 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.security; + +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import org.junit.Test; +import static org.junit.Assert.*; +import org.junit.Before; +import sonia.scm.config.ScmConfiguration; +import sonia.scm.user.User; +import sonia.scm.user.UserTestData; + +/** + * Unit tests for {@link AdminDetector}. + * + * @author Sebastian Sdorra + * @since 1.52 + */ +public class AdminDetectorTest { + + private ScmConfiguration configuration; + private AdminDetector detector; + + @Before + public void setUpObjectUnderTest(){ + configuration = new ScmConfiguration(); + detector = new AdminDetector(configuration); + } + + /** + * Tests {@link AdminDetector#checkForAuthenticatedAdmin(User, Set)} with configured admin users. + */ + @Test + public void testCheckForAuthenticatedAdminWithConfiguredAdminUsers() { + configuration.setAdminUsers(ImmutableSet.of("slarti")); + + User slarti = UserTestData.createSlarti(); + slarti.setAdmin(false); + Set groups = ImmutableSet.of(); + + detector.checkForAuthenticatedAdmin(slarti, groups); + assertTrue(slarti.isAdmin()); + } + + /** + * Tests {@link AdminDetector#checkForAuthenticatedAdmin(User, Set)} with configured admin group. + */ + @Test + public void testCheckForAuthenticatedAdminWithConfiguredAdminGroup() { + configuration.setAdminGroups(ImmutableSet.of("heartOfGold")); + + User slarti = UserTestData.createSlarti(); + slarti.setAdmin(false); + Set groups = ImmutableSet.of("heartOfGold"); + + detector.checkForAuthenticatedAdmin(slarti, groups); + assertTrue(slarti.isAdmin()); + } + + /** + * Tests {@link AdminDetector#checkForAuthenticatedAdmin(User, Set)} with non matching configuration. + */ + @Test + public void testCheckForAuthenticatedAdminWithNonMatchinConfiguration() { + configuration.setAdminUsers(ImmutableSet.of("slarti")); + configuration.setAdminGroups(ImmutableSet.of("heartOfGold")); + + User trillian = UserTestData.createTrillian(); + trillian.setAdmin(false); + Set groups = ImmutableSet.of("puzzle42"); + + detector.checkForAuthenticatedAdmin(trillian, groups); + assertFalse(trillian.isAdmin()); + } + +/** + * Tests {@link AdminDetector#checkForAuthenticatedAdmin(User, Set)} with user which is already admin. + */ + @Test + public void testCheckForAuthenticatedAdminWithUserWhichIsAlreadyAdmin() { + configuration.setAdminUsers(ImmutableSet.of("slarti")); + configuration.setAdminGroups(ImmutableSet.of("heartOfGold")); + + User trillian = UserTestData.createTrillian(); + trillian.setAdmin(true); + Set groups = ImmutableSet.of("puzzle42"); + + detector.checkForAuthenticatedAdmin(trillian, groups); + assertTrue(trillian.isAdmin()); + } +} \ No newline at end of file diff --git a/scm-webapp/src/test/java/sonia/scm/security/AuthenticationInfoCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/AuthenticationInfoCollectorTest.java new file mode 100644 index 0000000000..31504777fd --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/security/AuthenticationInfoCollectorTest.java @@ -0,0 +1,110 @@ +/** + * 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.security; + +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.DisabledAccountException; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.junit.Test; +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import static org.mockito.Mockito.*; +import org.mockito.runners.MockitoJUnitRunner; +import sonia.scm.group.GroupNames; +import sonia.scm.user.User; +import sonia.scm.user.UserTestData; +import sonia.scm.web.security.AuthenticationResult; + +/** + * Unit tests for {@link AuthenticationInfoCollector}. + * + * @author Sebastian Sdorra + * @since 1.52 + */ +@RunWith(MockitoJUnitRunner.class) +public class AuthenticationInfoCollectorTest { + + @Mock + private LocalDatabaseSynchronizer synchronizer; + + @Mock + private GroupCollector groupCollector; + + @Mock + private SessionStore sessionStore; + + @InjectMocks + private AuthenticationInfoCollector collector; + + /** + * Tests {@link AuthenticationInfoCollector#createAuthenticationInfo(UsernamePasswordToken, AuthenticationResult)}. + */ + @Test + public void testCreateAuthenticationInfo() { + User trillian = UserTestData.createTrillian(); + UsernamePasswordToken token = new UsernamePasswordToken(trillian.getId(), "secret"); + AuthenticationResult result = new AuthenticationResult(trillian); + Set groups = ImmutableSet.of("puzzle42", "heartOfGold"); + when(groupCollector.collectGroups(Mockito.any(AuthenticationResult.class))).thenReturn(groups); + + AuthenticationInfo authc = collector.createAuthenticationInfo(token, result); + verify(synchronizer).synchronize(trillian, groups); + verify(sessionStore).store(token); + + assertEquals(trillian.getId(), authc.getPrincipals().getPrimaryPrincipal()); + assertEquals(trillian, authc.getPrincipals().oneByType(User.class)); + assertThat(authc.getPrincipals().oneByType(GroupNames.class), contains(groups.toArray(new String[0]))); + } + + /** + * Tests {@link AuthenticationInfoCollector#createAuthenticationInfo(UsernamePasswordToken, AuthenticationResult)} + * with disabled user. + */ + @Test(expected = DisabledAccountException.class) + public void testCreateAuthenticationInfoWithDisabledUser() { + User trillian = UserTestData.createTrillian(); + trillian.setActive(false); + UsernamePasswordToken token = new UsernamePasswordToken(trillian.getId(), "secret"); + AuthenticationResult result = new AuthenticationResult(trillian); + Set groups = ImmutableSet.of("puzzle42", "heartOfGold"); + when(groupCollector.collectGroups(Mockito.any(AuthenticationResult.class))).thenReturn(groups); + + collector.createAuthenticationInfo(token, result); + } + +} \ No newline at end of file diff --git a/scm-webapp/src/test/java/sonia/scm/security/GroupCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/GroupCollectorTest.java new file mode 100644 index 0000000000..57f0362549 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/security/GroupCollectorTest.java @@ -0,0 +1,107 @@ +/** + * 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.security; + +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import jdk.nashorn.internal.ir.annotations.Immutable; +import org.junit.Test; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; +import static org.hamcrest.Matchers.*; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import sonia.scm.group.Group; +import sonia.scm.group.GroupManager; +import sonia.scm.user.UserTestData; +import sonia.scm.web.security.AuthenticationResult; + +/** + * Unit tests for {@link GroupCollector}. + * + * @author Sebastian Sdorra + * @since 1.52 + */ +@RunWith(MockitoJUnitRunner.class) +public class GroupCollectorTest { + + @Mock + private GroupManager groupManager; + + @InjectMocks + private GroupCollector collector; + + /** + * Tests {@link GroupCollector#collectGroups(AuthenticationResult)} without groups from authenticator. + */ + @Test + public void testCollectGroupsWithoutAuthenticatorGroups() { + Set groups = collector.collectGroups(new AuthenticationResult(UserTestData.createSlarti())); + assertThat(groups, containsInAnyOrder("_authenticated")); + } + + /** + * Tests {@link GroupCollector#collectGroups(AuthenticationResult)} with groups from authenticator. + */ + @Test + public void testCollectGroupsWithGroupsFromAuthenticator() { + Set authGroups = ImmutableSet.of("puzzle42"); + Set groups = collector.collectGroups(new AuthenticationResult(UserTestData.createSlarti(), authGroups)); + assertThat(groups, containsInAnyOrder("_authenticated", "puzzle42")); + } + + /** + * Tests {@link GroupCollector#collectGroups(AuthenticationResult)} with groups from db. + */ + @Test + public void testCollectGroupsWithGroupsFromDB() { + Set dbGroups = ImmutableSet.of(new Group("test", "puzzle42")); + when(groupManager.getGroupsForMember("slarti")).thenReturn(dbGroups); + Set groups = collector.collectGroups(new AuthenticationResult(UserTestData.createSlarti())); + assertThat(groups, containsInAnyOrder("_authenticated", "puzzle42")); + } + +/** + * Tests {@link GroupCollector#collectGroups(AuthenticationResult)} with groups from db. + */ + @Test + public void testCollectGroupsWithGroupsFromDBAndAuthenticator() { + Set dbGroups = ImmutableSet.of(new Group("test", "puzzle42")); + Set authGroups = ImmutableSet.of("heartOfGold"); + when(groupManager.getGroupsForMember("slarti")).thenReturn(dbGroups); + Set groups = collector.collectGroups(new AuthenticationResult(UserTestData.createSlarti(), authGroups)); + assertThat(groups, containsInAnyOrder("_authenticated", "puzzle42", "heartOfGold")); + } + +} \ No newline at end of file diff --git a/scm-webapp/src/test/java/sonia/scm/security/LocalDatabaseSynchronizerTest.java b/scm-webapp/src/test/java/sonia/scm/security/LocalDatabaseSynchronizerTest.java new file mode 100644 index 0000000000..4d29df6c03 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/security/LocalDatabaseSynchronizerTest.java @@ -0,0 +1,106 @@ +/** + * 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.security; + +import com.google.common.collect.ImmutableSet; +import org.junit.Test; +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import static org.mockito.Mockito.*; +import org.mockito.runners.MockitoJUnitRunner; +import sonia.scm.user.User; +import sonia.scm.user.UserDAO; +import sonia.scm.user.UserManager; +import sonia.scm.user.UserTestData; + +/** + * Unit tests for {@link LocalDatabaseSynchronizer}. + * + * @author Sebastian Sdorra + * @since 1.52 + */ +@RunWith(MockitoJUnitRunner.class) +public class LocalDatabaseSynchronizerTest { + + @Mock + private AdminDetector adminSelector; + + @Mock + private UserManager userManager; + + @Mock + private UserDAO userDAO; + + @InjectMocks + private LocalDatabaseSynchronizer synchronizer; + + /** + * Tests {@link LocalDatabaseSynchronizer#synchronize(User, java.util.Set)}. + */ + @Test + public void testSynchronizeWithoutDBUser() { + User trillian = UserTestData.createTrillian(); + trillian.setType("local"); + synchronizer.synchronize(trillian, ImmutableSet.of()); + verify(userDAO).add(trillian); + } + + /** + * Tests {@link LocalDatabaseSynchronizer#synchronize(sonia.scm.user.User, java.util.Set)}. + */ + @Test + public void testSynchronize() { + User trillian = UserTestData.createTrillian(); + trillian.setDisplayName("Trici"); + trillian.setType("local"); + trillian.setAdmin(false); + trillian.setActive(true); + + User dbTrillian = UserTestData.createTrillian(); + dbTrillian.setType("local"); + dbTrillian.setAdmin(true); + dbTrillian.setActive(false); + + when(userDAO.get(trillian.getId())).thenReturn(dbTrillian); + + synchronizer.synchronize(trillian, ImmutableSet.of()); + assertTrue(trillian.isAdmin()); + assertFalse(trillian.isActive()); + verify(userDAO).modify(trillian); + } + + + +} \ No newline at end of file