aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAurelien Poscia <aurelien.poscia@sonarsource.com>2024-12-18 18:04:38 +0100
committersonartech <sonartech@sonarsource.com>2024-12-20 20:03:10 +0000
commit1fce3f56f3135cf584a2c840c983788a3b111d0f (patch)
tree89a3a0cf2261439f7df179be99ef5e55ad8e7b87
parentc770ccb9dfb7e1e023cb7e63bb76c8ab1002f27e (diff)
downloadsonarqube-1fce3f56f3135cf584a2c840c983788a3b111d0f.tar.gz
sonarqube-1fce3f56f3135cf584a2c840c983788a3b111d0f.zip
SONAR-24023 Rewrite tests for SamlAuthenticator
-rw-r--r--server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthStatusPageGenerator.java10
-rw-r--r--server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlAuthenticator.java28
-rw-r--r--server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlModule.java4
-rw-r--r--server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlStatusChecker.java13
-rw-r--r--server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthStatusPageGeneratorTest.java13
-rw-r--r--server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlAuthenticatorTest.java164
-rw-r--r--server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlConfigurationTest.java39
-rw-r--r--server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlModuleTest.java3
-rw-r--r--server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlStatusCheckerTest.java29
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/ValidationAction.java2
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/ValidationActionTest.java4
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());