From: Julien Lancelot Date: Thu, 31 Mar 2016 09:43:37 +0000 (+0200) Subject: SONAR-7494 Fix IdentityProvider X-Git-Tag: 5.5-M12~8 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fpull%2F876%2Fhead;p=sonarqube.git SONAR-7494 Fix IdentityProvider --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/CsrfVerifier.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/CsrfVerifier.java index 9a0371506fb..20ea1417e23 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/CsrfVerifier.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/CsrfVerifier.java @@ -45,7 +45,7 @@ public class CsrfVerifier { // Store it in the session for later validation. String state = new BigInteger(130, new SecureRandom()).toString(32); Cookie cookie = new Cookie(CSRF_STATE_COOKIE, sha256Hex(state)); - cookie.setPath("/"); + cookie.setPath(server.getContextPath() + "/"); cookie.setHttpOnly(true); cookie.setMaxAge(-1); cookie.setSecure(server.isSecured()); @@ -69,7 +69,7 @@ public class CsrfVerifier { // remove cookie stateCookie.setValue(null); stateCookie.setMaxAge(0); - stateCookie.setPath("/"); + stateCookie.setPath(server.getContextPath() + "/"); response.addCookie(stateCookie); String stateInRequest = request.getParameter("state"); diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/InitFilter.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/InitFilter.java index d7b9e2a9606..00e4a5b6e46 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/InitFilter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/InitFilter.java @@ -27,6 +27,7 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.sonar.api.platform.Server; import org.sonar.api.server.authentication.BaseIdentityProvider; import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.api.server.authentication.OAuth2IdentityProvider; @@ -45,11 +46,13 @@ public class InitFilter extends ServletFilter { private final IdentityProviderRepository identityProviderRepository; private final BaseContextFactory baseContextFactory; private final OAuth2ContextFactory oAuth2ContextFactory; + private final Server server; - public InitFilter(IdentityProviderRepository identityProviderRepository, BaseContextFactory baseContextFactory, OAuth2ContextFactory oAuth2ContextFactory) { + public InitFilter(IdentityProviderRepository identityProviderRepository, BaseContextFactory baseContextFactory, OAuth2ContextFactory oAuth2ContextFactory, Server server) { this.identityProviderRepository = identityProviderRepository; this.baseContextFactory = baseContextFactory; this.oAuth2ContextFactory = oAuth2ContextFactory; + this.server = server; } @Override @@ -63,7 +66,7 @@ public class InitFilter extends ServletFilter { String requestURI = httpRequest.getRequestURI(); String keyProvider = ""; try { - keyProvider = extractKeyProvider(requestURI, INIT_CONTEXT); + keyProvider = extractKeyProvider(requestURI, server.getContextPath() + INIT_CONTEXT); IdentityProvider provider = identityProviderRepository.getEnabledByKey(keyProvider); if (provider instanceof BaseIdentityProvider) { BaseIdentityProvider baseIdentityProvider = (BaseIdentityProvider) provider; diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java index 3c708eb1a4d..f1ae0c5dcb9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java @@ -28,6 +28,7 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.sonar.api.CoreProperties; +import org.sonar.api.platform.Server; import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; @@ -44,10 +45,12 @@ public class OAuth2CallbackFilter extends ServletFilter { private final IdentityProviderRepository identityProviderRepository; private final OAuth2ContextFactory oAuth2ContextFactory; + private final Server server; - public OAuth2CallbackFilter(IdentityProviderRepository identityProviderRepository, OAuth2ContextFactory oAuth2ContextFactory) { + public OAuth2CallbackFilter(IdentityProviderRepository identityProviderRepository, OAuth2ContextFactory oAuth2ContextFactory, Server server) { this.identityProviderRepository = identityProviderRepository; this.oAuth2ContextFactory = oAuth2ContextFactory; + this.server = server; } @Override @@ -61,7 +64,7 @@ public class OAuth2CallbackFilter extends ServletFilter { String requestUri = httpRequest.getRequestURI(); String keyProvider = ""; try { - keyProvider = extractKeyProvider(requestUri, CALLBACK_PATH); + keyProvider = extractKeyProvider(requestUri, server.getContextPath() + CALLBACK_PATH); IdentityProvider provider = identityProviderRepository.getEnabledByKey(keyProvider); if (provider instanceof OAuth2IdentityProvider) { OAuth2IdentityProvider oauthProvider = (OAuth2IdentityProvider) provider; diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2ContextFactory.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2ContextFactory.java index 60cb6ff6fa9..4c52ef80910 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2ContextFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuth2ContextFactory.java @@ -104,7 +104,7 @@ public class OAuth2ContextFactory { @Override public void redirectToRequestedPage() { try { - getResponse().sendRedirect("/"); + getResponse().sendRedirect(server.getContextPath() + "/"); } catch (IOException e) { throw new IllegalStateException("Fail to redirect to home", e); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/CsrfVerifierTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/CsrfVerifierTest.java index 918e0e9f27b..5b77cd434e8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/CsrfVerifierTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/CsrfVerifierTest.java @@ -22,6 +22,7 @@ package org.sonar.server.authentication; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -49,6 +50,11 @@ public class CsrfVerifierTest { CsrfVerifier underTest = new CsrfVerifier(server); + @Before + public void setUp() throws Exception { + when(server.getContextPath()).thenReturn(""); + } + @Test public void generate_state_on_secured_server() throws Exception { when(server.isSecured()).thenReturn(true); @@ -89,6 +95,20 @@ public class CsrfVerifierTest { assertThat(updatedCookie.getMaxAge()).isEqualTo(0); } + @Test + public void verify_state_when_context() throws Exception { + String state = "state"; + when(request.getCookies()).thenReturn(new Cookie[] {new Cookie("OAUTHSTATE", sha256Hex(state))}); + when(request.getParameter("state")).thenReturn(state); + when(server.getContextPath()).thenReturn("/sonarqube"); + + underTest.verifyState(request, response); + + verify(response).addCookie(cookieArgumentCaptor.capture()); + Cookie updatedCookie = cookieArgumentCaptor.getValue(); + assertThat(updatedCookie.getPath()).isEqualTo("/sonarqube/"); + } + @Test public void fail_with_unauthorized_when_state_cookie_is_not_the_same_as_state_parameter() throws Exception { when(request.getCookies()).thenReturn(new Cookie[] {new Cookie("OAUTHSTATE", sha1Hex("state"))}); diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/InitFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/InitFilterTest.java index ef82a2def3e..5fb48bb9ec2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/InitFilterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/InitFilterTest.java @@ -26,6 +26,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.platform.Server; import org.sonar.api.server.authentication.BaseIdentityProvider; import org.sonar.api.server.authentication.Display; import org.sonar.api.server.authentication.IdentityProvider; @@ -55,6 +56,7 @@ public class InitFilterTest { BaseContextFactory baseContextFactory = mock(BaseContextFactory.class); OAuth2ContextFactory oAuth2ContextFactory = mock(OAuth2ContextFactory.class); + Server server = mock(Server.class); HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(HttpServletResponse.class); @@ -66,12 +68,13 @@ public class InitFilterTest { FakeBasicIdentityProvider baseIdentityProvider = new FakeBasicIdentityProvider(BASIC_PROVIDER_KEY, true); BaseIdentityProvider.Context baseContext = mock(BaseIdentityProvider.Context.class); - InitFilter underTest = new InitFilter(identityProviderRepository, baseContextFactory, oAuth2ContextFactory); + InitFilter underTest = new InitFilter(identityProviderRepository, baseContextFactory, oAuth2ContextFactory, server); @Before public void setUp() throws Exception { when(oAuth2ContextFactory.newContext(request, response, oAuth2IdentityProvider)).thenReturn(oauth2Context); when(baseContextFactory.newContext(request, response, baseIdentityProvider)).thenReturn(baseContext); + when(server.getContextPath()).thenReturn(""); } @Test @@ -79,6 +82,17 @@ public class InitFilterTest { assertThat(underTest.doGetPattern()).isNotNull(); } + @Test + public void do_filter_with_context() throws Exception { + when(server.getContextPath()).thenReturn("/sonarqube"); + when(request.getRequestURI()).thenReturn("/sonarqube/sessions/init/" + OAUTH2_PROVIDER_KEY); + identityProviderRepository.addIdentityProvider(oAuth2IdentityProvider); + + underTest.doFilter(request, response, chain); + + assertOAuth2InitCalled(); + } + @Test public void do_filter_on_auth2_identity_provider() throws Exception { when(request.getRequestURI()).thenReturn("/sessions/init/" + OAUTH2_PROVIDER_KEY); diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java index ef19c6a298b..e07443f4c29 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java @@ -26,6 +26,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.platform.Server; import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.utils.log.LogTester; @@ -53,16 +54,18 @@ public class OAuth2CallbackFilterTest { HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(HttpServletResponse.class); + Server server = mock(Server.class); FilterChain chain = mock(FilterChain.class); FakeOAuth2IdentityProvider oAuth2IdentityProvider = new FakeOAuth2IdentityProvider(OAUTH2_PROVIDER_KEY, true); OAuth2IdentityProvider.InitContext oauth2Context = mock(OAuth2IdentityProvider.InitContext.class); - OAuth2CallbackFilter underTest = new OAuth2CallbackFilter(identityProviderRepository, oAuth2ContextFactory); + OAuth2CallbackFilter underTest = new OAuth2CallbackFilter(identityProviderRepository, oAuth2ContextFactory, server); @Before public void setUp() throws Exception { when(oAuth2ContextFactory.newContext(request, response, oAuth2IdentityProvider)).thenReturn(oauth2Context); + when(server.getContextPath()).thenReturn(""); } @Test @@ -70,6 +73,17 @@ public class OAuth2CallbackFilterTest { assertThat(underTest.doGetPattern()).isNotNull(); } + @Test + public void do_filter_with_context() throws Exception { + when(server.getContextPath()).thenReturn("/sonarqube"); + when(request.getRequestURI()).thenReturn("/sonarqube/oauth2/callback/" + OAUTH2_PROVIDER_KEY); + identityProviderRepository.addIdentityProvider(oAuth2IdentityProvider); + + underTest.doFilter(request, response, chain); + + assertCallbackCalled(); + } + @Test public void do_filter_on_auth2_identity_provider() throws Exception { when(request.getRequestURI()).thenReturn("/oauth2/callback/" + OAUTH2_PROVIDER_KEY); diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2ContextFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2ContextFactoryTest.java index f44a9e7722f..b9344fb2615 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2ContextFactoryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/OAuth2ContextFactoryTest.java @@ -132,6 +132,7 @@ public class OAuth2ContextFactoryTest { @Test public void redirect_to_requested_page() throws Exception { + when(server.getContextPath()).thenReturn(""); OAuth2IdentityProvider.CallbackContext callback = underTest.newCallback(request, response, identityProvider); callback.redirectToRequestedPage(); @@ -139,6 +140,16 @@ public class OAuth2ContextFactoryTest { verify(response).sendRedirect("/"); } + @Test + public void redirect_to_requested_page_with_context() throws Exception { + when(server.getContextPath()).thenReturn("/sonarqube"); + OAuth2IdentityProvider.CallbackContext callback = underTest.newCallback(request, response, identityProvider); + + callback.redirectToRequestedPage(); + + verify(response).sendRedirect("/sonarqube/"); + } + @Test public void verify_csrf_state() throws Exception { OAuth2IdentityProvider.CallbackContext callback = underTest.newCallback(request, response, identityProvider); diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb index 9711bbadc42..2c5381d9690 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb @@ -10,7 +10,7 @@ style="background-color: <%= provider.getDisplay().getBackgroundColor().to_s %>" title="Log in with <%= provider.getName().to_s -%>"> <%= provider.getName().to_s -%> + src="<%= ApplicationController.root_context + provider.getDisplay().getIconPath().to_s -%>"> Log in with <%= provider.getName().to_s -%>