SAP-archive / spring-cloud-sap

Spring Cloud Connectors for SAP HANA Cloud Platform (HCP) and SAP HANA DB platform
Other
39 stars 17 forks source link

Establishing secured connection in CF #8

Open eranberg opened 5 years ago

eranberg commented 5 years ago

When trying to establish a Hana DB connection in our CF landscape using spring-cloud-cloudfoundry-hana-service-connector we are getting an exception from the Hana driver: 2018-09-14T13:11:07.52-0700 [APP/PROC/WEB/0] ERR com.sap.db.jdbc.exceptions.JDBCDriverException: SAP DBTech JDBC: [4321]: only secure connections are allowed 2018-09-14T13:11:07.52-0700 [APP/PROC/WEB/0] ERR at com.sap.db.jdbc.exceptions.SQLExceptionSapDB.createException(SQLExceptionSapDB.java:345) 2018-09-14T13:11:07.52-0700 [APP/PROC/WEB/0] ERR at com.sap.db.jdbc.exceptions.SQLExceptionSapDB.generateDatabaseException(SQLExceptionSapDB.java:185) 2018-09-14T13:11:07.52-0700 [APP/PROC/WEB/0] ERR at com.sap.db.jdbc.packet.ReplyPacket.buildExceptionChain(ReplyPacket.java:102) 2018-09-14T13:11:07.52-0700 [APP/PROC/WEB/0] ERR at com.sap.db.jdbc.ConnectionSapDB.execute(ConnectionSapDB.java:1033)

From looking into HANAServiceInfoCreator -> createServiceInfo() it seems that the URL created for the connectivity doesn't contain options for:

  1. encrypt
  2. validateCertificate

As a result the connectivity to our Hana instance is failing (see stack trace). It seems we need some configuration options for HANAServiceInfoCreator to allow for better URL composition.

eranberg commented 5 years ago

it seems https://github.com/SAP/spring-cloud-sap/pull/7 attempts to solve this issue but it is not done in a configurable (optional) way

rkschamer commented 5 years ago

A workaround is to configure the DataSource to be used manually:

@Bean
@Primary
public DataSource dataSource(
        @Value("${vcap.services.<your-haas.service>.credentials.url}")final String url,
        @Value("${vcap.services.<your-haas.service>.credentials.user}")final String user,
        @Value("${vcap.services.<your-haas.service>.credentials.password}")final String password
        ) {
    return DataSourceBuilder.create()
            .type(HikariDataSource.class)
            .driverClassName(com.sap.db.jdbc.Driver.class.getName())
            .url(url)
            .username(user)
            .password(password)
            .build();
}
junnyea commented 5 years ago

@flawi thank you. your solution works for me. Have to use HikariDataSource.class. ( DataSource.class is not working). This solution will be the workaround.

Alternatively, if you would want to use Embedded tomcat container to connect to Cloud. You may follow this link https://stackoverflow.com/questions/24941829/how-to-create-jndi-context-in-spring-boot-with-embedded-tomcat-container

Any chance that @jonathanbaker7 can fix the not detected HANAServiceInfoCreator during runtime?

naheedmk commented 5 years ago

Getting exception mentioned in this thread SAP DBTech JDBC: [4321]: only secure connections are allowed, when trying to connect a Springboot App deployed on SAP cloud CF. Any fix for this ?

jeffalbion commented 5 years ago

To enable Java encryption, "encrypt=true" needs to appear in JDBC URI. Are you doing this?

markdevries commented 5 years ago

Workaround including the security parameters would be:

@Bean
@Primary
public DataSource dataSource() {

    HANAServiceInfo serviceInfo = (HANAServiceInfo) cloud().getServiceInfo("hana-service-instance-name");

    String host = serviceInfo.getHost();
    int port = serviceInfo.getPort();

    String username = serviceInfo.getUserName();
    String password = serviceInfo.getPassword();
    String schema = serviceInfo.getUserName(); // The schemaname matches the username

    String url = new UriInfo("jdbc:sap", host, port, null, null, null,
            "currentschema=" + schema + "&encrypt=true&validateCertificate=true").toString();

    return DataSourceBuilder.create().type(HikariDataSource.class)
            .driverClassName(com.sap.db.jdbc.Driver.class.getName()).url(url).username(username).password(password)
            .build();

}