diff --git a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java index 8a79293642..eed03c2cd4 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java @@ -51,6 +51,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; +import sonia.scm.config.ScmConfiguration; import sonia.scm.group.GroupNames; import sonia.scm.group.GroupPermissions; import sonia.scm.plugin.Extension; @@ -76,9 +77,6 @@ import java.util.Set; public class DefaultAuthorizationCollector implements AuthorizationCollector { - // TODO move to util class - private static final String SEPARATOR = System.getProperty("line.separator", "\n"); - /** Field description */ private static final String ADMIN_PERMISSION = "*"; @@ -98,14 +96,16 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector * * * + * @param configuration * @param cacheManager * @param repositoryDAO * @param securitySystem */ @Inject - public DefaultAuthorizationCollector(CacheManager cacheManager, - RepositoryDAO repositoryDAO, SecuritySystem securitySystem) + public DefaultAuthorizationCollector(ScmConfiguration configuration, CacheManager cacheManager, + RepositoryDAO repositoryDAO, SecuritySystem securitySystem) { + this.configuration = configuration; this.cache = cacheManager.getCache(CACHE_NAME); this.repositoryDAO = repositoryDAO; this.securitySystem = securitySystem; @@ -239,7 +239,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector Set roles; Set permissions; - if (user.isAdmin()) + if (isAdmin(user, groups)) { if (logger.isDebugEnabled()) { @@ -270,6 +270,37 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector return info; } + private boolean isAdmin(User user, GroupNames groups) { + boolean admin = user.isAdmin(); + if (admin) { + logger.debug("user {} is marked as admin, because of the user flag", user.getName()); + return true; + } + if (isUserAdminInConfiguration(user)) { + logger.debug("user {} is marked as admin, because of the admin user configuration", user.getName()); + return true; + } + return isUserAdminInGroupConfiguration(user, groups); + } + + private boolean isUserAdminInGroupConfiguration(User user, GroupNames groups) { + Set adminGroups = configuration.getAdminGroups(); + if (adminGroups != null && groups != null) { + for (String group : groups) { + if (adminGroups.contains(group)) { + logger.debug("user {} is marked as admin, because of the admin group configuration for group {}", user.getName(), group); + return true; + } + } + } + return false; + } + + private boolean isUserAdminInConfiguration(User user) { + Set adminUsers = configuration.getAdminUsers(); + return adminUsers != null && adminUsers.contains(user.getName()); + } + private String getGroupAutocompletePermission() { return GroupPermissions.autocomplete().asShiroString(); } @@ -373,6 +404,8 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector //~--- fields --------------------------------------------------------------- + private final ScmConfiguration configuration; + /** authorization cache */ private final Cache cache; diff --git a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java index 2f455469dd..cc39965299 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/DefaultAuthorizationCollectorTest.java @@ -34,6 +34,7 @@ package sonia.scm.security; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; @@ -49,6 +50,7 @@ import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; +import sonia.scm.config.ScmConfiguration; import sonia.scm.group.GroupNames; import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; @@ -76,6 +78,8 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class DefaultAuthorizationCollectorTest { + private ScmConfiguration configuration; + @Mock private Cache cache; @@ -99,8 +103,38 @@ public class DefaultAuthorizationCollectorTest { @Before public void setUp(){ when(cacheManager.getCache(Mockito.any(String.class))).thenReturn(cache); + configuration = new ScmConfiguration(); + collector = new DefaultAuthorizationCollector(configuration, cacheManager, repositoryDAO, securitySystem); + } - collector = new DefaultAuthorizationCollector(cacheManager, repositoryDAO, securitySystem); + @Test + @SubjectAware( + configuration = "classpath:sonia/scm/shiro-001.ini" + ) + public void shouldGetAdminPrivilegedByConfiguration() { + configuration.setAdminUsers(ImmutableSet.of("trillian")); + authenticate(UserTestData.createTrillian(), "main"); + + AuthorizationInfo authInfo = collector.collect(); + assertIsAdmin(authInfo); + } + + private void assertIsAdmin(AuthorizationInfo authInfo) { + assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER, Role.ADMIN)); + assertThat(authInfo.getObjectPermissions(), nullValue()); + assertThat(authInfo.getStringPermissions(), Matchers.contains("*")); + } + + @Test + @SubjectAware( + configuration = "classpath:sonia/scm/shiro-001.ini" + ) + public void shouldGetAdminPrivilegedByGroupConfiguration() { + configuration.setAdminGroups(ImmutableSet.of("heartOfGold")); + authenticate(UserTestData.createTrillian(), "heartOfGold"); + + AuthorizationInfo authInfo = collector.collect(); + assertIsAdmin(authInfo); } /** @@ -142,7 +176,7 @@ public class DefaultAuthorizationCollectorTest { public void testCollectWithCache() { authenticate(UserTestData.createTrillian(), "main"); - AuthorizationInfo authInfo = collector.collect(); + collector.collect(); verify(cache).put(any(), any()); } @@ -176,9 +210,7 @@ public class DefaultAuthorizationCollectorTest { authenticate(trillian, "main"); AuthorizationInfo authInfo = collector.collect(); - assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER, Role.ADMIN)); - assertThat(authInfo.getObjectPermissions(), nullValue()); - assertThat(authInfo.getStringPermissions(), Matchers.contains("*")); + assertIsAdmin(authInfo); } /** @@ -238,7 +270,7 @@ public class DefaultAuthorizationCollectorTest { } /** - * Tests {@link AuthorizationCollector#invalidateCache(sonia.scm.security.AuthorizationChangedEvent)}. + * Tests {@link DefaultAuthorizationCollector#invalidateCache(sonia.scm.security.AuthorizationChangedEvent)}. */ @Test public void testInvalidateCache() {