Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
eamarce23
Active Participant
3,168
Edit 18/04/2021: For anyone looking around, The SAP App router supports principal propagation by default, thanks @Gregor.wolf for pointing that out. That transforms the following blog post into a didactic exercise on how to extend the app router functionality 🙂 Have fun!

A brief overview of Principal propagation


In Cloud Foundry, Principal propagation is the process used to "forward the identity of a cloud user to a remote system. This process is called principal propagation (also known as user propagation or user principal propagation)."
SAP BTP Connectivity (Principal Propagation)

When we talk about reaching a remote system in this context, we are talking about an on-premise system (ECC, S/4 HANA, for example).

Also, we would typically consume a service in the backend for this scenario (commonly oData or RFC). To access this service, our users would authenticate to the Cloud Platform directly, then the corresponding remote system calls (or backend calls) would be made. Once one of these remote calls is made, the user authentication information would be sent from the Cloud to the backend system via the Cloud Connector. Then, the back-end system would validate the call on the back-end user's context, meaning that the corresponding user authorizations (authorization objects/roles) in the backend would be granted for the service execution.

On the technical side, this flow (User Exchange Token) can be seen as a credential exchange, using the JWT token(s) to authenticate users on the Cloud side, then sending the corresponding token to the Cloud Connector along with the backend call. Then, this JWT token is used in the Cloud connector to generate a temporary x509 certificate which ultimately is used to authenticate the user in the backend.

This flow is detailed in the documentation as well as in different blogs from the community:

 

Principal propagation with Node.js ( Configure Principal Propagation via User Exchange Token ).


Speaking about the technical implementation of this User Exchange Token flow, a slim client library to execute Principal Propagation can be found for Java. The objective of this blog is to achieve this functionality by using the App Router in Node.js.

Taking the documentation description, here is a GitHub repository with a sample MTA application.
The App Router (The component in MTA applications in charge of forwarding or proxy requests, among other functionality) in this application has been extended to intercept particular routes (in our example, routes containing /sap). Once a call is made by an application to a route containing this prefix (for example, a Fiori application requesting metadata from an OData service as in the repo example), the extension code executes the JWT exchange flow, so it adds the required JWT token to the request, and the Principal propagation scenario is achieved.

Next, here is a brief of the code to achieve this scenario:
var approuter = require('@sap/approuter');
var axios = require('axios');
var FormData = require('form-data');

var ar = approuter();

const oVCAP_SERVICES = JSON.parse(process.env.VCAP_SERVICES);
const oConnectivityServiceCredentials = oVCAP_SERVICES.connectivity[0].credentials;

// Intercept requests going to /sap route (backend call) to add JWT Exchange Token
ar.beforeRequestHandler.use('/sap', async function myMiddleware(req, res, next) {

if (req.url.indexOf("/sap") > -1) { /// Review the route contains /sap TODO: Can be extended to use regular expression
try {

var oAuthorization = JSON.parse(req._passport.session.user); // Obtain Authorization object from request
// The original JWT token can be found at oAuthorization.token.accessToken;

/// Make the post call according to the documentation so we can obtain JWT Exchange Token
var params = new URLSearchParams();
params.append('client_id', oConnectivityServiceCredentials.clientid);
params.append('client_secret', oConnectivityServiceCredentials.clientsecret);
params.append('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer');
params.append('token_format', 'jwt');
params.append('response_type', 'token');
params.append('assertion', oAuthorization.token.accessToken); /// Send original JWT token to connectivity service

var response = await axios({
method: "post",
url: oConnectivityServiceCredentials.token_service_url + "/oauth/token",
params: params,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json"
}
});

var userExchangeToken = response.data.access_token;

req.headers('Proxy-Authorization', userExchangeToken); // Add JWT Exchange token to the original request

next(); /// Release the request with the new header

} catch (error) {

console.log(error);
res.end(JSON.stringify(error));
}

} else {
next();
return;
}


});
ar.start();

I hope you find this code useful whenever you want to implement Principal propagation via User Exchange token flow in your Cloud Foundry projects.

Thanks!
4 Comments
Labels in this area