This is the 4th blog post in the series on Centralised Transport Naming Standards.
See also blog posts:
|Centralised Transport Naming Standards|
Since the Centralised Transport Naming Standards solution has evolved and is rolled out to more development systems, a feature that has been requested is the validation of the reference number entered in segment 3 <Change_Ref> below:
i.e. CAU:R1:TASK000000000001:Example description:1
The plan is to validate this number to either Service Now or Azure DevOps depending on the prefix and since Service Now was the priority, all I needed to do was to call a predefined API from SAP. Shouldn’t be too much of a problem?!
Credit where Credit is Due
Firstly, a large part of the knowledge gained on my quest to validate reference numbers provided in transport titles is down to the two items below:
- The Wiki – Access Microsoft Azure using the OAuth 2.0 Client API
- and the SAP Code Samples on Github for abap-alv-google-upload-sheet
These were instrumental in steering me in the right direction and completed probably 90% of the puzzle. Many thanks to Joachim Doersam and Sebastian Machhausen for writing the wiki and providing the code respectively. If you are ever in need of connecting to external system via OAUTH2, these should be your first port of call. (Also, as background info to this blog, a quick skim through would also be very useful).
Unfortunately, and as is quite often the case, the remaining 10% of the solution seemed to take an age and it is this that I wish to focus this blog post on. Therefore, this is not an exhaustive list of the config and code set, that has already been provided in the items above, what follows are the differences due to the client credentials flow I specifically had to use.
OAUTH 2.0 Client Flows
Having never been exposed to OAUTH, this was a tricky piece for me to get my head around and a lesson learnt to trust others that know better than me! I was told several times that I had to use the client credentials flow rather than the authorisation grant flow but as I didn’t really understand the difference, plus I had made a large headway with the latter, I ploughed on. Later on, when the penny finally dropped in my understanding of the client credential flow, I realised that I should have just listened to those that knew better. Hindsight is a wonderful thing…
The nub of the issue I faced is that the documentation I was following and the code examples provided were for an authorisation grant flow and I needed to convert this into the client credentials flow. As it turns out, it’s not that difficult – when you know how.
The client credentials flow is to enforce the below process:
- Request from SAP (client application) goes to Azure Active Directory
- Bearer token provided back to SAP
- Bearer token then provided to authenticate to Service Now
- Access granted and data requested duly retrieved
Figure 1 – Client Credential Flow
The key thing about this flow is that there is no requirement for human interaction and that the token can get renewed automatically if it expires. With the authorisation grant flow, I had to initially set this up manually via the OA2C_GRANT transaction (as per the wiki). A refresh token (to ensure I don’t have continually re-authenticate manually) was also requested at the same time and, according to OA2C_GRANT was provided and accepted ok). This worked perfectly fine for the first hour of the initial grant but once this expired and the refresh token was requested, it never worked. Service Now was expecting a client credentials flow and I had not set this up, hence I was stuck with a solution that partially worked and one that I progressed with far too long before admitting defeat. Therefore, I thought it useful to provide a few steps that caught me out in case they are of use to someone else faced with a similar situation.
There a quite a few links in the chain to authenticating using OAUTH2 using SAP as the client and the wiki takes them on one by one. Below, I’ll just add the changes I needed to make in order for the client credentials flow to work.
Mentioned in the wiki but after providing it in a test profile to myself, I then later forgot when testing for other users – lots of debugging later and I remembered it. Hence I’m putting a the top!
There is a check on this when creating the oauth2 client via the create_oauth_client() method below:
Figure 2 – Authorisation requirement
Make sure you add the following to all userids that need to call the code.
- PROFILE = ‘Your profile name i.e. ZSERVICENOW*’
- ACTVT = 16
The target application – in this case Service Now – needs to be trusted and hence a certificate needs to be uploaded in STRUST. Depending on your company setup, Basis may have to do this for you. If you’ve already been using ABAPGit (which I highly recommend if not), the procedure is the same as adding in the Github certificate found here.
There are two BAdI’s mentioned in the wiki.
OA2C_CONFIG_EXTENSION_BADI_DEF and OA2C_SPECIFICS_BADI_DEF
As I document this, I now wonder whether OA2C_CONFIG_EXTENSION_BADI_DEF is actually required as it only makes reference to Authorisation Code Grant and SAML 2.0 Grant Tokens – neither of which are required for my implementation. I’ll review this and remove later if applicable.
Follow the wiki but ensure you add in the last line. Later on below, you will see where this enables options in the OA2C_CONFIG transaction further down.
Figure 3 – OA2C_SPECIFICS BAdI
Three client profiles are required that will be aligned to the AAD applications that are mentioned shortly. (The assumption is that you have already setup ZSERVICENOE in OA2C_TYPES as per the wiki).
Figure 4 – Client Profiles
Only a single scope is required and this was provided by the Service Now API team and is added to the Client Profiles on the Scopes tab. Scopes are also detailed here.
Azure Active Directory (AAD) Configuration
I then had to create 3 separate ‘applications’ within AAD. to match the client profiles above. These are very basic and purely there for the provision of the token. Information on setting these up can be found here .The client ids, client secret and endpoints provided, are then used in the OA2C_CONFIG transaction shown below.
The reason the fields are highlighted in yellow are explained in Figure 8.
Figure 5 – OA2C_CONFIG
The UML Diagram below shows the hierarchy of classes described by Sebastian Machhausen in his samples for accessing Google Sheets.
Figure 6 – UML of the Service Now Classes
I implemented these pretty much as a copy/paste exercise with a minor, but significant, change to the highlighted method above. This is typed to the interface below and has 3 different types of flow execution.
Figure 7 – IF_OAUTH2_CLIENT
The highlighted code was the final piece in the puzzle. I couldn’t understand why the flow was failing until I spotted that it was calling the execute_refresh_flow method and not an execute_cc_flow. Plus the code needed to use the header field but the OA2C_CONFIG specified Form Field. (My mistakes from experimenting).
In the method below, we can therefore see that the header field and execute_cc_flow method are in sync with the OA2C_CONFIG shown above in Figure 5.
Figure 8 – Setting the token
So finally it all works and I have validation to Service Now for both service tasks and incidents. In Figure 9 below, I have attempted to release the transport task and have been blocked as the reference number is in an incorrect status.
Figure 9 – Error message
Not the prettiest of popups I grant you but it does the job. I am currently using the SAP standard POPUP_WITH_TABLE_DISPLAY FM as it is present on all satellite dev systems from 7.31 upwards and therefore does not require any additional development to be pushed out. I would prefer a standard HTML version that would certainly look nicer and provide better flexibility – any suggestions welcome!
So the standards get a bit tighter again and auditing each transport against its reason for being in the system is a lot easier, saving many hours of trawling spreadsheets by development leads.
I certainly learnt a lot in this particular exercise which will stand me in good stead for also validating to Azure DevOps – whether I do this via SAP or AWS is yet to be decided. First I need to move this code from the Feature Branch to the Main branch though once I’ve completed testing.