Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.zowe.apiml.filter.AttlsFilter;
import org.zowe.apiml.filter.SecureConnectionFilter;
import org.zowe.apiml.security.FixedHeadersConfigurer;
import org.zowe.apiml.security.client.EnableApimlAuth;
import org.zowe.apiml.security.client.login.GatewayLoginProvider;
import org.zowe.apiml.security.client.token.GatewayTokenProvider;
Expand Down Expand Up @@ -197,7 +198,7 @@ SecurityFilterChain basicAuthOrTokenAllEndpointsFilterChain(HttpSecurity http, L
}

private HttpSecurity baseConfiguration(HttpSecurity http) throws Exception {
http
return FixedHeadersConfigurer.fix(http
.csrf(csrf -> csrf.disable()) // NOSONAR
.headers(headers -> headers
.httpStrictTransportSecurity().disable()
Expand All @@ -217,9 +218,8 @@ private HttpSecurity baseConfiguration(HttpSecurity http) throws Exception {
handlerInitializer.getUnAuthorizedHandler(), new AntPathRequestMatcher("/**")
))
.sessionManagement(management -> management
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

return http;
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
package org.zowe.apiml.apicatalog.standalone;


import javax.annotation.PostConstruct;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.zowe.apiml.security.FixedHeadersConfigurer;
import org.zowe.apiml.product.constants.CoreService;

import lombok.extern.slf4j.Slf4j;
import javax.annotation.PostConstruct;

@Configuration
@ConditionalOnProperty(value = "apiml.catalog.standalone.enabled", havingValue = "true")
Expand All @@ -37,15 +37,15 @@ void init() {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain permitAll(HttpSecurity http) throws Exception {
return http
.csrf().disable() // NOSONAR
.headers().httpStrictTransportSecurity().disable()
.frameOptions().disable().and()

.authorizeRequests()
.anyRequest().permitAll()
.and()
.build();
return FixedHeadersConfigurer.fix(http
.csrf().disable() // NOSONAR
.headers().httpStrictTransportSecurity().disable()
.frameOptions().disable().and()

.authorizeRequests()
.anyRequest().permitAll()
.and()
).build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml.apicatalog.acceptance;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.context.annotation.Profile;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.zowe.apiml.apicatalog.ApiCatalogApplication;

import javax.servlet.http.HttpServletResponse;

import static io.restassured.RestAssured.given;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;

@SpringBootTest(
classes = {
ApiCatalogApplication.class,
ResponseHeaderFixTest.TestController.class
},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
@ActiveProfiles("ResponseHeaderFixTest")
@DirtiesContext
class ResponseHeaderFixTest {

private static final int TEST_CONTENT_LENGTH = 101;
private static final String CONTENT_LENGTH = "Content-Length";

@LocalServerPort
protected int port;

@ParameterizedTest(name = "Test handling setting context-type using {1}")
@CsvSource({
"0,addHeader<String String>",
"1,setHeader<String String>",
"2,setIntHeader<String int>",
"3,addIntHeader<String int>"
})
void givenRequest_whenSetContentLength_thenIsPropagated(int method, String description) {
given()
.relaxedHTTPSValidation()
.when()
.get(String.format("https://localhost:%d/apicatalog/test/%d/%s", port, method, CONTENT_LENGTH))
.then()
.statusCode(SC_OK)
.header(CONTENT_LENGTH, String.valueOf(TEST_CONTENT_LENGTH))
.header("X-XSS-Protection", is(notNullValue()));
}

@ParameterizedTest(name = "Test handling headers without content-type using {1}")
@CsvSource({
"0,addHeader<String String>",
"1,setHeader<String String>",
"2,setIntHeader<String int>",
"3,addIntHeader<String int>"
})
void givenRequest_whenDontSetContentLength_thenIsMissing(int method, String description) {
given()
.relaxedHTTPSValidation()
.when()
.get(String.format("https://localhost:%d/apicatalog/test/%d/%s", port, method, "otherHeaderName"))
.then()
.statusCode(SC_OK)
.header(CONTENT_LENGTH,"0")
.header("X-XSS-Protection", is(notNullValue()));
}

@RestController
@Profile("ResponseHeaderFixTest")
static class TestController {

@GetMapping(value = "/test/{method}/{headerName}")
public void getApiDoc(@PathVariable("method") int method, @PathVariable("headerName") String headerName, HttpServletResponse response) {
switch (method) {
case 0:
response.addHeader(headerName, String.valueOf(TEST_CONTENT_LENGTH));
break;
case 1:
response.setHeader(headerName, String.valueOf(TEST_CONTENT_LENGTH));
break;
case 2:
response.setIntHeader(headerName, TEST_CONTENT_LENGTH);
break;
case 3:
response.addIntHeader(headerName, TEST_CONTENT_LENGTH);
break;
default:
throw new IllegalArgumentException("Unknown method: " + method);
}

}

}

}

Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
import org.zowe.apiml.filter.AttlsFilter;
import org.zowe.apiml.filter.SecureConnectionFilter;
import org.zowe.apiml.security.FixedHeadersConfigurer;

import java.util.Collections;

Expand Down Expand Up @@ -75,7 +76,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests(requests -> requests.anyRequest().permitAll());
}

return http.build();
return FixedHeadersConfigurer.fix(http).build();
}

private UserDetailsService x509UserDetailsService() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml.caching.acceptance;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.context.annotation.Profile;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.zowe.apiml.caching.CachingService;
import org.zowe.apiml.util.config.SslContext;
import org.zowe.apiml.util.config.SslContextConfigurer;

import javax.servlet.http.HttpServletResponse;

import static io.restassured.RestAssured.given;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;

@SpringBootTest(
classes = {
CachingService.class,
ResponseHeaderFixTest.TestController.class
},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
@ActiveProfiles("ResponseHeaderFixTest")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@DirtiesContext
class ResponseHeaderFixTest {

private static final int TEST_CONTENT_LENGTH = 101;
private static final String CONTENT_LENGTH = "Content-Length";

@LocalServerPort
protected int port;

@Value("${server.ssl.keyPassword}")
private char[] password;
@Value("${server.ssl.keyStore}")
private String clientCertKeystore;
@Value("${server.ssl.keyStore}")
private String keystore;

@BeforeAll
void setup() throws Exception {
SslContextConfigurer configurer = new SslContextConfigurer(password, clientCertKeystore, keystore);
SslContext.prepareSslAuthentication(configurer);
}

@ParameterizedTest(name = "Test handling setting context-type using {1}")
@CsvSource({
"0,addHeader<String String>",
"1,setHeader<String String>",
"2,setIntHeader<String int>",
"3,addIntHeader<String int>"
})
void givenRequest_whenSetContentLength_thenIsPropagated(int method, String description) {
given()
.config(SslContext.clientCertApiml)
.when()
.get(String.format("https://localhost:%d/test/%d/%s", port, method, CONTENT_LENGTH))
.then()
.statusCode(SC_OK)
.header(CONTENT_LENGTH, String.valueOf(TEST_CONTENT_LENGTH))
.header("X-Frame-Options", is(notNullValue()))
.header("X-XSS-Protection", is(notNullValue()));
}

@ParameterizedTest(name = "Test handling headers without content-type using {1}")
@CsvSource({
"0,addHeader<String String>",
"1,setHeader<String String>",
"2,setIntHeader<String int>",
"3,addIntHeader<String int>"
})
void givenRequest_whenDontSetContentLength_thenIsMissing(int method, String description) {
given()
.config(SslContext.clientCertApiml)
.when()
.get(String.format("https://localhost:%d/test/%d/%s", port, method, "otherHeaderName"))
.then()
.statusCode(SC_OK)
.header(CONTENT_LENGTH,"0")
.header("X-Frame-Options", is(notNullValue()))
.header("X-XSS-Protection", is(notNullValue()));
}

@RestController
@Profile("ResponseHeaderFixTest")
static class TestController {

@GetMapping(value = "/test/{method}/{headerName}")
public void getApiDoc(@PathVariable("method") int method, @PathVariable("headerName") String headerName, HttpServletResponse response) {
switch (method) {
case 0:
response.addHeader(headerName, String.valueOf(TEST_CONTENT_LENGTH));
break;
case 1:
response.setHeader(headerName, String.valueOf(TEST_CONTENT_LENGTH));
break;
case 2:
response.setIntHeader(headerName, TEST_CONTENT_LENGTH);
break;
case 3:
response.addIntHeader(headerName, TEST_CONTENT_LENGTH);
break;
default:
throw new IllegalArgumentException("Unknown method: " + method);
}

}

}

}

3 changes: 3 additions & 0 deletions common-service-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ dependencies {
compileOnly libs.eh.cache
testImplementation libs.eh.cache

compileOnly libs.spring.security.config
compileOnly libs.spring.security.web

implementation libs.spring.boot.starter.cache
testImplementation libs.spring.boot.starter.cache
implementation libs.spring.web
Expand Down
Loading
Loading