All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xlrit.gears.plugin.scim.GroupHandler Maven / Gradle / Ivy

There is a newer version: 1.17.6
Show newest version
package com.xlrit.gears.plugin.scim;

import java.time.OffsetDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.google.common.collect.Sets;
import com.xlrit.gears.base.model.Role;
import com.xlrit.gears.base.model.User;
import com.xlrit.gears.base.repository.RoleRepository;
import com.xlrit.gears.base.repository.UserRepository;
import com.xlrit.gears.engine.util.EngineUtils;
import de.captaingoldfish.scim.sdk.common.constants.enums.SortOrder;
import de.captaingoldfish.scim.sdk.common.exceptions.BadRequestException;
import de.captaingoldfish.scim.sdk.common.exceptions.ResourceNotFoundException;
import de.captaingoldfish.scim.sdk.common.resources.Group;
import de.captaingoldfish.scim.sdk.common.resources.complex.Meta;
import de.captaingoldfish.scim.sdk.common.resources.multicomplex.Member;
import de.captaingoldfish.scim.sdk.common.schemas.SchemaAttribute;
import de.captaingoldfish.scim.sdk.server.endpoints.Context;
import de.captaingoldfish.scim.sdk.server.endpoints.ResourceHandler;
import de.captaingoldfish.scim.sdk.server.filter.FilterNode;
import de.captaingoldfish.scim.sdk.server.response.PartialListResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.xlrit.gears.plugin.scim.Helper.createResponse;
import static com.xlrit.gears.plugin.scim.Helper.toLocalDateTime;

public class GroupHandler extends ResourceHandler {
	private static final Logger LOG = LoggerFactory.getLogger(GroupHandler.class);

	private final RoleRepository roles;
	private final UserRepository users;
	private final Map roleMapping;

	public GroupHandler(RoleRepository roles, UserRepository users, Map roleMapping) {
		this.roles = roles;
		this.users = users;
		this.roleMapping = roleMapping;

		LOG.info("SCIM role mapping: {}", roleMapping);
	}

	@Override
	public Group createResource(Group provGroup, Context context) {
		LOG.info("createResource: group={}", provGroup);

		String id = provGroup.getExternalId().map(EngineUtils::uuidToUlid).orElseThrow();
		LOG.debug("createResource: externalId '{}' converted to id '{}'", provGroup.getExternalId().get(), id);

		Role nativeRole = roles.create(id);
		OffsetDateTime now = OffsetDateTime.now();
		nativeRole.setCreatedAt(now);
		nativeRole.setModifiedAt(now);

		copy(provGroup, nativeRole);

		LOG.info("result: {}", nativeRole);
		return convert(nativeRole);
	}

	@Override
	public Group getResource(String id, List attributes, List excludedAttributes, Context context) {
		LOG.info("getResource: id={}, attributes={}, excludedAttributes={}", id, attributes, excludedAttributes);
		Role nativeRole = getRoleById(id);
		return convert(nativeRole);
	}

	@Override
	public PartialListResponse listResources(long startIndex, int count, FilterNode filter, SchemaAttribute sortBy, SortOrder sortOrder, List attrs, List excludedAttrs, Context context) {
		LOG.info("listResources: start={}, count={}, filter={}, sort={} {}, attrs={}", startIndex, count, filter, sortBy, sortOrder, attrs);
		List nativeRoles = this.roles.findAll();
		List provGroups = nativeRoles.stream()
			.filter(Role::getActive)
			.map(this::convert)
			.collect(Collectors.toList());

		return createResponse(provGroups);
	}

	@Override
	public Group updateResource(Group provGroup, Context context) {
		LOG.info("updateResource: group={}", provGroup);
		String groupId = provGroup.getId().orElseThrow(() -> new BadRequestException("Group id is required"));
		Role nativeRole = getRoleById(groupId);
		copy(provGroup, nativeRole);

		LOG.info("result: {}", nativeRole);
		return convert(nativeRole);
	}

	@Override
	public void deleteResource(String id, Context context) {
		LOG.info("deleteResource: id={}", id);
		Role nativeRole = getRoleById(id);
		nativeRole.setActive(false);
	}

	private Role getRoleById(String roleId) {
		Role nativeRole = roles.findById(roleId);
		if (nativeRole == null)  throw new ResourceNotFoundException("Group with id '" + roleId + "' not found");
		return nativeRole;
	}

	private void copy(Group provGroup, Role nativeRole) {
		nativeRole.setActive(true);
		provGroup.getExternalId().ifPresent(nativeRole::setExternalId);
		provGroup.getDisplayName().ifPresent(externalName -> {
			nativeRole.setExternalName(externalName);
			nativeRole.setName(externalNameToName(externalName));
			nativeRole.setType("WORKFLOW");
		});

		provGroup.getMeta().ifPresent(meta -> {
			meta.getCreated().ifPresent(created -> nativeRole.setCreatedAt(toLocalDateTime(created)));
			meta.getLastModified().ifPresent(modified -> nativeRole.setModifiedAt(toLocalDateTime(modified)));
		});

		syncMembers(provGroup, nativeRole);
	}

	private String externalNameToName(String externalName) {
		return roleMapping.getOrDefault(externalName, externalName);
	}

	private void syncMembers(Group provGroup, Role nativeRole) {
		Set targetUserIds = provGroup.getMembers().stream()
			.map(Member::getValue)
			.filter(Optional::isPresent)
			.map(Optional::get)
			.collect(Collectors.toSet());

		Set actualUserIds = nativeRole.getUsers().stream()
			.map(User::getId)
			.collect(Collectors.toSet());

		Collection addUsers = resolveUsers(List.copyOf(Sets.difference(targetUserIds, actualUserIds)));

		Collection remUsers = nativeRole.getUsers().stream()
			.filter(user -> !targetUserIds.contains(user.getId()))
			.collect(Collectors.toList());

		nativeRole.addUsersBidi(addUsers);
		nativeRole.removeUsersBidi(remUsers);
	}

	private List resolveUsers(List userIds) {
		List nativeUsers = this.users.findByIds(userIds);
		List missingUserIds = IntStream.range(0, nativeUsers.size())
			.filter(index -> nativeUsers.get(index) == null)
			.mapToObj(userIds::get)
			.collect(Collectors.toList());
		if (!missingUserIds.isEmpty()) {
			throw new ResourceNotFoundException("Users with the following ids were not found: " + missingUserIds);
		}
		return nativeUsers;
	}

	private Group convert(Role nativeRole) {
		String displayName = Objects.requireNonNullElseGet(nativeRole.getExternalName(), nativeRole::getName);
		List members = nativeRole.getUsers().stream()
			.map(this::toMember)
			.collect(Collectors.toList());

		return Group.builder()
			.id(nativeRole.getId())
			.externalId(nativeRole.getExternalId())
			.displayName(displayName)
			.meta(Meta.builder()
				.resourceType("Group")
				.created(nativeRole.getCreatedAt())
				.lastModified(nativeRole.getModifiedAt())
				.build()
			)
			.members(members)
			.build();
	}

	private Member toMember(User user) {
		return Member.builder().value(user.getId()).build();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy