diff --git a/scm-core/src/main/java/sonia/scm/group/ExternalGroupNames.java b/scm-core/src/main/java/sonia/scm/group/ExternalGroupNames.java deleted file mode 100644 index 179e488236..0000000000 --- a/scm-core/src/main/java/sonia/scm/group/ExternalGroupNames.java +++ /dev/null @@ -1,22 +0,0 @@ -package sonia.scm.group; - -import java.util.Collection; - -/** - * This class represents all associated groups which are provided by external systems for a certain user. - * - * @author Sebastian Sdorra - * @since 2.0.0 - */ -public class ExternalGroupNames extends GroupNames { - public ExternalGroupNames() { - } - - public ExternalGroupNames(String groupName, String... groupNames) { - super(groupName, groupNames); - } - - public ExternalGroupNames(Collection collection) { - super(collection); - } -} diff --git a/scm-core/src/main/java/sonia/scm/group/GroupCollector.java b/scm-core/src/main/java/sonia/scm/group/GroupCollector.java new file mode 100644 index 0000000000..4546db1bc4 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/group/GroupCollector.java @@ -0,0 +1,10 @@ +package sonia.scm.group; + +import java.util.Set; + +public interface GroupCollector { + + String AUTHENTICATED = "_authenticated"; + + Set collect(String principal); +} diff --git a/scm-core/src/main/java/sonia/scm/group/GroupNames.java b/scm-core/src/main/java/sonia/scm/group/GroupNames.java deleted file mode 100644 index c28f9f5ef1..0000000000 --- a/scm-core/src/main/java/sonia/scm/group/GroupNames.java +++ /dev/null @@ -1,187 +0,0 @@ -/** - * Copyright (c) 2010, 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.group; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.common.base.Joiner; -import com.google.common.base.Objects; -import com.google.common.collect.Lists; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; - -//~--- JDK imports ------------------------------------------------------------ - -/** - * This class represents all associated groups for a user. - * - * @author Sebastian Sdorra - * @since 1.21 - */ -public class GroupNames implements Serializable, Iterable -{ - - /** - * Group for all authenticated users - * @since 1.31 - */ - public static final String AUTHENTICATED = "_authenticated"; - - /** Field description */ - private static final long serialVersionUID = 8615685985213897947L; - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - */ - public GroupNames() - { - this(Collections.emptyList()); - } - - /** - * Constructs ... - * - * - * @param groupName - * @param groupNames - */ - public GroupNames(String groupName, String... groupNames) - { - this(Lists.asList(groupName, groupNames)); - } - - /** - * Constructs ... - * - * - * @param collection - */ - public GroupNames(Collection collection) - { - this.collection = Collections.unmodifiableCollection(collection); - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param groupName - * - * @return - */ - public boolean contains(String groupName) - { - return collection.contains(groupName); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - - if (getClass() != obj.getClass()) - { - return false; - } - - final GroupNames other = (GroupNames) obj; - - return Objects.equal(collection, other.collection); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() - { - return Objects.hashCode(collection); - } - - /** - * Method description - * - * - * @return - */ - @Override - public Iterator iterator() - { - return collection.iterator(); - } - - /** - * Method description - * - * - * @return - */ - @Override - public String toString() - { - return Joiner.on(", ").join(collection); - } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - */ - public Collection getCollection() - { - return collection; - } - - - //~--- fields --------------------------------------------------------------- - /** Field description */ - private final Collection collection; -} diff --git a/scm-core/src/main/java/sonia/scm/group/GroupResolver.java b/scm-core/src/main/java/sonia/scm/group/GroupResolver.java new file mode 100644 index 0000000000..5aba63c93b --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/group/GroupResolver.java @@ -0,0 +1,10 @@ +package sonia.scm.group; + +import sonia.scm.plugin.ExtensionPoint; + +import java.util.Set; + +@ExtensionPoint +public interface GroupResolver { + Set resolve(String principal); +} diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java index 5bb50db06f..8c7000c25a 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Repository.java +++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java @@ -82,7 +82,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per private String namespace; private String name; @XmlElement(name = "permission") - private final Set permissions = new HashSet<>(); + private Set permissions = new HashSet<>(); @XmlElement(name = "public") private boolean publicReadable = false; private boolean archived = false; @@ -331,6 +331,8 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per try { repository = (Repository) super.clone(); + // fix permission reference on clone + repository.permissions = new HashSet<>(permissions); } catch (CloneNotSupportedException ex) { throw new RuntimeException(ex); } diff --git a/scm-core/src/main/java/sonia/scm/security/AccessTokenBuilder.java b/scm-core/src/main/java/sonia/scm/security/AccessTokenBuilder.java index 0924716bd8..afe81ac27f 100644 --- a/scm-core/src/main/java/sonia/scm/security/AccessTokenBuilder.java +++ b/scm-core/src/main/java/sonia/scm/security/AccessTokenBuilder.java @@ -99,15 +99,6 @@ public interface AccessTokenBuilder { */ AccessTokenBuilder scope(Scope scope); - /** - * Define the logged in user as member of the given groups. - * - * @param groups group names - * - * @return {@code this} - */ - AccessTokenBuilder groups(String... groups); - /** * Creates a new {@link AccessToken} with the provided settings. * diff --git a/scm-core/src/main/java/sonia/scm/security/DAORealmHelper.java b/scm-core/src/main/java/sonia/scm/security/DAORealmHelper.java index ea3e7ce9f5..6ec64a67de 100644 --- a/scm-core/src/main/java/sonia/scm/security/DAORealmHelper.java +++ b/scm-core/src/main/java/sonia/scm/security/DAORealmHelper.java @@ -45,7 +45,6 @@ import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.subject.SimplePrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.group.GroupDAO; import sonia.scm.user.User; import sonia.scm.user.UserDAO; @@ -71,8 +70,6 @@ public final class DAORealmHelper { private final UserDAO userDAO; - private final GroupCollector groupCollector; - private final String realm; //~--- constructors --------------------------------------------------------- @@ -83,14 +80,12 @@ public final class DAORealmHelper { * * @param loginAttemptHandler login attempt handler for wrapping credentials matcher * @param userDAO user dao - * @param groupCollector collect groups for a principal * @param realm name of realm */ - public DAORealmHelper(LoginAttemptHandler loginAttemptHandler, UserDAO userDAO, GroupCollector groupCollector, String realm) { + public DAORealmHelper(LoginAttemptHandler loginAttemptHandler, UserDAO userDAO, String realm) { this.loginAttemptHandler = loginAttemptHandler; this.realm = realm; this.userDAO = userDAO; - this.groupCollector = groupCollector; } //~--- get methods ---------------------------------------------------------- @@ -120,7 +115,7 @@ public final class DAORealmHelper { UsernamePasswordToken upt = (UsernamePasswordToken) token; String principal = upt.getUsername(); - return getAuthenticationInfo(principal, null, null, Collections.emptySet()); + return getAuthenticationInfo(principal, null, null); } /** @@ -135,7 +130,7 @@ public final class DAORealmHelper { } - private AuthenticationInfo getAuthenticationInfo(String principal, String credentials, Scope scope, Iterable groups) { + private AuthenticationInfo getAuthenticationInfo(String principal, String credentials, Scope scope) { checkArgument(!Strings.isNullOrEmpty(principal), "username is required"); LOG.debug("try to authenticate {}", principal); @@ -153,7 +148,6 @@ public final class DAORealmHelper { collection.add(principal, realm); collection.add(user, realm); - collection.add(groupCollector.collect(principal, groups), realm); collection.add(MoreObjects.firstNonNull(scope, Scope.empty()), realm); String creds = credentials; @@ -207,17 +201,17 @@ public final class DAORealmHelper { return this; } - /** - * With groups adds extra groups, besides those which come from the {@link GroupDAO}, to the authentication info. - * - * @param groups extra groups - * - * @return {@code this} - */ - public AuthenticationInfoBuilder withGroups(Iterable groups) { - this.groups = groups; - return this; - } +// /** +// * With groups adds extra groups, besides those which come from the {@link GroupDAO}, to the authentication info. +// * +// * @param groups extra groups +// * +// * @return {@code this} +// */ +// public AuthenticationInfoBuilder withGroups(Iterable groups) { +// this.groups = groups; +// return this; +// } /** * Build creates the authentication info from the given information. @@ -225,7 +219,7 @@ public final class DAORealmHelper { * @return authentication info */ public AuthenticationInfo build() { - return getAuthenticationInfo(principal, credentials, scope, groups); + return getAuthenticationInfo(principal, credentials, scope); } } diff --git a/scm-core/src/main/java/sonia/scm/security/DAORealmHelperFactory.java b/scm-core/src/main/java/sonia/scm/security/DAORealmHelperFactory.java index ee2bf11e21..dd59de2ac8 100644 --- a/scm-core/src/main/java/sonia/scm/security/DAORealmHelperFactory.java +++ b/scm-core/src/main/java/sonia/scm/security/DAORealmHelperFactory.java @@ -30,7 +30,7 @@ */ package sonia.scm.security; -import sonia.scm.group.GroupDAO; +import sonia.scm.cache.CacheManager; import sonia.scm.user.UserDAO; import javax.inject.Inject; @@ -45,20 +45,19 @@ public final class DAORealmHelperFactory { private final LoginAttemptHandler loginAttemptHandler; private final UserDAO userDAO; - private final GroupCollector groupCollector; + private final CacheManager cacheManager; /** * Constructs a new instance. - * * @param loginAttemptHandler login attempt handler * @param userDAO user dao - * @param groupDAO group dao + * @param cacheManager */ @Inject - public DAORealmHelperFactory(LoginAttemptHandler loginAttemptHandler, UserDAO userDAO, GroupDAO groupDAO) { + public DAORealmHelperFactory(LoginAttemptHandler loginAttemptHandler, UserDAO userDAO, CacheManager cacheManager) { this.loginAttemptHandler = loginAttemptHandler; this.userDAO = userDAO; - this.groupCollector = new GroupCollector(groupDAO); + this.cacheManager = cacheManager; } /** @@ -69,7 +68,7 @@ public final class DAORealmHelperFactory { * @return new {@link DAORealmHelper} instance. */ public DAORealmHelper create(String realm) { - return new DAORealmHelper(loginAttemptHandler, userDAO, groupCollector, realm); + return new DAORealmHelper(loginAttemptHandler, userDAO, realm); } } diff --git a/scm-core/src/main/java/sonia/scm/security/GroupCollector.java b/scm-core/src/main/java/sonia/scm/security/GroupCollector.java deleted file mode 100644 index 56687af7ef..0000000000 --- a/scm-core/src/main/java/sonia/scm/security/GroupCollector.java +++ /dev/null @@ -1,43 +0,0 @@ -package sonia.scm.security; - -import com.google.common.collect.ImmutableSet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import sonia.scm.group.Group; -import sonia.scm.group.GroupDAO; -import sonia.scm.group.GroupNames; - -/** - * Collect groups for a certain principal. - * Warning: The class is only for internal use and should never used directly. - */ -class GroupCollector { - - private static final Logger LOG = LoggerFactory.getLogger(GroupCollector.class); - - private final GroupDAO groupDAO; - - GroupCollector(GroupDAO groupDAO) { - this.groupDAO = groupDAO; - } - - GroupNames collect(String principal, Iterable groupNames) { - ImmutableSet.Builder builder = ImmutableSet.builder(); - - builder.add(GroupNames.AUTHENTICATED); - - for (String group : groupNames) { - builder.add(group); - } - - for (Group group : groupDAO.getAll()) { - if (group.isMember(principal)) { - builder.add(group.getName()); - } - } - - GroupNames groups = new GroupNames(builder.build()); - LOG.debug("collected following groups for principal {}: {}", principal, groups); - return groups; - } -} diff --git a/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java b/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java index d421d33f45..b2175f304a 100644 --- a/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java +++ b/scm-core/src/main/java/sonia/scm/security/SyncingRealmHelper.java @@ -32,24 +32,15 @@ import com.google.inject.Inject; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.subject.SimplePrincipalCollection; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import sonia.scm.AlreadyExistsException; import sonia.scm.NotFoundException; -import sonia.scm.group.ExternalGroupNames; import sonia.scm.group.Group; -import sonia.scm.group.GroupDAO; import sonia.scm.group.GroupManager; import sonia.scm.plugin.Extension; import sonia.scm.user.User; import sonia.scm.user.UserManager; import sonia.scm.web.security.AdministrationContext; -import java.util.Collection; -import java.util.Collections; - -import static java.util.Arrays.asList; - /** * Helper class for syncing realms. The class should simplify the creation of realms, which are syncing authenticated * users with the local database. @@ -60,12 +51,9 @@ import static java.util.Arrays.asList; @Extension public final class SyncingRealmHelper { - private static final Logger LOG = LoggerFactory.getLogger(SyncingRealmHelper.class); - private final AdministrationContext ctx; private final UserManager userManager; private final GroupManager groupManager; - private final GroupCollector groupCollector; /** * Constructs a new SyncingRealmHelper. @@ -73,134 +61,28 @@ public final class SyncingRealmHelper { * @param ctx administration context * @param userManager user manager * @param groupManager group manager - * @param groupDAO group dao */ @Inject - public SyncingRealmHelper(AdministrationContext ctx, UserManager userManager, GroupManager groupManager, GroupDAO groupDAO) { + public SyncingRealmHelper(AdministrationContext ctx, UserManager userManager, GroupManager groupManager) { this.ctx = ctx; this.userManager = userManager; this.groupManager = groupManager; - this.groupCollector = new GroupCollector(groupDAO); } - /** - * Create {@link AuthenticationInfo} from user and groups. - */ - public AuthenticationInfoBuilder.ForRealm authenticationInfo() { - return new AuthenticationInfoBuilder().new ForRealm(); - } - - public class AuthenticationInfoBuilder { - private String realm; - private User user; - private Collection groups = Collections.emptySet(); - private Collection externalGroups = Collections.emptySet(); - - private AuthenticationInfo build() { - return SyncingRealmHelper.this.createAuthenticationInfo(realm, user, groups, externalGroups); - } - - public class ForRealm { - private ForRealm() { - } - - /** - * Sets the realm. - * @param realm name of the realm - */ - public ForUser forRealm(String realm) { - AuthenticationInfoBuilder.this.realm = realm; - return AuthenticationInfoBuilder.this.new ForUser(); - } - } - - public class ForUser { - private ForUser() { - } - - /** - * Sets the user. - * @param user authenticated user - */ - public AuthenticationInfoBuilder.WithGroups andUser(User user) { - AuthenticationInfoBuilder.this.user = user; - return AuthenticationInfoBuilder.this.new WithGroups(); - } - } - - public class WithGroups { - private WithGroups() { - } - - /** - * Set the internal groups for the user. - * @param groups groups of the authenticated user - * @return builder step for groups - */ - public WithGroups withGroups(String... groups) { - return withGroups(asList(groups)); - } - - /** - * Set the internal groups for the user. - * @param groups groups of the authenticated user - * @return builder step for groups - */ - public WithGroups withGroups(Collection groups) { - AuthenticationInfoBuilder.this.groups = groups; - return this; - } - - /** - * Set the external groups for the user. - * @param externalGroups external groups of the authenticated user - * @return builder step for groups - */ - public WithGroups withExternalGroups(String... externalGroups) { - return withExternalGroups(asList(externalGroups)); - } - - /** - * Set the external groups for the user. - * @param externalGroups external groups of the authenticated user - * @return builder step for groups - */ - public WithGroups withExternalGroups(Collection externalGroups) { - AuthenticationInfoBuilder.this.externalGroups = externalGroups; - return this; - } - - /** - * Builds the {@link AuthenticationInfo} from the given options. - * - * @return complete autentication info - */ - public AuthenticationInfo build() { - return AuthenticationInfoBuilder.this.build(); - } - } - } - - //~--- methods -------------------------------------------------------------- - /** * Create {@link AuthenticationInfo} from user and groups. * * * @param realm name of the realm * @param user authenticated user - * @param groups groups of the authenticated user * * @return authentication info */ - private AuthenticationInfo createAuthenticationInfo(String realm, User user, - Collection groups, Collection externalGroups) { + public AuthenticationInfo createAuthenticationInfo(String realm, User user) { SimplePrincipalCollection collection = new SimplePrincipalCollection(); collection.add(user.getId(), realm); collection.add(user, realm); - collection.add(groupCollector.collect(user.getId(), groups), realm); - collection.add(new ExternalGroupNames(externalGroups), realm); return new SimpleAuthenticationInfo(collection, user.getPassword()); } diff --git a/scm-core/src/test/java/sonia/scm/repository/RepositoryTest.java b/scm-core/src/test/java/sonia/scm/repository/RepositoryTest.java new file mode 100644 index 0000000000..6053e10ad5 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/RepositoryTest.java @@ -0,0 +1,22 @@ +package sonia.scm.repository; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +class RepositoryTest { + + @Test + void shouldCreateNewPermissionOnClone() { + Repository repository = new Repository(); + repository.setPermissions(Arrays.asList(new RepositoryPermission("one", "role", false))); + + Repository cloned = repository.clone(); + cloned.setPermissions(Arrays.asList(new RepositoryPermission("two", "role", false))); + + assertThat(repository.getPermissions()).extracting(r -> r.getName()).containsOnly("one"); + } + +} diff --git a/scm-core/src/test/java/sonia/scm/security/DAORealmHelperTest.java b/scm-core/src/test/java/sonia/scm/security/DAORealmHelperTest.java index 78dbd4fdd2..0fbcc20ac0 100644 --- a/scm-core/src/test/java/sonia/scm/security/DAORealmHelperTest.java +++ b/scm-core/src/test/java/sonia/scm/security/DAORealmHelperTest.java @@ -1,20 +1,16 @@ package sonia.scm.security; -import com.google.common.collect.ImmutableList; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.DisabledAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.PrincipalCollection; -import org.junit.Ignore; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import sonia.scm.group.Group; import sonia.scm.group.GroupDAO; -import sonia.scm.group.GroupNames; import sonia.scm.user.User; import sonia.scm.user.UserDAO; @@ -38,7 +34,7 @@ class DAORealmHelperTest { @BeforeEach void setUpObjectUnderTest() { - helper = new DAORealmHelper(loginAttemptHandler, userDAO, new GroupCollector(groupDAO), "hitchhiker"); + helper = new DAORealmHelper(loginAttemptHandler, userDAO, "hitchhiker"); } @Test @@ -73,29 +69,9 @@ class DAORealmHelperTest { AuthenticationInfo authenticationInfo = helper.authenticationInfoBuilder("trillian").build(); PrincipalCollection principals = authenticationInfo.getPrincipals(); assertThat(principals.oneByType(User.class)).isSameAs(user); - assertThat(principals.oneByType(GroupNames.class)).containsOnly("_authenticated"); assertThat(principals.oneByType(Scope.class)).isEmpty(); } - @Test - @Ignore - void shouldReturnAuthenticationInfoWithGroups() { - User user = new User("trillian"); - when(userDAO.get("trillian")).thenReturn(user); - - Group one = new Group("xml", "one", "trillian"); - Group two = new Group("xml", "two", "trillian"); - Group six = new Group("xml", "six", "dent"); - when(groupDAO.getAll()).thenReturn(ImmutableList.of(one, two, six)); - - AuthenticationInfo authenticationInfo = helper.authenticationInfoBuilder("trillian") - .withGroups(ImmutableList.of("three")) - .build(); - - PrincipalCollection principals = authenticationInfo.getPrincipals(); - assertThat(principals.oneByType(GroupNames.class)).containsOnly("_authenticated", "one", "two", "three"); - } - @Test void shouldReturnAuthenticationInfoWithScope() { User user = new User("trillian"); @@ -148,7 +124,6 @@ class DAORealmHelperTest { PrincipalCollection principals = authenticationInfo.getPrincipals(); assertThat(principals.oneByType(User.class)).isSameAs(user); - assertThat(principals.oneByType(GroupNames.class)).containsOnly("_authenticated"); assertThat(principals.oneByType(Scope.class)).isEmpty(); assertThat(authenticationInfo.getCredentials()).isNull(); diff --git a/scm-core/src/test/java/sonia/scm/security/GroupCollectorTest.java b/scm-core/src/test/java/sonia/scm/security/GroupCollectorTest.java deleted file mode 100644 index 3fb59d1614..0000000000 --- a/scm-core/src/test/java/sonia/scm/security/GroupCollectorTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package sonia.scm.security; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import sonia.scm.group.Group; -import sonia.scm.group.GroupDAO; -import sonia.scm.group.GroupNames; - -import java.util.Collections; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class GroupCollectorTest { - - @Mock - private GroupDAO groupDAO; - - @InjectMocks - private GroupCollector collector; - - @Test - void shouldAlwaysReturnAuthenticatedGroup() { - GroupNames groupNames = collector.collect("trillian", Collections.emptySet()); - assertThat(groupNames).containsOnly("_authenticated"); - } - - @Nested - class WithGroupsFromDao { - - @BeforeEach - void setUpGroupsDao() { - List groups = Lists.newArrayList( - new Group("xml", "heartOfGold", "trillian"), - new Group("xml", "g42", "dent", "prefect"), - new Group("xml", "fjordsOfAfrican", "dent", "trillian") - ); - when(groupDAO.getAll()).thenReturn(groups); - } - - @Test - void shouldReturnGroupsFromDao() { - GroupNames groupNames = collector.collect("trillian", Collections.emptySet()); - assertThat(groupNames).contains("_authenticated", "heartOfGold", "fjordsOfAfrican"); - } - - @Test - void shouldCombineGivenWithDao() { - GroupNames groupNames = collector.collect("trillian", ImmutableList.of("awesome", "incredible")); - assertThat(groupNames).contains("_authenticated", "heartOfGold", "fjordsOfAfrican", "awesome", "incredible"); - } - - } - -} diff --git a/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java b/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java index 20d1010b57..ca7c2efdc6 100644 --- a/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java +++ b/scm-core/src/test/java/sonia/scm/security/SyncingRealmHelperTest.java @@ -36,31 +36,30 @@ package sonia.scm.security; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.base.Throwables; -import com.google.common.collect.Lists; import org.apache.shiro.authc.AuthenticationInfo; -import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.AlreadyExistsException; -import sonia.scm.group.ExternalGroupNames; import sonia.scm.group.Group; -import sonia.scm.group.GroupDAO; import sonia.scm.group.GroupManager; -import sonia.scm.group.GroupNames; import sonia.scm.user.User; import sonia.scm.user.UserManager; import sonia.scm.web.security.AdministrationContext; import sonia.scm.web.security.PrivilegedAction; import java.io.IOException; -import java.util.List; import static org.hamcrest.Matchers.hasItem; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; //~--- JDK imports ------------------------------------------------------------ @@ -78,9 +77,6 @@ public class SyncingRealmHelperTest { @Mock private UserManager userManager; - @Mock - private GroupDAO groupDAO; - private SyncingRealmHelper helper; /** @@ -106,7 +102,7 @@ public class SyncingRealmHelperTest { } }; - helper = new SyncingRealmHelper(ctx, userManager, groupManager, groupDAO); + helper = new SyncingRealmHelper(ctx, userManager, groupManager); } /** @@ -183,67 +179,15 @@ public class SyncingRealmHelperTest { verify(userManager, times(1)).modify(user); } - @Test - public void builderShouldSetInternalGroups() { - AuthenticationInfo authenticationInfo = helper - .authenticationInfo() - .forRealm("unit-test") - .andUser(new User("ziltoid")) - .withGroups("internal") - .build(); - - GroupNames groupNames = authenticationInfo.getPrincipals().oneByType(GroupNames.class); - Assertions.assertThat(groupNames.getCollection()).contains("_authenticated", "internal"); - } - - @Test - public void builderShouldSetExternalGroups() { - AuthenticationInfo authenticationInfo = helper - .authenticationInfo() - .forRealm("unit-test") - .andUser(new User("ziltoid")) - .withExternalGroups("external") - .build(); - - ExternalGroupNames groupNames = authenticationInfo.getPrincipals().oneByType(ExternalGroupNames.class); - Assertions.assertThat(groupNames.getCollection()).containsOnly("external"); - } @Test public void builderShouldSetValues() { User user = new User("ziltoid"); - AuthenticationInfo authInfo = helper - .authenticationInfo() - .forRealm("unit-test") - .andUser(user) - .build(); + AuthenticationInfo authInfo = helper.createAuthenticationInfo("unit-test", user); assertNotNull(authInfo); assertEquals("ziltoid", authInfo.getPrincipals().getPrimaryPrincipal()); assertThat(authInfo.getPrincipals().getRealmNames(), hasItem("unit-test")); assertEquals(user, authInfo.getPrincipals().oneByType(User.class)); } - - @Test - public void shouldReturnCombinedGroupNames() { - User user = new User("tricia"); - - List groups = Lists.newArrayList(new Group("xml", "heartOfGold", "tricia")); - when(groupDAO.getAll()).thenReturn(groups); - - AuthenticationInfo authInfo = helper - .authenticationInfo() - .forRealm("unit-test") - .andUser(user) - .withGroups("fjordsOfAfrican") - .withExternalGroups("g42") - .build(); - - - GroupNames groupNames = authInfo.getPrincipals().oneByType(GroupNames.class); - Assertions.assertThat(groupNames).contains("_authenticated", "heartOfGold", "fjordsOfAfrican"); - - ExternalGroupNames externalGroupNames = authInfo.getPrincipals().oneByType(ExternalGroupNames.class); - Assertions.assertThat(externalGroupNames).contains("g42"); - } } diff --git a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java index 20de47ffa4..d632f13f60 100644 --- a/scm-it/src/test/java/sonia/scm/it/utils/TestData.java +++ b/scm-it/src/test/java/sonia/scm/it/utils/TestData.java @@ -123,23 +123,6 @@ public class TestData { ; } - public static void createUserPermission(String username, String roleName, String repositoryType) { - String defaultPermissionUrl = TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType); - LOG.info("create permission with name {} and role {} using the endpoint: {}", username, roleName, defaultPermissionUrl); - given(VndMediaType.REPOSITORY_PERMISSION) - .when() - .content("{\n" + - "\t\"role\": " + roleName + ",\n" + - "\t\"name\": \"" + username + "\",\n" + - "\t\"groupPermission\": false\n" + - "\t\n" + - "}") - .post(defaultPermissionUrl) - .then() - .statusCode(HttpStatus.SC_CREATED) - ; - } - public static List getUserPermissions(String username, String password, String repositoryType) { return callUserPermissions(username, password, repositoryType, HttpStatus.SC_OK) .extract() diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDto.java index 84fbbfe290..a87ad7df17 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDto.java @@ -7,7 +7,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import java.util.List; +import java.util.Set; @Getter @Setter @@ -17,7 +17,7 @@ public class MeDto extends HalRepresentation { private String name; private String displayName; private String mail; - private List groups; + private Set groups; MeDto(Links links, Embedded embedded) { super(links, embedded); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java index b5e1998066..c2bebd389a 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java @@ -1,18 +1,16 @@ package sonia.scm.api.v2.resources; -import com.google.common.collect.ImmutableList; import de.otto.edison.hal.Embedded; import de.otto.edison.hal.Links; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; -import sonia.scm.group.GroupNames; +import sonia.scm.group.GroupCollector; import sonia.scm.user.User; import sonia.scm.user.UserManager; import sonia.scm.user.UserPermissions; import javax.inject.Inject; -import java.util.Collections; import static de.otto.edison.hal.Embedded.embeddedBuilder; import static de.otto.edison.hal.Link.link; @@ -22,11 +20,13 @@ public class MeDtoFactory extends HalAppenderMapper { private final ResourceLinks resourceLinks; private final UserManager userManager; + private final GroupCollector groupCollector; @Inject - public MeDtoFactory(ResourceLinks resourceLinks, UserManager userManager) { + public MeDtoFactory(ResourceLinks resourceLinks, UserManager userManager, GroupCollector groupCollector) { this.resourceLinks = resourceLinks; this.userManager = userManager; + this.groupCollector = groupCollector; } public MeDto create() { @@ -35,16 +35,12 @@ public class MeDtoFactory extends HalAppenderMapper { MeDto dto = createDto(user); mapUserProperties(user, dto); - mapGroups(principals, dto); + mapGroups(user, dto); return dto; } - private void mapGroups(PrincipalCollection principals, MeDto dto) { - Iterable groups = principals.oneByType(GroupNames.class); - if (groups == null) { - groups = Collections.emptySet(); - } - dto.setGroups(ImmutableList.copyOf(groups)); + private void mapGroups(User user, MeDto dto) { + dto.setGroups(groupCollector.collect(user.getName())); } private void mapUserProperties(User user, MeDto dto) { diff --git a/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupCollector.java b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupCollector.java new file mode 100644 index 0000000000..8c6bac8103 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/group/DefaultGroupCollector.java @@ -0,0 +1,72 @@ +package sonia.scm.group; + +import com.cronutils.utils.VisibleForTesting; +import com.google.common.collect.ImmutableSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.cache.Cache; +import sonia.scm.cache.CacheManager; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.Set; + +/** + * Collect groups for a certain principal. + * Warning: The class is only for internal use and should never used directly. + */ +@Singleton +public class DefaultGroupCollector implements GroupCollector { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultGroupCollector.class); + + @VisibleForTesting + static final String CACHE_NAME = "sonia.cache.externalGroups"; + + private final GroupDAO groupDAO; + private final Cache> cache; + private final Set groupResolvers; + + @Inject + public DefaultGroupCollector(GroupDAO groupDAO, CacheManager cacheManager, Set groupResolvers) { + this.groupDAO = groupDAO; + this.cache = cacheManager.getCache(CACHE_NAME); + this.groupResolvers = groupResolvers; + } + + @Override + public Set collect(String principal) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + + builder.add(AUTHENTICATED); + builder.addAll(resolveExternalGroups(principal)); + appendInternalGroups(principal, builder); + + Set groups = builder.build(); + LOG.debug("collected following groups for principal {}: {}", principal, groups); + return groups; + } + + private void appendInternalGroups(String principal, ImmutableSet.Builder builder) { + for (Group group : groupDAO.getAll()) { + if (group.isMember(principal)) { + builder.add(group.getName()); + } + } + } + + private Set resolveExternalGroups(String principal) { + Set externalGroups = cache.get(principal); + + if (externalGroups == null) { + ImmutableSet.Builder newExternalGroups = ImmutableSet.builder(); + + for (GroupResolver groupResolver : groupResolvers) { + newExternalGroups.addAll(groupResolver.resolve(principal)); + } + externalGroups = newExternalGroups.build(); + cache.put(principal, externalGroups); + } + return externalGroups; + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ScmServletModule.java index 7ece64f719..cd34d03b50 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ScmServletModule.java @@ -50,8 +50,10 @@ import sonia.scm.cache.CacheManager; import sonia.scm.cache.GuavaCacheManager; import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; +import sonia.scm.group.DefaultGroupCollector; import sonia.scm.group.DefaultGroupDisplayManager; import sonia.scm.group.DefaultGroupManager; +import sonia.scm.group.GroupCollector; import sonia.scm.group.GroupDAO; import sonia.scm.group.GroupDisplayManager; import sonia.scm.group.GroupManager; @@ -195,7 +197,7 @@ class ScmServletModule extends ServletModule { bindDecorated(GroupManager.class, DefaultGroupManager.class, GroupManagerProvider.class); bind(GroupDisplayManager.class, DefaultGroupDisplayManager.class); - + bind(GroupCollector.class, DefaultGroupCollector.class); bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class); // bind sslcontext provider diff --git a/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java b/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java index 66dbb51073..3f81377992 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java +++ b/scm-webapp/src/main/java/sonia/scm/security/AuthorizationChangedEventProducer.java @@ -48,6 +48,8 @@ import sonia.scm.user.User; import sonia.scm.user.UserEvent; import sonia.scm.user.UserModificationEvent; +import javax.inject.Singleton; + /** * Receives all kinds of events, which affects authorization relevant data and fires an * {@link AuthorizationChangedEvent} if authorization data has changed. @@ -55,6 +57,7 @@ import sonia.scm.user.UserModificationEvent; * @author Sebastian Sdorra * @since 1.52 */ +@Singleton @EagerSingleton public class AuthorizationChangedEventProducer { diff --git a/scm-webapp/src/main/java/sonia/scm/security/BearerRealm.java b/scm-webapp/src/main/java/sonia/scm/security/BearerRealm.java index b237a0a5ff..324dfe9082 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/BearerRealm.java +++ b/scm-webapp/src/main/java/sonia/scm/security/BearerRealm.java @@ -104,7 +104,6 @@ public class BearerRealm extends AuthenticatingRealm return helper.authenticationInfoBuilder(accessToken.getSubject()) .withCredentials(bt.getCredentials()) .withScope(Scopes.fromClaims(accessToken.getClaims())) - .withGroups(accessToken.getGroups()) .build(); } 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 baff3b951c..28f61df34f 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultAuthorizationCollector.java @@ -52,17 +52,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; -import sonia.scm.group.GroupNames; +import sonia.scm.group.GroupCollector; import sonia.scm.group.GroupPermissions; import sonia.scm.plugin.Extension; -import sonia.scm.repository.RepositoryPermission; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryDAO; +import sonia.scm.repository.RepositoryPermission; import sonia.scm.user.User; import sonia.scm.user.UserPermissions; import sonia.scm.util.Util; import java.util.Collection; +import java.util.Set; //~--- JDK imports ------------------------------------------------------------ @@ -88,19 +89,21 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector /** * Constructs ... - * @param cacheManager + * @param cacheManager * @param repositoryDAO * @param securitySystem * @param repositoryPermissionProvider + * @param groupCollector */ @Inject public DefaultAuthorizationCollector(CacheManager cacheManager, - RepositoryDAO repositoryDAO, SecuritySystem securitySystem, RepositoryPermissionProvider repositoryPermissionProvider) + RepositoryDAO repositoryDAO, SecuritySystem securitySystem, RepositoryPermissionProvider repositoryPermissionProvider, GroupCollector groupCollector) { this.cache = cacheManager.getCache(CACHE_NAME); this.repositoryDAO = repositoryDAO; this.securitySystem = securitySystem; this.repositoryPermissionProvider = repositoryPermissionProvider; + this.groupCollector = groupCollector; } //~--- methods -------------------------------------------------------------- @@ -145,16 +148,16 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector Preconditions.checkNotNull(user, "no user found in principal collection"); - GroupNames groupNames = principals.oneByType(GroupNames.class); + Set groups = groupCollector.collect(user.getName()); - CacheKey cacheKey = new CacheKey(user.getId(), groupNames); + CacheKey cacheKey = new CacheKey(user.getId(), groups); AuthorizationInfo info = cache.get(cacheKey); if (info == null) { logger.trace("collect AuthorizationInfo for user {}", user.getName()); - info = createAuthorizationInfo(user, groupNames); + info = createAuthorizationInfo(user, groups); cache.put(cacheKey, info); } else if (logger.isTraceEnabled()) @@ -166,7 +169,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector } private void collectGlobalPermissions(Builder builder, - final User user, final GroupNames groups) + final User user, final Set groups) { Collection globalPermissions = securitySystem.getPermissions((AssignedPermission input) -> isUserPermitted(user, groups, input)); @@ -181,7 +184,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector } private void collectRepositoryPermissions(Builder builder, User user, - GroupNames groups) + Set groups) { for (Repository repository : repositoryDAO.getAll()) { @@ -190,7 +193,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector } private void collectRepositoryPermissions(Builder builder, - Repository repository, User user, GroupNames groups) + Repository repository, User user, Set groups) { Collection repositoryPermissions = repository.getPermissions(); @@ -245,7 +248,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector .getVerbs(); } - private AuthorizationInfo createAuthorizationInfo(User user, GroupNames groups) { + private AuthorizationInfo createAuthorizationInfo(User user, Set groups) { Builder builder = ImmutableSet.builder(); collectGlobalPermissions(builder, user, groups); @@ -279,7 +282,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector //~--- get methods ---------------------------------------------------------- - private boolean isUserPermitted(User user, GroupNames groups, + private boolean isUserPermitted(User user, Set groups, PermissionObject perm) { //J- @@ -314,7 +317,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector */ private static class CacheKey { - private CacheKey(String username, GroupNames groupnames) + private CacheKey(String username, Set groupnames) { this.username = username; this.groupnames = groupnames; @@ -356,7 +359,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector //~--- fields ------------------------------------------------------------- /** group names */ - private final GroupNames groupnames; + private final Set groupnames; /** username */ private final String username; @@ -374,4 +377,5 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector private final SecuritySystem securitySystem; private final RepositoryPermissionProvider repositoryPermissionProvider; + private final GroupCollector groupCollector; } diff --git a/scm-webapp/src/main/java/sonia/scm/security/DefaultRealm.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultRealm.java index bacbd9b314..e65c88e679 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/DefaultRealm.java +++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultRealm.java @@ -34,7 +34,6 @@ package sonia.scm.security; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.annotations.VisibleForTesting; - import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; @@ -45,21 +44,16 @@ import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; - -import org.apache.shiro.subject.SimplePrincipalCollection; -import sonia.scm.group.GroupNames; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.plugin.Extension; -//~--- JDK imports ------------------------------------------------------------ - import javax.inject.Inject; import javax.inject.Singleton; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * Default authorizing realm. * @@ -103,6 +97,9 @@ public class DefaultRealm extends AuthorizingRealm matcher.setPasswordService(service); setCredentialsMatcher(helper.wrapCredentialsMatcher(matcher)); setAuthenticationTokenClass(UsernamePasswordToken.class); + + // we cache in the AuthorizationCollector + setCachingEnabled(false); } //~--- methods -------------------------------------------------------------- @@ -149,7 +146,7 @@ public class DefaultRealm extends AuthorizingRealm LOG.trace("principal does not contain scope information, returning all permissions"); log(principals, info, null); } - + return info; } @@ -180,8 +177,6 @@ public class DefaultRealm extends AuthorizingRealm StringBuilder buffer = new StringBuilder("authorization summary: "); buffer.append(SEPARATOR).append("username : ").append(collection.getPrimaryPrincipal()); - buffer.append(SEPARATOR).append("groups : "); - append(buffer, collection.oneByType(GroupNames.class)); buffer.append(SEPARATOR).append("roles : "); append(buffer, original.getRoles()); buffer.append(SEPARATOR).append("scope : "); diff --git a/scm-webapp/src/main/java/sonia/scm/security/JwtAccessTokenBuilder.java b/scm-webapp/src/main/java/sonia/scm/security/JwtAccessTokenBuilder.java index cc1d4be7a7..5a74f77502 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/JwtAccessTokenBuilder.java +++ b/scm-webapp/src/main/java/sonia/scm/security/JwtAccessTokenBuilder.java @@ -40,11 +40,9 @@ import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.group.ExternalGroupNames; import java.time.Clock; import java.time.Instant; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -139,12 +137,6 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder { return this; } - @Override - public JwtAccessTokenBuilder groups(String... groups) { - Collections.addAll(this.groups, groups); - return this; - } - JwtAccessTokenBuilder refreshExpiration(Instant refreshExpiration) { this.refreshExpiration = refreshExpiration; this.refreshableFor = 0; @@ -206,16 +198,6 @@ public final class JwtAccessTokenBuilder implements AccessTokenBuilder { claims.setIssuer(issuer); } - if (!groups.isEmpty()) { - claims.put(JwtAccessToken.GROUPS_CLAIM_KEY, groups); - } else { - Subject currentSubject = SecurityUtils.getSubject(); - ExternalGroupNames externalGroupNames = currentSubject.getPrincipals().oneByType(ExternalGroupNames.class); - if (externalGroupNames != null) { - claims.put(JwtAccessToken.GROUPS_CLAIM_KEY, externalGroupNames.getCollection().toArray(new String[]{})); - } - } - // sign token and create compact version String compact = Jwts.builder() .setClaims(claims) diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAdministrationContext.java b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAdministrationContext.java index 0b380c8088..b62b6c63f3 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAdministrationContext.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAdministrationContext.java @@ -38,7 +38,6 @@ package sonia.scm.web.security; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Singleton; - import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; @@ -46,21 +45,17 @@ import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; import org.apache.shiro.util.ThreadContext; import org.apache.shiro.util.ThreadState; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sonia.scm.SCMContext; -import sonia.scm.group.GroupNames; import sonia.scm.security.Role; import sonia.scm.user.User; import sonia.scm.util.AssertUtil; -//~--- JDK imports ------------------------------------------------------------ - +import javax.xml.bind.JAXB; import java.net.URL; -import javax.xml.bind.JAXB; +//~--- JDK imports ------------------------------------------------------------ /** * @@ -161,7 +156,6 @@ public class DefaultAdministrationContext implements AdministrationContext collection.add(adminUser.getId(), REALM); collection.add(adminUser, REALM); - collection.add(new GroupNames(), REALM); collection.add(AdministrationContextMarker.MARKER, REALM); return collection; diff --git a/scm-webapp/src/main/resources/config/ehcache.xml b/scm-webapp/src/main/resources/config/ehcache.xml deleted file mode 100644 index 19abbde727..0000000000 --- a/scm-webapp/src/main/resources/config/ehcache.xml +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scm-webapp/src/main/resources/config/gcache.xml b/scm-webapp/src/main/resources/config/gcache.xml index eb59f36446..28876558df 100644 --- a/scm-webapp/src/main/resources/config/gcache.xml +++ b/scm-webapp/src/main/resources/config/gcache.xml @@ -40,15 +40,15 @@ />