diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LfsAccessTokenFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LfsAccessTokenFactory.java index ba24d0fd35..c290b513e1 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LfsAccessTokenFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LfsAccessTokenFactory.java @@ -7,7 +7,6 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryPermissions; import sonia.scm.security.AccessToken; import sonia.scm.security.AccessTokenBuilderFactory; -import sonia.scm.security.Permission; import sonia.scm.security.Scope; import javax.inject.Inject; diff --git a/scm-webapp/src/main/java/sonia/scm/security/XsrfAccessTokenEnricher.java b/scm-webapp/src/main/java/sonia/scm/security/XsrfAccessTokenEnricher.java index 617950ddea..b12a43ffe6 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/XsrfAccessTokenEnricher.java +++ b/scm-webapp/src/main/java/sonia/scm/security/XsrfAccessTokenEnricher.java @@ -1,19 +1,19 @@ /** * Copyright (c) 2014, 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. + * 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. + * 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. - * + * 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 @@ -24,17 +24,19 @@ * 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.security; import com.google.common.annotations.VisibleForTesting; + import java.util.UUID; import javax.inject.Inject; import javax.inject.Provider; import javax.servlet.http.HttpServletRequest; + +import com.google.inject.OutOfScopeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.config.ScmConfiguration; @@ -46,9 +48,9 @@ import sonia.scm.util.HttpUtil; * add the xsrf field, if the authentication request is issued from the web interface and xsrf protection is * enabled. The xsrf field will be validated on every request by the {@link XsrfAccessTokenValidator}. Xsrf protection * can be disabled with {@link ScmConfiguration#setEnabledXsrfProtection(boolean)}. - * - * @see Issue 793 + * * @author Sebastian Sdorra + * @see Issue 793 * @since 2.0.0 */ @Extension @@ -58,14 +60,14 @@ public class XsrfAccessTokenEnricher implements AccessTokenEnricher { * the logger for XsrfAccessTokenEnricher */ private static final Logger LOG = LoggerFactory.getLogger(XsrfAccessTokenEnricher.class); - + private final ScmConfiguration configuration; private final Provider requestProvider; /** * Constructs a new instance. - * - * @param configuration scm main configuration + * + * @param configuration scm main configuration * @param requestProvider http request provider */ @Inject @@ -73,12 +75,11 @@ public class XsrfAccessTokenEnricher implements AccessTokenEnricher { this.configuration = configuration; this.requestProvider = requestProvider; } - + @Override public void enrich(AccessTokenBuilder builder) { if (configuration.isEnabledXsrfProtection()) { - if (HttpUtil.isWUIRequest(requestProvider.get())) { - LOG.debug("received wui token claim, enrich jwt with xsrf key"); + if (isEnrichable()) { builder.custom(Xsrf.TOKEN_KEY, createToken()); } else { LOG.trace("skip xsrf enrichment, because jwt session is started from a non wui client"); @@ -87,11 +88,26 @@ public class XsrfAccessTokenEnricher implements AccessTokenEnricher { LOG.trace("xsrf is disabled, skip xsrf enrichment"); } } - + + private boolean isEnrichable() { + try { + HttpServletRequest request = requestProvider.get(); + if (HttpUtil.isWUIRequest(request)) { + LOG.debug("received wui token claim, enrich jwt with xsrf key"); + return true; + } else { + LOG.trace("skip xsrf enrichment, because jwt session is started from a non wui client"); + } + } catch (OutOfScopeException ex) { + LOG.trace("skip xsrf enrichment, because no request scope is available"); + } + return false; + } + @VisibleForTesting String createToken() { // TODO create interface and use a better method return UUID.randomUUID().toString(); } - + } diff --git a/scm-webapp/src/test/java/sonia/scm/security/XsrfAccessTokenEnricherTest.java b/scm-webapp/src/test/java/sonia/scm/security/XsrfAccessTokenEnricherTest.java index 37d853011d..0d8960b0ee 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/XsrfAccessTokenEnricherTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/XsrfAccessTokenEnricherTest.java @@ -1,19 +1,19 @@ /** * Copyright (c) 2014, 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. + * 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. + * 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. - * + * 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 @@ -24,103 +24,118 @@ * 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.security; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import com.google.inject.OutOfScopeException; +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.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.config.ScmConfiguration; import sonia.scm.util.HttpUtil; +import javax.inject.Provider; import javax.servlet.http.HttpServletRequest; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; /** * Unit tests for {@link XsrfAccessTokenEnricher}. - * + * * @author Sebastian Sdorra */ -@RunWith(MockitoJUnitRunner.class) -public class XsrfAccessTokenEnricherTest { +@ExtendWith(MockitoExtension.class) +class XsrfAccessTokenEnricherTest { @Mock private HttpServletRequest request; @Mock private AccessTokenBuilder builder; - + private ScmConfiguration configuration; - + private XsrfAccessTokenEnricher enricher; - - /** - * Prepare object under test. - */ - @Before - public void prepareObjectUnderTest() { + + @BeforeEach + void createConfiguration() { configuration = new ScmConfiguration(); - enricher = new XsrfAccessTokenEnricher(configuration, () -> request) { + } + + @Test + @SuppressWarnings("unchecked") + void testWithoutRequestScope() { + // prepare + Provider requestProvider = mock(Provider.class); + when(requestProvider.get()).thenThrow(new OutOfScopeException("request scope is not available")); + configuration.setEnabledXsrfProtection(true); + XsrfAccessTokenEnricher enricher = createEnricher(requestProvider); + + // execute + enricher.enrich(builder); + + // assert + verify(builder, never()).custom(Xsrf.TOKEN_KEY, "42"); + } + + private XsrfAccessTokenEnricher createEnricher(Provider requestProvider) { + return new XsrfAccessTokenEnricher(configuration, requestProvider) { @Override String createToken() { return "42"; } }; } - - /** - * Tests {@link XsrfAccessTokenEnricher#enrich(java.util.Map)}. - */ - @Test - public void testEnrich() { - // prepare - configuration.setEnabledXsrfProtection(true); - when(request.getHeader(HttpUtil.HEADER_SCM_CLIENT)).thenReturn(HttpUtil.SCM_CLIENT_WUI); - - // execute - enricher.enrich(builder); - - // assert - verify(builder).custom(Xsrf.TOKEN_KEY, "42"); - } - - /** - * Tests {@link XsrfAccessTokenEnricher#enrich(java.util.Map)} with disabled xsrf protection. - */ - @Test - public void testEnrichWithDisabledXsrf() { - // prepare - configuration.setEnabledXsrfProtection(false); - // execute - enricher.enrich(builder); - - // assert - verify(builder, never()).custom(Xsrf.TOKEN_KEY, "42"); - } - - /** - * Tests {@link XsrfAccessTokenEnricher#enrich(java.util.Map)} with disabled xsrf protection. - */ - @Test - public void testEnrichWithNonWuiClient() { - // prepare - configuration.setEnabledXsrfProtection(true); - - // execute - enricher.enrich(builder); - - // assert - verify(builder, never()).custom(Xsrf.TOKEN_KEY, "42"); - } + @Nested + class WithRequestMock { + @BeforeEach + void setupEnricher() { + enricher = createEnricher(() -> request); + } + + @Test + void testEnrich() { + // prepare + configuration.setEnabledXsrfProtection(true); + when(request.getHeader(HttpUtil.HEADER_SCM_CLIENT)).thenReturn(HttpUtil.SCM_CLIENT_WUI); + + // execute + enricher.enrich(builder); + + // assert + verify(builder).custom(Xsrf.TOKEN_KEY, "42"); + } + + @Test + void testEnrichWithDisabledXsrf() { + // prepare + configuration.setEnabledXsrfProtection(false); + + // execute + enricher.enrich(builder); + + // assert + verify(builder, never()).custom(Xsrf.TOKEN_KEY, "42"); + } + + @Test + void testEnrichWithNonWuiClient() { + // prepare + configuration.setEnabledXsrfProtection(true); + + // execute + enricher.enrich(builder); + + // assert + verify(builder, never()).custom(Xsrf.TOKEN_KEY, "42"); + } + } }