Merge branch 'develop' into bugfix/api-key-to-access-token

This commit is contained in:
Konstantin Schaper
2020-11-03 14:48:39 +01:00
committed by GitHub
117 changed files with 2003 additions and 833 deletions

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.api.v2.resources;
import org.junit.jupiter.params.ParameterizedTest;
@@ -29,6 +29,7 @@ import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static sonia.scm.repository.Branch.VALID_BRANCH_NAMES;
class BranchDtoTest {
@@ -54,10 +55,11 @@ class BranchDtoTest {
"val{d",
"val{}d",
"val|kill",
"val}"
"val}",
"va/li/d"
})
void shouldAcceptValidBranchName(String branchName) {
assertTrue(branchName.matches(BranchDto.VALID_BRANCH_NAMES));
assertTrue(branchName.matches(VALID_BRANCH_NAMES));
}
@ParameterizedTest
@@ -70,6 +72,6 @@ class BranchDtoTest {
"val id"
})
void shouldRejectInvalidBranchName(String branchName) {
assertFalse(branchName.matches(BranchDto.VALID_BRANCH_NAMES));
assertFalse(branchName.matches(VALID_BRANCH_NAMES));
}
}

View File

@@ -34,6 +34,7 @@ import sonia.scm.security.AnonymousMode;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.MockitoAnnotations.initMocks;
@@ -42,9 +43,7 @@ public class ConfigDtoToScmConfigurationMapperTest {
@InjectMocks
private ConfigDtoToScmConfigurationMapperImpl mapper;
private String[] expectedUsers = {"trillian", "arthur"};
private String[] expectedGroups = {"admin", "plebs"};
private String[] expectedExcludes = {"ex", "clude"};
private final String[] expectedExcludes = {"ex", "clude"};
@Before
public void init() {
@@ -73,6 +72,7 @@ public class ConfigDtoToScmConfigurationMapperTest {
assertEquals("https://plug.ins", config.getPluginUrl());
assertEquals(40, config.getLoginAttemptLimitTimeout());
assertTrue(config.isEnabledXsrfProtection());
assertFalse(config.isEnabledUserConverter());
assertEquals("username", config.getNamespaceStrategy());
assertEquals("https://scm-manager.org/login-info", config.getLoginInfoUrl());
assertEquals("hitchhiker.mail", config.getMailDomainName());
@@ -115,6 +115,7 @@ public class ConfigDtoToScmConfigurationMapperTest {
configDto.setNamespaceStrategy("username");
configDto.setLoginInfoUrl("https://scm-manager.org/login-info");
configDto.setMailDomainName("hitchhiker.mail");
configDto.setEnabledUserConverter(false);
return configDto;
}

View File

@@ -43,6 +43,7 @@ import sonia.scm.ContextEntry;
import sonia.scm.group.GroupCollector;
import sonia.scm.security.ApiKey;
import sonia.scm.security.ApiKeyService;
import sonia.scm.user.EMail;
import sonia.scm.user.InvalidPasswordException;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
@@ -96,6 +97,9 @@ public class MeResourceTest {
@Mock
private ApiKeyService apiKeyService;
@Mock
private EMail eMail;
@InjectMocks
private MeDtoFactory meDtoFactory;
@InjectMocks

View File

@@ -28,6 +28,7 @@ import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware;
import com.google.common.io.Resources;
import com.google.inject.util.Providers;
import com.sun.mail.iap.Argument;
import org.apache.shiro.authc.credential.PasswordService;
import org.jboss.resteasy.mock.MockHttpRequest;
import org.jboss.resteasy.mock.MockHttpResponse;
@@ -58,10 +59,12 @@ import java.util.Collection;
import java.util.function.Predicate;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
@@ -457,6 +460,43 @@ public class UserRootResourceTest {
assertEquals("other:*", captor.getValue().iterator().next().getValue());
}
@Test
public void shouldConvertUserToInternalAndSetNewPassword() throws URISyntaxException {
when(passwordService.encryptPassword(anyString())).thenReturn("abc");
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
MockHttpRequest request = MockHttpRequest
.put("/" + UserRootResource.USERS_PATH_V2 + "Neo/convert-to-internal")
.contentType(VndMediaType.USER)
.content("{\"newPassword\":\"trillian\"}".getBytes());
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
verify(passwordService).encryptPassword("trillian");
verify(userManager).overwritePassword("Neo", "abc");
verify(userManager).modify(userCaptor.capture());
User user = userCaptor.getValue();
assertThat(user.isExternal()).isFalse();
}
@Test
public void shouldConvertUserToExternalAndRemoveLocalPassword() throws URISyntaxException {
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
MockHttpRequest request = MockHttpRequest
.put("/" + UserRootResource.USERS_PATH_V2 + "Neo/convert-to-external")
.contentType(VndMediaType.USER);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
verify(userManager).overwritePassword("Neo", null);
verify(userManager).modify(userCaptor.capture());
User user = userCaptor.getValue();
assertThat(user.isExternal()).isTrue();
}
private PageResult<User> createSingletonPageResult(int overallCount) {
return new PageResult<>(singletonList(createDummyUser("Neo")), overallCount);
}

View File

@@ -90,25 +90,15 @@ public class UserToUserDtoMapperTest {
}
@Test
public void shouldGetPasswordLinkForAdmin() {
public void shouldGetInternalUserLinks() {
User user = createDefaultUser();
user.setExternal(false);
when(subject.isPermitted("user:modify:abc")).thenReturn(true);
when(userManager.isTypeDefault(eq(user))).thenReturn(true);
UserDto userDto = mapper.map(user);
assertEquals("expected password link with modify permission", expectedBaseUri.resolve("abc/password").toString(), userDto.getLinks().getLinkBy("password").get().getHref());
}
@Test
public void shouldGetPasswordLinkOnlyForDefaultUserType() {
User user = createDefaultUser();
when(subject.isPermitted("user:modify:abc")).thenReturn(true);
when(userManager.isTypeDefault(eq(user))).thenReturn(false);
UserDto userDto = mapper.map(user);
assertFalse("expected no password link", userDto.getLinks().getLinkBy("password").isPresent());
assertEquals("expected convert to external link with modify permission", expectedBaseUri.resolve("abc/convert-to-external").toString(), userDto.getLinks().getLinkBy("convertToExternal").get().getHref());
}
@Test

View File

@@ -148,12 +148,6 @@ class DefaultRepositoryRoleManagerTest {
verify(dao).modify(role);
}
@Test
void shouldNotModifyRole_whenTypeChanged() {
assertThrows(ScmConstraintViolationException.class, () -> manager.modify(new RepositoryRole(CUSTOM_ROLE_NAME, singletonList("changed"), null)));
verify(dao, never()).modify(any());
}
@Test
void shouldNotModifyRole_whenRoleDoesNotExists() {
assertThrows(NotFoundException.class, () -> manager.modify(new RepositoryRole("noSuchRole", singletonList("changed"), null)));

View File

@@ -103,7 +103,7 @@ class JwtAccessTokenBuilderTest {
void testBuild() {
JwtAccessToken token = factory.create().subject("dent")
.issuer("https://www.scm-manager.org")
.expiresIn(5, TimeUnit.SECONDS)
.expiresIn(1, TimeUnit.MINUTES)
.custom("a", "b")
.scope(Scope.valueOf("repo:*"))
.build();

View File

@@ -21,66 +21,52 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.user;
//~--- non-JDK imports --------------------------------------------------------
package sonia.scm.user;
import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware;
import com.google.common.collect.Lists;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import sonia.scm.NotFoundException;
import sonia.scm.store.JAXBConfigurationStoreFactory;
import sonia.scm.user.xml.XmlUserDAO;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.util.Collections;
import java.util.List;
import org.junit.Rule;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
*
* @author Sebastian Sdorra
*/
@SubjectAware(
username = "trillian",
password = "secret",
configuration = "classpath:sonia/scm/repository/shiro.ini"
username = "trillian",
password = "secret",
configuration = "classpath:sonia/scm/repository/shiro.ini"
)
public class DefaultUserManagerTest extends UserManagerTestBase
{
public class DefaultUserManagerTest extends UserManagerTestBase {
@Rule
public ShiroRule shiro = new ShiroRule();
private UserDAO userDAO ;
private User trillian;
private UserDAO userDAO;
/**
* Method description
*
*
* @return
*/
@Override
public UserManager createManager()
{
public UserManager createManager() {
return new DefaultUserManager(createXmlUserDAO());
}
@Before
public void initDao() {
trillian = UserTestData.createTrillian();
User trillian = UserTestData.createTrillian();
trillian.setPassword("oldEncrypted");
userDAO = mock(UserDAO.class);
@@ -108,15 +94,6 @@ public class DefaultUserManagerTest extends UserManagerTestBase
Assertions.assertThat(userCaptor.getValue().getPassword()).isEqualTo("newEncrypted");
}
@Test(expected = ChangePasswordNotAllowedException.class)
public void shouldFailOverwritePasswordForWrongType() {
trillian.setType("wrongType");
UserManager userManager = new DefaultUserManager(userDAO);
userManager.overwritePassword("trillian", "---");
}
@Test(expected = NotFoundException.class)
public void shouldFailOverwritePasswordForMissingUser() {
UserManager userManager = new DefaultUserManager(userDAO);
@@ -124,6 +101,16 @@ public class DefaultUserManagerTest extends UserManagerTestBase
userManager.overwritePassword("notExisting", "---");
}
@Test(expected = ChangePasswordNotAllowedException.class)
public void shouldFailOverwritePasswordForExternalUser() {
User trillian = new User("trillian");
trillian.setExternal(true);
when(userDAO.get("trillian")).thenReturn(trillian);
UserManager userManager = new DefaultUserManager(userDAO);
userManager.overwritePassword("trillian", "---");
}
@Test
public void shouldSucceedOverwritePassword() {
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);

View File

@@ -0,0 +1,79 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.user;
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.config.ScmConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class InternalToExternalUserConverterTest {
@Mock
ScmConfiguration scmConfiguration;
@InjectMocks
InternalToExternalUserConverter converter;
@Test
void shouldNotConvertExternalUser() {
User external = new User();
external.setExternal(true);
User user = converter.convert(external);
assertThat(user).isSameAs(external);
}
@Test
void shouldNotConvertIfConfigDisabled() {
when(scmConfiguration.isEnabledUserConverter()).thenReturn(false);
User external = new User();
external.setExternal(false);
User user = converter.convert(external);
assertThat(user).isSameAs(external);
}
@Test
void shouldReturnConvertedUser() {
when(scmConfiguration.isEnabledUserConverter()).thenReturn(true);
User internal = new User();
internal.setExternal(false);
User external = converter.convert(internal);
assertThat(external).isInstanceOf(User.class);
assertThat(external.isExternal()).isTrue();
assertThat(external.getPassword()).isNull();
}
}

View File

@@ -91,15 +91,12 @@ class HttpProtocolServletTest {
@BeforeEach
void prepareMocks() {
when(userAgentParser.parse(request)).thenReturn(userAgent);
when(userAgent.isBrowser()).thenReturn(true);
when(userAgent.isScmClient()).thenReturn(false);
when(request.getRequestURI()).thenReturn("uri");
}
@Test
void shouldDispatchBrowserRequests() throws ServletException, IOException {
when(userAgent.isBrowser()).thenReturn(true);
when(request.getRequestURI()).thenReturn("uri");
servlet.service(request, response);
verify(dispatcher).dispatch(request, response, "uri");
@@ -113,7 +110,7 @@ class HttpProtocolServletTest {
@BeforeEach
void prepareMocks() {
when(userAgentParser.parse(request)).thenReturn(userAgent);
when(userAgent.isBrowser()).thenReturn(false);
when(userAgent.isScmClient()).thenReturn(true);
}
@Test