Hello everyone,
Before we dive into the technical stuff, let me explain a few essential BTP Security Concepts briefly. It's good to be familiar with these concepts to understand the process better. If you already know them, feel free to jump straight to the main part of the blog, where I'll show you how to get the Current Logged-on User Details in various technologies from BTP.
The Reason Behind This Blog Post:
You might be wondering why I'm writing about something that already has a lot of information available. Well, the existing content mostly covers older libraries, and with the latest SAP Cloud Security 3.X Library, things have changed.
So, I want to demonstrate the most up-to-date approaches to help you stay current with the best practices in BTP Security.
Now, let's break down what this blog post will cover into three parts:
Additionally, I aim to make this blog post your go-to resource for getting Logged-in user details for CAP, NodeJS, SAPUI5/HTML-based applications from BTP.
SAP BTP Identity Providers:
Advantages of Using SAP IAS for SaaS Applications:
Authorization and Trust Management (XSUAA):
Application Router (APPRouter):
Managed Application Router:
For detailed information, refer to the official SAP Help :
No. | Successor | Description |
---|---|---|
1 | SAP Authorization and Trust Management Service in the Cloud Foundry Environment | Use SAP ID service as a pre-configured easy-to-use identity provider. Switch to your corporate identity provider for customized user management. Additional Information: Platform API Overview |
2 | Identity Directory Service API Information published on SAP site | A comprehensive Cloud Identity suite of services such as Identity Authentication or Identity Provisioning. To secure cloud-based access to business processes, applications, and data. It simplifies your user experience through state-of-the-art authentication mechanisms, secure single sign-on, on-premise integration, and convenient self-service options. Identity Authentication provides implementation for the System for Cross-domain Identity Management. IAS can provide central Authentication and SSO. Customers can have only one IAS tenant. Hence all the SAP cloud solution as well as BTP will be integrated with the same IAS tenant. Now, IAS itself has capabilities to have user details including roles, user group, etc. While implementing SSO and application security, we can map a BTP role collection to a user group based on which user authorization works.Additional Information:For detailed information, refer to the official SAP Help :Cloud Identity Services CommunityBlog Links:SAP BTP Security: How to Handle Authorization and Attributes with XSUAA and IAS |
<groupId>com.sap.cloud.security.xsuaa</groupId>
<artifactId>spring-xsuaa</artifactId>
Deprecated | Successor |
---|---|
|
|
Further information:Please use the following link to find further information on the topics above:
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.sap.cloud.security</groupId>
<artifactId>resourceserver-security-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.sap.cloud.security.xsuaa</groupId>
<artifactId>spring-security-compatibility</artifactId>
</dependency>
<!-- OAuth2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
import com.sap.cloud.security.spring.token.SpringSecurityContext; //new
import com.sap.cloud.security.token.SecurityContext;//new
import com.sap.cloud.security.token.Token;//new
//import com.sap.cloud.security.token.XsuaaTokenComp; or
import com.sap.cloud.security.token.TokenClaims;//new
....
// Sample Method
@GetMapping("v1/currentUserDetails")
@ResponseBody
public ResponseEntity<?> LoginUserDetailsFromAuthenticationPrincipaAl(@AuthenticationPrincipal Token token) {
HashMap<String, String> mapCurrentUser = new HashMap<String, String>();
mapCurrentUser.put("userid", token.getClaimAsString(TokenClaims.USER_NAME));
mapCurrentUser.put("email", token.getClaimAsString(TokenClaims.EMAIL));
String audienceList = StringUtils
.join(token.getClaimAsStringList(TokenClaims.AUDIENCE));
mapCurrentUser.put("audienceList", audienceList);
mapCurrentUser.put("SAPUserID", token.getClaimAsString(TokenClaims.SAP_GLOBAL_USER_ID));
mapCurrentUser.put("xsuaaClientID",
token.getClaimAsString(TokenClaims.XSUAA.CLIENT_ID));
String scopesList = StringUtils
.join(token.getClaimAsStringList(TokenClaims.XSUAA.SCOPES));
mapCurrentUser.put("xsuaaScopesList", scopesList);
mapCurrentUser.put("xsuaaOrigin", token.getClaimAsString(TokenClaims.XSUAA.ORIGIN));
return new ResponseEntity<>(mapCurrentUser, HttpStatus.OK);
}
import com.sap.cloud.security.token.AccessToken;
import com.sap.cloud.security.token.SecurityContext;
import com.sap.cloud.security.token.TokenClaims;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class DemoJavaServlet extends HttpServlet {
static final String ENDPOINT = "/hello-java-security";
private static final Logger LOGGER = LoggerFactory.getLogger(DemoJavaServlet.class);
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
response.setContentType("text/plain");
// same like SecurityContext.getToken() but more XSUAA specific methods
// Same like SecurityContext.getToken() but more XSUAA specific methods
// SecurityContext.getToken()
AccessToken token = SecurityContext.getAccessToken();
String message= "";
try {
message = "You ('" + token.getClaimAsString(TokenClaims.EMAIL) +
"') can access the application with the following scopes: '" +
token.getClaimAsStringList(TokenClaims.XSUAA.SCOPES) + "'. " +
// for authorization check you need the AccessToken interface (instead of Token)
" Having scope '$XSAPPNAME.Read'? " + token.hasLocalScope("display") +
" USER_NAME = " + token.getClaimAsString(TokenClaims.USER_NAME) +
" SAP_GLOBAL_USER_ID = " + token.getClaimAsString(TokenClaims.SAP_GLOBAL_USER_ID);
} catch (final Exception ex) {
LOGGER.error("Failed to write error response: {}.", ex.getMessage(), ex);
throw ex;
}
}
}
{
"SAPUserID": null,
"audienceList": "sb-xsac-showkathBTPdemo!t99486,uaa,openid,xsac-showkathBTPdemo!99486",
"userid": "P99486", (The user ID in the identity provider),
"xsuaaOrigin": "httpsaccounts400.sap.com", (The Origin in the identity provider),
"email": "john.doe@sap.com",
"xsuaaScopesList": "xsac-showkathBTPdemo!t99486.admin,xsac-showkathBTPdemo!t99486.read,openid,xsac-showkathBTPdemo!t99486.administrator,uaa.user",(Only if the authentication type is “xsuaa")
"xsuaaClientID": "sb-showkathBTPdemo!t99486"(Only if the authentication type is “xsuaa")
}
When running your CAP application, there are multiple types of Authentication Strategies available:
Token-Based Authentication (JWT) is used when your application is deployed to Cloud Foundry. It can easily be integrated with XSUAA. Dummy Authentication may be used to temporarily disable authentication, e.g. during integration tests. Mocked Authentication is the primary choice for development. It allows us to define users locally using passport and easily test the behavior of our different roles.
Users may be assigned to User Roles that are either pseudo-roles (authenticated-user, any,..) or map to local/XSUAA roles (admin, employee...). Static Restrictions can be used to restrict allowed operations (e.g. @readonly, @Capabilities{...},...). User specific restrictions (@requires / @restrict) allow you to restrict data to individual users. These restrictions usually contain predicate privileges, that are defined using a where clauses based on attributes of the currently logged-in user.
@restrict: [
{ grant: 'CREATE', to: 'authenticated-user',
where: '$user.country = ''DE''' }
]
For detailed information, you can follow the excellent documentation in the CAP source:
Make sure your service is annotated with @(requires:'authenticated-user')
Example
service CurrentUserProfileService @(requires: 'authenticated-user') {
In CAP Node.js, you get the ID of the current user from req.user.id
as shown in the example below:
module.exports = srv => {
const { Projects } = srv.entities
srv.before(['CREATE', 'READ', 'UPDATE', 'DELETE'], 'CurrentUserProfile',
(req) => {
const currentLoggedonUser = [
{
id: req.user.id,
email: req.req.authInfo.getEmail(),
username:
req.req.authInfo.getGivenName() +
" " +
req.req.authInfo.getFamilyName(),
roles: roles
},
];
return currentLoggedonUser;
});
}
For a detailed example, you can also refer to the following blog post:
This section provides valuable insights into obtaining the Current User in CAP Java applications.
The Request Context provides information about the request's parameters as well as the current user:
UserInfo: Exposes an API to fetch data of the (authenticated) user such as the logon name, id, CAP roles, and the tenant.
import cds.gen.Requestservice.CurrentUserContext;
//...
@On(event = "currentUser")
public void currentUser(CurrentUserContext context) {
UserInfo userInfo = context.getUserInfo();
boolean isAuthenticated = userInfo.isAuthenticated();
String uName = uI.getName();
// ...
}
To establish type-safe access, additional attributes may also be accessed via custom extensions of UserInfo. To map XSUAA users, the interface XsuaaUserInfo is available by default. You can create XsuaaUserInfo instances either by calling userInfo.as(XsuaaUserInfo.class) or by Spring injection:
@Autowired
XsuaaUserInfo xsuaaUserInfo;
@Before(event = CqnService.EVENT_READ)
public void beforeRead() {
boolean isAuthenticated = xsuaaUserInfo.isAuthenticated();
String email = xsuaaUserInfo.getEmail();
String givenName = xsuaaUserInfo.getGivenName();
// ...
}
For more details, please follow the instructions in the
In this section, I will guide you on how to access the Current Logged-on User Details for different application types, such as APPRouter, SAPUI5, and NodeJS.
{
"source": "^/user-api/currentUser$",
"target": "/currentUser",
"service": "sap-approuter-userapi"
}
{
"csrfProtection": false,
"source": "^/user-api(.*)",
"target": "$1",
"service": "sap-approuter-userapi",
"authenticationType": "xsuaa"
}
//Sample code
$.ajax({
"url": "/userapi/currentUser",
async: false,
success: jQuery.proxy(function (user) {
var currentUser = {
fullName: user.lastName + ", " + user.firstName,
userId: user.name,
};
//Here you can also set object to your oData Model
...
});
}
For more information and detailed implementation, you can refer to the following resources:
The User API service provides an API to query the details of the user that is currently logged on to the HTML5 application. The retrieved user details may include:
{
"firstname": "John",
"lastname": "Doe",
"email": "john.doe@sap.com",
"name": "john.doe@sap.com",
"displayName": "John Doe (john.doe@sap.com)", (The user ID in the identity provider),
"scopes": ["openid","user_attributes","uaa.user"] (Only if the authentication type is “xsuaa")
}
With this information, you can efficiently manage user authentication and tailor the user experience in your applications.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
30 | |
19 | |
10 | |
10 | |
8 | |
7 | |
7 | |
7 | |
7 | |
6 |