file: /var/log/policy-agent/application.log
server:
port : 8433
+ http-port: 8081
ssl:
- key-store-type: PKCS12
+ key-store-type: JKS
key-store-password: policy_agent
key-store: classpath:keystore.jks
key-password: policy_agent
+ key-alias: policy_agent
app:
filepath: /opt/app/policy-agent/config/application_configuration.json
-
+ webclient:
+ trust-store-used: false
+ trust-store-password: policy_agent
+ trust-store: classpath:keystore.jks
import org.oransc.policyagent.repository.PolicyTypes;
import org.oransc.policyagent.repository.Rics;
import org.oransc.policyagent.repository.Services;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
class BeanFactory {
private final ApplicationConfig applicationConfig = new ApplicationConfig();
+ @Value("${server.http-port}")
+ private int httpPort = 0;
+
@Bean
public Policies getPolicies() {
return new Policies();
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
- tomcat.addAdditionalTomcatConnectors(getHttpConnector());
+ if (httpPort > 0) {
+ tomcat.addAdditionalTomcatConnectors(getHttpConnector(httpPort));
+ }
return tomcat;
}
- private static Connector getHttpConnector() {
+ private static Connector getHttpConnector(int httpPort) {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
- connector.setPort(8081);
+ connector.setPort(httpPort);
connector.setSecure(false);
return connector;
}
A1Client createClient(Ric ric, A1ProtocolType version) throws ServiceException {
if (version == A1ProtocolType.STD_V1_1) {
assertNoControllerConfig(ric, version);
- return new StdA1ClientVersion1(ric.getConfig());
+ return new StdA1ClientVersion1(ric.getConfig(), this.appConfig.getWebClientConfig());
} else if (version == A1ProtocolType.OSC_V1) {
assertNoControllerConfig(ric, version);
- return new OscA1Client(ric.getConfig());
+ return new OscA1Client(ric.getConfig(), this.appConfig.getWebClientConfig());
} else if (version == A1ProtocolType.SDNC_OSC_STD_V1_1 || version == A1ProtocolType.SDNC_OSC_OSC_V1) {
return new SdncOscA1Client(version, ric.getConfig(), getControllerConfig(ric));
} else if (version == A1ProtocolType.SDNC_ONAP) {
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.lang.invoke.MethodHandles;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
-import javax.net.ssl.SSLException;
-
+import org.oransc.policyagent.configuration.ImmutableWebClientConfig;
+import org.oransc.policyagent.configuration.WebClientConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.lang.Nullable;
+import org.springframework.util.ResourceUtils;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
import org.springframework.web.reactive.function.client.WebClientResponseException;
private WebClient webClient = null;
private final String baseUrl;
private static final AtomicInteger sequenceNumber = new AtomicInteger();
+ private final WebClientConfig clientConfig;
public AsyncRestClient(String baseUrl) {
+ this(baseUrl,
+ ImmutableWebClientConfig.builder().isTrustStoreUsed(false).trustStore("").trustStorePassword("").build());
+ }
+
+ public AsyncRestClient(String baseUrl, WebClientConfig config) {
this.baseUrl = baseUrl;
+ this.clientConfig = config;
}
public Mono<ResponseEntity<String>> postForEntity(String uri, @Nullable String body) {
}
}
- private static SslContext createSslContext() throws SSLException {
+ private boolean isCertificateEntry(KeyStore trustStore, String alias) {
+ try {
+ return trustStore.isCertificateEntry(alias);
+ } catch (KeyStoreException e) {
+ logger.error("Error reading truststore {}", e.getMessage());
+ return false;
+ }
+ }
+
+ private Certificate getCertificate(KeyStore trustStore, String alias) {
+ try {
+ return trustStore.getCertificate(alias);
+ } catch (KeyStoreException e) {
+ logger.error("Error reading truststore {}", e.getMessage());
+ return null;
+ }
+ }
+
+ SslContext createSslContextSecure(String trustStorePath, String trustStorePass)
+ throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
+
+ final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ trustStore.load(new FileInputStream(ResourceUtils.getFile(trustStorePath)), trustStorePass.toCharArray());
+
+ List<Certificate> certificateList = Collections.list(trustStore.aliases()).stream() //
+ .filter(alias -> isCertificateEntry(trustStore, alias)) //
+ .map(alias -> getCertificate(trustStore, alias)) //
+ .collect(Collectors.toList());
+ final X509Certificate[] certificates = certificateList.toArray(new X509Certificate[certificateList.size()]);
+
return SslContextBuilder.forClient() //
- .trustManager(InsecureTrustManagerFactory.INSTANCE) //
+ .trustManager(certificates) //
.build();
}
- private static WebClient createWebClient(String baseUrl, SslContext sslContext) {
+ private SslContext createSslContext()
+ throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
+ if (this.clientConfig.isTrustStoreUsed()) {
+ return createSslContextSecure(this.clientConfig.trustStore(), this.clientConfig.trustStorePassword());
+ } else {
+ return SslContextBuilder.forClient() //
+ .trustManager(InsecureTrustManagerFactory.INSTANCE) //
+ .build();
+ }
+ }
+
+ private WebClient createWebClient(String baseUrl, SslContext sslContext) {
TcpClient tcpClient = TcpClient.create() //
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) //
.secure(c -> c.sslContext(sslContext)) //
try {
SslContext sslContext = createSslContext();
this.webClient = createWebClient(this.baseUrl, sslContext);
- } catch (SSLException e) {
+ } catch (Exception e) {
logger.error("Could not create WebClient {}", e.getMessage());
return Mono.error(e);
}
import org.json.JSONObject;
import org.oransc.policyagent.configuration.RicConfig;
+import org.oransc.policyagent.configuration.WebClientConfig;
import org.oransc.policyagent.repository.Policy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final AsyncRestClient restClient;
private final UriBuilder uri;
- public OscA1Client(RicConfig ricConfig) {
- this(ricConfig, new AsyncRestClient(""));
+ public OscA1Client(RicConfig ricConfig, WebClientConfig clientConfig) {
+ this(ricConfig, new AsyncRestClient("", clientConfig));
}
public OscA1Client(RicConfig ricConfig, AsyncRestClient restClient) {
import java.util.List;
import org.oransc.policyagent.configuration.RicConfig;
+import org.oransc.policyagent.configuration.WebClientConfig;
import org.oransc.policyagent.repository.Policy;
import reactor.core.publisher.Flux;
private final AsyncRestClient restClient;
private final UriBuilder uri;
- public StdA1ClientVersion1(RicConfig ricConfig) {
- this(new AsyncRestClient(""), ricConfig);
+ public StdA1ClientVersion1(RicConfig ricConfig, WebClientConfig webClientConfig) {
+ this(new AsyncRestClient("", webClientConfig), ricConfig);
}
public StdA1ClientVersion1(AsyncRestClient restClient, RicConfig ricConfig) {
import lombok.Getter;
import org.oransc.policyagent.exceptions.ServiceException;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import reactor.core.publisher.Flux;
@EnableConfigurationProperties
-@ConfigurationProperties("app")
+@ConfigurationProperties()
public class ApplicationConfig {
@NotEmpty
- private String filepath;
+ @Getter
+ @Value("${app.filepath}")
+ private String localConfigurationFilePath;
+
+ @Value("${app.webclient.trust-store-used}")
+ private boolean sslTrustStoreUsed = false;
+
+ @Value("${app.webclient.trust-store-password}")
+ private String sslTrustStorePassword = "";
+
+ @Value("${app.webclient.trust-store}")
+ private String sslTrustStore = "";
private Map<String, RicConfig> ricConfigs = new HashMap<>();
@Getter
private Map<String, ControllerConfig> controllerConfigs = new HashMap<>();
- public String getLocalConfigurationFilePath() {
- return this.filepath;
- }
-
- /*
- * Do not remove, used by framework!
- */
- public synchronized void setFilepath(String filepath) {
- this.filepath = filepath;
- }
-
public synchronized Collection<RicConfig> getRicConfigs() {
return this.ricConfigs.values();
}
+ public WebClientConfig getWebClientConfig() {
+ return ImmutableWebClientConfig.builder() //
+ .isTrustStoreUsed(this.sslTrustStoreUsed) //
+ .trustStore(this.sslTrustStore) //
+ .trustStorePassword(this.sslTrustStorePassword) //
+ .build();
+ }
+
public synchronized ControllerConfig getControllerConfig(String name) throws ServiceException {
ControllerConfig controllerConfig = this.controllerConfigs.get(name);
if (controllerConfig == null) {
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2020 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.policyagent.configuration;
+
+import org.immutables.value.Value;
+
+@Value.Immutable
+@Value.Style(redactedMask = "####")
+public interface WebClientConfig {
+ public boolean isTrustStoreUsed();
+
+ @Value.Redacted
+ public String trustStorePassword();
+
+ public String trustStore();
+
+}
private DmaapMessageHandler dmaapMessageHandler = null;
private MRConsumer messageRouterConsumer = null;
- @Value("${server.port}")
- private int localServerPort;
+ @Value("${server.http-port}")
+ private int localServerHttpPort;
@Autowired
public DmaapMessageConsumer(ApplicationConfig applicationConfig) {
protected DmaapMessageHandler getDmaapMessageHandler() throws IOException {
if (this.dmaapMessageHandler == null) {
- String agentBaseUrl = "https://localhost:" + this.localServerPort;
+ String agentBaseUrl = "http://localhost:" + this.localServerHttpPort;
AsyncRestClient agentClient = new AsyncRestClient(agentBaseUrl);
Properties dmaapPublisherProperties = applicationConfig.getDmaapPublisherConfig();
MRBatchingPublisher producer = MRClientFactory.createBatchingPublisher(dmaapPublisherProperties);
@Autowired
RicSupervision supervision;
+ @Autowired
+ ApplicationConfig applicationConfig;
+
@Autowired
Services services;
}
private AsyncRestClient restClient() {
- return new AsyncRestClient(baseUrl());
+ return new AsyncRestClient(baseUrl(), this.applicationConfig.getWebClientConfig());
}
private void testErrorCode(Mono<?> request, HttpStatus expStatus) {
@Autowired
PolicyTypes policyTypes;
+ @Autowired
+ ApplicationConfig applicationConfig;
+
static class MockApplicationConfig extends ApplicationConfig {
@Override
public String getLocalConfigurationFilePath() {
}
@Test
- @SuppressWarnings("squid:S2699") // Tests should include assertions. This test is only for keeping the server alive,
+ @SuppressWarnings("squid:S2699") // Tests should include assertions. This test is only for keeping the server
+ // alive,
// so it will only be confusing to add an assertion.
public void runMock() throws Exception {
keepServerAlive();