Skip to content

Commit be26a9a

Browse files
authored
feat: AT-TLS aware API ML (#1621)
Signed-off-by: achmelo <a.chmelo@gmail.com>
1 parent 0fac007 commit be26a9a

File tree

65 files changed

+841
-307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+841
-307
lines changed

.github/workflows/ci-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
jobs:
1010
BuildAndTest:
1111
runs-on: ubuntu-latest
12-
timeout-minutes: 10
12+
timeout-minutes: 13
1313

1414
steps:
1515
- uses: actions/checkout@v2

api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/security/SecurityConfiguration.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import com.fasterxml.jackson.databind.ObjectMapper;
1313
import lombok.RequiredArgsConstructor;
14+
import org.springframework.beans.factory.annotation.Qualifier;
1415
import org.springframework.beans.factory.annotation.Value;
1516
import org.springframework.context.annotation.Bean;
1617
import org.springframework.context.annotation.Configuration;
@@ -29,18 +30,21 @@
2930
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
3031
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
3132
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
32-
import org.zowe.apiml.product.filter.AttlsFilter;
33+
import org.zowe.apiml.filter.AttlsFilter;
3334
import org.zowe.apiml.security.client.EnableApimlAuth;
3435
import org.zowe.apiml.security.client.login.GatewayLoginProvider;
3536
import org.zowe.apiml.security.client.token.GatewayTokenProvider;
3637
import org.zowe.apiml.security.common.config.AuthConfigurationProperties;
38+
import org.zowe.apiml.security.common.config.CertificateAuthenticationProvider;
3739
import org.zowe.apiml.security.common.config.HandlerInitializer;
3840
import org.zowe.apiml.security.common.content.BasicContentFilter;
3941
import org.zowe.apiml.security.common.content.CookieContentFilter;
42+
import org.zowe.apiml.security.common.filter.ApimlX509Filter;
4043
import org.zowe.apiml.security.common.login.LoginFilter;
4144
import org.zowe.apiml.security.common.login.ShouldBeAlreadyAuthenticatedFilter;
4245

4346
import java.util.Collections;
47+
import java.util.Set;
4448

4549
/**
4650
* Main configuration class of Spring web security for Api Catalog
@@ -61,6 +65,8 @@ public class SecurityConfiguration {
6165
private final HandlerInitializer handlerInitializer;
6266
private final GatewayLoginProvider gatewayLoginProvider;
6367
private final GatewayTokenProvider gatewayTokenProvider;
68+
@Qualifier("publicKeyCertificatesBase64")
69+
private final Set<String> publicKeyCertificatesBase64;
6470

6571
/**
6672
* Filter chain for protecting /apidoc/** endpoints with MF credentials for client certificate.
@@ -78,10 +84,12 @@ public class FilterChainBasicAuthOrTokenOrCertForApiDoc extends WebSecurityConfi
7884
@Value("${server.attls.enabled:false}")
7985
private boolean isAttlsEnabled;
8086

87+
8188
@Override
8289
protected void configure(AuthenticationManagerBuilder auth) {
8390
auth.authenticationProvider(gatewayLoginProvider);
8491
auth.authenticationProvider(gatewayTokenProvider);
92+
auth.authenticationProvider(new CertificateAuthenticationProvider());
8593
}
8694

8795
@Override
@@ -94,16 +102,30 @@ protected void configure(HttpSecurity http) throws Exception {
94102
.antMatchers(APIDOC_ROUTES).authenticated();
95103

96104
if (verifySslCertificatesOfServices || nonStrictVerifySslCertificatesOfServices) {
97-
http.x509().userDetailsService(x509UserDetailsService());
98105
if (isAttlsEnabled) {
99-
http.addFilterBefore(new AttlsFilter(), X509AuthenticationFilter.class);
106+
http.x509()
107+
.x509AuthenticationFilter(apimlX509Filter(authenticationManager())) // filter out API ML certificate
108+
.userDetailsService(x509UserDetailsService())
109+
.and()
110+
.addFilterBefore(new AttlsFilter(), X509AuthenticationFilter.class);
111+
} else {
112+
http.x509()
113+
.userDetailsService(x509UserDetailsService());
100114
}
101115
}
102116
}
103117

104118
private UserDetailsService x509UserDetailsService() {
105119
return username -> new User(username, "", Collections.emptyList());
106120
}
121+
122+
private ApimlX509Filter apimlX509Filter(AuthenticationManager authenticationManager) {
123+
ApimlX509Filter out = new ApimlX509Filter(publicKeyCertificatesBase64);
124+
out.setCertificateForClientAuth(crt -> out.getPublicKeyCertificatesBase64().contains(out.base64EncodePublicKey(crt)));
125+
out.setNotCertificateForClientAuth(crt -> !out.getPublicKeyCertificatesBase64().contains(out.base64EncodePublicKey(crt)));
126+
out.setAuthenticationManager(authenticationManager);
127+
return out;
128+
}
107129
}
108130

109131
/**

api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV2Service.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import io.swagger.parser.SwaggerParser;
1818
import io.swagger.util.Json;
1919
import lombok.extern.slf4j.Slf4j;
20+
import org.springframework.beans.factory.annotation.Value;
2021
import org.zowe.apiml.apicatalog.services.cached.model.ApiDocInfo;
2122
import org.zowe.apiml.apicatalog.swagger.ApiDocTransformationException;
2223
import org.zowe.apiml.product.gateway.GatewayClient;
@@ -29,6 +30,9 @@
2930
@Slf4j
3031
public class ApiDocV2Service extends AbstractApiDocService<Swagger, Path> {
3132

33+
@Value("${gateway.scheme.external:https}")
34+
private String scheme;
35+
3236
public ApiDocV2Service(GatewayClient gatewayClient) {
3337
super(gatewayClient);
3438
}
@@ -64,9 +68,9 @@ public String transformApiDoc(String serviceId, ApiDocInfo apiDocInfo) {
6468
*/
6569
private void updateSchemeHostAndLink(Swagger swagger, String serviceId, boolean hidden) {
6670
GatewayConfigProperties gatewayConfigProperties = gatewayClient.getGatewayConfigProperties();
67-
String swaggerLink = OpenApiUtil.getOpenApiLink(serviceId, gatewayConfigProperties);
71+
String swaggerLink = OpenApiUtil.getOpenApiLink(serviceId, gatewayConfigProperties, scheme);
6872
log.debug("Updating host for service with id: " + serviceId + " to: " + gatewayConfigProperties.getHostname());
69-
swagger.setSchemes(Collections.singletonList(Scheme.forValue(gatewayConfigProperties.getScheme())));
73+
swagger.setSchemes(Collections.singletonList(Scheme.forValue(scheme)));
7074
swagger.setHost(gatewayConfigProperties.getHostname());
7175
if (!hidden) {
7276
swagger.getInfo().setDescription(swagger.getInfo().getDescription() + swaggerLink);

api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3Service.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.swagger.v3.parser.OpenAPIV3Parser;
2525
import io.swagger.v3.parser.core.models.SwaggerParseResult;
2626
import lombok.extern.slf4j.Slf4j;
27+
import org.springframework.beans.factory.annotation.Value;
2728
import org.zowe.apiml.apicatalog.services.cached.model.ApiDocInfo;
2829
import org.zowe.apiml.apicatalog.swagger.ApiDocTransformationException;
2930
import org.zowe.apiml.apicatalog.swagger.SecuritySchemeSerializer;
@@ -40,6 +41,8 @@
4041

4142
@Slf4j
4243
public class ApiDocV3Service extends AbstractApiDocService<OpenAPI, PathItem> {
44+
@Value("${gateway.scheme.external:https}")
45+
private String scheme;
4346

4447
public ApiDocV3Service(GatewayClient gatewayClient) {
4548
super(gatewayClient);
@@ -75,12 +78,12 @@ public String transformApiDoc(String serviceId, ApiDocInfo apiDocInfo) {
7578

7679
private void updateServerAndLink(OpenAPI openAPI, String serviceId, boolean hidden) {
7780
GatewayConfigProperties gatewayConfigProperties = gatewayClient.getGatewayConfigProperties();
78-
String swaggerLink = OpenApiUtil.getOpenApiLink(serviceId, gatewayConfigProperties);
81+
String swaggerLink = OpenApiUtil.getOpenApiLink(serviceId, gatewayConfigProperties, scheme);
7982

8083
if (openAPI.getServers() != null) {
8184
openAPI.getServers()
8285
.forEach(server -> server.setUrl(
83-
String.format("%s://%s/%s", gatewayConfigProperties.getScheme(), gatewayConfigProperties.getHostname(), server.getUrl())));
86+
String.format("%s://%s/%s", scheme, gatewayConfigProperties.getHostname(), server.getUrl())));
8487
}
8588
if (!hidden) {
8689
openAPI.getInfo().setDescription(openAPI.getInfo().getDescription() + swaggerLink);

api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/swagger/api/OpenApiUtil.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ public class OpenApiUtil {
2222
private static final String HARDCODED_VERSION = "/v1";
2323
public static final String SEPARATOR = "/";
2424

25-
public static String getOpenApiLink(String serviceId, GatewayConfigProperties gatewayConfigProperties) {
26-
String link = gatewayConfigProperties.getScheme() + "://" + gatewayConfigProperties.getHostname()
25+
public static String getOpenApiLink(String serviceId, GatewayConfigProperties gatewayConfigProperties, String scheme) {
26+
String link = scheme + "://" + gatewayConfigProperties.getHostname()
2727
+ SEPARATOR + CoreService.API_CATALOG.getServiceId() + CATALOG_VERSION
2828
+ CATALOG_APIDOC_ENDPOINT + SEPARATOR + serviceId + HARDCODED_VERSION;
2929
return "\n\n" + SWAGGER_LOCATION_LINK + "(" + link + ")";

api-catalog-services/src/main/resources/application.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ eureka:
217217
secureHealthCheckUrl: http://${apiml.service.hostname}:${apiml.service.port}${apiml.service.contextPath}/application/health
218218
metadata-map:
219219
apiml:
220+
corsEnabled: true
220221
apiInfo:
221222
- apiId: zowe.apiml.apicatalog
222223
version: 1.0.0
@@ -227,4 +228,3 @@ apiml:
227228
scheme: http
228229
nonSecurePortEnabled: true
229230
securePortEnabled: false
230-
discoveryServiceUrls: http://localhost:10001/eureka/

api-catalog-services/src/test/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV2ServiceTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.mockito.junit.jupiter.MockitoExtension;
2222
import org.mockito.junit.jupiter.MockitoSettings;
2323
import org.mockito.quality.Strictness;
24+
import org.springframework.test.util.ReflectionTestUtils;
2425
import org.zowe.apiml.apicatalog.services.cached.model.ApiDocInfo;
2526
import org.zowe.apiml.config.ApiInfo;
2627
import org.zowe.apiml.product.constants.CoreService;
@@ -61,6 +62,7 @@ void setUp() {
6162
gatewayConfigProperties = getProperties();
6263
gatewayClient = new GatewayClient(gatewayConfigProperties);
6364
apiDocV2Service = new ApiDocV2Service(gatewayClient);
65+
ReflectionTestUtils.setField(apiDocV2Service,"scheme","https");
6466
}
6567

6668
@Test

api-catalog-services/src/test/java/org/zowe/apiml/apicatalog/swagger/api/ApiDocV3ServiceTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.swagger.v3.oas.models.tags.Tag;
2222
import org.junit.jupiter.api.BeforeEach;
2323
import org.junit.jupiter.api.Test;
24+
import org.springframework.test.util.ReflectionTestUtils;
2425
import org.zowe.apiml.apicatalog.services.cached.model.ApiDocInfo;
2526
import org.zowe.apiml.config.ApiInfo;
2627
import org.zowe.apiml.product.constants.CoreService;
@@ -57,6 +58,7 @@ void setUp() {
5758
GatewayConfigProperties gatewayConfigProperties = getProperties();
5859
gatewayClient = new GatewayClient(gatewayConfigProperties);
5960
apiDocV3Service = new ApiDocV3Service(gatewayClient);
61+
ReflectionTestUtils.setField(apiDocV3Service,"scheme","https");
6062
}
6163

6264
@Test

apiml-common/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
dependencies {
22
compile project(':apiml-utility')
3-
3+
compile project(':apiml-tomcat-common')
44
compile libraries.spring_boot_starter_web
55
compile libraries.spring_boot_starter_validation
66
compile libraries.jackson_databind
77
compile libraries.apache_commons_lang3
88
compile libraries.http_client
99
compile libraries.http_core
1010

11+
1112
compileOnly libraries.spring_boot_configuration_processor
1213
compileOnly libraries.lombok
1314
annotationProcessor libraries.lombok

apiml-common/src/main/java/org/zowe/apiml/product/filter/AttlsFilter.java

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)