io.gravitee.rest.api.service.impl.MembershipServiceImpl Maven / Gradle / Ivy
/**
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.gravitee.rest.api.service.impl;
import static io.gravitee.repository.management.model.Membership.AuditEvent.MEMBERSHIP_CREATED;
import static io.gravitee.repository.management.model.Membership.AuditEvent.MEMBERSHIP_DELETED;
import static io.gravitee.rest.api.model.permissions.SystemRole.PRIMARY_OWNER;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singleton;
import static java.util.stream.Collectors.toList;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import io.gravitee.common.data.domain.Page;
import io.gravitee.repository.exceptions.TechnicalException;
import io.gravitee.repository.management.api.ApiRepository;
import io.gravitee.repository.management.api.ApplicationRepository;
import io.gravitee.repository.management.api.MembershipRepository;
import io.gravitee.repository.management.api.search.ApiCriteria;
import io.gravitee.repository.management.api.search.ApiFieldExclusionFilter;
import io.gravitee.repository.management.model.Audit;
import io.gravitee.repository.management.model.Membership;
import io.gravitee.rest.api.model.*;
import io.gravitee.rest.api.model.api.ApiEntity;
import io.gravitee.rest.api.model.common.Pageable;
import io.gravitee.rest.api.model.common.PageableImpl;
import io.gravitee.rest.api.model.pagedresult.Metadata;
import io.gravitee.rest.api.model.permissions.RoleScope;
import io.gravitee.rest.api.model.permissions.SystemRole;
import io.gravitee.rest.api.model.providers.User;
import io.gravitee.rest.api.service.*;
import io.gravitee.rest.api.service.builder.EmailNotificationBuilder;
import io.gravitee.rest.api.service.common.GraviteeContext;
import io.gravitee.rest.api.service.common.RandomString;
import io.gravitee.rest.api.service.exceptions.*;
import io.gravitee.rest.api.service.notification.NotificationParamsBuilder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Nicolas GERAUD (nicolas.geraud at graviteesource.com)
* @author GraviteeSource Team
*/
@Component
public class MembershipServiceImpl extends AbstractService implements MembershipService {
private static final Logger LOGGER = LoggerFactory.getLogger(MembershipServiceImpl.class);
private static final String DEFAULT_SOURCE = "system";
@Autowired
private UserService userService;
@Autowired
private EmailService emailService;
@Autowired
private IdentityService identityService;
@Autowired
private MembershipRepository membershipRepository;
@Autowired
private RoleService roleService;
@Autowired
private ApplicationService applicationService;
@Autowired
private ApiService apiService;
@Autowired
private GroupService groupService;
@Autowired
private AuditService auditService;
@Autowired
private ApiRepository apiRepository;
@Autowired
private ApplicationRepository applicationRepository;
@Autowired
private NotifierService notifierService;
private final Cache> roles = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build();
@Override
public MemberEntity addRoleToMemberOnReference(
MembershipReferenceType referenceType,
String referenceId,
MembershipMemberType memberType,
String memberId,
String role
) {
return addRoleToMemberOnReference(referenceType, referenceId, memberType, memberId, role, DEFAULT_SOURCE);
}
@Override
public MemberEntity addRoleToMemberOnReference(
MembershipReferenceType referenceType,
String referenceId,
MembershipMemberType memberType,
String memberId,
String role,
String source
) {
RoleEntity roleToAdd = roleService.findById(role);
return _addRoleToMemberOnReference(
new MembershipReference(referenceType, referenceId),
new MembershipMember(memberId, null, memberType),
new MembershipRole(roleToAdd.getScope(), roleToAdd.getName()),
source,
true
);
}
@Override
public MemberEntity addRoleToMemberOnReference(MembershipReference reference, MembershipMember member, MembershipRole role) {
return _addRoleToMemberOnReference(reference, member, role, DEFAULT_SOURCE, true);
}
private MemberEntity _addRoleToMemberOnReference(
MembershipReference reference,
MembershipMember member,
MembershipRole role,
String source,
boolean notify
) {
try {
LOGGER.debug("Add a new member for {} {}", reference.getType(), reference.getId());
assertRoleScopeAllowedForReference(reference, role);
assertRoleNameAllowedForReference(reference, role);
Optional optRole = roleService.findByScopeAndName(role.getScope(), role.getName());
if (optRole.isPresent()) {
if (member.getMemberId() != null) {
Set similarMemberships = membershipRepository.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceIdAndRoleId(
member.getMemberId(),
convert(member.getMemberType()),
convert(reference.getType()),
reference.getId(),
optRole.get().getId()
);
if (!similarMemberships.isEmpty()) {
throw new MembershipAlreadyExistsException(
member.getMemberId(),
member.getMemberType(),
reference.getId(),
reference.getType()
);
}
}
Date updateDate = new Date();
MemberEntity userMember = null;
if (member.getMemberType() == MembershipMemberType.USER) {
UserEntity userEntity = findUserFromMembershipMember(member);
io.gravitee.repository.management.model.Membership membership = new io.gravitee.repository.management.model.Membership(
RandomString.generate(),
userEntity.getId(),
convert(member.getMemberType()),
reference.getId(),
convert(reference.getType()),
optRole.get().getId()
);
membership.setSource(source);
membership.setCreatedAt(updateDate);
membership.setUpdatedAt(updateDate);
membershipRepository.create(membership);
createAuditLog(MEMBERSHIP_CREATED, membership.getCreatedAt(), null, membership);
Set userRolesOnReference = membershipRepository.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceId(
userEntity.getId(),
convert(member.getMemberType()),
convert(reference.getType()),
reference.getId()
);
boolean shouldNotify =
notify &&
userRolesOnReference != null &&
userRolesOnReference.size() == 1 &&
userEntity.getEmail() != null &&
!userEntity.getEmail().isEmpty();
if (shouldNotify) {
if (MembershipReferenceType.GROUP.equals(reference.getType())) {
final GroupEntity group = groupService.findById(reference.getId());
shouldNotify = !group.isDisableMembershipNotifications();
} else if (MembershipReferenceType.API.equals(reference.getType())) {
final ApiEntity api = apiService.findById(reference.getId());
shouldNotify = !api.isDisableMembershipNotifications();
} else if (MembershipReferenceType.APPLICATION.equals(reference.getType())) {
final ApplicationEntity application = applicationService.findById(reference.getId());
shouldNotify = !application.isDisableMembershipNotifications();
}
}
if (shouldNotify) {
EmailNotification emailNotification = buildEmailNotification(userEntity, reference.getType(), reference.getId());
if (emailNotification != null) {
emailService.sendAsyncEmailNotification(emailNotification, GraviteeContext.getCurrentContext());
}
}
userMember = getUserMember(reference.getType(), reference.getId(), userEntity.getId());
} else {
io.gravitee.repository.management.model.Membership membership = new io.gravitee.repository.management.model.Membership(
RandomString.generate(),
member.getMemberId(),
convert(member.getMemberType()),
reference.getId(),
convert(reference.getType()),
optRole.get().getId()
);
membership.setSource(source);
membership.setCreatedAt(updateDate);
membership.setUpdatedAt(updateDate);
membershipRepository.create(membership);
createAuditLog(MEMBERSHIP_CREATED, membership.getCreatedAt(), null, membership);
}
roles.invalidate(reference.getType().name() + reference.getId() + member.getMemberType() + member.getMemberId());
return userMember;
}
return null;
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to add member for {} {}", reference.getType(), reference.getId(), ex);
throw new TechnicalManagementException(
"An error occurs while trying to add member for " + reference.getType() + " " + reference.getId(),
ex
);
}
}
private void createAuditLog(
Audit.AuditEvent event,
Date date,
io.gravitee.repository.management.model.Membership oldValue,
io.gravitee.repository.management.model.Membership newValue
) {
io.gravitee.repository.management.model.MembershipReferenceType referenceType = oldValue != null
? oldValue.getReferenceType()
: newValue.getReferenceType();
String referenceId = oldValue != null ? oldValue.getReferenceId() : newValue.getReferenceId();
String username = oldValue != null ? oldValue.getMemberId() : newValue.getMemberId();
Map properties = new HashMap<>();
properties.put(Audit.AuditProperties.USER, username);
switch (referenceType) {
case API:
auditService.createApiAuditLog(referenceId, properties, event, date, oldValue, newValue);
break;
case APPLICATION:
auditService.createApplicationAuditLog(referenceId, properties, event, date, oldValue, newValue);
break;
case GROUP:
properties.put(Audit.AuditProperties.GROUP, referenceId);
auditService.createEnvironmentAuditLog(properties, event, date, oldValue, newValue);
break;
case ENVIRONMENT:
auditService.createEnvironmentAuditLog(properties, event, date, oldValue, newValue);
break;
case ORGANIZATION:
auditService.createOrganizationAuditLog(properties, event, date, oldValue, newValue);
break;
}
}
private EmailNotification buildEmailNotification(UserEntity user, MembershipReferenceType referenceType, String referenceId) {
EmailNotificationBuilder.EmailTemplate template = null;
Map params = null;
GroupEntity groupEntity;
NotificationParamsBuilder paramsBuilder = new NotificationParamsBuilder();
switch (referenceType) {
case APPLICATION:
ApplicationEntity applicationEntity = applicationService.findById(referenceId);
template = EmailNotificationBuilder.EmailTemplate.TEMPLATES_FOR_ACTION_APPLICATION_MEMBER_SUBSCRIPTION;
params = paramsBuilder.application(applicationEntity).user(user).build();
break;
case API:
ApiEntity apiEntity = apiService.findById(referenceId);
template = EmailNotificationBuilder.EmailTemplate.TEMPLATES_FOR_ACTION_API_MEMBER_SUBSCRIPTION;
params = paramsBuilder.api(apiEntity).user(user).build();
break;
case GROUP:
groupEntity = groupService.findById(referenceId);
template = EmailNotificationBuilder.EmailTemplate.TEMPLATES_FOR_ACTION_GROUP_MEMBER_SUBSCRIPTION;
params = paramsBuilder.group(groupEntity).user(user).build();
break;
default:
break;
}
if (template == null) {
return null;
}
return new EmailNotificationBuilder().to(user.getEmail()).template(template).params(params).build();
}
private MemberEntity convertToMemberEntity(io.gravitee.repository.management.model.Membership membership) {
final MemberEntity member = new MemberEntity();
member.setId(membership.getMemberId());
member.setCreatedAt(membership.getCreatedAt());
member.setUpdatedAt(membership.getUpdatedAt());
member.setReferenceId(membership.getReferenceId());
member.setReferenceType(convert(membership.getReferenceType()));
if (membership.getRoleId() != null) {
RoleEntity role = roleService.findById(membership.getRoleId());
member.setPermissions(role.getPermissions());
List roles = new ArrayList<>();
roles.add(role);
member.setRoles(roles);
}
return member;
}
private void fillMemberUserInformation(
Set memberships,
List members
) {
if (memberships != null && !memberships.isEmpty()) {
Set userEntities = userService.findByIds(members.stream().map(MemberEntity::getId).collect(toList()), false);
members.forEach(
m -> {
Optional membership = memberships
.stream()
.filter(ms -> ms.getMemberId().equals(m.getId()))
.findFirst();
membership.ifPresent(
ms -> {
Optional user = userEntities.stream().filter(u -> u.getId().equals(ms.getMemberId())).findFirst();
user.ifPresent(
u -> {
m.setDisplayName(u.getDisplayName());
m.setEmail(u.getEmail());
}
);
}
);
}
);
}
}
private UserEntity findUserFromMembershipMember(MembershipMember member) {
UserEntity userEntity;
if (member.getMemberId() != null) {
userEntity = userService.findById(member.getMemberId());
} else {
// We have a user reference, meaning that the user is coming from an external system
// User does not exist so we are looking into defined providers
Optional providerUser = identityService.findByReference(member.getReference());
if (providerUser.isPresent()) {
User identityUser = providerUser.get();
userEntity = findOrCreateUser(identityUser);
} else {
throw new UserNotFoundException(member.getReference());
}
}
return userEntity;
}
private UserEntity findOrCreateUser(User identityUser) {
UserEntity userEntity;
try {
userEntity = userService.findBySource(identityUser.getSource(), identityUser.getSourceId(), false);
} catch (UserNotFoundException unfe) {
// The user is not yet registered in repository
// Information will be updated after the first connection of the user
NewExternalUserEntity newUser = new NewExternalUserEntity();
newUser.setFirstname(identityUser.getFirstname());
newUser.setLastname(identityUser.getLastname());
newUser.setSource(identityUser.getSource());
newUser.setEmail(identityUser.getEmail());
newUser.setSourceId(identityUser.getSourceId());
newUser.setPicture(identityUser.getPicture());
if (identityUser.getRoles() == null || identityUser.getRoles().isEmpty()) {
userEntity = userService.create(newUser, true);
} else {
userEntity = userService.create(newUser, false);
for (Map.Entry role : identityUser.getRoles().entrySet()) {
MembershipReferenceType membershipReferenceType = MembershipReferenceType.valueOf(role.getKey());
MembershipReference reference = null;
if (membershipReferenceType == MembershipReferenceType.ORGANIZATION) {
reference = new MembershipReference(membershipReferenceType, GraviteeContext.getCurrentOrganization());
} else if (membershipReferenceType == MembershipReferenceType.ENVIRONMENT) {
reference = new MembershipReference(membershipReferenceType, GraviteeContext.getCurrentEnvironment());
}
if (reference != null) {
this.addRoleToMemberOnReference(
reference,
new MembershipMember(userEntity.getId(), null, MembershipMemberType.USER),
new MembershipRole(RoleScope.valueOf(role.getKey()), role.getValue())
);
}
}
}
}
return userEntity;
}
/**
* assert that the role's scope is allowed for the given reference
*/
private void assertRoleScopeAllowedForReference(MembershipReference reference, MembershipRole role) {
Optional optRoleEntity = roleService.findByScopeAndName(role.getScope(), role.getName());
if (optRoleEntity.isPresent()) {
RoleEntity roleEntity = optRoleEntity.get();
if (
(MembershipReferenceType.API == reference.getType() && RoleScope.API != roleEntity.getScope()) ||
(MembershipReferenceType.APPLICATION == reference.getType() && RoleScope.APPLICATION != roleEntity.getScope()) ||
(
MembershipReferenceType.GROUP == reference.getType() &&
RoleScope.GROUP != roleEntity.getScope() &&
RoleScope.API != roleEntity.getScope() &&
RoleScope.APPLICATION != roleEntity.getScope()
) ||
(MembershipReferenceType.GROUP == reference.getType() && SystemRole.PRIMARY_OWNER.name().equals(role.getName()))
) {
throw new NotAuthorizedMembershipException(role.getName());
}
} else {
throw new RoleNotFoundException(role.getScope().name() + "_" + role.getName());
}
}
/**
* assert that the role's name is allowed for the given reference
*/
private void assertRoleNameAllowedForReference(MembershipReference reference, MembershipRole role) {
if (MembershipReferenceType.GROUP == reference.getType() && SystemRole.PRIMARY_OWNER.name().equals(role.getName())) {
throw new NotAuthorizedMembershipException(role.getName());
}
}
@Override
public void deleteMembership(String membershipId) {
try {
Optional membership = membershipRepository.findById(membershipId);
if (membership.isPresent()) {
LOGGER.debug("Delete membership {}", membership.get());
membershipRepository.delete(membershipId);
createAuditLog(MEMBERSHIP_DELETED, new Date(), membership.get(), null);
}
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to delete membership {}", membershipId, ex);
throw new TechnicalManagementException("An error occurs while trying to delete membership " + membershipId, ex);
}
}
@Override
public void deleteReference(MembershipReferenceType referenceType, String referenceId) {
try {
Set memberships = membershipRepository.findByReferenceAndRoleId(
convert(referenceType),
referenceId,
null
);
if (!memberships.isEmpty()) {
for (io.gravitee.repository.management.model.Membership membership : memberships) {
LOGGER.debug("Delete membership {}", membership.getId());
membershipRepository.delete(membership.getId());
createAuditLog(MEMBERSHIP_DELETED, new Date(), membership, null);
}
}
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to delete memberships for {} {}", referenceType, referenceId, ex);
throw new TechnicalManagementException(
"An error occurs while trying to delete memberships for " + referenceType + " " + referenceId,
ex
);
}
}
@Override
public void deleteReferenceMember(
MembershipReferenceType referenceType,
String referenceId,
MembershipMemberType memberType,
String memberId
) {
try {
Set memberships = membershipRepository.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceId(
memberId,
convert(memberType),
convert(referenceType),
referenceId
);
if (!memberships.isEmpty()) {
for (io.gravitee.repository.management.model.Membership membership : memberships) {
LOGGER.debug("Delete membership {}", membership.getId());
membershipRepository.delete(membership.getId());
createAuditLog(MEMBERSHIP_DELETED, new Date(), membership, null);
}
}
} catch (TechnicalException ex) {
LOGGER.error(
"An error occurs while trying to delete memberships for {} {} {} {}",
referenceType,
referenceId,
memberType,
memberId,
ex
);
throw new TechnicalManagementException(
"An error occurs while trying to delete memberships for " +
referenceType +
" " +
referenceId +
" " +
memberType +
" " +
memberId,
ex
);
}
}
@Override
public List findUserMembershipBySource(MembershipReferenceType type, String userId, String sourceId) {
try {
Map roleMap = roleService.findAll().stream().collect(Collectors.toMap(RoleEntity::getId, r -> r));
HashMap userMembershipMap = new HashMap<>();
membershipRepository
.findByMemberIdAndMemberTypeAndReferenceTypeAndSource(
userId,
io.gravitee.repository.management.model.MembershipMemberType.USER,
convert(type),
sourceId
)
.stream()
.filter(membership -> sourceId != null && sourceId.equals(membership.getSource()))
.forEach(
membership -> {
UserMembership userMembership = new UserMembership();
userMembership.setType(type.name());
userMembership.setReference(membership.getReferenceId());
userMembership.setSource(membership.getSource());
RoleEntity role = roleMap.get(membership.getRoleId());
if (role != null) {
int key = userMembership.hashCode();
if (userMembershipMap.containsKey(key)) {
userMembershipMap.get(key).getRoles().put(role.getScope().name(), role.getName());
} else {
HashMap roles = new HashMap<>();
roles.put(role.getScope().name(), role.getName());
userMembership.setRoles(roles);
userMembershipMap.put(userMembership.hashCode(), userMembership);
}
}
}
);
return new ArrayList<>(userMembershipMap.values());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to remove user {}", userId, ex);
throw new TechnicalManagementException("An error occurs while trying to remove user " + userId, ex);
}
}
@Override
public List findUserMembership(MembershipReferenceType type, String userId) {
if (
type == null ||
(
!type.equals(MembershipReferenceType.API) &&
!type.equals(MembershipReferenceType.APPLICATION) &&
!type.equals(MembershipReferenceType.GROUP)
)
) {
return Collections.emptyList();
}
try {
Map roleMap = roleService
.findByScope(roleService.findScopeByMembershipReferenceType(type))
.stream()
.collect(Collectors.toMap(RoleEntity::getId, r -> r));
HashMap userMembershipMap = new HashMap<>();
membershipRepository
.findByMemberIdAndMemberTypeAndReferenceType(
userId,
io.gravitee.repository.management.model.MembershipMemberType.USER,
convert(type)
)
.forEach(
membership -> {
UserMembership userMembership = new UserMembership();
userMembership.setType(type.name());
userMembership.setReference(membership.getReferenceId());
userMembership.setSource(membership.getSource());
RoleEntity role = roleMap.get(membership.getRoleId());
if (role != null) {
int key = userMembership.hashCode();
if (userMembershipMap.containsKey(key)) {
userMembershipMap.get(key).getRoles().put(role.getScope().name(), role.getName());
} else {
HashMap roles = new HashMap<>();
roles.put(role.getScope().name(), role.getName());
userMembership.setRoles(roles);
userMembershipMap.put(userMembership.hashCode(), userMembership);
}
}
}
);
Set userMemberships = new HashSet<>(userMembershipMap.values());
if (type.equals(MembershipReferenceType.APPLICATION) || type.equals(MembershipReferenceType.API)) {
Set userGroups = groupService.findByUser(userId);
for (GroupEntity group : userGroups) {
userMemberships.addAll(
membershipRepository
.findByMemberIdAndMemberTypeAndReferenceType(
group.getId(),
io.gravitee.repository.management.model.MembershipMemberType.GROUP,
convert(type)
)
.stream()
.map(
membership -> {
UserMembership userMembership = new UserMembership();
userMembership.setType(type.name());
userMembership.setReference(membership.getReferenceId());
return userMembership;
}
)
.collect(Collectors.toSet())
);
}
}
return new ArrayList<>(userMemberships);
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to remove user {}", userId, ex);
throw new TechnicalManagementException("An error occurs while trying to remove user " + userId, ex);
}
}
@Override
public Metadata findUserMembershipMetadata(List memberships, MembershipReferenceType type) {
if (
memberships == null ||
memberships.isEmpty() ||
type == null ||
(
!type.equals(MembershipReferenceType.API) &&
!type.equals(MembershipReferenceType.APPLICATION) &&
!type.equals(MembershipReferenceType.GROUP)
)
) {
return new Metadata();
}
try {
Metadata metadata = new Metadata();
if (type.equals(MembershipReferenceType.API)) {
ApiCriteria.Builder criteria = new ApiCriteria.Builder();
ApiFieldExclusionFilter filter = (new ApiFieldExclusionFilter.Builder()).excludeDefinition().excludePicture().build();
criteria.ids(memberships.stream().map(UserMembership::getReference).toArray(String[]::new));
apiRepository
.search(criteria.build(), filter)
.forEach(
api -> {
metadata.put(api.getId(), "name", api.getName());
metadata.put(api.getId(), "version", api.getVersion());
metadata.put(api.getId(), "visibility", api.getVisibility());
}
);
} else if (type.equals(MembershipReferenceType.APPLICATION)) {
applicationRepository
.findByIds(memberships.stream().map(UserMembership::getReference).collect(Collectors.toList()))
.forEach(
application -> {
metadata.put(application.getId(), "name", application.getName());
}
);
}
return metadata;
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get user membership metadata", ex);
throw new TechnicalManagementException("An error occurs while trying to get user membership metadata", ex);
}
}
@Override
public Page getMembersByReference(MembershipReferenceType referenceType, String referenceId, Pageable pageable) {
return this.getMembersByReferenceAndRole(referenceType, referenceId, null, pageable);
}
@Override
public Set getMembersByReference(MembershipReferenceType referenceType, String referenceId) {
return new HashSet<>(this.getMembersByReferenceAndRole(referenceType, referenceId, null, null).getContent());
}
@Override
public Page getMembersByReference(
MembershipReferenceType referenceType,
String referenceId,
String role,
Pageable pageable
) {
return this.getMembersByReferenceAndRole(referenceType, referenceId, role, pageable);
}
@Override
public Set getMembersByReference(MembershipReferenceType referenceType, String referenceId, String role) {
return new HashSet<>(this.getMembersByReferenceAndRole(referenceType, referenceId, role, null).getContent());
}
@Override
public Page getMembersByReferenceAndRole(
MembershipReferenceType referenceType,
String referenceId,
String role,
Pageable pageable
) {
return this.getMembersByReferencesAndRole(referenceType, Collections.singletonList(referenceId), role, pageable);
}
@Override
public Set getMembersByReferenceAndRole(MembershipReferenceType referenceType, String referenceId, String role) {
return new HashSet<>(
this.getMembersByReferencesAndRole(referenceType, Collections.singletonList(referenceId), role, null).getContent()
);
}
@Override
public Set getMembersByReferencesAndRole(MembershipReferenceType referenceType, List referenceIds, String role) {
return new HashSet<>(this.getMembersByReferencesAndRole(referenceType, referenceIds, role, null).getContent());
}
@Override
public Page getMembersByReferencesAndRole(
MembershipReferenceType referenceType,
List referenceIds,
String role,
Pageable pageable
) {
try {
LOGGER.debug("Get members for {} {}", referenceType, referenceIds);
Set memberships = membershipRepository.findByReferencesAndRoleId(
convert(referenceType),
referenceIds,
role
);
Map results = new HashMap<>();
memberships
.stream()
.filter(member -> member.getMemberType() == io.gravitee.repository.management.model.MembershipMemberType.USER)
.map(this::convertToMemberEntity)
.forEach(
member -> {
String key = member.getId() + member.getReferenceId();
MemberEntity existingEntity = results.get(key);
if (existingEntity == null) {
results.put(key, member);
existingEntity = member;
} else {
Set existingRoles = new HashSet<>(existingEntity.getRoles());
existingRoles.addAll(member.getRoles());
existingEntity.setRoles(new ArrayList<>(existingRoles));
}
}
);
List members = new ArrayList<>(results.values());
fillMemberUserInformation(memberships, members);
return paginate(results.values(), pageable);
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get members for {} {}", referenceType, referenceIds, ex);
throw new TechnicalManagementException(
"An error occurs while trying to get members for " + referenceType + " " + referenceIds,
ex
);
}
}
private Page paginate(Collection members, Pageable pageable) {
// Pagination requires sorting members to be able to navigate through pages.
Comparator comparator = Comparator.comparing(memberEntity -> memberEntity.getDisplayName().toLowerCase(Locale.ROOT));
if (pageable == null) {
pageable = new PageableImpl(1, Integer.MAX_VALUE);
}
int totalCount = members.size();
int startIndex = (pageable.getPageNumber() - 1) * pageable.getPageSize();
if (pageable.getPageNumber() < 1 || (totalCount > 0 && startIndex >= totalCount)) {
throw new PaginationInvalidException();
}
List subsetApis = members
.stream()
.sorted(comparator)
.skip(startIndex)
.limit(pageable.getPageSize())
.collect(toList());
return new Page<>(subsetApis, pageable.getPageNumber(), pageable.getPageSize(), members.size());
}
private io.gravitee.repository.management.model.MembershipReferenceType convert(MembershipReferenceType referenceType) {
return io.gravitee.repository.management.model.MembershipReferenceType.valueOf(referenceType.name());
}
private MembershipReferenceType convert(io.gravitee.repository.management.model.MembershipReferenceType referenceType) {
return MembershipReferenceType.valueOf(referenceType.name());
}
private io.gravitee.repository.management.model.MembershipMemberType convert(MembershipMemberType memberType) {
return io.gravitee.repository.management.model.MembershipMemberType.valueOf(memberType.name());
}
private MembershipMemberType convert(io.gravitee.repository.management.model.MembershipMemberType memberType) {
return MembershipMemberType.valueOf(memberType.name());
}
private MembershipEntity convert(io.gravitee.repository.management.model.Membership membership) {
MembershipEntity result = new MembershipEntity();
result.setCreatedAt(membership.getCreatedAt());
result.setId(membership.getId());
result.setMemberId(membership.getMemberId());
result.setMemberType(convert(membership.getMemberType()));
result.setReferenceId(membership.getReferenceId());
result.setReferenceType(convert(membership.getReferenceType()));
result.setRoleId(membership.getRoleId());
result.setUpdatedAt(membership.getUpdatedAt());
return result;
}
@Override
public Set getMembershipsByMember(MembershipMemberType memberType, String memberId) {
try {
return membershipRepository
.findByMemberIdAndMemberType(memberId, convert(memberType))
.stream()
.map(this::convert)
.collect(Collectors.toSet());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get memberships for {} ", memberId, ex);
throw new TechnicalManagementException("An error occurs while trying to get memberships for " + memberId, ex);
}
}
@Override
public Set getMembershipsByMemberAndReference(
MembershipMemberType memberType,
String memberId,
MembershipReferenceType referenceType
) {
try {
return membershipRepository
.findByMemberIdAndMemberTypeAndReferenceType(memberId, convert(memberType), convert(referenceType))
.stream()
.map(this::convert)
.collect(Collectors.toSet());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get memberships for {} ", memberId, ex);
throw new TechnicalManagementException("An error occurs while trying to get memberships for " + memberId, ex);
}
}
@Override
public Set getMembershipsByMemberAndReferenceAndRole(
MembershipMemberType memberType,
String memberId,
MembershipReferenceType referenceType,
String role
) {
try {
return membershipRepository
.findByMemberIdAndMemberTypeAndReferenceTypeAndRoleId(memberId, convert(memberType), convert(referenceType), role)
.stream()
.map(this::convert)
.collect(Collectors.toSet());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get memberships for {} ", memberId, ex);
throw new TechnicalManagementException("An error occurs while trying to get memberships for " + memberId, ex);
}
}
@Override
public Set getMembershipsByMembersAndReference(
MembershipMemberType memberType,
List memberIds,
MembershipReferenceType referenceType
) {
try {
return membershipRepository
.findByMemberIdsAndMemberTypeAndReferenceType(memberIds, convert(memberType), convert(referenceType))
.stream()
.map(this::convert)
.collect(Collectors.toSet());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get memberships for {} ", memberIds, ex);
throw new TechnicalManagementException("An error occurs while trying to get memberships for " + memberIds, ex);
}
}
@Override
public Set getMembershipsByReference(MembershipReferenceType referenceType, String referenceId) {
try {
return membershipRepository
.findByReferenceAndRoleId(convert(referenceType), referenceId, null)
.stream()
.map(this::convert)
.collect(Collectors.toSet());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get memberships for {} {} ", referenceType, referenceId, ex);
throw new TechnicalManagementException(
"An error occurs while trying to get memberships for " + referenceType + " " + referenceId,
ex
);
}
}
@Override
public Set getMembershipsByReferenceAndRole(MembershipReferenceType referenceType, String referenceId, String role) {
try {
return membershipRepository
.findByReferenceAndRoleId(convert(referenceType), referenceId, role)
.stream()
.map(this::convert)
.collect(Collectors.toSet());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get memberships for {} {} and role", referenceType, referenceId, role, ex);
throw new TechnicalManagementException(
"An error occurs while trying to get memberships for " + referenceType + " " + referenceId + " and role " + role,
ex
);
}
}
@Override
public Set getMembershipsByReferencesAndRole(
MembershipReferenceType referenceType,
List referenceIds,
String role
) {
try {
return membershipRepository
.findByReferencesAndRoleId(convert(referenceType), referenceIds, role)
.stream()
.map(this::convert)
.collect(Collectors.toSet());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get memberships for {} {} and role", referenceType, referenceIds, role, ex);
throw new TechnicalManagementException(
"An error occurs while trying to get memberships for " + referenceType + " " + referenceIds + " and role " + role,
ex
);
}
}
@Override
public MembershipEntity getPrimaryOwner(MembershipReferenceType referenceType, String referenceId) {
RoleScope poRoleScope;
if (referenceType == MembershipReferenceType.API) {
poRoleScope = RoleScope.API;
} else if (referenceType == MembershipReferenceType.APPLICATION) {
poRoleScope = RoleScope.APPLICATION;
} else {
throw new RoleNotFoundException(referenceType.name() + "_PRIMARY_OWNER");
}
RoleEntity poRole = roleService.findPrimaryOwnerRoleByOrganization(GraviteeContext.getCurrentOrganization(), poRoleScope);
if (poRole != null) {
try {
Optional poMember = membershipRepository
.findByReferenceAndRoleId(convert(referenceType), referenceId, poRole.getId())
.stream()
.findFirst();
if (poMember.isPresent()) {
return convert(poMember.get());
} else {
return null;
}
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get primary owner for {} {} and role", referenceType, referenceId, ex);
throw new TechnicalManagementException(
"An error occurs while trying to get primary owner for " + referenceType + " " + referenceId,
ex
);
}
} else {
throw new RoleNotFoundException(referenceType.name() + "_PRIMARY_OWNER");
}
}
@Override
public Set getRoles(
MembershipReferenceType referenceType,
String referenceId,
MembershipMemberType memberType,
String memberId
) {
try {
LOGGER.debug("Get role for {} {} and member {} {}", referenceType, referenceId, memberType, memberId);
return roles.get(
referenceType.name() + referenceId + memberType + memberId,
() ->
membershipRepository
.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceId(
memberId,
convert(memberType),
convert(referenceType),
referenceId
)
.stream()
.map(io.gravitee.repository.management.model.Membership::getRoleId)
.map(roleService::findById)
.collect(Collectors.toSet())
);
} catch (Exception ex) {
final String message =
"An error occurs while trying to get roles for " + referenceType + " " + referenceId + " " + memberType + " " + memberId;
LOGGER.error(message, ex);
throw new TechnicalManagementException(message, ex);
}
}
@Override
public MemberEntity getUserMember(MembershipReferenceType referenceType, String referenceId, String userId) {
try {
Set userMemberships = membershipRepository.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceId(
userId,
convert(MembershipMemberType.USER),
convert(referenceType),
referenceId
);
//Get entity groups
Set entityGroups = new HashSet<>();
switch (referenceType) {
case API:
entityGroups = apiService.findById(referenceId).getGroups();
break;
case APPLICATION:
entityGroups = applicationService.findById(referenceId).getGroups();
break;
default:
break;
}
if (userMemberships.isEmpty() && (entityGroups == null || entityGroups.isEmpty())) {
return null;
}
MemberEntity memberEntity = new MemberEntity();
UserEntity userEntity = userService.findById(userId);
memberEntity.setCreatedAt(userEntity.getCreatedAt());
memberEntity.setDisplayName(userEntity.getDisplayName());
memberEntity.setEmail(userEntity.getEmail());
memberEntity.setId(userEntity.getId());
memberEntity.setUpdatedAt(userEntity.getUpdatedAt());
Set userRoles = new HashSet<>();
Set userDirectRoles = new HashSet<>();
if (!userMemberships.isEmpty()) {
userDirectRoles =
userMemberships
.stream()
.map(io.gravitee.repository.management.model.Membership::getRoleId)
.map(roleService::findById)
.collect(Collectors.toSet());
userRoles.addAll(userDirectRoles);
}
memberEntity.setRoles(new ArrayList<>(userDirectRoles));
if (entityGroups != null && !entityGroups.isEmpty()) {
for (String group : entityGroups) {
userRoles.addAll(
membershipRepository
.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceId(
userId,
convert(MembershipMemberType.USER),
convert(MembershipReferenceType.GROUP),
group
)
.stream()
.map(io.gravitee.repository.management.model.Membership::getRoleId)
.map(roleService::findById)
.filter(role -> role.getScope().name().equals(referenceType.name()))
.collect(Collectors.toSet())
);
}
}
Map permissions = new HashMap<>();
if (!userRoles.isEmpty()) {
permissions = computeGlobalPermissions(userRoles);
}
memberEntity.setPermissions(permissions);
return memberEntity;
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to get user member for {} {} {} {}", referenceType, referenceId, userId, ex);
throw new TechnicalManagementException(
"An error occurs while trying to get roles for " + referenceType + " " + referenceId + " " + userId,
ex
);
}
}
private Map computeGlobalPermissions(Set userRoles) {
Map> mergedPermissions = new HashMap<>();
for (RoleEntity role : userRoles) {
for (Map.Entry perm : role.getPermissions().entrySet()) {
if (mergedPermissions.containsKey(perm.getKey())) {
Set previousCRUD = mergedPermissions.get(perm.getKey());
for (char c : perm.getValue()) {
previousCRUD.add(c);
}
} else {
Set crudAsSet = new HashSet<>();
for (char c : perm.getValue()) {
crudAsSet.add(c);
}
mergedPermissions.put(perm.getKey(), crudAsSet);
}
}
}
Map permissions = new HashMap<>(mergedPermissions.size());
mergedPermissions.forEach(
(String k, Set v) -> {
Character[] characters = v.toArray(new Character[v.size()]);
char[] chars = new char[characters.length];
for (int i = 0; i < characters.length; i++) {
chars[i] = characters[i];
}
permissions.put(k, chars);
}
);
return permissions;
}
@Override
public Map getUserMemberPermissions(MembershipReferenceType referenceType, String referenceId, String userId) {
MemberEntity member = this.getUserMember(referenceType, referenceId, userId);
if (member != null) {
return member.getPermissions();
}
return emptyMap();
}
@Override
public Map getUserMemberPermissions(ApiEntity api, String userId) {
return getUserMemberPermissions(MembershipReferenceType.API, api.getId(), userId);
}
@Override
public Map getUserMemberPermissions(ApplicationEntity application, String userId) {
return getUserMemberPermissions(MembershipReferenceType.APPLICATION, application.getId(), userId);
}
@Override
public Map getUserMemberPermissions(GroupEntity group, String userId) {
return getUserMemberPermissions(MembershipReferenceType.GROUP, group.getId(), userId);
}
@Override
public Map getUserMemberPermissions(EnvironmentEntity environment, String userId) {
return getUserMemberPermissions(MembershipReferenceType.ENVIRONMENT, environment.getId(), userId);
}
@Override
public void removeRole(
MembershipReferenceType referenceType,
String referenceId,
MembershipMemberType memberType,
String memberId,
String roleId
) {
try {
Set membershipsToDelete = membershipRepository.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceIdAndRoleId(
memberId,
convert(memberType),
convert(referenceType),
referenceId,
roleId
);
for (io.gravitee.repository.management.model.Membership m : membershipsToDelete) {
membershipRepository.delete(m.getId());
}
} catch (TechnicalException ex) {
LOGGER.error(
"An error occurs while trying to remove role {} from member {} {} for {} {}",
roleId,
memberType,
memberId,
referenceType,
referenceId,
ex
);
throw new TechnicalManagementException(
"An error occurs while trying to remove role " +
roleId +
" from member " +
memberType +
" " +
memberId +
" for " +
referenceType +
" " +
referenceId,
ex
);
}
}
@Override
public void removeRoleUsage(String oldRoleId, String newRoleId) {
try {
Set membershipsWithOldRole = membershipRepository.findByRoleId(oldRoleId);
for (io.gravitee.repository.management.model.Membership membership : membershipsWithOldRole) {
Set membershipsWithNewRole = membershipRepository.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceIdAndRoleId(
membership.getMemberId(),
membership.getMemberType(),
membership.getReferenceType(),
membership.getReferenceId(),
newRoleId
);
String oldMembershipId = membership.getId();
if (membershipsWithNewRole.isEmpty()) {
membership.setId(RandomString.generate());
membership.setRoleId(newRoleId);
membership.setSource(DEFAULT_SOURCE);
membershipRepository.create(membership);
}
membershipRepository.delete(oldMembershipId);
}
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to remove role {} {}", oldRoleId, ex);
throw new TechnicalManagementException("An error occurs while trying to remove role " + oldRoleId, ex);
}
}
@Override
public void removeMemberMemberships(MembershipMemberType memberType, String memberId) {
try {
for (io.gravitee.repository.management.model.Membership membership : membershipRepository.findByMemberIdAndMemberType(
memberId,
convert(memberType)
)) {
membershipRepository.delete(membership.getId());
}
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to remove member {} {}", memberType, memberId, ex);
throw new TechnicalManagementException("An error occurs while trying to remove " + memberType + " " + memberId, ex);
}
}
@Override
public void transferApiOwnership(String apiId, MembershipMember member, List newPrimaryOwnerRoles) {
this.transferOwnership(MembershipReferenceType.API, RoleScope.API, apiId, member, newPrimaryOwnerRoles);
}
@Override
public void transferApplicationOwnership(String applicationId, MembershipMember member, List newPrimaryOwnerRoles) {
this.transferOwnership(MembershipReferenceType.APPLICATION, RoleScope.APPLICATION, applicationId, member, newPrimaryOwnerRoles);
}
private void transferOwnership(
MembershipReferenceType membershipReferenceType,
RoleScope roleScope,
String itemId,
MembershipMember member,
List newPrimaryOwnerRoles
) {
List newRoles;
if (newPrimaryOwnerRoles == null || newPrimaryOwnerRoles.isEmpty()) {
newRoles = roleService.findDefaultRoleByScopes(roleScope);
} else {
newRoles = newPrimaryOwnerRoles;
}
MembershipEntity primaryOwner = this.getPrimaryOwner(membershipReferenceType, itemId);
// Set the new primary owner
MemberEntity newPrimaryOwnerMember =
this.addRoleToMemberOnReference(
new MembershipReference(membershipReferenceType, itemId),
new MembershipMember(member.getMemberId(), member.getReference(), member.getMemberType()),
new MembershipRole(roleScope, PRIMARY_OWNER.name())
);
RoleEntity poRoleEntity = roleService.findPrimaryOwnerRoleByOrganization(GraviteeContext.getCurrentOrganization(), roleScope);
if (poRoleEntity != null) {
// remove previous role of the new primary owner
this.getRoles(membershipReferenceType, itemId, member.getMemberType(), newPrimaryOwnerMember.getId())
.forEach(
role -> {
if (!role.getId().equals(poRoleEntity.getId())) {
this.removeRole(
membershipReferenceType,
itemId,
MembershipMemberType.USER,
newPrimaryOwnerMember.getId(),
role.getId()
);
}
}
);
// Update the role for previous primary_owner
this.removeRole(membershipReferenceType, itemId, MembershipMemberType.USER, primaryOwner.getMemberId(), poRoleEntity.getId());
for (RoleEntity newRole : newRoles) {
this.addRoleToMemberOnReference(
new MembershipReference(membershipReferenceType, itemId),
new MembershipMember(primaryOwner.getMemberId(), null, MembershipMemberType.USER),
new MembershipRole(roleScope, newRole.getName())
);
}
}
}
@Override
public MemberEntity updateRoleToMemberOnReference(MembershipReference reference, MembershipMember member, MembershipRole role) {
return updateRolesToMemberOnReference(reference, member, singleton(role), null, true).stream().findFirst().orElse(null);
}
@Override
public List updateRolesToMemberOnReference(
MembershipReference reference,
MembershipMember member,
Collection roles,
String source,
boolean notify
) {
try {
Set existingMemberships =
this.membershipRepository.findByMemberIdAndMemberTypeAndReferenceTypeAndReferenceId(
member.getMemberId(),
convert(member.getMemberType()),
convert(reference.getType()),
reference.getId()
);
if (existingMemberships != null && !existingMemberships.isEmpty()) {
existingMemberships.forEach(membership -> this.deleteMembership(membership.getId()));
}
return roles
.stream()
.map(role -> _addRoleToMemberOnReference(reference, member, role, source, notify))
.collect(Collectors.toList());
} catch (TechnicalException ex) {
LOGGER.error("An error occurs while trying to update member for {} {}", reference.getType(), reference.getId(), ex);
throw new TechnicalManagementException(
"An error occurs while trying to update member for " + reference.getType() + " " + reference.getId(),
ex
);
}
}
@Override
public List updateRolesToMemberOnReferenceBySource(
MembershipReference reference,
MembershipMember member,
Collection roles,
String source
) {
return roles.stream().map(role -> _addRoleToMemberOnReference(reference, member, role, source, false)).collect(Collectors.toList());
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy