com.sap.cloud.security.ams.capsupport.UserInfoProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cap-support Show documentation
Show all versions of cap-support Show documentation
Client Library for integrating SAP CAP applications with SAP Authorization Management Service (AMS)
The newest version!
/************************************************************************
* © 2019-2023 SAP SE or an SAP affiliate company. All rights reserved. *
************************************************************************/
package com.sap.cloud.security.ams.capsupport;
import java.util.*;
import java.util.concurrent.TimeUnit;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sap.cds.services.request.ModifiableUserInfo;
import com.sap.cds.services.request.UserInfo;
import com.sap.cds.services.utils.CdsErrorStatuses;
import com.sap.cds.services.utils.ErrorStatusException;
import com.sap.cloud.security.ams.dcl.client.el.AttributeName;
import com.sap.cloud.security.ams.dcl.client.el.Call;
import com.sap.cloud.security.ams.dcl.client.el.FilterClause;
import com.sap.cloud.security.ams.dcl.client.el.Visitor;
import com.sap.cloud.security.ams.dcl.client.pdp.Attributes;
import com.sap.cloud.security.ams.dcl.client.pdp.PolicyDecisionPoint;
import com.sap.cloud.security.ams.dcl.client.pdp.PolicyEvaluationException;
/**
* The AMS UserInfoProvider retrieves roles assigned to the user by AMS policies using
* `GRANT {role} ON $SCOPES` and adds them to the current UserInfo.
*/
@Deprecated
public class UserInfoProvider implements com.sap.cds.services.runtime.UserInfoProvider { // NOSONAR
private static final Logger logger = LoggerFactory.getLogger(UserInfoProvider.class);
private com.sap.cds.services.runtime.UserInfoProvider previous;
private final PolicyDecisionPoint pdp;
private final TokenServices tokenServices;
private final Cache> roleCache;
public UserInfoProvider(PolicyDecisionPoint pdp, TokenServices tokenServices) {
this(pdp, tokenServices, CacheBuilder.newBuilder().expireAfterWrite(20, TimeUnit.SECONDS).maximumSize(10000).build());
}
public UserInfoProvider(PolicyDecisionPoint pdp, TokenServices tokenServices, Cache> cache) {
this.pdp = pdp;
this.tokenServices = tokenServices;
this.roleCache = cache;
}
@Override
public void setPrevious(com.sap.cds.services.runtime.UserInfoProvider previous) {
this.previous = previous;
}
@Override
public UserInfo get() {
logger.debug("Get enhanced user info.");
UserInfo previousUser;
if (previous != null) {
previousUser = previous.get();
} else {
return null;
}
if (previousUser != null && previousUser.getId() != null) {
ModifiableUserInfo amsUserInfo = tokenServices.getModeDependingUserInfo(previousUser);
String tenant = TokenServices.getTenant(amsUserInfo);
String userId = TokenServices.getScimId(amsUserInfo);
String cacheKey = tenant + userId;
logger.debug("User tenant:{}, user id:{}", tenant, userId);
Set userRoles;
userRoles = roleCache.getIfPresent(cacheKey);
if (userRoles == null) {
try {
FilterClause filterClause = pdp
.allowFilterClause(createCallAttributes(tenant, userId));
logger.debug("PDP response:{}", filterClause);
RoleExtractingVisitor v = new RoleExtractingVisitor();
Visitor.accept(v, filterClause);
userRoles = v.getResult();
roleCache.put(cacheKey, userRoles);
} catch (PolicyEvaluationException e) {
throw new ErrorStatusException(CdsErrorStatuses.EVENT_FORBIDDEN, e.getMessage());
}
}
userRoles.forEach(amsUserInfo::addRole);
return amsUserInfo;
} else {
logger.debug("No previous user info or userId found. Check the authentication and configuration of the UserInfoProvider chain.");
}
return previousUser;
}
private static final List SCOPES_UNKNOWNS = Collections.singletonList(Attributes.Names.DCL_ACTION);
private static final List SCOPES_IGNORES = Arrays.asList(Attributes.Names.APP, Attributes.Names.ENV);
private Attributes createCallAttributes(String zoneId, String userId) {
Attributes result = CapSupportServices.createBaseCallAttributes(zoneId, userId);
result.setResource("$SCOPES");
result.setIgnores(SCOPES_IGNORES);
result.setUnknowns(SCOPES_UNKNOWNS);
return result;
}
static class RoleExtractingVisitor extends Visitor {
private static final String[] CAP_PSEUDO_ROLES = new String[] { "any", "authenticated-user", "internal-user", "system-user" };
private final Set roles;
RoleExtractingVisitor() {
roles = new HashSet<>();
}
public Set getResult() {
return this.roles;
}
@Override
public void visit(Call it) {
super.visit(it);
if (Call.Names.EQ.equals(it.getName()) && it.getArgumentCount() == 2) {
Object arg0 = it.getArgument(0);
Object arg1 = it.getArgument(1);
String role = null;
if (Attributes.Names.DCL_ACTION.equals(arg0)) {
role = (String) arg1;
} else if (Attributes.Names.DCL_ACTION.equals(arg1)) {
role = (String) arg0;
}
if (role != null && !isPseudoRole(role)) {
roles.add(role);
}
}
}
private static boolean isPseudoRole(String role) {
return Arrays.asList(CAP_PSEUDO_ROLES).contains(role.toLowerCase());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy