diff --git a/CHANGELOG.md b/CHANGELOG.md index 41136781ab..a4775648d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Added - Automatic user converter for external users ([#1380](https://github.com/scm-manager/scm-manager/pull/1380)) +- Create _authenticated group on setup ([#1396](https://github.com/scm-manager/scm-manager/pull/1396)) - The name of the initial git branch can be configured and is set to `main` by default ([#1399](https://github.com/scm-manager/scm-manager/pull/1399)) ### Fixed diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/SetupContextListener.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/SetupContextListener.java index af95c09aa8..1f47f03686 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/SetupContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/SetupContextListener.java @@ -30,6 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; +import sonia.scm.group.Group; +import sonia.scm.group.GroupManager; import sonia.scm.plugin.Extension; import sonia.scm.security.AnonymousMode; import sonia.scm.security.PermissionAssigner; @@ -44,6 +46,8 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import java.util.Collections; +import static sonia.scm.group.GroupCollector.AUTHENTICATED; + @Extension public class SetupContextListener implements ServletContextListener { @@ -75,13 +79,18 @@ public class SetupContextListener implements ServletContextListener { private final PasswordService passwordService; private final PermissionAssigner permissionAssigner; private final ScmConfiguration scmConfiguration; + private final GroupManager groupManager; + + @VisibleForTesting + static final String AUTHENTICATED_GROUP_DESCRIPTION = "Includes all authenticated users"; @Inject - public SetupAction(UserManager userManager, PasswordService passwordService, PermissionAssigner permissionAssigner, ScmConfiguration scmConfiguration) { + public SetupAction(UserManager userManager, PasswordService passwordService, PermissionAssigner permissionAssigner, ScmConfiguration scmConfiguration, GroupManager groupManager) { this.userManager = userManager; this.passwordService = passwordService; this.permissionAssigner = permissionAssigner; this.scmConfiguration = scmConfiguration; + this.groupManager = groupManager; } @Override @@ -92,6 +101,10 @@ public class SetupContextListener implements ServletContextListener { if (anonymousUserRequiredButNotExists()) { userManager.create(SCMContext.ANONYMOUS); } + + if (authenticatedGroupDoesNotExists()) { + createAuthenticatedGroup(); + } } private boolean anonymousUserRequiredButNotExists() { @@ -115,5 +128,16 @@ public class SetupContextListener implements ServletContextListener { PermissionDescriptor descriptor = new PermissionDescriptor("*"); permissionAssigner.setPermissionsForUser("scmadmin", Collections.singleton(descriptor)); } + + private boolean authenticatedGroupDoesNotExists() { + return groupManager.get(AUTHENTICATED) == null; + } + + private void createAuthenticatedGroup() { + Group authenticated = new Group("xml", AUTHENTICATED); + authenticated.setDescription(AUTHENTICATED_GROUP_DESCRIPTION); + authenticated.setExternal(true); + groupManager.create(authenticated); + } } } diff --git a/scm-webapp/src/test/java/sonia/scm/lifecycle/SetupContextListenerTest.java b/scm-webapp/src/test/java/sonia/scm/lifecycle/SetupContextListenerTest.java index fab7b789ad..e6984ff537 100644 --- a/scm-webapp/src/test/java/sonia/scm/lifecycle/SetupContextListenerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/lifecycle/SetupContextListenerTest.java @@ -37,6 +37,8 @@ import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; +import sonia.scm.group.Group; +import sonia.scm.group.GroupManager; import sonia.scm.security.AnonymousMode; import sonia.scm.security.PermissionAssigner; import sonia.scm.security.PermissionDescriptor; @@ -56,6 +58,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static sonia.scm.group.GroupCollector.AUTHENTICATED; +import static sonia.scm.lifecycle.SetupContextListener.SetupAction.AUTHENTICATED_GROUP_DESCRIPTION; @ExtendWith(MockitoExtension.class) class SetupContextListenerTest { @@ -75,6 +79,9 @@ class SetupContextListenerTest { @Mock ScmConfiguration scmConfiguration; + @Mock + private GroupManager groupManager; + @Mock private PermissionAssigner permissionAssigner; @@ -96,6 +103,7 @@ class SetupContextListenerTest { @Test void shouldCreateAdminAccountIfNoUserExistsAndAssignPermissions() { + when(groupManager.get(AUTHENTICATED)).thenReturn(createAuthenticatedGroup()); when(passwordService.encryptPassword("scmadmin")).thenReturn("secret"); setupContextListener.contextInitialized(null); @@ -108,6 +116,7 @@ class SetupContextListenerTest { void shouldCreateAdminAccountIfOnlyAnonymousUserExistsAndAssignPermissions() { when(userManager.getAll()).thenReturn(Lists.newArrayList(SCMContext.ANONYMOUS)); when(userManager.contains(SCMContext.USER_ANONYMOUS)).thenReturn(true); + when(groupManager.get(AUTHENTICATED)).thenReturn(createAuthenticatedGroup()); when(passwordService.encryptPassword("scmadmin")).thenReturn("secret"); setupContextListener.contextInitialized(null); @@ -135,6 +144,7 @@ class SetupContextListenerTest { void shouldDoNothingOnSecondStart() { List users = Lists.newArrayList(UserTestData.createTrillian()); when(userManager.getAll()).thenReturn(users); + when(groupManager.get(AUTHENTICATED)).thenReturn(createAuthenticatedGroup()); setupContextListener.contextInitialized(null); @@ -146,6 +156,7 @@ class SetupContextListenerTest { void shouldCreateAnonymousUserIfRequired() { List users = Lists.newArrayList(UserTestData.createTrillian()); when(userManager.getAll()).thenReturn(users); + when(groupManager.get(AUTHENTICATED)).thenReturn(createAuthenticatedGroup()); when(scmConfiguration.getAnonymousMode()).thenReturn(AnonymousMode.FULL); setupContextListener.contextInitialized(null); @@ -157,6 +168,7 @@ class SetupContextListenerTest { void shouldNotCreateAnonymousUserIfNotRequired() { List users = Lists.newArrayList(UserTestData.createTrillian()); when(userManager.getAll()).thenReturn(users); + when(groupManager.get(AUTHENTICATED)).thenReturn(createAuthenticatedGroup()); setupContextListener.contextInitialized(null); @@ -167,6 +179,7 @@ class SetupContextListenerTest { void shouldNotCreateAnonymousUserIfAlreadyExists() { List users = Lists.newArrayList(SCMContext.ANONYMOUS); when(userManager.getAll()).thenReturn(users); + when(groupManager.get(AUTHENTICATED)).thenReturn(createAuthenticatedGroup()); when(scmConfiguration.getAnonymousMode()).thenReturn(AnonymousMode.FULL); setupContextListener.contextInitialized(null); @@ -174,6 +187,28 @@ class SetupContextListenerTest { verify(userManager, times(1)).create(SCMContext.ANONYMOUS); } + @Test + void shouldCreateAuthenticatedGroupIfMissing() { + when(groupManager.get(AUTHENTICATED)).thenReturn(null); + + setupContextListener.contextInitialized(null); + + Group authenticated = createAuthenticatedGroup(); + authenticated.setDescription(AUTHENTICATED_GROUP_DESCRIPTION); + authenticated.setExternal(true); + + verify(groupManager, times(1)).create(authenticated); + } + + @Test + void shouldNotCreateAuthenticatedGroupIfAlreadyExists() { + when(groupManager.get(AUTHENTICATED)).thenReturn(createAuthenticatedGroup()); + + setupContextListener.contextInitialized(null); + + verify(groupManager, never()).create(any()); + } + private void verifyAdminPermissionsAssigned() { ArgumentCaptor usernameCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor> permissionCaptor = ArgumentCaptor.forClass(Collection.class); @@ -192,4 +227,7 @@ class SetupContextListenerTest { assertThat(user.getPassword()).isEqualTo("secret"); } + private Group createAuthenticatedGroup() { + return new Group("xml", AUTHENTICATED); + } }