You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2023/08/29 19:43:39 UTC
[nifi] 01/02: NIFI-11195 Refactored Identity Mapping to nifi-security-identity
This is an automated email from the ASF dual-hosted git repository.
mattyb149 pushed a commit to branch support/nifi-1.x
in repository https://gitbox.apache.org/repos/asf/nifi.git
commit fec34036a58880947562a8d24ac100ec0f5a82a5
Author: exceptionfactory <ex...@apache.org>
AuthorDate: Thu Feb 16 20:51:25 2023 -0600
NIFI-11195 Refactored Identity Mapping to nifi-security-identity
- Moved StringUtils from nifi-properties to nifi-property-utils
- Moved Peer Identity methods from CertificateUtils to specific Site-to-Site classes
Signed-off-by: Joe Gresock <jg...@gmail.com>
This closes #6977.
---
nifi-commons/nifi-properties/pom.xml | 12 +-
.../java/org/apache/nifi/util/StringUtils.java | 0
.../java/org/apache/nifi/util/StringUtilsTest.java | 0
nifi-commons/nifi-security-identity/pom.xml | 35 +++++
.../nifi/authorization/util/IdentityMapping.java | 0
.../authorization/util/IdentityMappingUtil.java | 0
.../nifi/security/util/CertificateUtils.java | 140 -----------------
nifi-commons/nifi-site-to-site-client/pom.xml | 18 +--
.../client/socket/EndpointConnectionPool.java | 16 +-
.../client/socket/SocketPeerIdentityProvider.java | 33 ++++
.../socket/StandardSocketPeerIdentityProvider.java | 74 +++++++++
.../nifi/remote/util/SiteToSiteRestApiClient.java | 6 +-
.../nifi/remote/client/PeerSelectorTest.groovy | 23 ---
.../nifi/remote/client/http/TestHttpClient.java | 174 +--------------------
.../StandardSocketPeerIdentityProviderTest.java | 103 ++++++++++++
nifi-commons/nifi-utils/pom.xml | 6 +
nifi-commons/pom.xml | 1 +
.../nifi-email-processors/pom.xml | 6 +
.../nifi-event-transport/pom.xml | 10 ++
.../nifi-standard-record-utils/pom.xml | 4 +
.../nifi-reporting-utils/pom.xml | 4 +
.../nifi-framework/nifi-documentation/pom.xml | 1 -
.../nifi-framework/nifi-file-authorizer/pom.xml | 3 +-
.../nifi-framework/nifi-framework-core/pom.xml | 5 +
.../nifi-framework/nifi-site-to-site/pom.xml | 9 ++
.../nifi/remote/SocketRemoteSiteListener.java | 43 ++++-
.../src/test/resources/localhost-ks.jks | Bin 3076 -> 0 bytes
.../src/test/resources/localhost-ts.jks | Bin 911 -> 0 bytes
.../nifi-framework/nifi-web/nifi-web-api/pom.xml | 6 +
.../nifi-web/nifi-web-security/pom.xml | 5 +
.../nifi-gcp-parameter-providers/pom.xml | 1 -
.../nifi-ldap-iaa-providers/pom.xml | 5 +
.../nifi-record-sink-service/pom.xml | 5 +
.../nifi-web-client-provider-service/pom.xml | 6 +
34 files changed, 388 insertions(+), 366 deletions(-)
diff --git a/nifi-commons/nifi-properties/pom.xml b/nifi-commons/nifi-properties/pom.xml
index 3f5286effd..dea20ce96f 100644
--- a/nifi-commons/nifi-properties/pom.xml
+++ b/nifi-commons/nifi-properties/pom.xml
@@ -15,6 +15,12 @@
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-commons</artifactId>
+ <version>1.24.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>nifi-properties</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.nifi</groupId>
@@ -23,10 +29,4 @@
<scope>compile</scope>
</dependency>
</dependencies>
- <parent>
- <groupId>org.apache.nifi</groupId>
- <artifactId>nifi-commons</artifactId>
- <version>1.24.0-SNAPSHOT</version>
- </parent>
- <artifactId>nifi-properties</artifactId>
</project>
diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/StringUtils.java b/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/util/StringUtils.java
similarity index 100%
rename from nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/StringUtils.java
rename to nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/util/StringUtils.java
diff --git a/nifi-commons/nifi-properties/src/test/java/org/apache/nifi/util/StringUtilsTest.java b/nifi-commons/nifi-property-utils/src/test/java/org/apache/nifi/util/StringUtilsTest.java
similarity index 100%
rename from nifi-commons/nifi-properties/src/test/java/org/apache/nifi/util/StringUtilsTest.java
rename to nifi-commons/nifi-property-utils/src/test/java/org/apache/nifi/util/StringUtilsTest.java
diff --git a/nifi-commons/nifi-security-identity/pom.xml b/nifi-commons/nifi-security-identity/pom.xml
new file mode 100644
index 0000000000..b6c3fd397f
--- /dev/null
+++ b/nifi-commons/nifi-security-identity/pom.xml
@@ -0,0 +1,35 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+ -->
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-commons</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>nifi-security-identity</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-properties</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ </dependencies>
+</project>
+
diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/authorization/util/IdentityMapping.java b/nifi-commons/nifi-security-identity/src/main/java/org/apache/nifi/authorization/util/IdentityMapping.java
similarity index 100%
rename from nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/authorization/util/IdentityMapping.java
rename to nifi-commons/nifi-security-identity/src/main/java/org/apache/nifi/authorization/util/IdentityMapping.java
diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/authorization/util/IdentityMappingUtil.java b/nifi-commons/nifi-security-identity/src/main/java/org/apache/nifi/authorization/util/IdentityMappingUtil.java
similarity index 100%
rename from nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/authorization/util/IdentityMappingUtil.java
rename to nifi-commons/nifi-security-identity/src/main/java/org/apache/nifi/authorization/util/IdentityMappingUtil.java
diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java
index d386e0f0fc..c00ea50262 100644
--- a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java
+++ b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java
@@ -18,12 +18,10 @@ package org.apache.nifi.security.util;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
-import java.net.Socket;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
-import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
@@ -42,8 +40,6 @@ import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSocket;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -81,14 +77,8 @@ import org.slf4j.LoggerFactory;
public final class CertificateUtils {
private static final Logger logger = LoggerFactory.getLogger(CertificateUtils.class);
- private static final String PEER_NOT_AUTHENTICATED_MSG = "peer not authenticated";
private static final Map<ASN1ObjectIdentifier, Integer> dnOrderMap = createDnOrderMap();
- public static final String JAVA_8_MAX_SUPPORTED_TLS_PROTOCOL_VERSION = "TLSv1.2";
- public static final String JAVA_11_MAX_SUPPORTED_TLS_PROTOCOL_VERSION = "TLSv1.3";
- public static final String[] JAVA_8_SUPPORTED_TLS_PROTOCOL_VERSIONS = new String[]{JAVA_8_MAX_SUPPORTED_TLS_PROTOCOL_VERSION};
- public static final String[] JAVA_11_SUPPORTED_TLS_PROTOCOL_VERSIONS = new String[]{JAVA_11_MAX_SUPPORTED_TLS_PROTOCOL_VERSION, JAVA_8_MAX_SUPPORTED_TLS_PROTOCOL_VERSION};
-
static {
Security.addProvider(new BouncyCastleProvider());
}
@@ -206,136 +196,6 @@ public final class CertificateUtils {
return result;
}
- /**
- * Returns the DN extracted from the peer certificate (the server DN if run on the client; the client DN (if available) if run on the server).
- * <p>
- * If the client auth setting is WANT or NONE and a client certificate is not present, this method will return {@code null}.
- * If the client auth is NEED, it will throw a {@link CertificateException}.
- *
- * @param socket the SSL Socket
- * @return the extracted DN
- * @throws CertificateException if there is a problem parsing the certificate
- */
- public static String extractPeerDNFromSSLSocket(Socket socket) throws CertificateException {
- String dn = null;
- if (socket instanceof SSLSocket) {
- final SSLSocket sslSocket = (SSLSocket) socket;
-
- boolean clientMode = sslSocket.getUseClientMode();
- logger.debug("SSL Socket in {} mode", clientMode ? "client" : "server");
- ClientAuth clientAuth = getClientAuthStatus(sslSocket);
- logger.debug("SSL Socket client auth status: {}", clientAuth);
-
- if (clientMode) {
- logger.debug("This socket is in client mode, so attempting to extract certificate from remote 'server' socket");
- dn = extractPeerDNFromServerSSLSocket(sslSocket);
- } else {
- logger.debug("This socket is in server mode, so attempting to extract certificate from remote 'client' socket");
- dn = extractPeerDNFromClientSSLSocket(sslSocket);
- }
- }
-
- return dn;
- }
-
- /**
- * Returns the DN extracted from the client certificate.
- * <p>
- * If the client auth setting is WANT or NONE and a certificate is not present (and {@code respectClientAuth} is {@code true}), this method will return {@code null}.
- * If the client auth is NEED, it will throw a {@link CertificateException}.
- *
- * @param sslSocket the SSL Socket
- * @return the extracted DN
- * @throws CertificateException if there is a problem parsing the certificate
- */
- private static String extractPeerDNFromClientSSLSocket(SSLSocket sslSocket) throws CertificateException {
- String dn = null;
-
- /** The clientAuth value can be "need", "want", or "none"
- * A client must send client certificates for need, should for want, and will not for none.
- * This method should throw an exception if none are provided for need, return null if none are provided for want, and return null (without checking) for none.
- */
-
- ClientAuth clientAuth = getClientAuthStatus(sslSocket);
- logger.debug("SSL Socket client auth status: {}", clientAuth);
-
- if (clientAuth != ClientAuth.NONE) {
- try {
- final Certificate[] certChains = sslSocket.getSession().getPeerCertificates();
- if (certChains != null && certChains.length > 0) {
- X509Certificate x509Certificate = convertAbstractX509Certificate(certChains[0]);
- dn = x509Certificate.getSubjectDN().getName().trim();
- logger.debug("Extracted DN={} from client certificate", dn);
- }
- } catch (SSLPeerUnverifiedException e) {
- if (e.getMessage().equals(PEER_NOT_AUTHENTICATED_MSG)) {
- logger.error("The incoming request did not contain client certificates and thus the DN cannot" +
- " be extracted. Check that the other endpoint is providing a complete client certificate chain");
- }
- if (clientAuth == ClientAuth.WANT) {
- logger.warn("Suppressing missing client certificate exception because client auth is set to 'want'");
- return null;
- }
- throw new CertificateException(e);
- }
- }
- return dn;
- }
-
- /**
- * Returns the DN extracted from the server certificate.
- *
- * @param socket the SSL Socket
- * @return the extracted DN
- * @throws CertificateException if there is a problem parsing the certificate
- */
- private static String extractPeerDNFromServerSSLSocket(Socket socket) throws CertificateException {
- String dn = null;
- if (socket instanceof SSLSocket) {
- final SSLSocket sslSocket = (SSLSocket) socket;
- try {
- final Certificate[] certChains = sslSocket.getSession().getPeerCertificates();
- if (certChains != null && certChains.length > 0) {
- X509Certificate x509Certificate = convertAbstractX509Certificate(certChains[0]);
- dn = x509Certificate.getSubjectDN().getName().trim();
- logger.debug("Extracted DN={} from server certificate", dn);
- }
- } catch (SSLPeerUnverifiedException e) {
- if (e.getMessage().equals(PEER_NOT_AUTHENTICATED_MSG)) {
- logger.error("The server did not present a certificate and thus the DN cannot" +
- " be extracted. Check that the other endpoint is providing a complete certificate chain");
- }
- throw new CertificateException(e);
- }
- }
- return dn;
- }
-
- private static ClientAuth getClientAuthStatus(SSLSocket sslSocket) {
- return sslSocket.getNeedClientAuth() ? ClientAuth.REQUIRED : sslSocket.getWantClientAuth() ? ClientAuth.WANT : ClientAuth.NONE;
- }
-
- /**
- * Accepts a legacy {@link javax.security.cert.X509Certificate} and returns an {@link X509Certificate}. The {@code javax.*} package certificate classes are for legacy compatibility and should
- * not be used for new development.
- *
- * @param legacyCertificate the {@code javax.security.cert.X509Certificate}
- * @return a new {@code java.security.cert.X509Certificate}
- * @throws CertificateException if there is an error generating the new certificate
- */
- @SuppressWarnings("deprecation")
- public static X509Certificate convertLegacyX509Certificate(javax.security.cert.X509Certificate legacyCertificate) throws CertificateException {
- if (legacyCertificate == null) {
- throw new IllegalArgumentException("The X.509 certificate cannot be null");
- }
-
- try {
- return formX509Certificate(legacyCertificate.getEncoded());
- } catch (javax.security.cert.CertificateEncodingException e) {
- throw new CertificateException(e);
- }
- }
-
/**
* Accepts an abstract {@link java.security.cert.Certificate} and returns an {@link X509Certificate}. Because {@code sslSocket.getSession().getPeerCertificates()} returns an array of the
* abstract certificates, they must be translated to X.509 to replace the functionality of {@code sslSocket.getSession().getPeerCertificateChain()}.
diff --git a/nifi-commons/nifi-site-to-site-client/pom.xml b/nifi-commons/nifi-site-to-site-client/pom.xml
index e7912f4095..25eb9053dc 100644
--- a/nifi-commons/nifi-site-to-site-client/pom.xml
+++ b/nifi-commons/nifi-site-to-site-client/pom.xml
@@ -46,16 +46,6 @@
<artifactId>nifi-utils</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
- <dependency>
- <groupId>org.apache.nifi</groupId>
- <artifactId>nifi-security-utils</artifactId>
- <version>1.24.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.apache.nifi</groupId>
- <artifactId>nifi-security-utils-api</artifactId>
- <version>1.24.0-SNAPSHOT</version>
- </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-security-ssl</artifactId>
@@ -136,6 +126,14 @@
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
+ <dependency>
+ <groupId>jakarta.xml.bind</groupId>
+ <artifactId>jakarta.xml.bind-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>jaxb-runtime</artifactId>
+ </dependency>
</dependencies>
<profiles>
<profile>
diff --git a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/EndpointConnectionPool.java b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/EndpointConnectionPool.java
index 83fce50b97..878d16b1e3 100644
--- a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/EndpointConnectionPool.java
+++ b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/EndpointConnectionPool.java
@@ -26,12 +26,12 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
-import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
@@ -64,7 +64,6 @@ import org.apache.nifi.remote.io.socket.SocketCommunicationsSession;
import org.apache.nifi.remote.protocol.CommunicationsSession;
import org.apache.nifi.remote.protocol.SiteToSiteTransportProtocol;
import org.apache.nifi.remote.protocol.socket.SocketClientProtocol;
-import org.apache.nifi.security.util.CertificateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,6 +71,8 @@ public class EndpointConnectionPool implements PeerStatusProvider {
private static final Logger logger = LoggerFactory.getLogger(EndpointConnectionPool.class);
+ private static final SocketPeerIdentityProvider socketPeerIdentityProvider = new StandardSocketPeerIdentityProvider();
+
private final ConcurrentMap<PeerDescription, BlockingQueue<EndpointConnection>> connectionQueueMap = new ConcurrentHashMap<>();
private final Set<EndpointConnection> activeConnections = Collections.synchronizedSet(new HashSet<>());
@@ -449,11 +450,12 @@ public class EndpointConnectionPool implements PeerStatusProvider {
socket.setSoTimeout(commsTimeout);
commsSession = new SocketCommunicationsSession(socket);
- try {
- final String dn = CertificateUtils.extractPeerDNFromSSLSocket(socket);
- commsSession.setUserDn(dn);
- } catch (final CertificateException ex) {
- throw new IOException(ex);
+ final Optional<String> peerIdentity = socketPeerIdentityProvider.getPeerIdentity(socket);
+ if (peerIdentity.isPresent()) {
+ final String userDn = peerIdentity.get();
+ commsSession.setUserDn(userDn);
+ } else {
+ throw new IOException(String.format("Site-to-Site Peer [%s] Identity not found", socket.getRemoteSocketAddress()));
}
} else {
diff --git a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/SocketPeerIdentityProvider.java b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/SocketPeerIdentityProvider.java
new file mode 100644
index 0000000000..6d1a1c4297
--- /dev/null
+++ b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/SocketPeerIdentityProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.nifi.remote.client.socket;
+
+import java.net.Socket;
+import java.util.Optional;
+
+/**
+ * Abstraction for reading identity information from socket connections
+ */
+public interface SocketPeerIdentityProvider {
+ /**
+ * Get Peer Identity from Socket
+ *
+ * @param socket Socket
+ * @return Peer Identity or empty when not found
+ */
+ Optional<String> getPeerIdentity(Socket socket);
+}
diff --git a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/StandardSocketPeerIdentityProvider.java b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/StandardSocketPeerIdentityProvider.java
new file mode 100644
index 0000000000..45a64f1820
--- /dev/null
+++ b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/socket/StandardSocketPeerIdentityProvider.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.nifi.remote.client.socket;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.net.Socket;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Optional;
+
+/**
+ * Standard implementation attempts to read X.509 certificates from an SSLSocket
+ */
+public class StandardSocketPeerIdentityProvider implements SocketPeerIdentityProvider {
+ private static final Logger logger = LoggerFactory.getLogger(StandardSocketPeerIdentityProvider.class);
+
+ @Override
+ public Optional<String> getPeerIdentity(final Socket socket) {
+ final Optional<String> peerIdentity;
+
+ if (socket instanceof SSLSocket) {
+ final SSLSocket sslSocket = (SSLSocket) socket;
+ final SSLSession sslSession = sslSocket.getSession();
+ peerIdentity = getPeerIdentity(sslSession);
+ } else {
+ peerIdentity = Optional.empty();
+ }
+
+ return peerIdentity;
+ }
+
+ private Optional<String> getPeerIdentity(final SSLSession sslSession) {
+ String peerIdentity = null;
+
+ final String peerHost = sslSession.getPeerHost();
+ final int peerPort = sslSession.getPeerPort();
+
+ try {
+ final Certificate[] peerCertificates = sslSession.getPeerCertificates();
+ if (peerCertificates == null || peerCertificates.length == 0) {
+ logger.warn("Peer Identity not found: Peer Certificates not provided [{}:{}]", peerHost, peerPort);
+ } else {
+ final X509Certificate peerCertificate = (X509Certificate) peerCertificates[0];
+ final Principal subjectDistinguishedName = peerCertificate.getSubjectDN();
+ peerIdentity = subjectDistinguishedName.getName();
+ }
+ } catch (final SSLPeerUnverifiedException e) {
+ logger.warn("Peer Identity not found: Peer Unverified [{}:{}]", peerHost, peerPort);
+ logger.debug("TLS Protocol [{}] Peer Unverified [{}:{}]", sslSession.getProtocol(), peerHost, peerPort, e);
+ }
+
+ return Optional.ofNullable(peerIdentity);
+ }
+}
diff --git a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/util/SiteToSiteRestApiClient.java b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/util/SiteToSiteRestApiClient.java
index 8726c49ce5..cd34cbccf3 100644
--- a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/util/SiteToSiteRestApiClient.java
+++ b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/util/SiteToSiteRestApiClient.java
@@ -47,7 +47,6 @@ import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collection;
@@ -128,7 +127,6 @@ import org.apache.nifi.remote.protocol.ResponseCode;
import org.apache.nifi.remote.protocol.http.HttpHeaders;
import org.apache.nifi.remote.protocol.http.HttpProxy;
import org.apache.nifi.reporting.Severity;
-import org.apache.nifi.security.util.CertificateUtils;
import org.apache.nifi.stream.io.StreamUtils;
import org.apache.nifi.web.api.dto.ControllerDTO;
import org.apache.nifi.web.api.dto.remote.PeerDTO;
@@ -319,9 +317,9 @@ public class SiteToSiteRestApiClient implements Closeable {
}
try {
- final X509Certificate cert = CertificateUtils.convertAbstractX509Certificate(certChain[0]);
+ final X509Certificate cert = (X509Certificate) certChain[0];
trustedPeerDn = cert.getSubjectDN().getName().trim();
- } catch (final CertificateException e) {
+ } catch (final RuntimeException e) {
final String msg = "Could not extract subject DN from SSL session peer certificate";
logger.warn(msg);
eventReporter.reportEvent(Severity.WARNING, EVENT_CATEGORY, msg);
diff --git a/nifi-commons/nifi-site-to-site-client/src/test/groovy/org/apache/nifi/remote/client/PeerSelectorTest.groovy b/nifi-commons/nifi-site-to-site-client/src/test/groovy/org/apache/nifi/remote/client/PeerSelectorTest.groovy
index d644f8e5d1..fc1c76535a 100644
--- a/nifi-commons/nifi-site-to-site-client/src/test/groovy/org/apache/nifi/remote/client/PeerSelectorTest.groovy
+++ b/nifi-commons/nifi-site-to-site-client/src/test/groovy/org/apache/nifi/remote/client/PeerSelectorTest.groovy
@@ -16,21 +16,16 @@
*/
package org.apache.nifi.remote.client
-
import org.apache.nifi.remote.PeerDescription
import org.apache.nifi.remote.PeerStatus
import org.apache.nifi.remote.TransferDirection
import org.apache.nifi.remote.protocol.SiteToSiteTransportProtocol
import org.apache.nifi.remote.util.PeerStatusCache
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.junit.jupiter.api.AfterEach
-import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.slf4j.Logger
import org.slf4j.LoggerFactory
-import java.security.Security
import java.util.concurrent.ArrayBlockingQueue
import static org.junit.jupiter.api.Assertions.assertEquals
@@ -52,16 +47,6 @@ class PeerSelectorTest {
private static mockPSP
private static mockPP
-
- @BeforeAll
- static void setUpOnce() throws Exception {
- Security.addProvider(new BouncyCastleProvider())
-
- logger.metaClass.methodMissing = { String name, args ->
- logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
- }
- }
-
@BeforeEach
void setUp() {
// Mock collaborators
@@ -69,11 +54,6 @@ class PeerSelectorTest {
mockPP = mockPeerPersistence()
}
- @AfterEach
- void tearDown() {
-
- }
-
private static String buildRemoteInstanceUris(List<String> nodes = DEFAULT_NODES) {
String remoteInstanceUris = "http://" + nodes.join(":8443/nifi-api,http://") + ":8443/nifi-api";
remoteInstanceUris
@@ -206,7 +186,6 @@ class PeerSelectorTest {
new PeerStatusCache(peerStatuses, System.currentTimeMillis(), remoteInstanceUris, SiteToSiteTransportProtocol.HTTP)
},
save : { PeerStatusCache psc ->
- logger.mock("Persisting PeerStatusCache: ${psc}")
}] as PeerPersistence
}
@@ -985,8 +964,6 @@ class PeerSelectorTest {
bootstrapDescription
},
fetchRemotePeerStatuses : { PeerDescription pd ->
- // Depending on the scenario, return given peer statuses
- logger.mock("Scenario ${currentAttempt} fetchRemotePeerStatus for ${pd}")
switch (currentAttempt) {
case 1:
return [bootstrapStatus, node2Status] as Set<PeerStatus>
diff --git a/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/http/TestHttpClient.java b/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/http/TestHttpClient.java
index 93a1fe8def..892388708b 100644
--- a/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/http/TestHttpClient.java
+++ b/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/http/TestHttpClient.java
@@ -22,10 +22,8 @@ import org.apache.nifi.events.EventReporter;
import org.apache.nifi.remote.Peer;
import org.apache.nifi.remote.Transaction;
import org.apache.nifi.remote.TransferDirection;
-import org.apache.nifi.remote.client.KeystoreType;
import org.apache.nifi.remote.client.SiteToSiteClient;
import org.apache.nifi.remote.codec.StandardFlowFileCodec;
-import org.apache.nifi.remote.exception.HandshakeException;
import org.apache.nifi.remote.io.CompressionInputStream;
import org.apache.nifi.remote.io.CompressionOutputStream;
import org.apache.nifi.remote.protocol.DataPacket;
@@ -34,8 +32,6 @@ import org.apache.nifi.remote.protocol.SiteToSiteTransportProtocol;
import org.apache.nifi.remote.protocol.http.HttpHeaders;
import org.apache.nifi.remote.protocol.http.HttpProxy;
import org.apache.nifi.remote.util.StandardDataPacket;
-import org.apache.nifi.security.util.TemporaryKeyStoreBuilder;
-import org.apache.nifi.security.util.TlsConfiguration;
import org.apache.nifi.stream.io.StreamUtils;
import org.apache.nifi.web.api.dto.ControllerDTO;
import org.apache.nifi.web.api.dto.PortDTO;
@@ -45,16 +41,11 @@ import org.apache.nifi.web.api.entity.PeersEntity;
import org.apache.nifi.web.api.entity.TransactionResultEntity;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
@@ -117,7 +108,6 @@ public class TestHttpClient {
private static Server server;
private static ServerConnector httpConnector;
- private static ServerConnector sslConnector;
private static CountDownLatch testCaseFinished;
private static HttpProxyServer proxyServer;
@@ -126,11 +116,8 @@ public class TestHttpClient {
private static Set<PortDTO> inputPorts;
private static Set<PortDTO> outputPorts;
private static Set<PeerDTO> peers;
- private static Set<PeerDTO> peersSecure;
private static String serverChecksum;
- private static TlsConfiguration tlsConfiguration;
-
private static final int INITIAL_TRANSACTIONS = 0;
private static final AtomicInteger outputExtendTransactions = new AtomicInteger(INITIAL_TRANSACTIONS);
@@ -141,16 +128,13 @@ public class TestHttpClient {
public static class SiteInfoServlet extends HttpServlet {
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
final ControllerDTO controller = new ControllerDTO();
if (req.getLocalPort() == httpConnector.getLocalPort()) {
controller.setRemoteSiteHttpListeningPort(httpConnector.getLocalPort());
controller.setSiteToSiteSecure(false);
- } else {
- controller.setRemoteSiteHttpListeningPort(sslConnector.getLocalPort());
- controller.setSiteToSiteSecure(true);
}
controller.setId("remote-controller-id");
@@ -175,7 +159,7 @@ public class TestHttpClient {
public static class WrongSiteInfoServlet extends HttpServlet {
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// This response simulates when a Site-to-Site is given a URL which has wrong path.
respondWithText(resp, "<p class=\"message-pane-content\">You may have mistyped...</p>", 200);
}
@@ -184,16 +168,13 @@ public class TestHttpClient {
public static class PeersServlet extends HttpServlet {
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
final PeersEntity peersEntity = new PeersEntity();
if (req.getLocalPort() == httpConnector.getLocalPort()) {
assertNotNull(peers, "Test case should set <peers> depending on the test scenario.");
peersEntity.setPeers(peers);
- } else {
- assertNotNull(peersSecure, "Test case should set <peersSecure> depending on the test scenario.");
- peersEntity.setPeers(peersSecure);
}
respondWithJson(resp, peersEntity);
@@ -368,7 +349,7 @@ public class TestHttpClient {
}
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
final int reqProtocolVersion = getReqProtocolVersion(req);
@@ -477,24 +458,10 @@ public class TestHttpClient {
final ServletHandler wrongPathServletHandler = new ServletHandler();
wrongPathContextHandler.insertHandler(wrongPathServletHandler);
- final SslContextFactory sslContextFactory = new SslContextFactory.Server();
-
- setTlsConfiguration();
- sslContextFactory.setKeyStorePath(tlsConfiguration.getKeystorePath());
- sslContextFactory.setKeyStorePassword(tlsConfiguration.getKeystorePassword());
- sslContextFactory.setKeyStoreType(tlsConfiguration.getKeystoreType().getType());
- sslContextFactory.setProtocol(TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
httpConnector = new ServerConnector(server);
- final HttpConfiguration https = new HttpConfiguration();
- https.addCustomizer(new SecureRequestCustomizer());
- sslConnector = new ServerConnector(server,
- new SslConnectionFactory(sslContextFactory, "http/1.1"),
- new HttpConnectionFactory(https));
- logger.info("SSL Connector: " + sslConnector.dump());
-
- server.setConnectors(new Connector[] { httpConnector, sslConnector });
+ server.setConnectors(new Connector[] { httpConnector });
wrongPathServletHandler.addServletWithMapping(WrongSiteInfoServlet.class, "/site-to-site");
@@ -528,8 +495,6 @@ public class TestHttpClient {
server.start();
- logger.info("Starting server on port {} for HTTP, and {} for HTTPS", httpConnector.getLocalPort(), sslConnector.getLocalPort());
-
startProxyServer();
startProxyServerWithAuth();
}
@@ -634,15 +599,6 @@ public class TestHttpClient {
peers = new HashSet<>();
peers.add(peer);
- final PeerDTO peerSecure = new PeerDTO();
- peerSecure.setHostname("localhost");
- peerSecure.setPort(sslConnector.getLocalPort());
- peerSecure.setFlowFileCount(10);
- peerSecure.setSecure(true);
-
- peersSecure = new HashSet<>();
- peersSecure.add(peerSecure);
-
inputPorts = new HashSet<>();
final PortDTO runningInputPort = new PortDTO();
@@ -711,18 +667,6 @@ public class TestHttpClient {
;
}
- private SiteToSiteClient.Builder getDefaultBuilderHTTPS() {
- return new SiteToSiteClient.Builder().transportProtocol(SiteToSiteTransportProtocol.HTTP)
- .url("https://localhost:" + sslConnector.getLocalPort() + "/nifi")
- .timeout(3, TimeUnit.MINUTES)
- .keystoreFilename(tlsConfiguration.getKeystorePath())
- .keystorePass(tlsConfiguration.getKeystorePassword())
- .keystoreType(KeystoreType.valueOf(tlsConfiguration.getKeystoreType().getType()))
- .truststoreFilename(tlsConfiguration.getTruststorePath())
- .truststorePass(tlsConfiguration.getTruststorePassword())
- .truststoreType(KeystoreType.valueOf(tlsConfiguration.getTruststoreType().getType()));
- }
-
private static void consumeDataPacket(DataPacket packet) throws IOException {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
StreamUtils.copy(packet.getData(), bos);
@@ -893,31 +837,6 @@ public class TestHttpClient {
}
- @Test
- public void testSendAccessDeniedHTTPS() throws Exception {
-
- try (
- final SiteToSiteClient client = getDefaultBuilderHTTPS()
- .portName("input-access-denied")
- .build()
- ) {
- assertThrows(HandshakeException.class, () -> client.createTransaction(TransferDirection.SEND));
- }
- }
-
- @Test
- public void testSendSuccessHTTPS() throws Exception {
-
- try (
- final SiteToSiteClient client = getDefaultBuilderHTTPS()
- .portName("input-running")
- .build()
- ) {
- testSend(client);
- }
-
- }
-
private interface SendData {
void apply(final Transaction transaction) throws IOException;
}
@@ -1013,47 +932,6 @@ public class TestHttpClient {
}
- @Test
- public void testSendLargeFileHTTPS() throws Exception {
-
- try (
- SiteToSiteClient client = getDefaultBuilderHTTPS()
- .portName("input-running")
- .build()
- ) {
- testSendLargeFile(client);
- }
-
- }
-
- @Test
- public void testSendLargeFileHTTPSWithProxy() throws Exception {
-
- try (
- SiteToSiteClient client = getDefaultBuilderHTTPS()
- .portName("input-running")
- .httpProxy(new HttpProxy("localhost", proxyServer.getListenAddress().getPort(), null, null))
- .build()
- ) {
- testSendLargeFile(client);
- }
-
- }
-
- @Test
- public void testSendLargeFileHTTPSWithProxyAuth() throws Exception {
-
- try (
- SiteToSiteClient client = getDefaultBuilderHTTPS()
- .portName("input-running")
- .httpProxy(new HttpProxy("localhost", proxyServerWithAuth.getListenAddress().getPort(), PROXY_USER, PROXY_PASSWORD))
- .build()
- ) {
- testSendLargeFile(client);
- }
-
- }
-
@Test
public void testSendSuccessCompressed() throws Exception {
@@ -1264,44 +1142,6 @@ public class TestHttpClient {
}
}
- @Test
- public void testReceiveSuccessHTTPS() throws Exception {
-
- try (
- SiteToSiteClient client = getDefaultBuilderHTTPS()
- .portName("output-running")
- .build()
- ) {
- testReceive(client);
- }
- }
-
- @Test
- public void testReceiveSuccessHTTPSWithProxy() throws Exception {
-
- try (
- SiteToSiteClient client = getDefaultBuilderHTTPS()
- .portName("output-running")
- .httpProxy(new HttpProxy("localhost", proxyServer.getListenAddress().getPort(), null, null))
- .build()
- ) {
- testReceive(client);
- }
- }
-
- @Test
- public void testReceiveSuccessHTTPSWithProxyAuth() throws Exception {
-
- try (
- SiteToSiteClient client = getDefaultBuilderHTTPS()
- .portName("output-running")
- .httpProxy(new HttpProxy("localhost", proxyServerWithAuth.getListenAddress().getPort(), PROXY_USER, PROXY_PASSWORD))
- .build()
- ) {
- testReceive(client);
- }
- }
-
@Test
public void testReceiveSuccessCompressed() throws Exception {
@@ -1375,8 +1215,4 @@ public class TestHttpClient {
assertNotSame(INITIAL_TRANSACTIONS, outputExtendTransactions.get());
}
}
-
- private static void setTlsConfiguration() {
- tlsConfiguration = new TemporaryKeyStoreBuilder().trustStoreType(KeystoreType.JKS.name()).build();
- }
}
diff --git a/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/socket/StandardSocketPeerIdentityProviderTest.java b/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/socket/StandardSocketPeerIdentityProviderTest.java
new file mode 100644
index 0000000000..9fa921050b
--- /dev/null
+++ b/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/socket/StandardSocketPeerIdentityProviderTest.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.nifi.remote.client.socket;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.security.auth.x500.X500Principal;
+import java.io.IOException;
+import java.net.Socket;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class StandardSocketPeerIdentityProviderTest {
+ private static final String DISTINGUISHED_NAME = "CN=Common Name,OU=Organizational Unit,O=Organization";
+
+ @Mock
+ SSLSocket sslSocket;
+
+ @Mock
+ SSLSession sslSession;
+
+ @Mock
+ X509Certificate peerCertificate;
+
+ StandardSocketPeerIdentityProvider provider;
+
+ @BeforeEach
+ void setProvider() {
+ provider = new StandardSocketPeerIdentityProvider();
+ }
+
+ @Test
+ void testGetPeerIdentityStandardSocket() throws IOException {
+ try (Socket socket = new Socket()) {
+ final Optional<String> peerIdentity = provider.getPeerIdentity(socket);
+
+ assertFalse(peerIdentity.isPresent());
+ }
+ }
+
+ @Test
+ void testGetPeerIdentitySSLSocketPeerUnverifiedException() throws SSLPeerUnverifiedException {
+ when(sslSocket.getSession()).thenReturn(sslSession);
+ when(sslSession.getPeerCertificates()).thenThrow(new SSLPeerUnverifiedException(SSLPeerUnverifiedException.class.getSimpleName()));
+
+ final Optional<String> peerIdentity = provider.getPeerIdentity(sslSocket);
+
+ assertFalse(peerIdentity.isPresent());
+ }
+
+ @Test
+ void testGetPeerIdentitySSLSocketPeerCertificatesNotFound() throws SSLPeerUnverifiedException {
+ when(sslSocket.getSession()).thenReturn(sslSession);
+ when(sslSession.getPeerCertificates()).thenReturn(new Certificate[]{});
+
+ final Optional<String> peerIdentity = provider.getPeerIdentity(sslSocket);
+
+ assertFalse(peerIdentity.isPresent());
+ }
+
+ @Test
+ void testGetPeerIdentityFound() throws SSLPeerUnverifiedException {
+ when(sslSocket.getSession()).thenReturn(sslSession);
+ when(sslSession.getPeerCertificates()).thenReturn(new X509Certificate[]{peerCertificate});
+
+ final X500Principal subjectDistinguishedName = new X500Principal(DISTINGUISHED_NAME);
+ when(peerCertificate.getSubjectDN()).thenReturn(subjectDistinguishedName);
+
+ final Optional<String> peerIdentity = provider.getPeerIdentity(sslSocket);
+
+ assertTrue(peerIdentity.isPresent());
+ final String identity = peerIdentity.get();
+ assertEquals(DISTINGUISHED_NAME, identity);
+ }
+}
diff --git a/nifi-commons/nifi-utils/pom.xml b/nifi-commons/nifi-utils/pom.xml
index ba1b116449..cddbbd4b78 100644
--- a/nifi-commons/nifi-utils/pom.xml
+++ b/nifi-commons/nifi-utils/pom.xml
@@ -39,6 +39,12 @@
<artifactId>nifi-api</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
+ <!-- Included for StringUtils -->
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-property-utils</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
diff --git a/nifi-commons/pom.xml b/nifi-commons/pom.xml
index edf68a568d..9e3d8ecebf 100644
--- a/nifi-commons/pom.xml
+++ b/nifi-commons/pom.xml
@@ -55,6 +55,7 @@
<module>nifi-repository-encryption</module>
<module>nifi-schema-utils</module>
<module>nifi-security-crypto-key</module>
+ <module>nifi-security-identity</module>
<module>nifi-security-kerberos-api</module>
<module>nifi-security-kerberos</module>
<module>nifi-security-kms</module>
diff --git a/nifi-nar-bundles/nifi-email-bundle/nifi-email-processors/pom.xml b/nifi-nar-bundles/nifi-email-bundle/nifi-email-processors/pom.xml
index e3d65640e7..71f40c3d24 100644
--- a/nifi-nar-bundles/nifi-email-bundle/nifi-email-processors/pom.xml
+++ b/nifi-nar-bundles/nifi-email-bundle/nifi-email-processors/pom.xml
@@ -136,6 +136,12 @@
<version>1.24.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-event-transport/pom.xml b/nifi-nar-bundles/nifi-extension-utils/nifi-event-transport/pom.xml
index 5f083d8537..3eabf7dac0 100644
--- a/nifi-nar-bundles/nifi-extension-utils/nifi-event-transport/pom.xml
+++ b/nifi-nar-bundles/nifi-extension-utils/nifi-event-transport/pom.xml
@@ -32,6 +32,16 @@
<artifactId>nifi-api</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-mock</artifactId>
diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/pom.xml b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/pom.xml
index e94d2fd14f..b307b0713c 100644
--- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/pom.xml
+++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/pom.xml
@@ -38,6 +38,10 @@
<artifactId>nifi-security-socket-ssl</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils-api</artifactId>
+ </dependency>
<!-- Other modules using nifi-standard-record-utils are expected to have these APIs available, typically through a NAR dependency -->
<dependency>
<groupId>org.apache.nifi</groupId>
diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-reporting-utils/pom.xml b/nifi-nar-bundles/nifi-extension-utils/nifi-reporting-utils/pom.xml
index 3328215597..bc17102e61 100644
--- a/nifi-nar-bundles/nifi-extension-utils/nifi-reporting-utils/pom.xml
+++ b/nifi-nar-bundles/nifi-extension-utils/nifi-reporting-utils/pom.xml
@@ -34,6 +34,10 @@
<artifactId>nifi-utils</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
index 29b1246ffc..1679a4eb01 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
@@ -45,7 +45,6 @@
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
index 868ff8614c..424c55f968 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
@@ -202,7 +202,8 @@
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
- <artifactId>nifi-security-utils</artifactId>
+ <artifactId>nifi-security-identity</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
index 984c03b33a..50e3a6c719 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
@@ -77,6 +77,11 @@
<artifactId>nifi-security-kms</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-identity</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-repository-encryption</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/pom.xml
index 501b488bd0..960fc39a0d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/pom.xml
@@ -38,6 +38,15 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-framework-core-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-identity</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-mock</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/SocketRemoteSiteListener.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/SocketRemoteSiteListener.java
index 5f0284addc..d25edbcf2a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/SocketRemoteSiteListener.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/SocketRemoteSiteListener.java
@@ -26,6 +26,10 @@ import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -33,7 +37,12 @@ import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.remote.cluster.ClusterNodeInformation;
import org.apache.nifi.remote.cluster.NodeInformant;
@@ -46,7 +55,6 @@ import org.apache.nifi.remote.io.socket.SocketCommunicationsSession;
import org.apache.nifi.remote.protocol.CommunicationsSession;
import org.apache.nifi.remote.protocol.RequestType;
import org.apache.nifi.remote.protocol.ServerProtocol;
-import org.apache.nifi.security.util.CertificateUtils;
import org.apache.nifi.security.util.TlsConfiguration;
import org.apache.nifi.util.NiFiProperties;
import org.slf4j.Logger;
@@ -160,7 +168,8 @@ public class SocketRemoteSiteListener implements RemoteSiteListener {
try {
if (secure) {
LOG.trace("{} Connection is secure", this);
- dn = CertificateUtils.extractPeerDNFromSSLSocket(socket);
+ final SSLSocket sslSocket = (SSLSocket) socket;
+ dn = getPeerIdentity(sslSocket);
commsSession = new SocketCommunicationsSession(socket);
commsSession.setUserDn(dn);
@@ -174,7 +183,7 @@ public class SocketRemoteSiteListener implements RemoteSiteListener {
// TODO: Add SocketProtocolListener#handleTlsError logic here
String msg = String.format("RemoteSiteListener Unable to accept connection from %s due to %s", socket, e.getLocalizedMessage());
// Suppress repeated TLS errors
- if (CertificateUtils.isTlsError(e)) {
+ if (isTlsError(e)) {
boolean printedAsWarning = handleTlsError(msg);
// TODO: Move into handleTlsError and refactor shared behavior
@@ -320,6 +329,32 @@ public class SocketRemoteSiteListener implements RemoteSiteListener {
listenerThread.start();
}
+ private boolean isTlsError(final Throwable e) {
+ final boolean tlsError;
+
+ if (e instanceof SSLException || e instanceof GeneralSecurityException) {
+ tlsError = true;
+ } else if (e.getCause() == null) {
+ tlsError = false;
+ } else {
+ tlsError = isTlsError(e.getCause());
+ }
+
+ return tlsError;
+ }
+
+ private String getPeerIdentity(final SSLSocket sslSocket) throws SSLPeerUnverifiedException {
+ final SSLSession sslSession = sslSocket.getSession();
+ final Certificate[] peerCertificates = sslSession.getPeerCertificates();
+ if (peerCertificates == null || peerCertificates.length == 0) {
+ throw new SSLPeerUnverifiedException(String.format("Peer [%s] certificates not found", sslSocket.getRemoteSocketAddress()));
+ }
+
+ final X509Certificate peerCertificate = (X509Certificate) peerCertificates[0];
+ final Principal subjectDistinguishedName = peerCertificate.getSubjectDN();
+ return subjectDistinguishedName.getName();
+ }
+
private boolean handleTlsError(String msg) {
if (tlsErrorRecentlySeen()) {
LOG.debug(msg);
@@ -331,7 +366,7 @@ public class SocketRemoteSiteListener implements RemoteSiteListener {
}
/**
- * Returns {@code true} if any related exception (determined by {@link CertificateUtils#isTlsError(Throwable)}) has occurred within the last
+ * Returns {@code true} if any related exception has occurred within the last
* {@link #EXCEPTION_THRESHOLD_MILLIS} milliseconds. Does not evaluate the error locally,
* simply checks the last time the timestamp was updated.
*
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/test/resources/localhost-ks.jks b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/test/resources/localhost-ks.jks
deleted file mode 100755
index 6db775d765..0000000000
Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/test/resources/localhost-ks.jks and /dev/null differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/test/resources/localhost-ts.jks b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/test/resources/localhost-ts.jks
deleted file mode 100755
index 5a4fd2d292..0000000000
Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/test/resources/localhost-ts.jks and /dev/null differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
index 5c911bc404..ed16d77621 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
@@ -198,6 +198,12 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-xml-processing</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-identity</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-web-security</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
index cb475e8930..01994189f7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
@@ -152,6 +152,11 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-security-utils</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-identity</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-framework-core</artifactId>
diff --git a/nifi-nar-bundles/nifi-gcp-bundle/nifi-gcp-parameter-providers/pom.xml b/nifi-nar-bundles/nifi-gcp-bundle/nifi-gcp-parameter-providers/pom.xml
index 7d46735e1e..345d5f778a 100644
--- a/nifi-nar-bundles/nifi-gcp-bundle/nifi-gcp-parameter-providers/pom.xml
+++ b/nifi-nar-bundles/nifi-gcp-bundle/nifi-gcp-parameter-providers/pom.xml
@@ -32,7 +32,6 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
<version>1.24.0-SNAPSHOT</version>
- <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/pom.xml b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/pom.xml
index 67a1d44176..c0415fd326 100644
--- a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/pom.xml
+++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/pom.xml
@@ -41,6 +41,11 @@
<artifactId>nifi-security-utils</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-identity</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-properties</artifactId>
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-record-sink-service-bundle/nifi-record-sink-service/pom.xml b/nifi-nar-bundles/nifi-standard-services/nifi-record-sink-service-bundle/nifi-record-sink-service/pom.xml
index ad42c09420..c67812c6f6 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-record-sink-service-bundle/nifi-record-sink-service/pom.xml
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-record-sink-service-bundle/nifi-record-sink-service/pom.xml
@@ -59,6 +59,11 @@
<artifactId>nifi-event-transport</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils-api</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-mock</artifactId>
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-web-client-provider-bundle/nifi-web-client-provider-service/pom.xml b/nifi-nar-bundles/nifi-standard-services/nifi-web-client-provider-bundle/nifi-web-client-provider-service/pom.xml
index bcf2458e7d..0f4ee733c6 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-web-client-provider-bundle/nifi-web-client-provider-service/pom.xml
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-web-client-provider-bundle/nifi-web-client-provider-service/pom.xml
@@ -57,6 +57,12 @@
<artifactId>nifi-utils</artifactId>
<version>1.24.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-mock</artifactId>