mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-02-22 06:26:56 +01:00
Merge branch 'develop' into feature/import_git_from_url
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.filter;
|
||||
|
||||
import com.github.sdorra.shiro.ShiroRule;
|
||||
@@ -34,6 +34,7 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.slf4j.MDC;
|
||||
import sonia.scm.AbstractTestBase;
|
||||
import sonia.scm.SCMContext;
|
||||
import sonia.scm.TransactionId;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -50,28 +51,28 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MDCFilter}.
|
||||
*
|
||||
*
|
||||
* @author Sebastian Sdorra <sebastian.sdorra@gmail.com>
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class MDCFilterTest extends AbstractTestBase {
|
||||
|
||||
|
||||
@Rule
|
||||
public ShiroRule shiro = new ShiroRule();
|
||||
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest request;
|
||||
|
||||
|
||||
@Mock
|
||||
private HttpServletResponse response;
|
||||
|
||||
|
||||
private final MDCFilter filter = new MDCFilter();
|
||||
|
||||
/**
|
||||
* Tests {@link MDCFilter#doFilter(HttpServletRequest, HttpServletResponse, FilterChain)}.
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware(
|
||||
@@ -85,44 +86,44 @@ public class MDCFilterTest extends AbstractTestBase {
|
||||
when(request.getRemoteAddr()).thenReturn("127.0.0.1");
|
||||
when(request.getRemoteHost()).thenReturn("localhost");
|
||||
when(request.getMethod()).thenReturn("GET");
|
||||
|
||||
|
||||
MDCCapturingFilterChain chain = new MDCCapturingFilterChain();
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
|
||||
assertNotNull(chain.ctx);
|
||||
assertEquals("trillian", chain.ctx.get(MDCFilter.MDC_USERNAME));
|
||||
assertEquals("api/v1/repositories", chain.ctx.get(MDCFilter.MDC_REQUEST_URI));
|
||||
assertEquals("127.0.0.1", chain.ctx.get(MDCFilter.MDC_CLIENT_IP));
|
||||
assertEquals("localhost", chain.ctx.get(MDCFilter.MDC_CLIENT_HOST));
|
||||
assertEquals("GET", chain.ctx.get(MDCFilter.MDC_REQUEST_METHOD));
|
||||
assertNotNull(chain.ctx.get(MDCFilter.MDC_TRANSACTION_ID));
|
||||
assertNotNull(chain.ctx.get(TransactionId.KEY));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link MDCFilter#doFilter(HttpServletRequest, HttpServletResponse, FilterChain)} as anonymous user.
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Test
|
||||
@SubjectAware
|
||||
public void testDoFilterAsAnonymous() throws IOException, ServletException {
|
||||
MDCCapturingFilterChain chain = new MDCCapturingFilterChain();
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
|
||||
assertNotNull(chain.ctx);
|
||||
assertEquals(SCMContext.USER_ANONYMOUS, chain.ctx.get(MDCFilter.MDC_USERNAME));
|
||||
}
|
||||
|
||||
|
||||
private static class MDCCapturingFilterChain implements FilterChain {
|
||||
|
||||
private Map<String, String> ctx;
|
||||
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
|
||||
this.ctx = MDC.getCopyOfContextMap();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,15 +39,17 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.util.Collections.singleton;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static sonia.scm.security.SecureKeyTestUtil.createSecureKey;
|
||||
|
||||
/**
|
||||
@@ -85,52 +87,107 @@ class JwtAccessTokenBuilderTest {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mocks and set up object under test.
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUpObjectUnderTest() {
|
||||
void setUpDependencies() {
|
||||
lenient().when(keyGenerator.createKey()).thenReturn("42");
|
||||
lenient().when(secureKeyResolver.getSecureKey(anyString())).thenReturn(createSecureKey());
|
||||
enrichers = Sets.newHashSet();
|
||||
factory = new JwtAccessTokenBuilderFactory(keyGenerator, secureKeyResolver, enrichers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link JwtAccessTokenBuilder#build()}.
|
||||
*/
|
||||
@Test
|
||||
void testBuild() {
|
||||
JwtAccessToken token = factory.create().subject("dent")
|
||||
.issuer("https://www.scm-manager.org")
|
||||
.expiresIn(1, TimeUnit.MINUTES)
|
||||
.custom("a", "b")
|
||||
.scope(Scope.valueOf("repo:*"))
|
||||
.build();
|
||||
@Nested
|
||||
class SimpleTests {
|
||||
|
||||
// assert claims
|
||||
assertClaims(token);
|
||||
/**
|
||||
* Prepare mocks and set up object under test.
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUpObjectUnderTest() {
|
||||
factory = new JwtAccessTokenBuilderFactory(keyGenerator, secureKeyResolver, enrichers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link JwtAccessTokenBuilder#build()}.
|
||||
*/
|
||||
@Test
|
||||
void testBuild() {
|
||||
JwtAccessToken token = factory.create().subject("dent")
|
||||
.issuer("https://www.scm-manager.org")
|
||||
.expiresIn(1, TimeUnit.MINUTES)
|
||||
.custom("a", "b")
|
||||
.scope(Scope.valueOf("repo:*"))
|
||||
.build();
|
||||
|
||||
// assert claims
|
||||
assertClaims(token);
|
||||
|
||||
// reparse and assert again
|
||||
String compact = token.compact();
|
||||
assertThat(compact).isNotEmpty();
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secureKeyResolver.getSecureKey("dent").getBytes())
|
||||
.parseClaimsJws(compact)
|
||||
.getBody();
|
||||
assertClaims(new JwtAccessToken(claims, compact));
|
||||
}
|
||||
|
||||
private void assertClaims(JwtAccessToken token) {
|
||||
assertThat(token.getId()).isNotEmpty();
|
||||
assertThat(token.getIssuedAt()).isNotNull();
|
||||
assertThat(token.getExpiration()).isNotNull();
|
||||
assertThat(token.getExpiration().getTime() > token.getIssuedAt().getTime()).isTrue();
|
||||
assertThat(token.getSubject()).isEqualTo("dent");
|
||||
assertThat(token.getIssuer()).isNotEmpty();
|
||||
assertThat(token.getIssuer()).get().isEqualTo("https://www.scm-manager.org");
|
||||
assertThat(token.getCustom("a")).get().isEqualTo("b");
|
||||
assertThat(token.getScope()).hasToString("[\"repo:*\"]");
|
||||
}
|
||||
|
||||
// reparse and assert again
|
||||
String compact = token.compact();
|
||||
assertThat(compact).isNotEmpty();
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secureKeyResolver.getSecureKey("dent").getBytes())
|
||||
.parseClaimsJws(compact)
|
||||
.getBody();
|
||||
assertClaims(new JwtAccessToken(claims, compact));
|
||||
}
|
||||
|
||||
private void assertClaims(JwtAccessToken token) {
|
||||
assertThat(token.getId()).isNotEmpty();
|
||||
assertThat(token.getIssuedAt()).isNotNull();
|
||||
assertThat(token.getExpiration()).isNotNull();
|
||||
assertThat(token.getExpiration().getTime() > token.getIssuedAt().getTime()).isTrue();
|
||||
assertThat(token.getSubject()).isEqualTo("dent");
|
||||
assertThat(token.getIssuer()).isNotEmpty();
|
||||
assertThat(token.getIssuer()).get().isEqualTo("https://www.scm-manager.org");
|
||||
assertThat(token.getCustom("a")).get().isEqualTo("b");
|
||||
assertThat(token.getScope()).hasToString("[\"repo:*\"]");
|
||||
@Nested
|
||||
class ClockTests {
|
||||
|
||||
@Mock
|
||||
private Clock clock;
|
||||
|
||||
@BeforeEach
|
||||
void setUpObjectUnderTest() {
|
||||
factory = new JwtAccessTokenBuilderFactory(keyGenerator, secureKeyResolver, enrichers, clock);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSetRefreshExpiration() {
|
||||
Instant now = Instant.now();
|
||||
when(clock.instant()).thenReturn(now);
|
||||
|
||||
JwtAccessToken token = factory.create()
|
||||
.subject("dent")
|
||||
.refreshableFor(2, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
assertThat(token.getRefreshExpiration()).isPresent();
|
||||
Date date = token.getRefreshExpiration().get();
|
||||
|
||||
assertThat(date).hasSameTimeAs(Date.from(now.plusSeconds(2L)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSetDefaultRefreshExpiration() {
|
||||
Instant now = Instant.now();
|
||||
when(clock.instant()).thenReturn(now);
|
||||
|
||||
JwtAccessToken token = factory.create()
|
||||
.subject("dent")
|
||||
.build();
|
||||
|
||||
assertThat(token.getRefreshExpiration()).isPresent();
|
||||
Date date = token.getRefreshExpiration().get();
|
||||
|
||||
long defaultRefresh = JwtAccessTokenBuilder.DEFAULT_REFRESHABLE_UNIT.toMillis(JwtAccessTokenBuilder.DEFAULT_REFRESHABLE);
|
||||
assertThat(date).hasSameTimeAs(Date.from(now.plusMillis(defaultRefresh)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -48,12 +48,15 @@ import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@@ -239,6 +242,30 @@ class I18nServletTest {
|
||||
assertJson(json);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotHaveInvalidPluginsJsonFiles() throws IOException {
|
||||
String path = getClass().getClassLoader().getResource("locales/en/plugins.json").getPath();
|
||||
assertThat(path).isNotNull();
|
||||
|
||||
Path filePath = Paths.get(path);
|
||||
Path translationRootPath = filePath.getParent().getParent();
|
||||
assertThat(translationRootPath).isDirectoryContaining("glob:**/en");
|
||||
|
||||
Files
|
||||
.list(translationRootPath)
|
||||
.filter(Files::isDirectory)
|
||||
.map(localePath -> localePath.resolve("plugins.json"))
|
||||
.forEach(this::validatePluginsJson);
|
||||
}
|
||||
|
||||
private void validatePluginsJson(Path path) {
|
||||
try {
|
||||
new ObjectMapper().readTree(path.toFile());
|
||||
} catch (IOException e) {
|
||||
fail("error while parsing translation file " + path, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyHeaders(HttpServletResponse response) {
|
||||
verify(response).setCharacterEncoding("UTF-8");
|
||||
verify(response).setContentType("application/json");
|
||||
|
||||
Reference in New Issue
Block a user