com.sap.xs.hdb.options.HanaServiceConnectionHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xs-hdb-conn-options Show documentation
Show all versions of xs-hdb-conn-options Show documentation
Use this library to handle SAP HANA DB connection options
package com.sap.xs.hdb.options;
import static java.lang.String.format;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.xs.env.Credentials;
import com.sap.xs.env.Service;
import com.sap.xs.hdb.utils.DigestUtils;
import com.sap.xs.hdb.utils.KeyStoreInitializer;
public class HanaServiceConnectionHelper {
private static final String CLIENT_AUTHENTICATION_PRIVATE_KEY = "client_authentication_private_key";
private static final String CLIENT_AUTHENTICATION_CERTIFICATE = "client_authentication_certificate";
private static final Logger LOGGER = Logger.getLogger(HanaServiceConnectionHelper.class.getName());
public static final Path DEFAULT_SECURITY_PATH = Paths.get("META-INF/.sap_java_buildpack/hana_jdbc/security");
private final Service hanaService;
private final Credentials hanaCredentials;
private Path keyStorePath = DEFAULT_SECURITY_PATH;
private String keyStoreName;
private char[] keyStorePass;
public HanaServiceConnectionHelper(Service service) {
hanaService = ensureHanaService(service);
hanaCredentials = hanaService.getCredentials();
}
private Service ensureHanaService(Service service) {
if (service == null) {
throw new IllegalArgumentException("HANA Service cannot be null");
}
if (service.getCredentials() == null) {
throw new IllegalArgumentException(service.getName() + " has no credentials.");
}
return service;
}
/**
* @return {@link ConnectionPropertiesBuilder}
*/
public ConnectionPropertiesBuilder getBuilder() {
ConnectionPropertiesBuilder builder = new ConnectionPropertiesBuilder().withUser(hanaCredentials.getUser())
.withPassword(hanaCredentials.getPassword());
if (hanaCredentials.any().containsKey("schema")) {
builder.withCurrentSchema((String) hanaCredentials.any().get("schema"));
}
// These properties are not listed in the official documentation of the hana jdbc driver but are present in the service def
// builder.withProperty("url", hanaCredentials.getUrl());
// builder.withProperty("driver", hanaCredentials.getDriver());
// builder.withProperty("host", hanaCredentials.getHost());
// builder.withProperty("port", hanaCredentials.getPort());
if (hanaCredentials.any().containsKey("encrypt")) {
builder.withEncrypt(ensureBoolean(hanaCredentials, "encrypt"));
}
if (hanaCredentials.any().containsKey("validate_certificate")) {
builder.withValidateCertificate(ensureBoolean(hanaCredentials, "validate_certificate"));
}
if (hanaCredentials.any().containsKey("hostname_in_certificate")) {
builder.withHostNameInCertificate((String) hanaCredentials.any().get("hostname_in_certificate"));
}
if (isClientAuthenticationEnabled()) {
try {
ensureClientAuthenticationKeyStore();
builder.withKeyStore(keyStorePath.resolve(keyStoreName).toAbsolutePath().toString())
.withKeyStorePassword(new String(keyStorePass));
} catch (ClientAuthenticationInitializationException e) {
LOGGER.log(Level.SEVERE, e, ()->"Client authentication initialization failed for service " + hanaService.getName());
}
}
return builder;
}
// This is the behavior of other such utils (@sap/hdbext for example). May be
// unnecessary.
private boolean ensureBoolean(Credentials credentials, String key) {
final Object value = credentials.any().get(key);
if (value == null
|| !(value.toString().equalsIgnoreCase("true") || value.toString().equalsIgnoreCase("false"))) {
throw new IllegalArgumentException(format("Invalid HANA credentials: \"%s\" must be a boolean", key));
}
return Boolean.parseBoolean(value.toString());
}
/**
* @return true or false if client authentication is enabled
*/
public boolean isClientAuthenticationEnabled() {
return hanaCredentials.any().containsKey(CLIENT_AUTHENTICATION_PRIVATE_KEY)
&& hanaCredentials.any().containsKey(CLIENT_AUTHENTICATION_CERTIFICATE);
}
/**
* Ensures the KeyStore used for client authentication is properly set up.
* Should not be called unless isClientAuthenticationEnabled() returns true.
*/
public void ensureClientAuthenticationKeyStore() {
initKeyStoreName();
initKeyStorePassword();
initKeyStore();
}
private void initKeyStoreName() {
if (keyStoreName == null) {
keyStoreName = hanaService.getName();
}
try {
// TODO find a better approach for sanitizing the keystore filename
keyStoreName = DigestUtils.getSha256HexString(keyStoreName);
} catch (NoSuchAlgorithmException e) {
throw new ClientAuthenticationInitializationException("Unable to initialize KeyStore filename", e);
}
}
private void initKeyStorePassword() {
try {
keyStorePass = DigestUtils.getSha256Hex(getPrivateKey());
} catch (NoSuchAlgorithmException e) {
throw new ClientAuthenticationInitializationException("Unable to initialize KeyStore password", e);
}
}
private File getKeyStoreFile() {
return keyStorePath.resolve(keyStoreName).toFile();
}
private void initKeyStore() {
if (getKeyStoreFile().exists()) {
LOGGER.info(()->"KeyStore already exists at " + getKeyStoreFile() + " and will be used.");
} else {
try {
new KeyStoreInitializer(hanaService.getName(), getPrivateKey(), getPrivateKeyCertificate())
.initAndStore(keyStorePass, keyStorePath.resolve(keyStoreName));
} catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | InvalidKeySpecException
| IOException e) {
throw new ClientAuthenticationInitializationException("Unable to initialize KeyStore", e);
}
}
}
private String getPrivateKey() {
return (String) hanaCredentials.any().get(CLIENT_AUTHENTICATION_PRIVATE_KEY);
}
private String getPrivateKeyCertificate() {
return (String) hanaCredentials.any().get(CLIENT_AUTHENTICATION_CERTIFICATE);
}
/**
* @return key store name
*/
public String getKeyStoreName() {
return keyStoreName;
}
/**
* @param keyStoreName
* key store name to set
*/
public void setKeyStoreName(String keyStoreName) {
this.keyStoreName = keyStoreName;
}
/**
* @return key store path
*/
public Path getKeyStorePath() {
return keyStorePath;
}
/**
* @param keyStorePath
* key store path to set
*/
public void setKeyStorePath(Path keyStorePath) {
this.keyStorePath = keyStorePath;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy