use of org.kuali.kfs.kim.api.role.RoleMembership in project cu-kfs by CU-CommunityApps.
the class RoleServiceImpl method resolveDelegationMemberRoles.
/**
* Once the delegations for a RoleMembershipInfo object have been determined, any "role" member types need to be
* resolved into groups and principals so that further KIM requests are not needed.
*/
protected void resolveDelegationMemberRoles(List<RoleMembership.Builder> membershipBuilders, Map<String, String> qualification, Set<String> foundRoleTypeMembers) {
// check delegations assigned to this role
for (RoleMembership.Builder roleMembership : membershipBuilders) {
// this code examines those delegations and obtains the member groups and principals
for (DelegateType delegation : roleMembership.getDelegates()) {
List<DelegateMember> newMembers = new ArrayList<>();
for (DelegateMember member : delegation.getMembers()) {
if (MemberType.ROLE.equals(member.getType())) {
// loop over delegation roles and extract the role IDs where the qualifications match
Collection<RoleMembership> delegateMembers = getRoleMembers(Collections.singletonList(member.getMemberId()), qualification, false, foundRoleTypeMembers);
// loop over the role members and create the needed DelegationMember builders
for (RoleMembership rmi : delegateMembers) {
DelegateMember delegateMember = new DelegateMember();
KimCommonUtilsInternal.copyProperties(delegateMember, member);
delegateMember.setMemberId(rmi.getMemberId());
delegateMember.setType(rmi.getType());
newMembers.add(delegateMember);
}
} else {
newMembers.add(member);
}
}
delegation.setDelegationMembers(newMembers);
}
}
}
use of org.kuali.kfs.kim.api.role.RoleMembership in project cu-kfs by CU-CommunityApps.
the class RoleServiceImpl method getNestedRoleMembers.
protected Collection<RoleMembership> getNestedRoleMembers(Map<String, String> qualification, RoleMembership rm, Set<String> foundRoleTypeMembers) {
// If this role has already been traversed, skip it
if (foundRoleTypeMembers.contains(rm.getMemberId())) {
return new ArrayList<>();
}
foundRoleTypeMembers.add(rm.getMemberId());
ArrayList<String> roleIdList = new ArrayList<>(1);
roleIdList.add(rm.getMemberId());
// get the list of members from the nested role - ignore delegations on those sub-roles
Collection<RoleMembership> currentNestedRoleMembers = getRoleMembers(roleIdList, qualification, false, foundRoleTypeMembers);
// add the roles whose members matched to the list for delegateType checks later
Collection<RoleMembership> returnRoleMembers = new ArrayList<>();
for (RoleMembership roleMembership : currentNestedRoleMembers) {
RoleMembership.Builder rmBuilder = RoleMembership.Builder.create(roleMembership);
// use the member ID of the parent role (needed for responsibility joining)
rmBuilder.setId(rm.getId());
// store the role ID, so we know where this member actually came from
rmBuilder.setRoleId(rm.getRoleId());
rmBuilder.setEmbeddedRoleId(rm.getMemberId());
returnRoleMembers.add(rmBuilder.build());
}
return returnRoleMembers;
}
use of org.kuali.kfs.kim.api.role.RoleMembership in project cu-kfs by CU-CommunityApps.
the class RoleServiceImpl method principalHasRole.
protected boolean principalHasRole(Context context, String principalId, List<String> roleIds, Map<String, String> qualification, boolean checkDelegations) {
/*
* This method uses a multi-phase approach to determining if the given principal of any of the roles given
* based on the qualification map that is passed.
*
* Phase 1: Check the cache to find if it's already been determined that the principal is a member of any of
* the roles with the given ids.
* Phase 2: Perform exact database-level matching. This can be done for all roles if the given qualification
* map is null or empty since that means qualification matching does not need to be performed. It can
* also be done for roles who's RoleTypeService defines qualifiers for exact match.
* Phase 3: Use RoleTypeService matching for roles which have not already been checked. Will need to determine
* which role memberships match the given principal then delegate to the appropriate RoleTypeService
* to execute matching logic.
* Phase 4: Check nested roles.
* Phase 5: For any cases where derived roles are used, determine if the principal is a member of those
* derived roles.
* Phase 6: If checkDelegations is true, check if any delegations match
*/
try {
// Phase 1: first check if any of the role membership is cached, only proceed with checking the role ids
// that aren't already cached
List<String> roleIdsToCheck = new ArrayList<>(roleIds.size());
for (String roleId : roleIds) {
Boolean hasRole = getPrincipalHasRoleFromCache(principalId, roleId, qualification, checkDelegations);
if (hasRole != null) {
if (hasRole) {
return true;
}
} else {
roleIdsToCheck.add(roleId);
}
}
// load the roles, this will also filter out inactive roles!
List<RoleLite> roles = loadRoles(roleIdsToCheck);
// short-circuit if no roles match
if (roles.isEmpty()) {
return false;
}
// Phase 2: If they didn't pass any qualifications or they are using exact qualifier matching, we can go
// straight to the database
Set<String> rolesCheckedForExactMatch = new HashSet<>();
for (RoleLite role : roles) {
Map<String, String> qualificationForExactMatch = null;
if (qualification == null || qualification.isEmpty()) {
qualificationForExactMatch = new HashMap<>();
} else {
RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
if (roleTypeService != null) {
List<String> attributesForExactMatch = getQualifiersForExactMatch(role.getKimTypeId(), roleTypeService);
if (CollectionUtils.isNotEmpty(attributesForExactMatch)) {
qualificationForExactMatch = populateQualifiersForExactMatch(qualification, attributesForExactMatch);
if (qualificationForExactMatch.isEmpty()) {
// go onto the next role.
continue;
}
}
}
}
if (qualificationForExactMatch != null) {
rolesCheckedForExactMatch.add(role.getId());
List<RoleMember> matchingRoleMembers = getStoredRolePrincipalsForPrincipalIdAndRoleIds(Collections.singletonList(role.getId()), principalId, qualificationForExactMatch);
// if a role member matched our principal, we're good to go
if (CollectionUtils.isNotEmpty(matchingRoleMembers)) {
return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
}
// now check groups
if (!context.getPrincipalGroupIds().isEmpty()) {
List<RoleMember> matchingRoleGroupMembers = getStoredRoleGroupsUsingExactMatchOnQualification(context.getPrincipalGroupIds(), role.getId(), qualification);
if (CollectionUtils.isNotEmpty(matchingRoleGroupMembers)) {
return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
}
}
// if we drop to this point, either we didn't match or the role has nested or derived role
// membership, we'll check that later
}
}
for (RoleLite role : roles) {
// if we didn't do an exact match, we need to do a manual match
if (!rolesCheckedForExactMatch.contains(role.getId())) {
List<RoleMember> matchingPrincipalRoleMembers = getRoleMembersForPrincipalId(role.getId(), principalId);
List<RoleMember> matchingGroupRoleMembers = getRoleMembersForGroupIds(role.getId(), context.getPrincipalGroupIds());
List<RoleMembership> roleMemberships = convertToRoleMemberships(matchingPrincipalRoleMembers, matchingGroupRoleMembers);
for (RoleMembership roleMembership : roleMemberships) {
try {
RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
if (!roleTypeService.getMatchingRoleMemberships(qualification, roleMemberships).isEmpty()) {
return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
}
} catch (Exception ex) {
LOG.warn("Unable to find role type service with id: " + role.getKimTypeId());
}
}
}
}
// Phase 4: If we have nested roles, execute a recursive check on those
// first, check that the qualifiers on the role membership match then, perform a principalHasRole on the
// embedded role
Map<String, RoleLite> roleIndex = new HashMap<>();
for (RoleLite role : roles) {
roleIndex.put(role.getId(), role);
}
List<RoleMember> roleMembers = getStoredRoleMembersForRoleIds(new ArrayList<>(roleIndex.keySet()), MemberType.ROLE.getCode(), null);
for (RoleMember roleMember : roleMembers) {
RoleLite role = roleIndex.get(roleMember.getRoleId());
RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
if (roleTypeService != null) {
// it can't be guaranteed that it is up and working, so using a try/catch to catch this possibility.
try {
if (roleTypeService.doesRoleQualifierMatchQualification(qualification, roleMember.getAttributes())) {
RoleLite memberRole = getRoleLite(roleMember.getMemberId());
Map<String, String> nestedRoleQualification = roleTypeService.convertQualificationForMemberRoles(role.getNamespaceCode(), role.getName(), memberRole.getNamespaceCode(), memberRole.getName(), qualification);
if (principalHasRole(context, principalId, Collections.singletonList(roleMember.getMemberId()), nestedRoleQualification, true)) {
return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
}
}
} catch (Exception ex) {
LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + roleMember.getRoleId(), ex);
}
} else {
// no role type service, so can't convert qualification - just pass as is
if (principalHasRole(context, principalId, Collections.singletonList(roleMember.getMemberId()), qualification, true)) {
return putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
}
}
}
// external system (application)
for (RoleLite role : roles) {
// to catch this possibility.
try {
boolean isDerivedRoleType = context.isDerivedRoleType(role.getKimTypeId());
if (isDerivedRoleType) {
RoleTypeService roleTypeService = context.getRoleTypeService(role.getKimTypeId());
if (roleTypeService.hasDerivedRole(principalId, context.getPrincipalGroupIds(), role.getNamespaceCode(), role.getName(), qualification)) {
if (!roleTypeService.dynamicRoleMembership(role.getNamespaceCode(), role.getName())) {
putPrincipalHasRoleInCache(true, principalId, role.getId(), qualification, checkDelegations);
}
return true;
}
} else {
if (!checkDelegations) {
putPrincipalHasRoleInCache(false, principalId, role.getId(), qualification, false);
}
}
} catch (Exception ex) {
LOG.warn("Not able to retrieve RoleTypeService from remote system for role Id: " + role.getId(), ex);
}
}
if (checkDelegations) {
if (matchesOnDelegation(roleIndex.keySet(), principalId, context.getPrincipalGroupIds(), qualification, context)) {
return true;
}
}
} catch (Exception e) {
LOG.warn("Caught exception during a principalHasRole check", e);
}
return false;
}
use of org.kuali.kfs.kim.api.role.RoleMembership in project cu-kfs by CU-CommunityApps.
the class RoleServiceImpl method getRoleMemberPrincipalIds.
// backport redis annotations
@Cacheable(cacheNames = RoleMember.CACHE_NAME, key = "'namespaceCode=' + #p0 + '|' + 'roleName=' + #p1 + '|' + 'qualification=' +" + "T(org.kuali.kfs.core.api.cache.CacheKeyUtils).mapKey(#p2)", condition = "!T(org.kuali.kfs.kim.api.cache.KimCacheUtils).isDynamicMembshipRoleByNamespaceAndName(#p0, #p1)")
@Override
public Collection<String> getRoleMemberPrincipalIds(String namespaceCode, String roleName, Map<String, String> qualification) throws IllegalStateException {
incomingParamCheck(namespaceCode, "namespaceCode");
incomingParamCheck(roleName, "roleName");
Set<String> principalIds = new HashSet<>();
Set<String> foundRoleTypeMembers = new HashSet<>();
List<String> roleIds = Collections.singletonList(getRoleIdByNamespaceCodeAndName(namespaceCode, roleName));
for (RoleMembership roleMembership : getRoleMembers(roleIds, qualification, false, foundRoleTypeMembers)) {
if (MemberType.GROUP.equals(roleMembership.getType())) {
principalIds.addAll(getGroupService().getMemberPrincipalIds(roleMembership.getMemberId()));
} else {
principalIds.add(roleMembership.getMemberId());
}
}
return Collections.unmodifiableSet(principalIds);
}
Aggregations