diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationFilter.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationFilter.java new file mode 100644 index 000000000000..7ff858199b36 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationFilter.java @@ -0,0 +1,73 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.authentication; + +import javax.annotation.CheckForNull; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.sonar.api.platform.Server; +import org.sonar.api.server.authentication.IdentityProvider; +import org.sonar.api.web.ServletFilter; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.lang.String.format; +import static org.sonar.server.authentication.AuthenticationError.handleError; + +public abstract class AuthenticationFilter extends ServletFilter { + static final String CALLBACK_PATH = "/oauth2/callback/"; + private final IdentityProviderRepository identityProviderRepository; + private final Server server; + + public AuthenticationFilter(Server server, IdentityProviderRepository identityProviderRepository) { + this.server = server; + this.identityProviderRepository = identityProviderRepository; + } + + /** + * @return the {@link IdentityProvider} for the key extracted in the request if is exists, or {@code null}, in which + * case the request is fully handled and caller should not handle it + */ + @CheckForNull + IdentityProvider resolveProviderOrHandleResponse(HttpServletRequest request, HttpServletResponse response, String path) { + String requestUri = request.getRequestURI(); + String providerKey = extractKeyProvider(requestUri, server.getContextPath() + path); + if (providerKey == null) { + handleError(response, "No provider key found in URI"); + return null; + } + try { + return identityProviderRepository.getEnabledByKey(providerKey); + } catch (Exception e) { + handleError(e, response, format("Failed to retrieve IdentityProvider for key '%s'", providerKey)); + return null; + } + } + + @CheckForNull + private static String extractKeyProvider(String requestUri, String context) { + if (requestUri.contains(context)) { + String key = requestUri.replace(context, ""); + if (!isNullOrEmpty(key)) { + return key; + } + } + return null; + } +} 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 a95f788b8102..89857702f3b8 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 @@ -20,7 +20,6 @@ package org.sonar.server.authentication; import java.io.IOException; -import javax.annotation.CheckForNull; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; @@ -33,32 +32,27 @@ import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; -import org.sonar.api.web.ServletFilter; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationException; -import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import static org.sonar.server.authentication.AuthenticationError.handleAuthenticationError; import static org.sonar.server.authentication.AuthenticationError.handleError; import static org.sonar.server.authentication.event.AuthenticationEvent.Source; -public class InitFilter extends ServletFilter { +public class InitFilter extends AuthenticationFilter { private static final String INIT_CONTEXT = "/sessions/init/"; - private final IdentityProviderRepository identityProviderRepository; private final BaseContextFactory baseContextFactory; private final OAuth2ContextFactory oAuth2ContextFactory; - private final Server server; private final AuthenticationEvent authenticationEvent; public InitFilter(IdentityProviderRepository identityProviderRepository, BaseContextFactory baseContextFactory, OAuth2ContextFactory oAuth2ContextFactory, Server server, AuthenticationEvent authenticationEvent) { - this.identityProviderRepository = identityProviderRepository; + super(server, identityProviderRepository); this.baseContextFactory = baseContextFactory; this.oAuth2ContextFactory = oAuth2ContextFactory; - this.server = server; this.authenticationEvent = authenticationEvent; } @@ -72,39 +66,12 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; - IdentityProvider provider = resolveProviderOrHandleResponse(httpRequest, httpResponse); + IdentityProvider provider = resolveProviderOrHandleResponse(httpRequest, httpResponse, INIT_CONTEXT); if (provider != null) { handleProvider(httpRequest, httpResponse, provider); } } - @CheckForNull - private IdentityProvider resolveProviderOrHandleResponse(HttpServletRequest request, HttpServletResponse response) { - String requestURI = request.getRequestURI(); - String providerKey = extractKeyProvider(requestURI, server.getContextPath() + INIT_CONTEXT); - if (providerKey == null) { - handleError(response, "No provider key found in URI"); - return null; - } - try { - return identityProviderRepository.getEnabledByKey(providerKey); - } catch (Exception e) { - handleError(e, response, format("Failed to retrieve IdentityProvider for key '%s'", providerKey)); - return null; - } - } - - @CheckForNull - private static String extractKeyProvider(String requestUri, String context) { - if (requestUri.contains(context)) { - String key = requestUri.replace(context, ""); - if (!isNullOrEmpty(key)) { - return key; - } - } - return null; - } - private void handleProvider(HttpServletRequest request, HttpServletResponse response, IdentityProvider provider) { try { if (provider instanceof BaseIdentityProvider) { 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 d376634d3db5..5ae0537e9144 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 @@ -33,30 +33,23 @@ import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; -import org.sonar.api.web.ServletFilter; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationException; -import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import static org.sonar.server.authentication.AuthenticationError.handleAuthenticationError; import static org.sonar.server.authentication.AuthenticationError.handleError; import static org.sonar.server.authentication.event.AuthenticationEvent.Source; -public class OAuth2CallbackFilter extends ServletFilter { +public class OAuth2CallbackFilter extends AuthenticationFilter { - public static final String CALLBACK_PATH = "/oauth2/callback/"; - - private final IdentityProviderRepository identityProviderRepository; private final OAuth2ContextFactory oAuth2ContextFactory; - private final Server server; private final AuthenticationEvent authenticationEvent; public OAuth2CallbackFilter(IdentityProviderRepository identityProviderRepository, OAuth2ContextFactory oAuth2ContextFactory, Server server, AuthenticationEvent authenticationEvent) { - this.identityProviderRepository = identityProviderRepository; + super(server, identityProviderRepository); this.oAuth2ContextFactory = oAuth2ContextFactory; - this.server = server; this.authenticationEvent = authenticationEvent; } @@ -70,39 +63,12 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; - IdentityProvider provider = resolveProviderOrHandleResponse(httpRequest, httpResponse); + IdentityProvider provider = resolveProviderOrHandleResponse(httpRequest, httpResponse, CALLBACK_PATH); if (provider != null) { handleProvider(httpRequest, (HttpServletResponse) response, provider); } } - @CheckForNull - private IdentityProvider resolveProviderOrHandleResponse(HttpServletRequest request, HttpServletResponse response) { - String requestUri = request.getRequestURI(); - String providerKey = extractKeyProvider(requestUri, server.getContextPath() + CALLBACK_PATH); - if (providerKey == null) { - handleError(response, "No provider key found in URI"); - return null; - } - try { - return identityProviderRepository.getEnabledByKey(providerKey); - } catch (Exception e) { - handleError(e, response, format("Failed to retrieve IdentityProvider for key '%s'", providerKey)); - return null; - } - } - - @CheckForNull - private static String extractKeyProvider(String requestUri, String context) { - if (requestUri.contains(context)) { - String key = requestUri.replace(context, ""); - if (!isNullOrEmpty(key)) { - return key; - } - } - return null; - } - private void handleProvider(HttpServletRequest request, HttpServletResponse response, IdentityProvider provider) { try { if (provider instanceof OAuth2IdentityProvider) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuthCsrfVerifier.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuthCsrfVerifier.java index 874734d859a8..2c29f2c1a093 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuthCsrfVerifier.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/OAuthCsrfVerifier.java @@ -48,10 +48,9 @@ public String generateState(HttpServletRequest request, HttpServletResponse resp public void verifyState(HttpServletRequest request, HttpServletResponse response, OAuth2IdentityProvider provider) { Cookie cookie = findCookie(CSRF_STATE_COOKIE, request) - .orElseThrow(() -> AuthenticationException.newBuilder() + .orElseThrow(AuthenticationException.newBuilder() .setSource(Source.oauth2(provider)) - .setMessage(format("Cookie '%s' is missing", CSRF_STATE_COOKIE)) - .build()); + .setMessage(format("Cookie '%s' is missing", CSRF_STATE_COOKIE))::build); String hashInCookie = cookie.getValue(); // remove cookie 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 10dabe5f749c..c1375e0e4f5d 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 @@ -154,7 +154,6 @@ public void fail_if_identity_provider_class_is_unsupported() throws Exception { assertError("Unsupported IdentityProvider class: class org.sonar.server.authentication.InitFilterTest$UnsupportedIdentityProvider"); verifyZeroInteractions(authenticationEvent); - } @Test