Hello World! I guess this is how each programming language learning path starts. Independent of the language of choice the semantics of what needs to be done are quite similar, you just have to find the right command to output text to the screen and voila – the two magic words appear and you are all in! Now what? You browse the web for numerous tutorials, which tell you to do this and that, and not to do the other 500 things that came to your mind known as bad practices. You are getting the grasp of it and you become better every day. Eventually you reach the point where you need to program a service that will be consumed by another system.
Oh, excuse me for the slow intro, but it’s important to understand the history of events and if you already haven’t given up to this moment, then now is definitely not the right time to do so, since we are jumping into the specifics:)
It turns out you couldn’t wait for another 10 or 20 years and you were not born a Millennial, nor a Generation Z kid. Good or bad, it is a matter of opinion, but the fact is that your brand new service is written in Java and not just any kind of Java, but Java 8. OMG, does that exist at all?!? – you might wonder. Well it does, and pretty much a whole platform depends on it – The SAP NetWeaver Java. If this is the first time you hear something like this exists in the SAP world, then the rest of the read would be more like a science-fiction book, but if you enjoy that genre, please do continue. For all the others, who are already hooked to the idea of consuming Java on-premise services in the cloud, you know what to do. Read on!
For the sake of not having a novel with 3 chapters likе “The sons of Great Bear”, we will assume that you already are that good that you managed to write and test your service on-premise and it is delivering the results you expect or in other words – working like a charm. Since you also read a minimum of 100 blog posts and tutorials on the topic, you already know that a service that will be consumed from another system should never be left unprotected. The next assumption we will make is that even Java semi-gods like the cloud at least a bit. So you also developed a simple app in SAP Cloud Foundry, which will consume your Java service and use the delivered data to do miracles.
So that we don’t get lost in the translation, below is the architecture of the solution:
(diagram was created by the author)
In the current example our application on the SAP Cloud Foundry (CF) Account is a SAPUI5 app, therefore we will expose a REST service, which supports both GET and POST requests.
As shown in the architecture picture we will use the cloud connector to establish a secure connection between the cloud and on-premise. There are quite a few blog posts on how to install Cloud connector, so we will just assume that you already did that and you connected your CF subaccount to it. The next step would be to create a connection to the SAP NetWeaver Java server:
Within the Internal host field, provide the full qualified name of your NetWeaver Java server. It is a good practice to use a different name for the virtual host (something simple you can refer to later in the cloud). You can keep the same port as the internal port or you can change that as well. This really depends on the security guidelines of your company. The rest of the settings should be as shown on the screenshot. Important to mention is that we should establish the connection using the secure protocol HTTPS, which automatically means that your SAP NetWeaver Java should be HTTPS enabled. You can easily check if this is the case by following the below easy steps:
- Login to your NW Java server -> http://<host>:<port>/nwa
- Within the NetWeaver Administrator, search for ‘SSL’ in the Search field on the top right:
- If you have SSL Access Points with status Green, then you are good to go:
- If the green status is not so green, then I suggest you contact your BASIS team to set this up for you. If you happen to be the BASIS team, then good luck with setting this up yourself:)
Back to the cloud connector. Once you create the connection, you can check if it is reachable – if so, you should get a similar screen:
Now it’s time to open the resources, which you would like to expose from your on-premise system. The best practice here is to expose the absolute minimum you need, so I guess the URL Path “/” would be the worst thing you can do in your professional life. OK, we are past the mentoring, you are a Java semi-god, let’s not forget that. Since you already tested your REST service, you should know very well the path to access it. Well, just remove the host and port in front and put the rest in the available resources:
The red marked rectangle is important, since if your app is more sophisticated than just displaying a “Hello World!” message, you definitely would like to point to the root of the REST API and then select the second radio button -> “Path and all sub-paths”. After you save, a quick check on the status column should show green.
Last step, for now, in the cloud connector would be to sync the trust configuration for the principal propagation:
This should be enough for now within the cloud connector, let’s jump in the Cloud Foundry account to setup our destination:
The above screenshot should bother you….at least a bit. First the communication protocol is http and second the Authentication is BasicAuthentication. Two things you read multiple times not to do. Let me explain. If you have created destinations in the past within Cloud Foundry, then you perfectly know that there is no “HTTPS” type in the dropdown of the destination creation and the reason for this is that it is up to you to make sure that your URL is using the proper protocol for the communication. OK, but here even our URL is http. This is because communication from the cloud to on-premise that goes over the cloud connector is always encrypted! There is no way around it. Now a few words on the authentication. The above was set just for test purposes. In a productive scenario I would highly recommend to use the option from the screenshot below:
At the end of this blog post I will explain shortly how this can work with your app in SAP Cloud Foundry and IAS.
The last step before testing our app connectivity would be to configure its xs-app.json. Below you will see an example of our configuration, but please do not take it for granted, since there are so many variations to it, I will mark out the important lines with red rectangles:
It is important to set the “authenticationMethod” to “route” and within the routes to point out the source, which you used during the consumption of the service in your SAPUI5 and the name of the destination we created a few steps back. We will talk about the “csrfProtection” flag a bit later in the blog post. Just accept for now that it is set to “false”.
So much configuration and fumbling around without any result yet. Well guess what, we are not even scratching the surface:) You can easily verify that by trying to run the app, which tries to consume your on-premise Java REST service – it successfully finds the destination you created, it connects to the cloud connector, but then for some reason your connection to the SAP NetWeaver Java server fails. The answer here is simple and it lies in the configuration we have done in the beginning in the cloud connector. The selected principal type was X.509 certificate, but wait…we have setup BasicAuthentication in the cloud destination, so how would that work?!?
Time for a quick theory detour:) Cloud connector has a special way of communicating with the SAP NetWeaver Java. It relies on short-lived X.509 certificates. The flow is as follows ->
- The incoming call from the cloud enters the Cloud connector
- Cloud connector checks the data of the person that was authenticated in the cloud and thanks to an established trust store and certification authority, transforms it into a X.509 short-lived certificate, which is then forwarded along with the rest of the request to the SAP NetWeaver Java server
- On the other hand, SAP NetWeaver Java checks if the certificate is issued by a trusted authority and if so, tries to map the provided data to a user, which exists in Java UME.
- Once successful, all roles, groups and actions available to the user in UME are fully active and available to perform operations within the on-premise server
The theory behind sounds just a bit simpler than the actual realization. That is why I won’t leave you hanging here and we will go through the needed steps in order to have a successful call to SAP NetWeaver Java from the cloud connector.
First step is to establish a trustful certificate authority in the cloud connector. With the correct sub-account selected, click on the Configuration menu:
Then we navigate to the On Premise tab and there we will find 4 key sub-sections: “System certificate”, “Trust Store”, “CA Certificate” and “Principal Propagation”. The first three are important for issuing the short-lived certificate, while the last one is the one that defines what attributes will be included in the certificate, which later will be used to authenticate to SAP NetWeaver Java.
The setup could look like this: (keep in mind that this is just a test scenario setup)
For a simple non-productive scenario, you can follow this help.sap.com page, which explains how to generate your own certificates under a Linux environment:
https://help.sap.com/viewer/70ac991a4f734773b1892a8d0d45eabc/Cloud/en-US/590e173911084f17b73caff26f79a4ae.html – Create a self-signed root CA
https://help.sap.com/viewer/70ac991a4f734773b1892a8d0d45eabc/Cloud/en-US/713d30fa7aa346f39896acd1229dc06f.html – Create intermediate certificates
You will need the intermediate certificates for the cloud connector and the root CA for the SAP NetWeaver Java server.
For productive scenarios, I highly recommend to connect with your security officers, who can assist you with all of the above certificates, so that you won’t have to generate them yourself.
The Subject pattern marked in the red rectangle defines the fields, from which you will read the data later in SAP NetWeaver Java. For this setup, we will use only the email field, which means that in order for the mapping in Java UME to be successful, each user should have a correctly maintained email.
Talking about the java backend, let’s take the root CA and import it there, since it will be needed so that those short-lived certificates from Cloud connector are trusted. Within the SSL configuration menu of the NetWeaver administrator, we have already checked that the SSL port is enabled and working. However there was one more detail to that screenshot, which is important – the column “Keystore View Name”. It points to the correct key store where we need to import the root CA.
Once we know that, we can search for “Certificates” in the NWA search and pick the “Key storage” configuration option:
Search for the same name that was mentioned in the SSL config and add the root CA there using the Import Entry button as shown on the screenshot below:
Now trust is established and the short-lived certificates from Cloud connector will be accepted by the NetWeaver Java server, however that is not all.
We need to define an authentication schema for our application, which provides the REST service. To do that, we need to again navigate within the NWA by searching for “authentication”:
If we plan to have multiple apps, which provide such RESTful services to other systems, then it makes sense to create a policy, which we can apply to each application, instead of re-entering all the information from scratch. If you are doing this just for test purposes, then it would be sufficient to maintain the configuration just once. In both cases, we first have to clean the filter, which is added by default from the “Type” column, in order to see all policy configuration names:
Once the filter is deleted and you press Enter, a much longer list of items will load in the table. Search for your application name (using the filter on top of each column), which provides the REST service and click on Edit:
What login modules you will add to your app depends on the usage you have planned for it. For our scenario the only mandatory login module is the ClientCertLoginModule. It also comes with a couple of rules, which instruct it from which attribute to retrieve the user, which will be mapped to the Java UME.
Once this step is done, we are ready to test the cloud application. GET requests should be working without any issues. POST requests, on the other hand might prove to be more challenging. This is because normally POST requests have one additional level of protection – CSRF token exchange. So what you have to do is first get a valid token from SAP NetWeaver Java with a proper GET call for the purpose and then include the response of that very same GET call in a follow-up POST call. To be able to achieve this in our scenario, you should keep one very important thing in mind – within the xs-app.json of your cloud application do not set the parameter “csrfProtection” to true. I know it doesn’t sound logical, but this parameter has a whole other purpose than what you might think. Setting it to true will actually overwrite your logic and the csrf token you sent will be removed from the request, ending up in a 403 request to the backend. If you keep the above recommendation, your POST requests should work as well. If not, check out the debugging section below.
In such a complex landscape passing through so many components, it is always handy to know where to look for potential problems. Below I will list a few of the tools that came quite handy during the debugging phase.
- SAP Cloud Foundry
- It is always a good idea to keep an eye on the Logs generated from your cloud app. The information you are looking for there would be if your setup is correct, so that the app can find the correct destination to the on-premise server
- SAP Cloud Connector
- Once you are sure that the destination is found and your call has reached the cloud connector, then you can check the Log and Trace Files of your sub-account communication.
- If those do not provide enough information, maybe it is worth enabling the Payload Trace, so you can check exactly what information reaches the cloud connector:
- SAP NetWeaver Java
- Since the platform has been around for more than 15 years, there are plenty of tools for troubleshooting. Let’s say that if you reached the point where all your calls pass through the previous steps correctly, but fail in SAP NW, your problem is easily solvable, by just revising once more the steps in this tutorial.
- If however, this doesn’t bring you forward, then you can explore the following tools:
- The NWA log viewer and more precisely two of its views:
- Developer Traces
- Authentication Logs
- If again, this doesn’t help, then there is one quite well hidden tool, which full functionality is revealed only when accessed through an alias in the URL:
- The troubleshooting wizard is normally available through NWA in the Troubleshooting tab, but there you do not have the possibility to add your own packages for tracing.
- However, if you open the tool directly with the alias above, you get an additional option, which let’s you configure the packages you can monitor:
- The NWA log viewer and more precisely two of its views:
- More on the Troubleshooting wizard can be found in this SAP Note -> https://launchpad.support.sap.com/#/notes/1332726
Productive setup with IAS
If you would like to use the above scenario productive, you should set the cloud destination authentication to a principal propagation scenario. In this case, however, you will have a different type of challenge -> e.g. how you will have the same users between your on-premise SAP NetWeaver Java server and the cloud. Thankfully, the solution to this lies in another cloud service – Identity Authentication Service, or shortly IAS. It allows you to switch the authentication mechanism for your application and instead of authenticating to SAP ID as identity provider, your users can authenticate directly to your SAP NetWeaver Java server. This way, you can always be sure that any user, who is allowed to login is also available in your backend Java system.
Congratulations, you have reached the next level (i mean the one after semi-god, of course)! I know it was a long journey, but I hope you believe it was worth it! And always remember, no level is the last one! Learning is an ever-ongoing process! Stay safe and stay on the constant learning path!
As a last note, I would like to thank everyone who contributed their knowledge and time and made this blog post a reality!