Get verbs from repository roles

This commit is contained in:
René Pfeuffer
2019-05-06 16:01:01 +02:00
parent e4e335b7e1
commit 45ca558101
2 changed files with 86 additions and 24 deletions

View File

@@ -52,7 +52,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.cache.Cache; import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager; import sonia.scm.cache.CacheManager;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.group.GroupNames; import sonia.scm.group.GroupNames;
import sonia.scm.group.GroupPermissions; import sonia.scm.group.GroupPermissions;
import sonia.scm.plugin.Extension; import sonia.scm.plugin.Extension;
@@ -64,7 +63,6 @@ import sonia.scm.user.UserPermissions;
import sonia.scm.util.Util; import sonia.scm.util.Util;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
@@ -90,18 +88,19 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
/** /**
* Constructs ... * Constructs ...
* * @param cacheManager
* @param cacheManager
* @param repositoryDAO * @param repositoryDAO
* @param securitySystem * @param securitySystem
* @param repositoryPermissionProvider
*/ */
@Inject @Inject
public DefaultAuthorizationCollector(CacheManager cacheManager, public DefaultAuthorizationCollector(CacheManager cacheManager,
RepositoryDAO repositoryDAO, SecuritySystem securitySystem) RepositoryDAO repositoryDAO, SecuritySystem securitySystem, RepositoryPermissionProvider repositoryPermissionProvider)
{ {
this.cache = cacheManager.getCache(CACHE_NAME); this.cache = cacheManager.getCache(CACHE_NAME);
this.repositoryDAO = repositoryDAO; this.repositoryDAO = repositoryDAO;
this.securitySystem = securitySystem; this.securitySystem = securitySystem;
this.repositoryPermissionProvider = repositoryPermissionProvider;
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -201,16 +200,8 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
for (RepositoryPermission permission : repositoryPermissions) for (RepositoryPermission permission : repositoryPermissions)
{ {
hasPermission = isUserPermitted(user, groups, permission); hasPermission = isUserPermitted(user, groups, permission);
if (hasPermission && !permission.getVerbs().isEmpty()) if (hasPermission) {
{ addRepositoryPermission(builder, repository, user, hasPermission, permission);
String perm = "repository:" + String.join(",", permission.getVerbs()) + ":" + repository.getId();
if (logger.isTraceEnabled())
{
logger.trace("add repository permission {} for user {} at repository {}",
perm, user.getName(), repository.getName());
}
builder.add(perm);
} }
} }
@@ -226,6 +217,29 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
} }
} }
private void addRepositoryPermission(Builder<String> builder, Repository repository, User user, boolean hasPermission, RepositoryPermission permission) {
Collection<String> verbs = getVerbs(permission);
if (!verbs.isEmpty())
{
String perm = "repository:" + String.join(",", verbs) + ":" + repository.getId();
if (logger.isTraceEnabled())
{
logger.trace("add repository permission {} for user {} at repository {}",
perm, user.getName(), repository.getName());
}
builder.add(perm);
}
}
private Collection<String> getVerbs(RepositoryPermission permission) {
return permission.getRole() == null? permission.getVerbs(): getVerbsForRole(permission.getRole());
}
private Collection<String> getVerbsForRole(String roleName) {
return repositoryPermissionProvider.availableRoles().stream().filter(role -> roleName.equals(role.getName())).findFirst().orElseThrow(() -> new RuntimeException()).getVerbs();
}
private AuthorizationInfo createAuthorizationInfo(User user, GroupNames groups) { private AuthorizationInfo createAuthorizationInfo(User user, GroupNames groups) {
Builder<String> builder = ImmutableSet.builder(); Builder<String> builder = ImmutableSet.builder();
@@ -353,4 +367,6 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
/** security system */ /** security system */
private final SecuritySystem securitySystem; private final SecuritySystem securitySystem;
private final RepositoryPermissionProvider repositoryPermissionProvider;
} }

View File

@@ -33,10 +33,10 @@ package sonia.scm.security;
import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware; import com.github.sdorra.shiro.SubjectAware;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.Subject;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
@@ -49,11 +49,11 @@ import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import sonia.scm.cache.Cache; import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager; import sonia.scm.cache.CacheManager;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.group.GroupNames; import sonia.scm.group.GroupNames;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryDAO; import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryPermission; import sonia.scm.repository.RepositoryPermission;
import sonia.scm.repository.RepositoryRole;
import sonia.scm.repository.RepositoryTestData; import sonia.scm.repository.RepositoryTestData;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.user.UserTestData; import sonia.scm.user.UserTestData;
@@ -90,6 +90,9 @@ public class DefaultAuthorizationCollectorTest {
@Mock @Mock
private SecuritySystem securitySystem; private SecuritySystem securitySystem;
@Mock
private RepositoryPermissionProvider repositoryPermissionProvider;
private DefaultAuthorizationCollector collector; private DefaultAuthorizationCollector collector;
@Rule @Rule
@@ -101,11 +104,11 @@ public class DefaultAuthorizationCollectorTest {
@Before @Before
public void setUp(){ public void setUp(){
when(cacheManager.getCache(Mockito.any(String.class))).thenReturn(cache); when(cacheManager.getCache(Mockito.any(String.class))).thenReturn(cache);
collector = new DefaultAuthorizationCollector(cacheManager, repositoryDAO, securitySystem); collector = new DefaultAuthorizationCollector(cacheManager, repositoryDAO, securitySystem, repositoryPermissionProvider);
} }
/** /**
* Tests {@link AuthorizationCollector#collect()} without user role. * Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} without user role.
*/ */
@Test @Test
@SubjectAware @SubjectAware
@@ -118,7 +121,7 @@ public class DefaultAuthorizationCollectorTest {
} }
/** /**
* Tests {@link AuthorizationCollector#collect()} from cache. * Tests {@link AuthorizationCollector#collect(PrincipalCollection)} from cache.
*/ */
@Test @Test
@SubjectAware( @SubjectAware(
@@ -134,7 +137,7 @@ public class DefaultAuthorizationCollectorTest {
} }
/** /**
* Tests {@link AuthorizationCollector#collect()} with cache. * Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} with cache.
*/ */
@Test @Test
@SubjectAware( @SubjectAware(
@@ -148,7 +151,7 @@ public class DefaultAuthorizationCollectorTest {
} }
/** /**
* Tests {@link AuthorizationCollector#collect()} without permissions. * Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} without permissions.
*/ */
@Test @Test
@SubjectAware( @SubjectAware(
@@ -165,7 +168,7 @@ public class DefaultAuthorizationCollectorTest {
} }
/** /**
* Tests {@link AuthorizationCollector#collect()} with repository permissions. * Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} with repository permissions.
*/ */
@Test @Test
@SubjectAware( @SubjectAware(
@@ -191,7 +194,50 @@ public class DefaultAuthorizationCollectorTest {
} }
/** /**
* Tests {@link AuthorizationCollector#collect()} with global permissions. * Tests {@link AuthorizationCollector#collect(PrincipalCollection)} with repository roles.
*/
@Test
@SubjectAware(
configuration = "classpath:sonia/scm/shiro-001.ini"
)
public void testCollectWithRepositoryRolePermissions() {
when(repositoryPermissionProvider.availableRoles()).thenReturn(
asList(
new RepositoryRole("user role", asList("user"), "xml"),
new RepositoryRole("group role", asList("group"), "xml"),
new RepositoryRole("system role", asList("system"), "system")
));
String group = "heart-of-gold-crew";
authenticate(UserTestData.createTrillian(), group);
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
heartOfGold.setId("one");
heartOfGold.setPermissions(Lists.newArrayList(
new RepositoryPermission("trillian", "user role", false),
new RepositoryPermission("trillian", "system role", false)
));
Repository puzzle42 = RepositoryTestData.create42Puzzle();
puzzle42.setId("two");
RepositoryPermission permission = new RepositoryPermission(group, "group role", true);
puzzle42.setPermissions(Lists.newArrayList(permission));
when(repositoryDAO.getAll()).thenReturn(Lists.newArrayList(heartOfGold, puzzle42));
// execute and assert
AuthorizationInfo authInfo = collector.collect();
assertThat(authInfo.getRoles(), Matchers.containsInAnyOrder(Role.USER));
assertThat(authInfo.getObjectPermissions(), nullValue());
assertThat(authInfo.getStringPermissions(), containsInAnyOrder(
"user:autocomplete",
"group:autocomplete",
"user:changePassword:trillian",
"repository:user:one",
"repository:system:one",
"repository:group:two",
"user:read:trillian"));
}
/**
* Tests {@link AuthorizationCollector#collect(PrincipalCollection)} ()} with global permissions.
*/ */
@Test @Test
@SubjectAware( @SubjectAware(