Java Project to get you started with SAP Private Link Service for Azure with SAP Cloud SDK.
This app was built from SAP's Cloud SDK getting-started Java project.
Find my blog post series on the topic here.
The templates folder contains Postman collections and blue prints for integrations mentioned on the blog series.
Warning The Java runtime and mvn dev environment on SAP BTP has moved on. You will need to upgrade the setup to the latest supported by SAP. It doesn't run anymore as is. I focussed on the CAP nodejs implementation instead now. Please use that project going forward for a turn key solution. In case you upgrade the Java sample would appreciate a PR :-)
We used the /sap/opu/odata/sap/epm_ref_apps_prod_man_srv
OData service for this project.
mvn command cheat sheet🧙🏿♂️
mvn clean package
cf push
mvn package tomee:run
Azure Private Link Service allows private connectivity between resources running on Azure in different environments. That includes SAP's Business Technology Platform when provisioned on Azure. SAP made that functionality available via a CloudFoundry Service.
Meaning you get now a managed component to expose your SAP backends to BTP on Azure without the need for a Cloud Connector. We developed against S4 primarily but anything executable in a service behind the Azure load balancer would be reachable. That involves for instance ECC, BO, PI/PO, SolMan etc.
We describe a set of Destinations, whereas the first one refers to the initial simple setup discussed in part 1 of the blog series. The next two are required to realize the SAMLAssertion flow. This additional complexity is due to the fact that the SAML2BearerAssertion flow cannot be used, because the SAP Private Link Service operates isolated from all other BTP services by design. As part of the flow the connectivity service would need to reach the OAuth2 server on the SAP backend but can't because it has no visibility of the private endpoint.
We could get away with 2 destinations, because the target configuration is the same except the authorization header. For a cleaner approach and better separation I decided to have a separate instance to avoid overriding authentication.
In general for end-to-end SSL you need to consider three options:
- Use TrustAll property setting to accept any certificate
- Override the verifier within your code (see BTPAzureProxyServletIgnoreSSL)
- Maintain the trust store of your destination and configure Server Name Indicator (SNI) with your SAP Personal Security Environment (PSE) on your backend (either through STRUST on NetWeaver or SAP Web Dispatcher). Find details on this setup on part 7 of the blog series.
In case your version of the CloudSDK doesn't support the new Proxy Type PrivateLink, revert to Internet. Be aware that this is a configuration topic only. By no means does traffic flow to the Internet. It will be resolved to the private tunnel exposed by PLS.
The last destination describes the setup for SQL connection to the newly added PLS feature scope for Azure PaaS. MariaDB and MySQL have been added first.
Skip this sub section if you don't want to secure your private linke enabled CF app just yet and proceed with 1
Furthermore you need to deploy the approuter to authenticate through XSUAA and be able to initiate the required token exchange for SAP Principal Propagation. Find more details on the SAP tutorial.
- Uncomment login-config, security-constraint and security-role in web.xml
- Run cf cli command:
cf create-service xsuaa application my-xsuaa -c xs-security.json
to create associated XSUAA instance - Navigate to approuter project subfolder
cd approuter
cf push
Going forward you can access your Java Servlets only through the approuter now (if they enforce the ServletSecurity
annotation).
key | value |
---|---|
Name | s4BasicAuth |
Type | HTTP |
URL | https://[your private hostname]/ |
Proxy Type | PrivateLink |
Authentication | Whatever you have here. We tested Basic Auth initially. (Adjust user id and pwd for SAP Principal Propagation!) |
key | value |
---|---|
sap-client | your client no |
TrustAll | true |
HTML5.DynamicDestination | true |
WebIDEEnabled | true |
WebIDEUsage | odata_abap |
key | value |
---|---|
Name | s4oauth |
Type | HTTP |
URL | https://[your private hostname]/sap/bc/sec/oauth2/token?sap-client=[your client no] |
Proxy Type | PrivateLink |
Authentication | SAMLAssertion |
Audience | check Provider Name on SAML2 backend transaction |
AuthnContextClassRef | urn:oasis:names:tc:SAML:2.0:ac:classes:x509 |
key | value |
---|---|
sap-client | your client no |
TrustAll | true |
HTML5.DynamicDestination | true |
WebIDEEnabled | true |
WebIDEUsage | odata_abap |
nameIdFormat | urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress |
tokenServiceURL (type manually and put cursor at beginning to replace capital "T") | https://[your private hostname]/sap/bc/sec/oauth2/token?sap-client=[your client no] |
Be aware that currently the property tokenServiceURL will be hidden after save. Also adding trust store will override your tokenServiceURL setting. So, make sure to maintain it again when you make changes to the additional properties. You can just type it again. It will override if still existing.
Hence we need to inject the Bearer token from preceeding calls described in above paragraph.
key | value |
---|---|
Name | s4NoAuth |
Type | HTTP |
URL | identical to first destination |
Proxy Type | PrivateLink |
Authentication | No Authentication |
key | value |
---|---|
sap-client | your client no |
TrustAll | true |
HTML5.DynamicDestination | true |
WebIDEEnabled | true |
WebIDEUsage | odata_abap |
If you configure SAP Principal Propagation based upon above config, please note that you need to change the BasicAuthentication user on the first Destination to match the OAuth2 Client Id and secret (check backend transaction SOAUTH2).
I can warmly recommend transaction sec_diag_tool to troubleshoot any Principal Propagation related issues.
To get started I recommend to test your authentication flow without SAP Private Link to rule out any hickups. I provided a Postman collection for that. It is meant to be executed from top to bottom.
key | value |
---|---|
Name | s4BasicAuth |
Type | RFC |
Proxy Type | PrivateLink |
User | Your SAP RFC User |
Password | Your SAP RFC User Password |
key | value |
---|---|
jco.client.client | your SAP client no |
jco.client.lang | potentially define the language for the output or pass down from your CF app |
jco.client.wshost | btp_private_link_hostname that points to your SAP WDisp |
jco.client.wsport | your SAP WDisp port |
jco.destination.pool_capacity | default 1 |
Note WebSocket RFC is available as of S4 1909. Also for initial testing of the RFC connection with JCo, the property jco.client.tls_trust_all might be helpful. Find more details on JCo properties here and from the NEO docs here.
key | value |
---|---|
Name | AzureMySQLBasic |
Type | HTTP |
URL | https://[your db domain].[mysql or mariadb].database.azure.com:3306 |
Proxy Type | PrivateLink |
User | sql_user@your_db_domain |
Password | Your SQL User Password |
key | value |
---|---|
HTML5.DynamicDestination | true |
Note: I am not actually using the http destination, but for the lack of another type I chose this one. It serves only as config store for the jdbc connection on the backend. The http part is ignored.
Reach out via the GitHub Issues page of this repos to talk about it some more :-)