diff options
author | Aurelien Poscia <aurelien.poscia@sonarsource.com> | 2024-12-18 18:04:38 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-12-20 20:03:10 +0000 |
commit | 1fce3f56f3135cf584a2c840c983788a3b111d0f (patch) | |
tree | 89a3a0cf2261439f7df179be99ef5e55ad8e7b87 | |
parent | c770ccb9dfb7e1e023cb7e63bb76c8ab1002f27e (diff) | |
download | sonarqube-1fce3f56f3135cf584a2c840c983788a3b111d0f.tar.gz sonarqube-1fce3f56f3135cf584a2c840c983788a3b111d0f.zip |
SONAR-24023 Rewrite tests for SamlAuthenticator
11 files changed, 214 insertions, 95 deletions
diff --git a/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthStatusPageGenerator.java b/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthStatusPageGenerator.java index 62f9071a84f..641b2f39b56 100644 --- a/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthStatusPageGenerator.java +++ b/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthStatusPageGenerator.java @@ -26,19 +26,17 @@ import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Map; import org.json.JSONObject; +import org.sonar.api.server.ServerSide; import org.sonar.api.server.http.HttpRequest; -public final class SamlAuthStatusPageGenerator { +@ServerSide +final class SamlAuthStatusPageGenerator { private static final String WEB_CONTEXT = "WEB_CONTEXT"; private static final String SAML_AUTHENTICATION_STATUS = "%SAML_AUTHENTICATION_STATUS%"; private static final String HTML_TEMPLATE_NAME = "samlAuthResult.html"; - private SamlAuthStatusPageGenerator() { - throw new IllegalStateException("This Utility class cannot be instantiated"); - } - - public static String getSamlAuthStatusHtml(HttpRequest request, SamlAuthenticationStatus samlAuthenticationStatus) { + public String getSamlAuthStatusHtml(HttpRequest request, SamlAuthenticationStatus samlAuthenticationStatus) { Map<String, String> substitutionsMap = getSubstitutionsMap(request, samlAuthenticationStatus); String htmlTemplate = getPlainTemplate(); diff --git a/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthenticator.java b/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthenticator.java index 09492f9b06e..e5f92f382d3 100644 --- a/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthenticator.java +++ b/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthenticator.java @@ -20,6 +20,7 @@ package org.sonar.auth.saml; import java.io.IOException; +import java.io.UncheckedIOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.server.ServerSide; @@ -30,9 +31,6 @@ import org.sonar.api.server.http.HttpResponse; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; -import static org.sonar.auth.saml.SamlAuthStatusPageGenerator.getSamlAuthStatusHtml; -import static org.sonar.auth.saml.SamlStatusChecker.getSamlAuthenticationStatus; - @ServerSide public class SamlAuthenticator { @@ -40,17 +38,20 @@ public class SamlAuthenticator { private static final String STATE_REQUEST_PARAMETER = "RelayState"; - private final SamlSettings samlSettings; private final RedirectToUrlProvider redirectToUrlProvider; private final SamlResponseAuthenticator samlResponseAuthenticator; private final PrincipalToUserIdentityConverter principalToUserIdentityConverter; + private final SamlStatusChecker samlStatusChecker; + private final SamlAuthStatusPageGenerator samlAuthStatusPageGenerator; - public SamlAuthenticator(SamlSettings samlSettings, RedirectToUrlProvider redirectToUrlProvider, - SamlResponseAuthenticator samlResponseAuthenticator, PrincipalToUserIdentityConverter principalToUserIdentityConverter) { - this.samlSettings = samlSettings; + public SamlAuthenticator(RedirectToUrlProvider redirectToUrlProvider, + SamlResponseAuthenticator samlResponseAuthenticator, PrincipalToUserIdentityConverter principalToUserIdentityConverter, SamlStatusChecker samlStatusChecker, + SamlAuthStatusPageGenerator samlAuthStatusPageGenerator) { this.redirectToUrlProvider = redirectToUrlProvider; this.samlResponseAuthenticator = samlResponseAuthenticator; this.principalToUserIdentityConverter = principalToUserIdentityConverter; + this.samlStatusChecker = samlStatusChecker; + this.samlAuthStatusPageGenerator = samlAuthStatusPageGenerator; } public void initLogin(String callbackUrl, String relayState, HttpRequest request, HttpResponse response) { @@ -58,7 +59,7 @@ public class SamlAuthenticator { try { response.sendRedirect(redirectToUrl); } catch (IOException e) { - throw new RuntimeException(e); + throw new UncheckedIOException(e); } } @@ -71,15 +72,18 @@ public class SamlAuthenticator { return principalToUserIdentityConverter.convertToUserIdentity(principal); } - public String getAuthenticationStatusPage(HttpRequest request, HttpResponse response) { + public String getAuthenticationStatusPage(HttpRequest request) { try { Saml2AuthenticatedPrincipal principal = samlResponseAuthenticator.authenticate(request, request.getRequestURL()); String samlResponse = request.getParameter("SAMLResponse"); - return getSamlAuthStatusHtml(request, getSamlAuthenticationStatus(samlResponse, principal, samlSettings)); + SamlAuthenticationStatus samlAuthenticationStatus = samlStatusChecker.getSamlAuthenticationStatus(samlResponse, principal); + return samlAuthStatusPageGenerator.getSamlAuthStatusHtml(request, samlAuthenticationStatus); } catch (Saml2AuthenticationException e) { - return getSamlAuthStatusHtml(request, getSamlAuthenticationStatus(e.getMessage())); + SamlAuthenticationStatus samlAuthenticationStatus = samlStatusChecker.getSamlAuthenticationStatus(e.getMessage()); + return samlAuthStatusPageGenerator.getSamlAuthStatusHtml(request, samlAuthenticationStatus); } catch (IllegalStateException e) { - return getSamlAuthStatusHtml(request, getSamlAuthenticationStatus(String.format("%s due to: %s", e.getMessage(), e.getCause().getMessage()))); + SamlAuthenticationStatus samlAuthenticationStatus = samlStatusChecker.getSamlAuthenticationStatus(String.format("%s due to: %s", e.getMessage(), e.getCause().getMessage())); + return samlAuthStatusPageGenerator.getSamlAuthStatusHtml(request, samlAuthenticationStatus); } } } diff --git a/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlModule.java b/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlModule.java index 81c5e38dcab..6926014c273 100644 --- a/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlModule.java +++ b/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlModule.java @@ -29,8 +29,10 @@ public class SamlModule extends Module { protected void configureModule() { add( PrincipalToUserIdentityConverter.class, + RedirectToUrlProvider.class, RelyingPartyRegistrationRepositoryProvider.class, SamlAuthenticator.class, + SamlAuthStatusPageGenerator.class, SamlConfiguration.class, SamlCertificateConverter.class, SamlIdentityProvider.class, @@ -38,7 +40,7 @@ public class SamlModule extends Module { SamlPrivateKeyConverter.class, SamlResponseAuthenticator.class, SamlSettings.class, - RedirectToUrlProvider.class, + SamlStatusChecker.class, SonarqubeSaml2ResponseValidator.class ); List<PropertyDefinition> definitions = SamlSettings.definitions(); diff --git a/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlStatusChecker.java b/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlStatusChecker.java index c8774d98813..2249253809b 100644 --- a/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlStatusChecker.java +++ b/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlStatusChecker.java @@ -31,6 +31,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.annotation.Nullable; +import org.sonar.api.server.ServerSide; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import static org.sonar.auth.saml.SamlSettings.GROUP_NAME_ATTRIBUTE; @@ -38,15 +39,17 @@ import static org.sonar.auth.saml.SamlSettings.USER_EMAIL_ATTRIBUTE; import static org.sonar.auth.saml.SamlSettings.USER_LOGIN_ATTRIBUTE; import static org.sonar.auth.saml.SamlSettings.USER_NAME_ATTRIBUTE; -public final class SamlStatusChecker { +@ServerSide +final class SamlStatusChecker { + private final SamlSettings samlSettings; private static final Pattern encryptedAssertionPattern = Pattern.compile("<saml:EncryptedAssertion|<EncryptedAssertion"); - private SamlStatusChecker() { - throw new IllegalStateException("This Utility class cannot be instantiated"); + SamlStatusChecker(SamlSettings samlSettings) { + this.samlSettings = samlSettings; } - public static SamlAuthenticationStatus getSamlAuthenticationStatus(String samlResponse, Saml2AuthenticatedPrincipal principal, SamlSettings samlSettings) { + public SamlAuthenticationStatus getSamlAuthenticationStatus(String samlResponse, Saml2AuthenticatedPrincipal principal) { SamlAuthenticationStatus samlAuthenticationStatus = new SamlAuthenticationStatus(); @@ -70,7 +73,7 @@ public final class SamlStatusChecker { } - public static SamlAuthenticationStatus getSamlAuthenticationStatus(String errorMessage) { + public SamlAuthenticationStatus getSamlAuthenticationStatus(String errorMessage) { SamlAuthenticationStatus samlAuthenticationStatus = new SamlAuthenticationStatus(); samlAuthenticationStatus.getErrors().add(errorMessage); samlAuthenticationStatus.setStatus("error"); diff --git a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthStatusPageGeneratorTest.java b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthStatusPageGeneratorTest.java index 0867167906e..d36389eed9f 100644 --- a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthStatusPageGeneratorTest.java +++ b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthStatusPageGeneratorTest.java @@ -25,16 +25,23 @@ import java.util.Base64; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; import org.sonar.api.server.http.HttpRequest; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.sonar.auth.saml.SamlAuthStatusPageGenerator.getSamlAuthStatusHtml; +@ExtendWith(MockitoExtension.class) public class SamlAuthStatusPageGeneratorTest { + @InjectMocks + private SamlAuthStatusPageGenerator samlAuthStatusPageGenerator; + + @Test public void getSamlAuthStatusHtml_whenCalled_shouldGeneratePageWithData() { SamlAuthenticationStatus samlAuthenticationStatus = mock(SamlAuthenticationStatus.class); @@ -49,7 +56,7 @@ public class SamlAuthStatusPageGeneratorTest { when(samlAuthenticationStatus.isSignatureEnabled()).thenReturn(false); when(request.getContextPath()).thenReturn("context"); - String decodedDataResponse = getDecodedDataResponse(getSamlAuthStatusHtml(request, samlAuthenticationStatus)); + String decodedDataResponse = getDecodedDataResponse(samlAuthStatusPageGenerator.getSamlAuthStatusHtml(request, samlAuthenticationStatus)); assertThat(decodedDataResponse).contains( "\"encryptionEnabled\":false", diff --git a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthenticatorTest.java b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthenticatorTest.java index 3e4a3bdcf75..ecf6ff384ca 100644 --- a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthenticatorTest.java +++ b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthenticatorTest.java @@ -19,78 +19,144 @@ */ package org.sonar.auth.saml; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.junit.Test; -import org.sonar.api.config.PropertyDefinitions; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.server.http.HttpRequest; -import org.sonar.api.server.http.HttpResponse; -import org.sonar.api.utils.System2; +import java.io.IOException; +import java.io.UncheckedIOException; +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 org.sonar.api.server.authentication.OAuth2IdentityProvider; +import org.sonar.api.server.authentication.UserIdentity; import org.sonar.server.http.JakartaHttpRequest; import org.sonar.server.http.JakartaHttpResponse; - -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.junit.Assert.assertFalse; +import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatException; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) public class SamlAuthenticatorTest { - private MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, SamlSettings.definitions())); + public static final String CALLBACK_URL = "callbackUrl"; + public static final String RELAY_STATE = "relayState"; + public static final String REDIRECT_URL = "redirectUrl"; + + @Mock + private RedirectToUrlProvider redirectToUrlProvider; + @Mock + private SamlResponseAuthenticator samlResponseAuthenticator; + @Mock + private PrincipalToUserIdentityConverter principalToUserIdentityConverter; + @Mock + private SamlStatusChecker samlStatusChecker; + @Mock + private SamlAuthStatusPageGenerator samlAuthStatusPageGenerator; + @Mock + private SamlAuthenticationStatus samlAuthenticationStatus; + + @InjectMocks + private SamlAuthenticator samlAuthenticator; + + @Mock + private JakartaHttpRequest request; + @Mock + private JakartaHttpResponse response; + + @Test + void initLogin_generatesUrlAndSendsRedirect() throws IOException { + when(redirectToUrlProvider.getRedirectToUrl(request, CALLBACK_URL, RELAY_STATE)).thenReturn(REDIRECT_URL); - private SamlSettings samlSettings = new SamlSettings(settings.asConfig()); + samlAuthenticator.initLogin(CALLBACK_URL, RELAY_STATE, request, response); - private final SamlAuthenticator underTest = new SamlAuthenticator(samlSettings, null, null, null); //TODO + verify(response).sendRedirect(REDIRECT_URL); + } @Test - public void authentication_status_with_errors_returned_when_init_fails() { - HttpRequest request = new JakartaHttpRequest(mock(HttpServletRequest.class)); - HttpResponse response = new JakartaHttpResponse(mock(HttpServletResponse.class)); - when(request.getContextPath()).thenReturn("context"); + void initLogin_whenIoException_convertsToRuntimeException() throws IOException { + when(redirectToUrlProvider.getRedirectToUrl(request, CALLBACK_URL, RELAY_STATE)).thenReturn(REDIRECT_URL); + + IOException ioException = new IOException(); + doThrow(ioException).when(response).sendRedirect(REDIRECT_URL); + + assertThatException() + .isThrownBy(() -> samlAuthenticator.initLogin(CALLBACK_URL, RELAY_STATE, request, response)) + .isInstanceOf(UncheckedIOException.class) + .withCause(ioException); + } + + @Test + void onCallback_verifiesCsrfStateAndAuthenticates() { + OAuth2IdentityProvider.CallbackContext context = mock(); + when(context.getCallbackUrl()).thenReturn(CALLBACK_URL); + + Saml2AuthenticatedPrincipal principal = mock(); + when(samlResponseAuthenticator.authenticate(request, CALLBACK_URL)).thenReturn(principal); + + UserIdentity userIdentity = mock(); + when(principalToUserIdentityConverter.convertToUserIdentity(principal)).thenReturn(userIdentity); - String authenticationStatus = underTest.getAuthenticationStatusPage(request, response); + UserIdentity actualUserIdentity = samlAuthenticator.onCallback(context, request); - assertFalse(authenticationStatus.isEmpty()); + verify(context).verifyCsrfState("RelayState"); + verify(samlResponseAuthenticator).authenticate(request, CALLBACK_URL); + assertThat(actualUserIdentity).isEqualTo(userIdentity); } @Test - public void givenPrivateKeyIsNotPkcs8Encrypted_whenInitializingTheAuthentication_thenExceptionIsThrown() { - initBasicSamlSettings(); - - settings.setProperty("sonar.auth.saml.signature.enabled", true); - settings.setProperty("sonar.auth.saml.sp.certificate.secured", "CERTIFICATE"); - settings.setProperty("sonar.auth.saml.sp.privateKey.secured", "Not a PKCS8 key"); - - assertThatIllegalStateException() - .isThrownBy(() -> underTest.initLogin("", "", mock(JakartaHttpRequest.class), mock(JakartaHttpResponse.class))) - .withMessage("Failed to create a SAML Auth") - .havingCause() - .withMessage("Error in parsing service provider private key, please make sure that it is in PKCS 8 format."); + void getAuthenticationStatusPage_returnsHtml() { + String samlResponse = "samlResponse"; + when(request.getRequestURL()).thenReturn("url"); + when(request.getParameter("SAMLResponse")).thenReturn(samlResponse); + + Saml2AuthenticatedPrincipal principal = mock(); + when(samlResponseAuthenticator.authenticate(request, request.getRequestURL())).thenReturn(principal); + + when(samlStatusChecker.getSamlAuthenticationStatus(samlResponse, principal)).thenReturn(samlAuthenticationStatus); + when(samlAuthStatusPageGenerator.getSamlAuthStatusHtml(request, samlAuthenticationStatus)).thenReturn("html"); + + String authenticationStatusPage = samlAuthenticator.getAuthenticationStatusPage(request); + + assertThat(authenticationStatusPage).isEqualTo("html"); } @Test - public void givenMissingSpCertificate_whenInitializingTheAuthentication_thenExceptionIsThrown() { - initBasicSamlSettings(); + void getAuthenticationStatusPage_whenSaml2AuthenticationException_returnsHtml() { + when(request.getRequestURL()).thenReturn("url"); + + String errorMessage = "error"; + when(samlResponseAuthenticator.authenticate(request, request.getRequestURL())).thenThrow(new Saml2AuthenticationException(new Saml2Error("erorCode", errorMessage))); + + when(samlStatusChecker.getSamlAuthenticationStatus(errorMessage)).thenReturn(samlAuthenticationStatus); + when(samlAuthStatusPageGenerator.getSamlAuthStatusHtml(request, samlAuthenticationStatus)).thenReturn("html"); - settings.setProperty("sonar.auth.saml.signature.enabled", true); - settings.setProperty("sonar.auth.saml.sp.privateKey.secured", "PRIVATE_KEY"); + String authenticationStatusPage = samlAuthenticator.getAuthenticationStatusPage(request); - assertThatIllegalStateException() - .isThrownBy(() -> underTest.initLogin("", "", mock(JakartaHttpRequest.class), mock(JakartaHttpResponse.class))) - .withMessage("Failed to create a SAML Auth") - .havingCause() - .withMessage("Service provider certificate is missing"); + assertThat(authenticationStatusPage).isEqualTo("html"); } - private void initBasicSamlSettings() { - settings.setProperty("sonar.auth.saml.applicationId", "MyApp"); - settings.setProperty("sonar.auth.saml.providerId", "http://localhost:8080/auth/realms/sonarqube"); - settings.setProperty("sonar.auth.saml.loginUrl", "http://localhost:8080/auth/realms/sonarqube/protocol/saml"); - settings.setProperty("sonar.auth.saml.certificate.secured", "ABCDEFG"); - settings.setProperty("sonar.auth.saml.user.login", "login"); - settings.setProperty("sonar.auth.saml.user.name", "name"); - settings.setProperty("sonar.auth.saml.enabled", true); + @Test + void getAuthenticationStatusPage_whenIllegalStateException_returnsHtml() { + when(request.getRequestURL()).thenReturn("url"); + + RuntimeException runtimeException = new RuntimeException("error"); + IllegalStateException illegalStateException = new IllegalStateException(runtimeException); + when(samlResponseAuthenticator.authenticate(request, request.getRequestURL())).thenThrow(illegalStateException); + + when(samlStatusChecker.getSamlAuthenticationStatus(any())).thenReturn(samlAuthenticationStatus); + when(samlAuthStatusPageGenerator.getSamlAuthStatusHtml(request, samlAuthenticationStatus)).thenReturn("html"); + + String authenticationStatusPage = samlAuthenticator.getAuthenticationStatusPage(request); + + assertThat(authenticationStatusPage).isEqualTo("html"); + verify(samlAuthStatusPageGenerator).getSamlAuthStatusHtml(request, samlAuthenticationStatus); } } diff --git a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlConfigurationTest.java b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlConfigurationTest.java new file mode 100644 index 00000000000..3246e83449b --- /dev/null +++ b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlConfigurationTest.java @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info 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.auth.saml; + +import org.junit.jupiter.api.Test; +import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +class SamlConfigurationTest { + + @Test + void openSaml4AuthenticationProvider_doesNotFail() { + SamlConfiguration samlConfiguration = new SamlConfiguration(); + SonarqubeSaml2ResponseValidator sonarqubeSaml2ResponseValidator = mock(); + + OpenSaml4AuthenticationProvider openSaml4AuthenticationProvider = samlConfiguration.openSaml4AuthenticationProvider(sonarqubeSaml2ResponseValidator); + + assertThat(openSaml4AuthenticationProvider).isNotNull(); + } +} diff --git a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlModuleTest.java b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlModuleTest.java index fc432a50648..0ae8cadb7b9 100644 --- a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlModuleTest.java +++ b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlModuleTest.java @@ -30,6 +30,7 @@ public class SamlModuleTest { public void verify_count_of_added_components() { ListContainer container = new ListContainer(); new SamlModule().configure(container); - assertThat(container.getAddedObjects()).hasSize(25); + assertThat(container.getAddedObjects()).hasSize(27); } + } diff --git a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlStatusCheckerTest.java b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlStatusCheckerTest.java index 5ad07485adf..2c0ca209897 100644 --- a/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlStatusCheckerTest.java +++ b/server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlStatusCheckerTest.java @@ -39,7 +39,6 @@ import static org.sonar.auth.saml.SamlSettings.GROUP_NAME_ATTRIBUTE; import static org.sonar.auth.saml.SamlSettings.USER_EMAIL_ATTRIBUTE; import static org.sonar.auth.saml.SamlSettings.USER_LOGIN_ATTRIBUTE; import static org.sonar.auth.saml.SamlSettings.USER_NAME_ATTRIBUTE; -import static org.sonar.auth.saml.SamlStatusChecker.getSamlAuthenticationStatus; public class SamlStatusCheckerTest { @@ -73,7 +72,7 @@ public class SamlStatusCheckerTest { @Test public void authentication_status_has_errors_when_no_idp_certificate_is_provided() { - samlAuthenticationStatus = getSamlAuthenticationStatus("error message"); + samlAuthenticationStatus = new SamlStatusChecker(null).getSamlAuthenticationStatus("error message"); assertThat(samlAuthenticationStatus.getStatus()).isEqualTo("error"); assertThat(samlAuthenticationStatus.getErrors()).containsExactly("error message"); @@ -84,7 +83,7 @@ public class SamlStatusCheckerTest { setSettings(); Saml2AuthenticatedPrincipal principal = PRINCIPAL_WITH_ALL_ATTRIBUTES; - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, principal, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, principal); assertThat("success").isEqualTo(samlAuthenticationStatus.getStatus()); assertThat(samlAuthenticationStatus.getErrors()).isEmpty(); @@ -114,7 +113,7 @@ public class SamlStatusCheckerTest { Saml2AuthenticationException saml2AuthenticationException = new Saml2AuthenticationException( new Saml2Error("Error in Authentication", "Authentication failed due to a missing parameter.")); - samlAuthenticationStatus = getSamlAuthenticationStatus(saml2AuthenticationException.getMessage()); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(saml2AuthenticationException.getMessage()); assertThat("error").isEqualTo(samlAuthenticationStatus.getStatus()); assertThat(samlAuthenticationStatus.getErrors()).containsExactly("Authentication failed due to a missing parameter."); @@ -127,7 +126,7 @@ public class SamlStatusCheckerTest { settings.setProperty(USER_EMAIL_ATTRIBUTE, "wrongEmailField"); settings.setProperty("sonar.auth.saml.sp.privateKey.secured", (String) null); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat("success").isEqualTo(samlAuthenticationStatus.getStatus()); @@ -144,7 +143,7 @@ public class SamlStatusCheckerTest { settings.setProperty(USER_LOGIN_ATTRIBUTE, "wrongLoginField"); settings.setProperty(USER_NAME_ATTRIBUTE, "wrongNameField"); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat("error").isEqualTo(samlAuthenticationStatus.getStatus()); assertThat(samlAuthenticationStatus.getWarnings()).isEmpty(); @@ -159,7 +158,7 @@ public class SamlStatusCheckerTest { setSettings(); Saml2AuthenticatedPrincipal principal = buildPrincipal("", "", List.of("user@sonar.com"), List.of("group1", "group2")); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, principal, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, principal); assertThat("error").isEqualTo(samlAuthenticationStatus.getStatus()); assertThat(samlAuthenticationStatus.getWarnings()).isEmpty(); @@ -177,7 +176,7 @@ public class SamlStatusCheckerTest { settings.setProperty(GROUP_NAME_ATTRIBUTE, (String) null); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat("success").isEqualTo(samlAuthenticationStatus.getStatus()); assertThat(samlAuthenticationStatus.getErrors()).isEmpty(); @@ -189,7 +188,7 @@ public class SamlStatusCheckerTest { setSettings(); settings.setProperty("sonar.auth.saml.sp.privateKey.secured", (String) null); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat("success").isEqualTo(samlAuthenticationStatus.getStatus()); assertThat(samlAuthenticationStatus.getErrors()).isEmpty(); @@ -203,7 +202,7 @@ public class SamlStatusCheckerTest { setSettings(); settings.setProperty("sonar.auth.saml.signature.enabled", true); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat(samlAuthenticationStatus.isSignatureEnabled()).isTrue(); } @@ -213,7 +212,7 @@ public class SamlStatusCheckerTest { setSettings(); settings.setProperty("sonar.auth.saml.signature.enabled", false); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat(samlAuthenticationStatus.isSignatureEnabled()).isFalse(); } @@ -222,7 +221,7 @@ public class SamlStatusCheckerTest { public void givenEncryptionEnabled_whenUserIsAuthenticated_thenSamlStatusReportsItEnabled() { setSettings(); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_ENCRYPTED_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_ENCRYPTED_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat(samlAuthenticationStatus.isEncryptionEnabled()).isTrue(); } @@ -231,7 +230,7 @@ public class SamlStatusCheckerTest { public void givenEncryptionDisabled_whenUserIsAuthenticated_thenSamlStatusReportsItDisabled() { setSettings(); - samlAuthenticationStatus = getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(BASE64_SAML_RESPONSE, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat(samlAuthenticationStatus.isEncryptionEnabled()).isFalse(); } @@ -241,7 +240,7 @@ public class SamlStatusCheckerTest { setSettings(); settings.setProperty("sonar.auth.saml.signature.enabled", true); - samlAuthenticationStatus = getSamlAuthenticationStatus("error"); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus("error"); assertThat(samlAuthenticationStatus.isEncryptionEnabled()).isFalse(); assertThat(samlAuthenticationStatus.isSignatureEnabled()).isFalse(); @@ -251,7 +250,7 @@ public class SamlStatusCheckerTest { public void whenSamlResponseIsNull_thenEncryptionIsReportedDisabled() { setSettings(); - samlAuthenticationStatus = getSamlAuthenticationStatus(null, PRINCIPAL_WITH_ALL_ATTRIBUTES, new SamlSettings(settings.asConfig())); + samlAuthenticationStatus = new SamlStatusChecker(new SamlSettings(settings.asConfig())).getSamlAuthenticationStatus(null, PRINCIPAL_WITH_ALL_ATTRIBUTES); assertThat(samlAuthenticationStatus.isEncryptionEnabled()).isFalse(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/ValidationAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/ValidationAction.java index 97f665f0f1f..c5201e829f7 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/ValidationAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/ValidationAction.java @@ -93,7 +93,7 @@ public class ValidationAction extends HttpFilter implements SamlAction { - String htmlResponse = samlAuthenticator.getAuthenticationStatusPage(new JakartaHttpRequest(httpRequest), response); + String htmlResponse = samlAuthenticator.getAuthenticationStatusPage(new JakartaHttpRequest(httpRequest)); String nonce = SamlValidationCspHeaders.addCspHeadersWithNonceToResponse(response); htmlResponse = htmlResponse.replace("%NONCE%", nonce); response.getWriter().print(htmlResponse); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/ValidationActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/ValidationActionTest.java index 520128081bb..51a313cb207 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/ValidationActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/ValidationActionTest.java @@ -92,11 +92,11 @@ public class ValidationActionTest { doReturn(true).when(userSession).hasSession(); doReturn(true).when(userSession).isSystemAdministrator(); final String mockedHtmlContent = "mocked html content"; - doReturn(mockedHtmlContent).when(samlAuthenticator).getAuthenticationStatusPage(any(), any()); + doReturn(mockedHtmlContent).when(samlAuthenticator).getAuthenticationStatusPage(any()); underTest.doFilter(new JakartaHttpRequest(servletRequest), new JakartaHttpResponse(servletResponse), filterChain); - verify(samlAuthenticator).getAuthenticationStatusPage(any(), any()); + verify(samlAuthenticator).getAuthenticationStatusPage(any()); verify(servletResponse).getWriter(); CSP_HEADERS.forEach(h -> verify(servletResponse).setHeader(eq(h), anyString())); assertEquals(mockedHtmlContent, stringWriter.toString()); |