3 * Copyright (C) 2009-2022 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 package org.sonar.server.authentication;
23 import java.io.IOException;
24 import java.io.PrintWriter;
25 import javax.servlet.FilterChain;
26 import javax.servlet.FilterConfig;
27 import javax.servlet.ServletException;
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.mockito.ArgumentCaptor;
33 import org.sonar.api.platform.Server;
35 import static org.assertj.core.api.Assertions.assertThat;
36 import static org.junit.Assert.assertThrows;
37 import static org.mockito.ArgumentMatchers.matches;
38 import static org.mockito.Mockito.doReturn;
39 import static org.mockito.Mockito.mock;
40 import static org.mockito.Mockito.verify;
41 import static org.mockito.Mockito.verifyNoInteractions;
42 import static org.mockito.Mockito.when;
44 public class SamlValidationRedirectionFilterTest {
46 SamlValidationRedirectionFilter underTest;
49 public void setup() throws ServletException {
50 Server server = mock(Server.class);
51 doReturn("").when(server).getContextPath();
52 underTest = new SamlValidationRedirectionFilter(server);
53 underTest.init(mock(FilterConfig.class));
57 public void do_get_pattern() {
58 assertThat(underTest.doGetPattern().matches("/oauth2/callback/saml")).isTrue();
59 assertThat(underTest.doGetPattern().matches("/oauth2/callback/")).isFalse();
60 assertThat(underTest.doGetPattern().matches("/oauth2/callback/test")).isFalse();
61 assertThat(underTest.doGetPattern().matches("/oauth2/")).isFalse();
65 public void do_filter_validation_relay_state() throws ServletException, IOException {
66 HttpServletRequest servletRequest = mock(HttpServletRequest.class);
67 HttpServletResponse servletResponse = mock(HttpServletResponse.class);
68 FilterChain filterChain = mock(FilterChain.class);
70 String validSample = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
71 when(servletRequest.getParameter(matches("SAMLResponse"))).thenReturn(validSample);
72 when(servletRequest.getParameter(matches("RelayState"))).thenReturn("validation-query");
73 PrintWriter pw = mock(PrintWriter.class);
74 when(servletResponse.getWriter()).thenReturn(pw);
76 underTest.doFilter(servletRequest, servletResponse, filterChain);
78 verify(servletResponse).setContentType("text/html");
79 ArgumentCaptor<String> htmlProduced = ArgumentCaptor.forClass(String.class);
80 verify(pw).print(htmlProduced.capture());
81 assertThat(htmlProduced.getValue()).contains(validSample);
85 public void do_filter_validation_wrong_SAML_response() throws ServletException, IOException {
86 HttpServletRequest servletRequest = mock(HttpServletRequest.class);
87 HttpServletResponse servletResponse = mock(HttpServletResponse.class);
88 FilterChain filterChain = mock(FilterChain.class);
90 String maliciousSaml = "test\"</input><script>/*hack website*/</script><input value=\"";
92 when(servletRequest.getParameter(matches("SAMLResponse"))).thenReturn(maliciousSaml);
93 when(servletRequest.getParameter(matches("RelayState"))).thenReturn("validation-query");
94 PrintWriter pw = mock(PrintWriter.class);
95 when(servletResponse.getWriter()).thenReturn(pw);
97 underTest.doFilter(servletRequest, servletResponse, filterChain);
99 verify(servletResponse).setContentType("text/html");
100 ArgumentCaptor<String> htmlProduced = ArgumentCaptor.forClass(String.class);
101 verify(pw).print(htmlProduced.capture());
102 assertThat(htmlProduced.getValue()).doesNotContain("<script>/*hack website*/</script>");
103 assertThat(htmlProduced.getValue()).contains("action=\"/saml/validation\"");
107 public void do_filter_no_validation_relay_state() throws ServletException, IOException {
108 HttpServletRequest servletRequest = mock(HttpServletRequest.class);
109 HttpServletResponse servletResponse = mock(HttpServletResponse.class);
110 FilterChain filterChain = mock(FilterChain.class);
112 doReturn("random_query").when(servletRequest).getParameter("RelayState");
113 underTest.doFilter(servletRequest, servletResponse, filterChain);
115 verifyNoInteractions(servletResponse);
119 public void extract_nonexistant_template() {
120 assertThrows(IllegalStateException.class, () -> underTest.extractTemplate("not-there"));