@@ -57,6 +57,7 @@ If the **Force user authentication** property is set to false, the following API | |||
| * api/rules/show | |||
| * api/rules/tags | |||
| * api/server/version | |||
| * api/settings/login_message | |||
| * api/sources/scm (for public repositories) | |||
| * api/sources/show (for public repositories) | |||
| * api/system/db_migration_status |
@@ -63,7 +63,8 @@ public class UserSessionInitializer { | |||
"/api/server/version", | |||
"/api/users/identity_providers", "/api/l10n/index", | |||
"/api/authentication/login", "/api/authentication/logout", "/api/authentication/validate", | |||
"/api/project_badges/measure", "/api/project_badges/quality_gate"); | |||
"/api/project_badges/measure", "/api/project_badges/quality_gate", | |||
"/api/settings/login_message"); | |||
private static final Set<String> URL_USING_PASSCODE = Set.of( | |||
"/api/ce/info", "/api/ce/pause", |
@@ -0,0 +1,81 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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.server.setting.ws; | |||
import com.google.common.io.Resources; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.text.JsonWriter; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.property.PropertyDto; | |||
import org.sonar.markdown.Markdown; | |||
import org.sonar.server.loginmessage.LoginMessageFeature; | |||
import static org.sonar.core.config.WebConstants.SONAR_LOGIN_DISPLAY_MESSAGE; | |||
import static org.sonar.core.config.WebConstants.SONAR_LOGIN_MESSAGE; | |||
public class LoginMessageAction implements SettingsWsAction { | |||
private final DbClient dbClient; | |||
private final LoginMessageFeature loginMessageFeature; | |||
public LoginMessageAction(DbClient dbClient, LoginMessageFeature loginMessageFeature) { | |||
this.dbClient = dbClient; | |||
this.loginMessageFeature = loginMessageFeature; | |||
} | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
controller.createAction("login_message") | |||
.setDescription("Returns the formatted login message, set to the '" + SONAR_LOGIN_MESSAGE + "' property.") | |||
.setSince("9.8") | |||
.setInternal(true) | |||
.setResponseExample(Resources.getResource(getClass(), "example-login-message.json")) | |||
.setHandler(this); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
try (JsonWriter writer = response.newJsonWriter()) { | |||
writer.beginObject() | |||
.prop("message", isMessageDisplayEnabled() && loginMessageFeature.isEnabled() ? Markdown.convertToHtml(getLoginMessage()) : "") | |||
.endObject() | |||
.close(); | |||
} | |||
} | |||
/** | |||
* Gets the boolean value of the property "sonar.login.displayMessage". | |||
* @return True if the property is enabled, false if it's disabled or not set. | |||
*/ | |||
private boolean isMessageDisplayEnabled() { | |||
PropertyDto displayMessageProperty = dbClient.propertiesDao().selectGlobalProperty(SONAR_LOGIN_DISPLAY_MESSAGE); | |||
return displayMessageProperty != null && Boolean.TRUE.toString().equals(displayMessageProperty.getValue()); | |||
} | |||
/** | |||
* Retrieves the String value of the property "sonar.login.message". | |||
* @return The saved String value, or empty String if it's not set. | |||
*/ | |||
private String getLoginMessage() { | |||
PropertyDto loginMessageProperty = dbClient.propertiesDao().selectGlobalProperty(SONAR_LOGIN_MESSAGE); | |||
return loginMessageProperty != null && loginMessageProperty.getValue() != null ? loginMessageProperty.getValue() : ""; | |||
} | |||
} |
@@ -29,6 +29,7 @@ public class SettingsWsModule extends Module { | |||
org.sonar.server.setting.ws.SetAction.class, | |||
SettingsWsSupport.class, | |||
ListDefinitionsAction.class, | |||
LoginMessageAction.class, | |||
ValuesAction.class, | |||
ResetAction.class, | |||
EncryptAction.class, |
@@ -0,0 +1,3 @@ | |||
{ | |||
"message": "Login message set by admin with a link to [SonarQube Home Page](https://www.sonarqube.org)" | |||
} |
@@ -0,0 +1,111 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2022 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.server.setting.ws; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.property.PropertiesDao; | |||
import org.sonar.db.property.PropertyDto; | |||
import org.sonar.server.loginmessage.LoginMessageFeature; | |||
import org.sonar.server.ws.TestResponse; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.doReturn; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.core.config.WebConstants.SONAR_LOGIN_DISPLAY_MESSAGE; | |||
import static org.sonar.core.config.WebConstants.SONAR_LOGIN_MESSAGE; | |||
public class LoginMessageActionTest { | |||
private final DbClient dbClient = mock(DbClient.class); | |||
private final LoginMessageFeature loginMessageFeature = mock(LoginMessageFeature.class); | |||
private final LoginMessageAction underTest = new LoginMessageAction(dbClient, loginMessageFeature); | |||
private final WsActionTester ws = new WsActionTester(underTest); | |||
private static final String LOGIN_MESSAGE_TEXT = "test link [SonarQube™ Home Page](https://www.sonarqube.org)\n* list 1\n* list 2"; | |||
private static final String FORMATTED_LOGIN_MESSAGE_TEXT = "test link \\u003ca href\\u003d\\\"https://www.sonarqube.org\\\" target\\u003d\\\"_blank\\\"\\u003eSonarQube\\u0026trade; Home Page\\u003c/a\\u003e\\u003cbr/\\u003e\\u003cul\\u003e\\u003cli\\u003elist 1\\u003c/li\\u003e\\n\\u003cli\\u003elist 2\\u003c/li\\u003e\\u003c/ul\\u003e"; | |||
private static final String JSON_RESPONSE = "{\"message\":\"" + FORMATTED_LOGIN_MESSAGE_TEXT + "\"}"; | |||
private static final String EMPTY_JSON_RESPONSE = "{\"message\":\"\"}"; | |||
private PropertiesDao propertiesDao; | |||
@Before | |||
public void setup() { | |||
propertiesDao = mock(PropertiesDao.class); | |||
doReturn(true).when(loginMessageFeature).isEnabled(); | |||
doReturn(propertiesDao).when(dbClient).propertiesDao(); | |||
} | |||
@Test | |||
public void test_definition() { | |||
WebService.Action action = ws.getDef(); | |||
assertThat(action.key()).isEqualTo("login_message"); | |||
assertThat(action.isPost()).isFalse(); | |||
assertThat(action.isInternal()).isTrue(); | |||
assertThat(action.params()).isEmpty(); | |||
} | |||
@Test | |||
public void returns_login_formatted_message_json() { | |||
mockProperty(SONAR_LOGIN_DISPLAY_MESSAGE, "true"); | |||
mockProperty(SONAR_LOGIN_MESSAGE, LOGIN_MESSAGE_TEXT); | |||
TestResponse response = ws.newRequest().execute(); | |||
assertThat(response.getInput()).isEqualTo(JSON_RESPONSE); | |||
} | |||
@Test | |||
public void return_empty_message_when_no_message_saved() { | |||
mockProperty(SONAR_LOGIN_DISPLAY_MESSAGE, "true"); | |||
TestResponse response = ws.newRequest().execute(); | |||
assertThat(response.getInput()).isEqualTo(EMPTY_JSON_RESPONSE); | |||
} | |||
@Test | |||
public void return_empty_message_when_feature_not_enabled() { | |||
mockProperty(SONAR_LOGIN_DISPLAY_MESSAGE, "true"); | |||
mockProperty(SONAR_LOGIN_MESSAGE, LOGIN_MESSAGE_TEXT); | |||
when(loginMessageFeature.isEnabled()).thenReturn(false); | |||
TestResponse response = ws.newRequest().execute(); | |||
assertThat(response.getInput()).isEqualTo(EMPTY_JSON_RESPONSE); | |||
} | |||
@Test | |||
public void return_empty_message_when_login_message_flag_is_disabled() { | |||
mockProperty(SONAR_LOGIN_DISPLAY_MESSAGE, "false"); | |||
mockProperty(SONAR_LOGIN_MESSAGE, LOGIN_MESSAGE_TEXT); | |||
TestResponse response = ws.newRequest().execute(); | |||
assertThat(response.getInput()).isEqualTo(EMPTY_JSON_RESPONSE); | |||
} | |||
private void mockProperty(String key, String value) { | |||
var propertyDto = mock(PropertyDto.class); | |||
doReturn(value).when(propertyDto).getValue(); | |||
doReturn(key).when(propertyDto).getKey(); | |||
doReturn(propertyDto).when(propertiesDao).selectGlobalProperty(key); | |||
} | |||
} |
@@ -29,6 +29,6 @@ public class SettingsWsModuleTest { | |||
public void verify_count_of_added_components() { | |||
ListContainer container = new ListContainer(); | |||
new SettingsWsModule().configure(container); | |||
assertThat(container.getAddedObjects()).hasSize(11); | |||
assertThat(container.getAddedObjects()).hasSize(12); | |||
} | |||
} |
@@ -28,6 +28,8 @@ public final class WebConstants { | |||
public static final String SONAR_LF_GRAVATAR_SERVER_URL = "sonar.lf.gravatarServerUrl"; | |||
public static final String SONAR_LF_LOGO_URL = "sonar.lf.logoUrl"; | |||
public static final String SONAR_LF_LOGO_WIDTH_PX = "sonar.lf.logoWidthPx"; | |||
public static final String SONAR_LOGIN_MESSAGE = "sonar.login.message"; | |||
public static final String SONAR_LOGIN_DISPLAY_MESSAGE = "sonar.login.displayMessage"; | |||
private WebConstants() { | |||
} |