com.sap.cds.feature.postgresql.PostgreSqlDataSourceDescriptor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cds-feature-postgresql Show documentation
Show all versions of cds-feature-postgresql Show documentation
PostgreSQL service connectivity feature for CDS Services Java
/**************************************************************************
* (C) 2019-2024 SAP SE or an SAP affiliate company. All rights reserved. *
**************************************************************************/
package com.sap.cds.feature.postgresql;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.Base64;
import java.util.Base64.Encoder;
import java.util.Map;
import com.sap.cds.services.datasource.DataSourceDescriptor;
import com.sap.cds.services.utils.StringUtils;
import com.sap.cloud.environment.servicebinding.api.ServiceBinding;
import org.postgresql.Driver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Converts a PostgreSQL {@link ServiceBinding} into a {@link DataSourceDescriptor}
*/
public class PostgreSqlDataSourceDescriptor implements DataSourceDescriptor {
private static final Logger log = LoggerFactory.getLogger(PostgreSqlDataSourceDescriptor.class);
private final String name;
private final String url;
private final String username;
private final String password;
public PostgreSqlDataSourceDescriptor(ServiceBinding binding) {
this.name = binding.getName().get(); // NOSONAR
Map credentials = binding.getCredentials();
String jdbcUrl = createJdbcUrl(credentials);
this.url = enableSsl(jdbcUrl, credentials);
this.username = getUser(credentials);
this.password = (String) credentials.get("password");
}
@Override
public String getName() {
return name;
}
@Override
public String getDriverClassName() {
return Driver.class.getName();
}
@Override
public String getUrl() {
return url;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
private String enableSsl(String jdbcUrl, Map credentials) {
String sslRootCert = getCaCert(credentials);
// enable SSL mode and host verification, if root/ca certificate is available
if (!StringUtils.isEmpty(sslRootCert)) {
Encoder encoder = Base64.getUrlEncoder();
/*
* Use existence of 'sslkey' field as an indicator if the hyperscaler only supports 'verify-ca' mode.
* There is no hard relation between these properties, but it is a common pattern on current hyperscalers.
* Further details can be found in the PostgreSQL documentation:
* https://jdbc.postgresql.org/documentation/ssl/#configuring-the-client
*/
String sslVerificationMode = credentials.containsKey("sslkey") ? "verify-ca" : "verify-full";
jdbcUrl += "?sslmode=%s&sslfactory=%s&sslrootcertbase64=%s".formatted(sslVerificationMode,
PostgreSqlSSLFactory.class.getName(), encoder.encodeToString(sslRootCert.getBytes(UTF_8)));
log.debug("Enabled SSL certificate and hostname verification for PostgreSQL binding '{}'", this.name);
String sslClientCert = getClientCert(credentials);
String sslPrivateKey = getPrivateKey(credentials);
// enable mTLS if private key and client cert are provided
if (!StringUtils.isEmpty(sslClientCert) && !StringUtils.isEmpty(sslPrivateKey)) {
jdbcUrl += "&sslclientcertbase64=%s&sslprivatekeybase64=%s".formatted(
encoder.encodeToString(sslClientCert.getBytes(UTF_8)),
encoder.encodeToString(sslPrivateKey.getBytes(UTF_8)));
log.debug("Enabled mTLS for PostgreSQL binding '{}'", this.name);
}
} else {
log.debug("PostgreSQL binding '{}' is missing the CA certificate.", this.name);
}
return jdbcUrl;
}
private static String createJdbcUrl(Map credentials) {
String host = (String) credentials.get("hostname");
if (StringUtils.isEmpty(host)) {
host = (String) credentials.get("host");
}
Object port = credentials.get("port");
if (port != null) {
port = port.toString();
} else {
port = "5432";
}
String dbName = (String) credentials.get("dbname");
if (StringUtils.isEmpty(dbName)) {
dbName = (String) credentials.get("database");
}
return "jdbc:postgresql://%s:%s/%s".formatted(host, port, dbName);
}
private static String getCaCert(Map credentials) {
return (String) credentials.get("sslrootcert");
}
private static String getClientCert(Map credentials) {
return (String) credentials.get("sslcert");
}
private static String getPrivateKey(Map credentials) {
return (String) credentials.get("sslkey");
}
private static String getUser(Map credentials) {
String user = (String) credentials.get("username");
if (StringUtils.isEmpty(user)) {
user = (String) credentials.get("user");
}
return user;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy