Restore MsTeams legacy permission compatibility

This commit is contained in:
Meik
2026-03-29 22:58:29 +02:00
parent d95a9c0ea9
commit 54be771569

View File

@@ -35,19 +35,75 @@ namespace C4IT.LIAM
private string lastErrorMessage = null; private string lastErrorMessage = null;
private static readonly string[] RequiredGraphRoles = new[] private sealed class GraphPermissionRequirement
{ {
"Application.Read.All", public string Description { get; private set; }
"Channel.ReadBasic.All",
"Directory.Read.All", public string[] AcceptedPermissions { get; private set; }
"Files.ReadWrite.All",
public GraphPermissionRequirement(string description, params string[] acceptedPermissions)
{
Description = description;
AcceptedPermissions = acceptedPermissions ?? new string[0];
}
}
private static readonly GraphPermissionRequirement[] RequiredGraphPermissions = new[]
{
new GraphPermissionRequirement(
"Team lesen",
"Team.ReadBasic.All",
"Group.Read.All",
"Group.ReadWrite.All", "Group.ReadWrite.All",
"Directory.Read.All",
"Directory.ReadWrite.All"),
new GraphPermissionRequirement(
"Channels lesen",
"Channel.ReadBasic.All",
"ChannelSettings.Read.All",
"ChannelSettings.ReadWrite.All",
"Group.Read.All",
"Group.ReadWrite.All",
"Directory.Read.All",
"Directory.ReadWrite.All"),
new GraphPermissionRequirement(
"Dateien lesen und schreiben",
"Files.ReadWrite.All",
"Sites.ReadWrite.All",
"Sites.FullControl.All"),
new GraphPermissionRequirement(
"Benutzer lesen",
"User.Read.All",
"User.ReadWrite.All",
"Directory.Read.All",
"Directory.ReadWrite.All"),
};
private static readonly GraphPermissionRequirement[] CloneBaseGraphPermissions = new[]
{
new GraphPermissionRequirement("Teams klonen", "Team.Create"),
};
private static readonly GraphPermissionRequirement[] CloneAppsGraphPermissions = new[]
{
new GraphPermissionRequirement("Apps mitklonen", "Application.Read.All", "Application.ReadWrite.All"),
};
private static readonly GraphPermissionRequirement[] CloneSettingsGraphPermissions = new[]
{
new GraphPermissionRequirement("Team-Einstellungen mitklonen", "TeamSettings.Read.All", "TeamSettings.ReadWrite.All"),
};
private static readonly GraphPermissionRequirement[] CloneMemberGraphPermissions = new[]
{
new GraphPermissionRequirement(
"Mitglieder mitklonen",
"GroupMember.Read.All", "GroupMember.Read.All",
"GroupMember.ReadWrite.All", "GroupMember.ReadWrite.All",
"Team.Create", "Group.Read.All",
"Team.ReadBasic.All", "Group.ReadWrite.All",
"TeamSettings.Read.All", "Directory.Read.All",
"User.Read.All", "Directory.ReadWrite.All"),
}; };
private void SetLastError(string message) private void SetLastError(string message)
@@ -182,9 +238,57 @@ namespace C4IT.LIAM
private bool EnsureGraphPermissions(string accessToken) private bool EnsureGraphPermissions(string accessToken)
{ {
return EnsureGraphPermissions(accessToken, RequiredGraphPermissions, null);
}
private bool EnsureClonePermissions(string accessToken, int partsToClone)
{
var requirements = new List<GraphPermissionRequirement>(CloneBaseGraphPermissions);
var cloneParts = (CloneTeamRequest.ClonableTeamParts)partsToClone;
if (cloneParts.HasFlag(CloneTeamRequest.ClonableTeamParts.Apps))
requirements.AddRange(CloneAppsGraphPermissions);
if (cloneParts.HasFlag(CloneTeamRequest.ClonableTeamParts.Settings))
requirements.AddRange(CloneSettingsGraphPermissions);
if (cloneParts.HasFlag(CloneTeamRequest.ClonableTeamParts.Members))
requirements.AddRange(CloneMemberGraphPermissions);
return EnsureGraphPermissions(accessToken, requirements, "Team-Klonen");
}
private bool EnsureGraphPermissions(string accessToken, IEnumerable<GraphPermissionRequirement> requirements, string operationName)
{
if (!TryGetGrantedGraphPermissions(accessToken, out var granted, out var errorMessage))
{
SetLastError(errorMessage);
return false;
}
var missing = requirements
.Where(requirement => requirement.AcceptedPermissions == null || !requirement.AcceptedPermissions.Any(granted.Contains))
.Select(requirement => $"{requirement.Description} ({string.Join(" / ", requirement.AcceptedPermissions)})")
.ToList();
if (missing.Count > 0)
{
var prefix = string.IsNullOrWhiteSpace(operationName)
? "Fehlende Graph-Berechtigungen: "
: $"Fehlende Graph-Berechtigungen für {operationName}: ";
SetLastError(prefix + string.Join(", ", missing));
return false;
}
return true;
}
private bool TryGetGrantedGraphPermissions(string accessToken, out HashSet<string> granted, out string errorMessage)
{
granted = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
errorMessage = null;
if (string.IsNullOrWhiteSpace(accessToken)) if (string.IsNullOrWhiteSpace(accessToken))
{ {
SetLastError("Kein Access Token für Berechtigungsprüfung verfügbar"); errorMessage = "Kein Access Token für Berechtigungsprüfung verfügbar";
return false; return false;
} }
@@ -193,7 +297,7 @@ namespace C4IT.LIAM
var parts = accessToken.Split('.'); var parts = accessToken.Split('.');
if (parts.Length < 2) if (parts.Length < 2)
{ {
SetLastError("Ungültiges Access Token"); errorMessage = "Ungültiges Access Token";
return false; return false;
} }
@@ -209,12 +313,10 @@ namespace C4IT.LIAM
var payloadObj = JsonConvert.DeserializeObject<JObject>(payloadJson); var payloadObj = JsonConvert.DeserializeObject<JObject>(payloadJson);
if (payloadObj == null) if (payloadObj == null)
{ {
SetLastError("Token-Payload konnte nicht gelesen werden"); errorMessage = "Token-Payload konnte nicht gelesen werden";
return false; return false;
} }
var granted = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (payloadObj.TryGetValue("roles", out var rolesToken) && rolesToken is JArray roleArray) if (payloadObj.TryGetValue("roles", out var rolesToken) && rolesToken is JArray roleArray)
{ {
foreach (var role in roleArray.Values<string>()) foreach (var role in roleArray.Values<string>())
@@ -231,10 +333,9 @@ namespace C4IT.LIAM
granted.Add(scope); granted.Add(scope);
} }
var missing = RequiredGraphRoles.Where(required => !granted.Contains(required)).ToList(); if (!granted.Any())
if (missing.Count > 0)
{ {
SetLastError("Fehlende Graph-Berechtigungen: " + string.Join(", ", missing)); errorMessage = "Keine Graph-Berechtigungen im Access Token gefunden";
return false; return false;
} }
@@ -242,7 +343,7 @@ namespace C4IT.LIAM
} }
catch (Exception ex) catch (Exception ex)
{ {
SetLastError("Berechtigungsprüfung fehlgeschlagen: " + ex.Message); errorMessage = "Berechtigungsprüfung fehlgeschlagen: " + ex.Message;
return false; return false;
} }
} }
@@ -349,6 +450,11 @@ namespace C4IT.LIAM
public async Task<cMsGraphResultBase> cloneTeam(string teamId, string name, string description, int visibility, int partsToClone, string additionalMembers, string additionalOwners) public async Task<cMsGraphResultBase> cloneTeam(string teamId, string name, string description, int visibility, int partsToClone, string additionalMembers, string additionalOwners)
{ {
if (!await LogonAsync())
return null;
if (!EnsureClonePermissions(MsSharepoint.Base?.AccessToken, partsToClone))
return null;
var request = new CloneTeamRequest() var request = new CloneTeamRequest()
{ {
DisplayName = name, DisplayName = name,