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);
}
}
}