org.neo4j.driver.internal.security.SSLContextManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-java-driver Show documentation
Show all versions of neo4j-java-driver Show documentation
Access to the Neo4j graph database through Java
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* 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.
*/
package org.neo4j.driver.internal.security;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import org.neo4j.driver.ClientCertificateManager;
import org.neo4j.driver.Logger;
import org.neo4j.driver.Logging;
import org.neo4j.driver.exceptions.ClientException;
import org.neo4j.driver.internal.InternalClientCertificate;
import org.neo4j.driver.internal.pki.PemParser;
import org.neo4j.driver.internal.util.Futures;
class SSLContextManager {
private final ClientCertificateManager clientCertificateManager;
private final SecurityPlan.SSLContextSupplier sslContextSupplier;
private final Logger logger;
private CompletableFuture sslContextFuture;
private SSLContext sslContext;
private Throwable throwable;
public SSLContextManager(
ClientCertificateManager clientCertificateManager,
SecurityPlan.SSLContextSupplier sslContextSupplier,
Logging logging)
throws NoSuchAlgorithmException, KeyManagementException {
this.clientCertificateManager = clientCertificateManager;
this.sslContextSupplier = sslContextSupplier;
logger = logging.getLog(getClass());
if (clientCertificateManager == null) {
var sslContext = sslContextSupplier.get(new KeyManager[0]);
sslContextFuture = CompletableFuture.completedFuture(sslContext);
}
}
public CompletionStage getSSLContext() {
return clientCertificateManager != null ? getSSLContextWithClientCertificate() : sslContextFuture;
}
private CompletionStage getSSLContextWithClientCertificate() {
CompletableFuture sslContextFuture;
CompletionStage sslContextStage = null;
synchronized (this) {
if (this.sslContextFuture == null) {
this.sslContextFuture = new CompletableFuture<>();
sslContextFuture = this.sslContextFuture;
var sslContext = this.sslContext;
var previousThrowable = this.throwable;
sslContextStage = clientCertificateManager
.getClientCertificate()
.thenApply(clientCertificate -> {
if (clientCertificate != null) {
var certificate = (InternalClientCertificate) clientCertificate;
try {
var keyManagers = createKeyManagers(certificate);
return sslContextSupplier.get(keyManagers);
} catch (Throwable throwable) {
var exception = new ClientException(
"An error occured while loading client certficate.", throwable);
logger.error("An error occured while loading client certficate.", exception);
throw new CompletionException(exception);
}
} else {
if (previousThrowable != null) {
throw new CompletionException(previousThrowable);
} else {
if (sslContext == null) {
var exception = new ClientException(
"The initial client certificate returned by the manager must not be null.");
logger.error(
"The initial client certificate returned by the manager must not be null.",
exception);
throw new CompletionException(exception);
} else {
return sslContext;
}
}
}
});
} else {
sslContextFuture = this.sslContextFuture;
}
}
if (sslContextStage != null) {
sslContextStage.whenComplete((sslContext, throwable) -> {
throwable = Futures.completionExceptionCause(throwable);
synchronized (this) {
this.sslContextFuture = null;
this.sslContext = sslContext;
this.throwable = throwable;
}
if (throwable != null) {
sslContextFuture.completeExceptionally(throwable);
} else {
sslContextFuture.complete(this.sslContext);
}
});
}
return sslContextFuture;
}
protected KeyManager[] createKeyManagers(InternalClientCertificate clientCertificate)
throws CertificateException, IOException, KeyException, KeyStoreException, NoSuchAlgorithmException,
UnrecoverableKeyException {
var certificateFactory = CertificateFactory.getInstance("X.509");
var chain = certificateFactory.generateCertificates(new FileInputStream(clientCertificate.certificate()));
var password = clientCertificate.password();
var key = new PemParser(new FileInputStream(clientCertificate.privateKey())).getPrivateKey(password);
var clientKeyStore = KeyStore.getInstance("JKS");
var pwdChars = password != null ? password.toCharArray() : "password".toCharArray();
clientKeyStore.load(null, null);
clientKeyStore.setKeyEntry("neo4j.javadriver.clientcert.", key, pwdChars, chain.toArray(new Certificate[0]));
var keyMgrFactory = KeyManagerFactory.getInstance("SunX509");
keyMgrFactory.init(clientKeyStore, pwdChars);
return keyMgrFactory.getKeyManagers();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy