aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZlatko Murgoski <zlatko.murgoski@nokia.com>2019-04-09 15:32:52 +0200
committerZlatko Murgoski <zlatko.murgoski@nokia.com>2019-04-15 10:04:19 +0200
commita6ffdd5cb52d61792dfe8e233620b34098a5fb37 (patch)
tree94d06e42027f4a51bc622765b07e28e9cd28c348
parent740ce4c075564a7005be5737adb9ff5b3f8120aa (diff)
Collector authentication enhancement
Add cert subject verifier Change-Id: If2c3c0984e9eec63e2884ca17db953fff2719888 Issue-ID: DCAEGEN2-1101 Signed-off-by: Zlatko Murgoski <zlatko.murgoski@nokia.com>
-rw-r--r--etc/certSubjectMatcher.properties1
-rwxr-xr-xetc/collector.properties2
-rw-r--r--pom.xml2
-rw-r--r--src/main/java/org/onap/dcae/ApplicationSettings.java5
-rw-r--r--src/main/java/org/onap/dcae/common/configuration/CertAuth.java31
-rw-r--r--src/main/java/org/onap/dcae/common/configuration/CertBasicAuth.java31
-rw-r--r--src/main/java/org/onap/dcae/common/configuration/CustomFilter.java83
-rw-r--r--src/main/java/org/onap/dcae/restapi/ApiAuthInterceptor.java1
-rw-r--r--src/test/java/org/onap/dcae/TLSTest.java1
-rw-r--r--src/test/java/org/onap/dcae/TLSTestBase.java3
-rw-r--r--src/test/resources/certSubjectMatcher1
-rw-r--r--version.properties2
12 files changed, 156 insertions, 7 deletions
diff --git a/etc/certSubjectMatcher.properties b/etc/certSubjectMatcher.properties
new file mode 100644
index 00000000..9abb766c
--- /dev/null
+++ b/etc/certSubjectMatcher.properties
@@ -0,0 +1 @@
+.* \ No newline at end of file
diff --git a/etc/collector.properties b/etc/collector.properties
index 36c79b51..82ba5954 100755
--- a/etc/collector.properties
+++ b/etc/collector.properties
@@ -40,6 +40,8 @@ header.authlist=sample1,$2a$10$0buh.2WeYwN868YMwnNNEuNEAMNYVU9.FSMJGyIKV3dGET/7o
collector.keystore.file.location=etc/keystore
collector.keystore.passwordfile=etc/passwordfile
+collector.cert.subject.matcher=etc/certSubjectMatcher.properties
+
## The truststore must be setup per installation when mutual tls support is configured
collector.truststore.file.location=etc/truststore
collector.truststore.passwordfile=etc/trustpasswordfile
diff --git a/pom.xml b/pom.xml
index 383595d1..304221a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
</parent>
<groupId>org.onap.dcaegen2.collectors.ves</groupId>
<artifactId>VESCollector</artifactId>
- <version>1.4.3-SNAPSHOT</version>
+ <version>1.4.4-SNAPSHOT</version>
<name>dcaegen2-collectors-ves</name>
<description>VESCollector</description>
<properties>
diff --git a/src/main/java/org/onap/dcae/ApplicationSettings.java b/src/main/java/org/onap/dcae/ApplicationSettings.java
index c4f2c063..61bcf4b4 100644
--- a/src/main/java/org/onap/dcae/ApplicationSettings.java
+++ b/src/main/java/org/onap/dcae/ApplicationSettings.java
@@ -183,11 +183,14 @@ public class ApplicationSettings {
public String exceptionConfigFileLocation() {
return properties.getString("exceptionConfig", null);
}
-
public String dMaaPConfigurationFileLocation() {
return prependWithUserDirOnRelative(properties.getString("collector.dmaapfile", "etc/DmaapConfig.json"));
}
+ public String certSubjectMatcher(){
+ return prependWithUserDirOnRelative(properties.getString("collector.cert.subject.matcher", "etc/certSubjectMatcher.properties"));
+ }
+
public String authMethod(){
return properties.getString("auth.method", AuthMethodType.NO_AUTH.value());
}
diff --git a/src/main/java/org/onap/dcae/common/configuration/CertAuth.java b/src/main/java/org/onap/dcae/common/configuration/CertAuth.java
index 3c4fb62c..481fb5ec 100644
--- a/src/main/java/org/onap/dcae/common/configuration/CertAuth.java
+++ b/src/main/java/org/onap/dcae/common/configuration/CertAuth.java
@@ -21,13 +21,24 @@
package org.onap.dcae.common.configuration;
+import org.onap.dcae.ApplicationException;
import org.onap.dcae.ApplicationSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.server.Ssl.ClientAuth;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
-public class CertAuth implements AuthMethod {
+@Configuration
+@Order(0)
+@EnableWebSecurity
+public class CertAuth extends WebSecurityConfigurerAdapter implements AuthMethod {
private static final Logger log = LoggerFactory.getLogger(CertAuth.class);
private final ConfigurableServletWebServerFactory container;
@@ -39,6 +50,24 @@ public class CertAuth implements AuthMethod {
}
@Override
+ public void configure(WebSecurity web) {
+ web.ignoring().anyRequest();
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) {
+ try {
+ http.authorizeRequests()
+ .anyRequest().authenticated().and()
+ .addFilterBefore(new CustomFilter(properties), FilterSecurityInterceptor.class);
+
+ } catch (Exception ex) {
+ log.error("Cannot authorize request cause: ",ex);
+ throw new ApplicationException(ex);
+ }
+ }
+
+ @Override
public void configure() {
SslContextCreator sslContextCreator = new SslContextCreator(properties);
container.setSsl(sslContextCreator.httpsContextWithTlsAuthentication(ClientAuth.NEED));
diff --git a/src/main/java/org/onap/dcae/common/configuration/CertBasicAuth.java b/src/main/java/org/onap/dcae/common/configuration/CertBasicAuth.java
index f756b47d..c9e0af41 100644
--- a/src/main/java/org/onap/dcae/common/configuration/CertBasicAuth.java
+++ b/src/main/java/org/onap/dcae/common/configuration/CertBasicAuth.java
@@ -21,13 +21,24 @@
package org.onap.dcae.common.configuration;
+import org.onap.dcae.ApplicationException;
import org.onap.dcae.ApplicationSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.server.Ssl.ClientAuth;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
-public class CertBasicAuth implements AuthMethod{
+@Configuration
+@Order(1)
+@EnableWebSecurity
+public class CertBasicAuth extends WebSecurityConfigurerAdapter implements AuthMethod{
private static final Logger log = LoggerFactory.getLogger(CertAuth.class);
private final ConfigurableServletWebServerFactory container;
@@ -39,6 +50,24 @@ public class CertBasicAuth implements AuthMethod{
}
@Override
+ public void configure(WebSecurity web) {
+ web.ignoring().anyRequest();
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) {
+ try {
+ http.authorizeRequests()
+ .anyRequest().authenticated().and()
+ .addFilterBefore(new CustomFilter(properties), FilterSecurityInterceptor.class);
+
+ } catch (Exception ex) {
+ log.error("Cannot authorize request cause: ",ex);
+ throw new ApplicationException(ex);
+ }
+ }
+
+ @Override
public void configure() {
SslContextCreator sslContextCreator = new SslContextCreator(properties);
container.setPort(properties.httpsPort());
diff --git a/src/main/java/org/onap/dcae/common/configuration/CustomFilter.java b/src/main/java/org/onap/dcae/common/configuration/CustomFilter.java
new file mode 100644
index 00000000..ae693fa6
--- /dev/null
+++ b/src/main/java/org/onap/dcae/common/configuration/CustomFilter.java
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * ================================================================================
+ * 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.onap.dcae.common.configuration;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import org.onap.dcae.ApplicationSettings;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.filter.GenericFilterBean;
+
+@Configuration
+public class CustomFilter extends GenericFilterBean {
+
+ private static final String CERTIFICATE_X_509 = "javax.servlet.request.X509Certificate";
+ private static final String MESSAGE = "SubjectDN didn't match with any regexp from %s file like %s";
+ private ApplicationSettings properties;
+
+ public CustomFilter(ApplicationSettings properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
+ FilterChain filterChain) throws IOException, ServletException {
+
+ X509Certificate[] cert = (X509Certificate[]) servletRequest.getAttribute(CERTIFICATE_X_509);
+
+ if (cert != null) {
+ if (getLines().anyMatch(element -> Pattern.compile(element).matcher(getSubjectDN(cert)).find())) {
+ filterChain.doFilter(servletRequest, servletResponse);
+ } else {
+ setResponse((HttpServletResponse) servletResponse);
+ }
+ } else {
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+ }
+
+ private void setResponse(HttpServletResponse servletResponse) throws IOException {
+ HttpServletResponse response = servletResponse;
+ response.sendError(HttpServletResponse.SC_FORBIDDEN,
+ String.format(MESSAGE, properties.certSubjectMatcher(), getLines().collect(Collectors.joining(" "))));
+ }
+
+ private Stream<String> getLines() throws IOException {
+ return Files.lines(Paths.get(properties.certSubjectMatcher()));
+ }
+
+ private String getSubjectDN(X509Certificate[] certs) {
+ return Arrays.stream(certs).map(e -> e.getSubjectDN().getName())
+ .map(x -> x.split(",")).flatMap(Arrays::stream)
+ .collect(Collectors.joining(","));
+ }
+}
diff --git a/src/main/java/org/onap/dcae/restapi/ApiAuthInterceptor.java b/src/main/java/org/onap/dcae/restapi/ApiAuthInterceptor.java
index e2ac74c7..bb290575 100644
--- a/src/main/java/org/onap/dcae/restapi/ApiAuthInterceptor.java
+++ b/src/main/java/org/onap/dcae/restapi/ApiAuthInterceptor.java
@@ -54,7 +54,6 @@ final class ApiAuthInterceptor extends HandlerInterceptorAdapter {
return true;
}
}
-
if (isBasicAuth()) {
String authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader == null || !isAuthorized(authorizationHeader)) {
diff --git a/src/test/java/org/onap/dcae/TLSTest.java b/src/test/java/org/onap/dcae/TLSTest.java
index b1f90371..3cf0a162 100644
--- a/src/test/java/org/onap/dcae/TLSTest.java
+++ b/src/test/java/org/onap/dcae/TLSTest.java
@@ -125,6 +125,7 @@ public class TLSTest extends TLSTestBase {
when(settings.authMethod()).thenReturn(AuthMethodType.CERT_ONLY.value());
when(settings.truststoreFileLocation()).thenReturn(TRUSTSTORE.toString());
when(settings.truststorePasswordFileLocation()).thenReturn(TRUSTSTORE_PASSWORD_FILE.toString());
+ when(settings.certSubjectMatcher()).thenReturn(CERT_SUBJECT_MATCHER.toString());
}
}
diff --git a/src/test/java/org/onap/dcae/TLSTestBase.java b/src/test/java/org/onap/dcae/TLSTestBase.java
index 8b486ec7..4dada129 100644
--- a/src/test/java/org/onap/dcae/TLSTestBase.java
+++ b/src/test/java/org/onap/dcae/TLSTestBase.java
@@ -45,12 +45,12 @@ import static org.onap.dcae.TestingUtilities.*;
@Configuration
@ExtendWith(SpringExtension.class)
public class TLSTestBase {
- protected static final String KEYSTORE_ALIAS = "localhost";
protected static final Path RESOURCES = Paths.get("src", "test", "resources");
protected static final Path KEYSTORE = Paths.get(RESOURCES.toString(), "keystore");
protected static final Path KEYSTORE_PASSWORD_FILE = Paths.get(RESOURCES.toString(), "passwordfile");
protected static final Path TRUSTSTORE = Paths.get(RESOURCES.toString(), "truststore");
protected static final Path TRUSTSTORE_PASSWORD_FILE = Paths.get(RESOURCES.toString(), "trustpasswordfile");
+ protected static final Path CERT_SUBJECT_MATCHER = Paths.get(RESOURCES.toString(), "certSubjectMatcher");
protected static abstract class ConfigurationBase {
protected final ApplicationSettings settings = Mockito.mock(ApplicationSettings.class);
@@ -67,6 +67,7 @@ public class TLSTestBase {
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
protected abstract class TestClassBase {
+
@MockBean
@Qualifier("inputQueue")
protected LinkedBlockingQueue<JSONObject> queue;
diff --git a/src/test/resources/certSubjectMatcher b/src/test/resources/certSubjectMatcher
new file mode 100644
index 00000000..9abb766c
--- /dev/null
+++ b/src/test/resources/certSubjectMatcher
@@ -0,0 +1 @@
+.* \ No newline at end of file
diff --git a/version.properties b/version.properties
index 44b6acf6..9e50923f 100644
--- a/version.properties
+++ b/version.properties
@@ -1,6 +1,6 @@
major=1
minor=4
-patch=3
+patch=4
base_version=${major}.${minor}.${patch}
release_version=${base_version}
snapshot_version=${base_version}-SNAPSHOT