Browse Source

SONAR-14662 Redirecting admin to the risk consent page

tags/8.9.0.43852
Lukasz Jarocki 3 years ago
parent
commit
c54b7df81f

+ 93
- 0
server/sonar-webserver-core/src/main/java/org/sonar/server/plugins/PluginsRiskConsentFilter.java View File

@@ -0,0 +1,93 @@
/*
* SonarQube
* Copyright (C) 2009-2021 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.plugins;

import com.google.common.collect.ImmutableSet;
import org.sonar.api.config.Configuration;
import org.sonar.api.web.ServletFilter;
import org.sonar.core.extension.PluginRiskConsent;
import org.sonar.server.user.ThreadLocalUserSession;

import static org.sonar.api.web.ServletFilter.UrlPattern.Builder.staticResourcePatterns;
import static org.sonar.core.config.CorePropertyDefinitions.PLUGINS_RISK_CONSENT;
import static org.sonar.core.extension.PluginRiskConsent.NOT_ACCEPTED;
import static org.sonar.core.extension.PluginRiskConsent.REQUIRED;
import static org.sonar.server.authentication.AuthenticationRedirection.redirectTo;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;

public class PluginsRiskConsentFilter extends ServletFilter {

private static final String PLUGINS_RISK_CONSENT_PATH = "/admin/plugin_risk_consent"; //NOSONAR this path will be the same in every environment

private static final Set<String> SKIPPED_URLS = ImmutableSet.of(
PLUGINS_RISK_CONSENT_PATH,
"/account/reset_password",
"/admin/change_admin_password",
"/batch/*", "/api/*");
private final ThreadLocalUserSession userSession;
private final Configuration config;

public PluginsRiskConsentFilter(Configuration config, ThreadLocalUserSession userSession) {
this.userSession = userSession;
this.config = config;
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
//nothing to do
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
PluginRiskConsent riskConsent = PluginRiskConsent.valueOf(config.get(PLUGINS_RISK_CONSENT).orElse(NOT_ACCEPTED.name()));

if (userSession.hasSession() && userSession.isLoggedIn()
&& userSession.isSystemAdministrator() && riskConsent == REQUIRED) {
redirectTo(response, request.getContextPath() + PLUGINS_RISK_CONSENT_PATH);
}

chain.doFilter(request, response);
}

@Override
public UrlPattern doGetPattern() {
return UrlPattern.builder()
.includes("/*")
.excludes(staticResourcePatterns())
.excludes(SKIPPED_URLS)
.build();
}

@Override
public void destroy() {
//nothing to do
}
}

+ 176
- 0
server/sonar-webserver-core/src/test/java/org/sonar/server/plugins/PluginsRiskConsentFilterTest.java View File

@@ -0,0 +1,176 @@
/*
* SonarQube
* Copyright (C) 2009-2021 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.plugins;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.sonar.api.config.Configuration;
import org.sonar.api.web.ServletFilter;
import org.sonar.core.extension.PluginRiskConsent;
import org.sonar.server.plugins.PluginsRiskConsentFilter;
import org.sonar.server.user.ThreadLocalUserSession;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.sonar.core.config.CorePropertyDefinitions.PLUGINS_RISK_CONSENT;
import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Optional;

public class PluginsRiskConsentFilterTest {

private Configuration configuration;
private ThreadLocalUserSession userSession;

private ServletRequest servletRequest;
private HttpServletResponse servletResponse;
private FilterChain chain;

@Before
public void before() {
configuration = mock(Configuration.class);
when(configuration.get(PLUGINS_RISK_CONSENT)).thenReturn(Optional.of(PluginRiskConsent.REQUIRED.name()));
userSession = mock(ThreadLocalUserSession.class);

servletRequest = mock(HttpServletRequest.class);
servletResponse = mock(HttpServletResponse.class);
chain = mock(FilterChain.class);
}

@Test
public void doFilter_givenNoUserSession_dontRedirect() throws Exception {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

when(userSession.hasSession()).thenReturn(true);

consentFilter.doFilter(servletRequest, servletResponse, chain);

verify(servletResponse, times(0)).sendRedirect(Mockito.anyString());
}

@Test
public void doFilter_givenNotLoggedIn_dontRedirect() throws Exception {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

when(userSession.hasSession()).thenReturn(true);
when(userSession.isLoggedIn()).thenReturn(false);

consentFilter.doFilter(servletRequest, servletResponse, chain);

verify(servletResponse, times(0)).sendRedirect(Mockito.anyString());
}

@Test
public void doFilter_givenNotLoggedInAndRequired_dontRedirect() throws Exception {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

when(userSession.hasSession()).thenReturn(true);
when(userSession.isLoggedIn()).thenReturn(false);
when(configuration.get(PLUGINS_RISK_CONSENT)).thenReturn(Optional.of(PluginRiskConsent.REQUIRED.name()));

consentFilter.doFilter(servletRequest, servletResponse, chain);

verify(servletResponse, times(0)).sendRedirect(Mockito.anyString());
}

@Test
public void doFilter_givenNotLoggedInAndConsentAccepted_dontRedirect() throws Exception {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

when(userSession.hasSession()).thenReturn(true);
when(userSession.isLoggedIn()).thenReturn(false);
when(configuration.get(PLUGINS_RISK_CONSENT)).thenReturn(Optional.of(PluginRiskConsent.ACCEPTED.name()));

consentFilter.doFilter(servletRequest, servletResponse, chain);

verify(servletResponse, times(0)).sendRedirect(Mockito.anyString());
}

@Test
public void doFilter_givenLoggedInNotAdmin_dontRedirect() throws Exception {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

when(userSession.hasSession()).thenReturn(true);
when(userSession.isLoggedIn()).thenReturn(true);
when(userSession.isSystemAdministrator()).thenReturn(false);

consentFilter.doFilter(servletRequest, servletResponse, chain);

verify(servletResponse, times(0)).sendRedirect(Mockito.anyString());
}

@Test
public void doFilter_givenLoggedInNotAdminAndRequiredConsent_dontRedirect() throws Exception {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

when(userSession.hasSession()).thenReturn(true);
when(userSession.isLoggedIn()).thenReturn(true);
when(userSession.isSystemAdministrator()).thenReturn(false);
when(configuration.get(PLUGINS_RISK_CONSENT)).thenReturn(Optional.of(PluginRiskConsent.REQUIRED.name()));

consentFilter.doFilter(servletRequest, servletResponse, chain);

verify(servletResponse, times(0)).sendRedirect(Mockito.anyString());
}

@Test
public void doFilter_givenLoggedInAdminAndConsentRequired_redirect() throws Exception {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

when(userSession.hasSession()).thenReturn(true);
when(userSession.isLoggedIn()).thenReturn(true);
when(userSession.isSystemAdministrator()).thenReturn(true);

consentFilter.doFilter(servletRequest, servletResponse, chain);

verify(servletResponse, times(1)).sendRedirect(Mockito.anyString());
}

@Test
public void doFilter_givenLoggedInAdminAndConsentNotRequired_dontRedirect() throws Exception {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

when(userSession.hasSession()).thenReturn(true);
when(userSession.isLoggedIn()).thenReturn(true);
when(userSession.isSystemAdministrator()).thenReturn(true);
when(configuration.get(PLUGINS_RISK_CONSENT)).thenReturn(Optional.of(PluginRiskConsent.ACCEPTED.name()));

consentFilter.doFilter(servletRequest, servletResponse, chain);

verify(servletResponse, times(0)).sendRedirect(Mockito.anyString());
}

@Test
public void doGetPattern_excludesNotEmpty() {
PluginsRiskConsentFilter consentFilter = new PluginsRiskConsentFilter(configuration, userSession);

ServletFilter.UrlPattern urlPattern = consentFilter.doGetPattern();

assertThat(urlPattern.getExclusions()).isNotEmpty();

}
}

+ 5
- 2
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.platform.platformlevel;

import java.util.List;
import org.sonar.alm.client.TimeoutConfigurationImpl;
import org.sonar.alm.client.azure.AzureDevOpsHttpClient;
import org.sonar.alm.client.bitbucket.bitbucketcloud.BitbucketCloudRestClient;
@@ -181,6 +180,7 @@ import org.sonar.server.qualityprofile.QProfileTreeImpl;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.qualityprofile.ws.QProfilesWsModule;
import org.sonar.server.plugins.PluginsRiskConsentFilter;
import org.sonar.server.root.ws.RootWsModule;
import org.sonar.server.rule.CommonRuleDefinitionsImpl;
import org.sonar.server.rule.RuleCreator;
@@ -234,6 +234,7 @@ import org.sonar.server.ws.ws.WebServicesWsModule;

import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter;
import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel4OrNone;
import java.util.List;

public class PlatformLevel4 extends PlatformLevel {

@@ -557,7 +558,9 @@ public class PlatformLevel4 extends PlatformLevel {
TelemetryDataLoaderImpl.class,
TelemetryDataJsonWriter.class,
TelemetryDaemon.class,
TelemetryClient.class
TelemetryClient.class,

PluginsRiskConsentFilter.class

);


Loading…
Cancel
Save