fixed admin permissions of initial created scmadmin user account

This commit is contained in:
Sebastian Sdorra
2019-03-13 12:15:13 +01:00
parent 4ffdde6417
commit 017879619c
6 changed files with 166 additions and 159 deletions

View File

@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
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
-->
<users>
<name>scmadmin</name>
<displayName>SCM Administrator</displayName>
<mail>scm-admin@scm-manager.org</mail>
<password>$shiro1$SHA-512$8192$$yrNahBVDa4Gz+y5gat4msdjyvjtHlVE+N5nTl4WIDhtBFwhSIib13mKJt1sWmVqgHDWi3VwX7fkdkJ2+WToTbw==</password>
<admin>true</admin>
<type>xml</type>
</users>

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<!--
Document : anonymous-account.xml
Created on : December 30, 2010, 12:44 PM
Author : sdorra
Description:
Purpose of the document follows.
-->
<users>
<name>anonymous</name>
<displayName>SCM Anonymous</displayName>
<mail>scm-anonymous@scm-manager.org</mail>
<admin>false</admin>
<type>xml</type>
</users>

View File

@@ -0,0 +1,71 @@
package sonia.scm.boot;
import com.google.common.annotations.VisibleForTesting;
import org.apache.shiro.authc.credential.PasswordService;
import sonia.scm.plugin.Extension;
import sonia.scm.security.PermissionAssigner;
import sonia.scm.security.PermissionDescriptor;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import sonia.scm.web.security.AdministrationContext;
import sonia.scm.web.security.PrivilegedAction;
import javax.inject.Inject;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.Collections;
@Extension
public class SetupContextListener implements ServletContextListener {
private final AdministrationContext administrationContext;
@Inject
public SetupContextListener(AdministrationContext administrationContext) {
this.administrationContext = administrationContext;
}
@Override
public void contextInitialized(ServletContextEvent sce) {
administrationContext.runAsAdmin(SetupAction.class);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {}
@VisibleForTesting
static class SetupAction implements PrivilegedAction {
private final UserManager userManager;
private final PasswordService passwordService;
private final PermissionAssigner permissionAssigner;
@Inject
public SetupAction(UserManager userManager, PasswordService passwordService, PermissionAssigner permissionAssigner) {
this.userManager = userManager;
this.passwordService = passwordService;
this.permissionAssigner = permissionAssigner;
}
@Override
public void run() {
if (isFirstStart()) {
createAdminAccount();
}
}
private boolean isFirstStart() {
return userManager.getAll().isEmpty();
}
private void createAdminAccount() {
User scmadmin = new User("scmadmin", "SCM Administrator", "scm-admin@scm-manager.org");
String password = passwordService.encryptPassword("scmadmin");
scmadmin.setPassword(password);
userManager.create(scmadmin);
PermissionDescriptor descriptor = new PermissionDescriptor("*");
permissionAssigner.setPermissionsForUser("scmadmin", Collections.singleton(descriptor));
}
}
}

View File

@@ -71,13 +71,6 @@ import java.util.List;
public class DefaultUserManager extends AbstractUserManager public class DefaultUserManager extends AbstractUserManager
{ {
/** Field description */
public static final String ADMIN_PATH = "/sonia/scm/config/admin-account.xml";
/** Field description */
public static final String ANONYMOUS_PATH =
"/sonia/scm/config/anonymous-account.xml";
/** Field description */ /** Field description */
public static final String STORE_NAME = "users"; public static final String STORE_NAME = "users";
@@ -173,12 +166,6 @@ public class DefaultUserManager extends AbstractUserManager
@Override @Override
public void init(SCMContextProvider context) public void init(SCMContextProvider context)
{ {
// create default account only, if no other account is available
if (userDAO.getAll().isEmpty())
{
createDefaultAccounts();
}
} }
/** /**
@@ -457,28 +444,6 @@ public class DefaultUserManager extends AbstractUserManager
} }
} }
/**
* Method description
*
*/
private void createDefaultAccounts()
{
try
{
logger.info("create default accounts");
JAXBContext context = JAXBContext.newInstance(User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
createDefaultAccount(unmarshaller, ADMIN_PATH);
createDefaultAccount(unmarshaller, ANONYMOUS_PATH);
}
catch (JAXBException ex)
{
logger.error("could not create default accounts", ex);
}
}
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
private final UserDAO userDAO; private final UserDAO userDAO;

View File

@@ -0,0 +1,94 @@
package sonia.scm.boot;
import com.google.common.collect.Lists;
import org.apache.shiro.authc.credential.PasswordService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.security.PermissionAssigner;
import sonia.scm.security.PermissionDescriptor;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import sonia.scm.user.UserTestData;
import sonia.scm.web.security.AdministrationContext;
import java.util.Collection;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class SetupContextListenerTest {
@Mock
private AdministrationContext administrationContext;
@InjectMocks
private SetupContextListener setupContextListener;
@Mock
private UserManager userManager;
@Mock
private PasswordService passwordService;
@Mock
private PermissionAssigner permissionAssigner;
@InjectMocks
private SetupContextListener.SetupAction setupAction;
@BeforeEach
void setupObjectUnderTest() {
doAnswer(ic -> {
setupAction.run();
return null;
}).when(administrationContext).runAsAdmin(SetupContextListener.SetupAction.class);
}
@Test
void shouldCreateAdminAccountAndAssignPermissions() {
when(passwordService.encryptPassword("scmadmin")).thenReturn("secret");
setupContextListener.contextInitialized(null);
verifyAdminCreated();
verifyAdminPermissionsAssigned();
}
@Test
void shouldDoNothingOnSecondStart() {
List<User> users = Lists.newArrayList(UserTestData.createTrillian());
when(userManager.getAll()).thenReturn(users);
setupContextListener.contextInitialized(null);
verify(userManager, never()).create(any(User.class));
verify(permissionAssigner, never()).setPermissionsForUser(anyString(), any(Collection.class));
}
private void verifyAdminPermissionsAssigned() {
ArgumentCaptor<String> usernameCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Collection<PermissionDescriptor>> permissionCaptor = ArgumentCaptor.forClass(Collection.class);
verify(permissionAssigner).setPermissionsForUser(usernameCaptor.capture(), permissionCaptor.capture());
String username = usernameCaptor.getValue();
assertThat(username).isEqualTo("scmadmin");
PermissionDescriptor descriptor = permissionCaptor.getValue().iterator().next();
assertThat(descriptor.getValue()).isEqualTo("*");
}
private void verifyAdminCreated() {
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
verify(userManager).create(userCaptor.capture());
User user = userCaptor.getValue();
assertThat(user.getName()).isEqualTo("scmadmin");
assertThat(user.getPassword()).isEqualTo("secret");
}
}

View File

@@ -67,7 +67,7 @@ import org.junit.Rule;
) )
public class DefaultUserManagerTest extends UserManagerTestBase public class DefaultUserManagerTest extends UserManagerTestBase
{ {
@Rule @Rule
public ShiroRule shiro = new ShiroRule(); public ShiroRule shiro = new ShiroRule();
@@ -97,39 +97,6 @@ public class DefaultUserManagerTest extends UserManagerTestBase
when(userDAO.get("trillian")).thenReturn(trillian); when(userDAO.get("trillian")).thenReturn(trillian);
} }
/**
* Method description
*
*/
@Test
public void testDefaultAccountAfterFristStart()
{
List<User> users = Lists.newArrayList(new User("tuser"));
when(userDAO.getAll()).thenReturn(users);
UserManager userManager = new DefaultUserManager(userDAO);
userManager.init(contextProvider);
verify(userDAO, never()).add(any(User.class));
}
/**
* Method description
*
*/
@Test
@SuppressWarnings("unchecked")
public void testDefaultAccountCreation()
{
when(userDAO.getAll()).thenReturn(Collections.EMPTY_LIST);
UserManager userManager = new DefaultUserManager(userDAO);
userManager.init(contextProvider);
verify(userDAO, times(2)).add(any(User.class));
}
@Test(expected = InvalidPasswordException.class) @Test(expected = InvalidPasswordException.class)
public void shouldFailChangePasswordForWrongOldPassword() { public void shouldFailChangePasswordForWrongOldPassword() {
UserManager userManager = new DefaultUserManager(userDAO); UserManager userManager = new DefaultUserManager(userDAO);