Skip to content

Commit

Permalink
Disable user-collection-based authorization automatically if the iden…
Browse files Browse the repository at this point in the history
…tity and access management implementation doesn't support to make Turms easier to use correctly #1423
  • Loading branch information
JamesChenX committed Mar 31, 2024
1 parent c20cba4 commit 1e6dc1b
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@

package im.turms.server.common.infra.property.constant;

import lombok.Getter;

/**
* @author James Chen
*/
public enum IdentityAccessManagementType {
NOOP,
HTTP,
JWT,
PASSWORD,
LDAP,
NOOP(false),
HTTP(false),
JWT(false),
PASSWORD(true),
LDAP(false);

@Getter
private final boolean isUserCollectionBasedAuthEnabled;

IdentityAccessManagementType(boolean isUserCollectionBasedAuthEnabled) {
this.isUserCollectionBasedAuthEnabled = isUserCollectionBasedAuthEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -826,8 +826,8 @@ public Mono<ServicePermission> isAllowedToCreateGroupAndHaveGroupType(
} catch (ResponseException e) {
return Mono.error(e);
}
Mono<UserPermissionGroup> userPermissionGroupMono =
userPermissionGroupService.queryUserPermissionGroupByUserId(requesterId);
Mono<UserPermissionGroup> userPermissionGroupMono = userPermissionGroupService
.queryStoredOrDefaultUserPermissionGroupByUserId(requesterId);
return userPermissionGroupMono.flatMap(userPermissionGroup -> isAllowedToCreateGroup(
requesterId,
userPermissionGroup)
Expand All @@ -853,7 +853,8 @@ public Mono<ServicePermission> isAllowedToCreateGroup(
return Mono.error(e);
}
Mono<UserPermissionGroup> userPermissionGroupMono = auxiliaryUserPermissionGroup == null
? userPermissionGroupService.queryUserPermissionGroupByUserId(requesterId)
? userPermissionGroupService
.queryStoredOrDefaultUserPermissionGroupByUserId(requesterId)
: Mono.just(auxiliaryUserPermissionGroup);
return userPermissionGroupMono.flatMap(userPermissionGroup -> {
Integer ownedGroupLimit = userPermissionGroup.getOwnedGroupLimit();
Expand Down Expand Up @@ -900,7 +901,7 @@ public Mono<ServicePermission> isAllowedCreateGroupWithGroupType(
Mono<UserPermissionGroup> groupMono = auxiliaryUserPermissionGroup != null
? Mono.just(auxiliaryUserPermissionGroup)
: userPermissionGroupService
.queryUserPermissionGroupByUserId(requesterId);
.queryStoredOrDefaultUserPermissionGroupByUserId(requesterId);
return groupMono.flatMap(userPermissionGroup -> {
Set<Long> creatableGroupTypeIds =
userPermissionGroup.getCreatableGroupTypeIds();
Expand Down Expand Up @@ -948,7 +949,7 @@ public Mono<ServicePermission> isAllowedUpdateGroupToGroupType(
Mono<UserPermissionGroup> groupMono = auxiliaryUserPermissionGroup != null
? Mono.just(auxiliaryUserPermissionGroup)
: userPermissionGroupService
.queryUserPermissionGroupByUserId(requesterId);
.queryStoredOrDefaultUserPermissionGroupByUserId(requesterId);
return groupMono.flatMap(userPermissionGroup -> {
Set<Long> creatableGroupTypeIds =
userPermissionGroup.getCreatableGroupTypeIds();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ public Mono<UserFriendRequest> authAndCreateFriendRequest(
}

/**
* @return The requester ID, recipient ID and status.
* @return The requester ID, recipient ID, creation date and status.
*/
public Mono<UserFriendRequest> authAndRecallFriendRequest(
@NotNull Long requesterId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,17 +242,18 @@ public Mono<UserPermissionGroup> queryUserPermissionGroup(@NotNull Long groupId)
return Mono.just(userPermissionGroup);
}

public Mono<UserPermissionGroup> queryUserPermissionGroupByUserId(@NotNull Long userId) {
return userService.queryUserPermissionGroupId(userId)
public Mono<UserPermissionGroup> queryStoredOrDefaultUserPermissionGroupByUserId(
@NotNull Long userId) {
Mono<Long> queryUserPermissionGroupId = userService.queryUserPermissionGroupId(userId)
.defaultIfEmpty(DEFAULT_USER_PERMISSION_GROUP_ID);
return queryUserPermissionGroupId
.flatMap(groupId -> queryUserPermissionGroup(groupId).switchIfEmpty(
Mono.error(ResponseException.get(ResponseStatusCode.SERVER_INTERNAL_ERROR,
"The user ("
+ userId
+ ") is in the nonexistent permission group ("
+ groupId
+ ")"))))
.switchIfEmpty(Mono.error(ResponseException
.get(ResponseStatusCode.QUERY_PERMISSION_OF_NONEXISTENT_USER)));
+ ")"))));
}

public Mono<Long> countUserPermissionGroups() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ public class UserRelationshipGroupService {
private final UserRelationshipGroupRepository userRelationshipGroupRepository;
private final UserRelationshipGroupMemberRepository userRelationshipGroupMemberRepository;
private final UserVersionService userVersionService;
private final UserRelationshipService userRelationshipService;

/**
* @param userRelationshipService is lazy because: UserRelationshipService ->
Expand All @@ -94,7 +93,6 @@ public UserRelationshipGroupService(
this.userRelationshipGroupRepository = userRelationshipGroupRepository;
this.userRelationshipGroupMemberRepository = userRelationshipGroupMemberRepository;
this.userVersionService = userVersionService;
this.userRelationshipService = userRelationshipService;
}

public Mono<UserRelationshipGroup> createRelationshipGroup(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import io.micrometer.core.instrument.Counter;
import lombok.Getter;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
Expand All @@ -50,6 +51,7 @@
import im.turms.server.common.infra.logging.core.logger.LoggerFactory;
import im.turms.server.common.infra.property.TurmsProperties;
import im.turms.server.common.infra.property.TurmsPropertiesManager;
import im.turms.server.common.infra.property.env.gateway.GatewayProperties;
import im.turms.server.common.infra.property.env.service.business.message.MessageProperties;
import im.turms.server.common.infra.property.env.service.business.user.UserProperties;
import im.turms.server.common.infra.reactor.PublisherPool;
Expand Down Expand Up @@ -109,6 +111,8 @@ public class UserService {

private boolean allowSendMessagesToOneself;
private boolean allowSendMessagesToStranger;
@Getter
private boolean isUserCollectionBasedAuthEnabled;
private boolean checkIfTargetActiveAndNotDeleted;

public UserService(
Expand Down Expand Up @@ -174,7 +178,22 @@ private void updateProperties(TurmsProperties properties) {
.getMessage();
allowSendMessagesToOneself = messageProperties.isAllowSendMessagesToOneself();
allowSendMessagesToStranger = messageProperties.isAllowSendMessagesToStranger();
checkIfTargetActiveAndNotDeleted = messageProperties.isCheckIfTargetActiveAndNotDeleted();

GatewayProperties gatewayProperties = properties.getGateway();
// We need to check if it's null because "properties" comes from the global properties,
// this will be null if no a turms-gateway server ever started in the cluster
// (because if a turms-gateway server ever started in the cluster,
// it will store the global properties in MongoDB).
isUserCollectionBasedAuthEnabled = gatewayProperties != null
&& gatewayProperties.getSession()
.getIdentityAccessManagement()
.getType()
.isUserCollectionBasedAuthEnabled();

boolean localCheckIfTargetActiveAndNotDeleted =
messageProperties.isCheckIfTargetActiveAndNotDeleted();
checkIfTargetActiveAndNotDeleted =
isUserCollectionBasedAuthEnabled && localCheckIfTargetActiveAndNotDeleted;
}

public Mono<ServicePermission> isAllowedToSendMessageToTarget(
Expand Down Expand Up @@ -323,26 +342,30 @@ public Mono<ServicePermission> isAllowToQueryUserProfile(
} catch (ResponseException e) {
return Mono.error(e);
}
return userRepository.findProfileAccessIfNotDeleted(targetUserId)
.flatMap(strategy -> switch (strategy) {
case ALL -> Mono.just(ServicePermission.OK);
case FRIENDS -> userRelationshipService
.hasRelationshipAndNotBlocked(targetUserId, requesterId, false)
.map(isRelatedAndAllowed -> isRelatedAndAllowed
? ServicePermission.OK
: ServicePermission.get(
ResponseStatusCode.NOT_FRIEND_TO_QUERY_USER_PROFILE));
case ALL_EXCEPT_BLOCKED_USERS -> userRelationshipService
.isNotBlocked(targetUserId, requesterId, false)
.map(isNotBlocked -> isNotBlocked
? ServicePermission.OK
: ServicePermission.get(
ResponseStatusCode.BLOCKED_USER_TO_QUERY_USER_PROFILE));
default ->
Mono.error(ResponseException.get(ResponseStatusCode.SERVER_INTERNAL_ERROR,
"Unexpected profile access strategy: "
+ strategy));
})

Mono<ProfileAccessStrategy> findProfileAccess =
userRepository.findProfileAccessIfNotDeleted(targetUserId);
if (!isUserCollectionBasedAuthEnabled) {
findProfileAccess = findProfileAccess.defaultIfEmpty(ProfileAccessStrategy.ALL);
}
return findProfileAccess.flatMap(strategy -> switch (strategy) {
case ALL -> Mono.just(ServicePermission.OK);
case FRIENDS -> userRelationshipService
.hasRelationshipAndNotBlocked(targetUserId, requesterId, false)
.map(isRelatedAndAllowed -> isRelatedAndAllowed
? ServicePermission.OK
: ServicePermission
.get(ResponseStatusCode.NOT_FRIEND_TO_QUERY_USER_PROFILE));
case ALL_EXCEPT_BLOCKED_USERS -> userRelationshipService
.isNotBlocked(targetUserId, requesterId, false)
.map(isNotBlocked -> isNotBlocked
? ServicePermission.OK
: ServicePermission
.get(ResponseStatusCode.BLOCKED_USER_TO_QUERY_USER_PROFILE));
default -> Mono.error(ResponseException.get(ResponseStatusCode.SERVER_INTERNAL_ERROR,
"Unexpected profile access strategy: "
+ strategy));
})
.switchIfEmpty(ResponseExceptionPublisherPool.resourceNotFound());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ void setup() {
true)
.block(timeout);

userPermissionGroupService.queryUserPermissionGroupByUserId(USER_ID)
userPermissionGroupService.queryStoredOrDefaultUserPermissionGroupByUserId(USER_ID)
.flatMap(permissionGroup -> userPermissionGroupService.updateUserPermissionGroups(
Set.of(permissionGroup.getId()),
Set.of(0L,
Expand Down

0 comments on commit 1e6dc1b

Please sign in to comment.