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

com.xlrit.gears.plugin.msgraph.Sync Maven / Gradle / Ivy

package com.xlrit.gears.plugin.msgraph;

import java.net.MalformedURLException;
import java.util.*;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.microsoft.aad.msal4j.ClientCredentialFactory;
import com.microsoft.aad.msal4j.ConfidentialClientApplication;
import com.microsoft.aad.msal4j.IClientSecret;
import com.microsoft.graph.models.DirectoryObject;
import com.microsoft.graph.models.DirectoryObjectGetByIdsParameterSet;
import com.microsoft.graph.requests.*;
import com.xlrit.gears.base.model.Role;
import com.xlrit.gears.base.model.User;

import okhttp3.Request;

public class Sync {
	private static final Logger LOG = LoggerFactory.getLogger(Sync.class);

	private static final String USER_READ_ALL = "User.Read.All";
	private static final String ODT_USER      = "#microsoft.graph.user";

	private final SyncProperties properties;
	private final GraphServiceClient client;

	public Sync(SyncProperties properties) {
		this.properties = properties;
		LOG.info("Initialized using {}", properties);

		ConfidentialClientApplication app = createConfidentialClientInstance(properties, USER_READ_ALL);
		this.client = GraphServiceClient.builder()
			.authenticationProvider(new CustomAuthenticationProvider(app))
			.buildClient();
	}

	public void run(SyncHandler handler) {
		LOG.info("Running now for {} groups", properties.getGroupMapping().size());

		Set              allUserUUIDs     = new HashSet<>();
		Map> groupMemberUUIDs = new HashMap<>();
		Map        rolesByGroupUUID = new HashMap<>();
		Map        usersByUUID      = new HashMap<>();

		for (var entry : properties.getGroupMapping().entrySet()) {
			LOG.info("Processing group mapping '{}' -> '{}'", entry.getKey(), entry.getValue());
			String groupUUID = entry.getKey();
			var provGroup = retrieveGroup(groupUUID);
			Role role = handler.handleGroup(provGroup);
			rolesByGroupUUID.put(groupUUID, role);

			Set memberUUIDs = retrieveGroupMembers(groupUUID).stream()
				.filter(member -> ODT_USER.equals(member.oDataType))
				.map(member -> member.id)
				.collect(Collectors.toSet());

			LOG.info("Group '{}' has {} members", provGroup.displayName, memberUUIDs.size());

			allUserUUIDs.addAll(memberUUIDs);
			groupMemberUUIDs.put(provGroup.id, memberUUIDs);
		}

		for (var provUser : retrieveUsersBatched(allUserUUIDs)) {
			User user = handler.handleUser(provUser);
			usersByUUID.put(provUser.id, user);
			LOG.info("User '{}' synchronized", provUser.displayName);
		}

		for (var entry : groupMemberUUIDs.entrySet()) {
			String groupUUID = entry.getKey();
			Set userUUIDs = entry.getValue();

			Role role = rolesByGroupUUID.get(groupUUID);
			Set users = userUUIDs.stream().map(usersByUUID::get).collect(Collectors.toSet());

			handler.handleMembership(role, users);
		}
	}

	private com.microsoft.graph.models.Group retrieveGroup(String groupId) {
		return client.groups(groupId).buildRequest().get();
	}

	private com.microsoft.graph.models.User retrieveUser(String userId) {
		return client.users(userId).buildRequest().get();
	}

	private Set retrieveUsers(Collection userIds) {
		return userIds.stream()
			.map(this::retrieveUser)
			.collect(Collectors.toSet());
	}

	private Set retrieveUsersBatched(Collection userIds) {
		var ids = DirectoryObjectGetByIdsParameterSet.newBuilder().withIds(List.copyOf(userIds)).build();
		DirectoryObjectGetByIdsCollectionPage r = client.users().getByIds(ids).buildRequest().post();
		List objects = r.getCurrentPage();

		return objects.stream()
			.filter(obj -> ODT_USER.equals(obj.oDataType))
			.map(obj -> (com.microsoft.graph.models.User) obj)
			.collect(Collectors.toSet());
	}

	private List retrieveGroupMembers(String groupId) {
		DirectoryObjectCollectionWithReferencesPage members =
			client
				.groups(groupId)
				.members()
				.buildRequest()
				.get();
		return members.getCurrentPage();
	}

	private static ConfidentialClientApplication createConfidentialClientInstance(SyncProperties properties, String policy) {
		try {
			IClientSecret secret = ClientCredentialFactory.createFromSecret(properties.getSecret());
			String authority = properties.getAuthority() + (policy == null ? "" : "/" + policy);
			return ConfidentialClientApplication.builder(properties.getClientId(), secret)
				.b2cAuthority(authority)
				.build();
		}
		catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy