Register created app as public client (fix connect AADSTS7000218) #1
@@ -58,6 +58,10 @@ public class ElevationCoordinator : IElevationCoordinator
|
||||
await ElevateAsync(siteUrl, ct);
|
||||
_elevatedSites.Add(key);
|
||||
|
||||
// Verify the grant actually took effect for this delegated token before retrying,
|
||||
// so the logs distinguish "grant failed/no-op" from "scan still fails for another reason".
|
||||
await VerifyAdminAsync(siteUrl, ct);
|
||||
|
||||
// Re-run once. The closure re-issues its loads; the now-granted admin right applies.
|
||||
return await operation(ct);
|
||||
}
|
||||
@@ -88,12 +92,31 @@ public class ElevationCoordinator : IElevationCoordinator
|
||||
}
|
||||
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||
{
|
||||
Log.Error(ex, "Auto-elevate ownership failed for {Site}", siteUrl);
|
||||
throw new InvalidOperationException(
|
||||
$"Auto-elevate ownership failed for {siteUrl}. Granting site-collection admin requires " +
|
||||
$"SharePoint tenant administrator rights on the signed-in account. ({ex.Message})", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the current user's site-admin flag on the target site right after elevation.
|
||||
// Diagnostic only — never throws into the operation flow.
|
||||
private async Task VerifyAdminAsync(string siteUrl, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ctx = await _sessionManager.GetOrCreateContextAsync(siteUrl, _session.CurrentProfile!, ct);
|
||||
ctx.Load(ctx.Web.CurrentUser, u => u.LoginName, u => u.IsSiteAdmin);
|
||||
await ctx.ExecuteQueryAsync();
|
||||
Log.Information("Post-elevation check {Site}: user={Login} IsSiteAdmin={IsAdmin}",
|
||||
siteUrl, ctx.Web.CurrentUser.LoginName, ctx.Web.CurrentUser.IsSiteAdmin);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning("Post-elevation check failed for {Site}: {Error}", siteUrl, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// https://abcube.sharepoint.com/sites/Foo → https://abcube-admin.sharepoint.com
|
||||
private static string BuildAdminUrl(string siteUrl)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Microsoft.Online.SharePoint.TenantAdministration;
|
||||
using Microsoft.SharePoint.Client;
|
||||
using Serilog;
|
||||
using SharepointToolbox.Web.Core.Helpers;
|
||||
using SharepointToolbox.Web.Services.Audit;
|
||||
|
||||
namespace SharepointToolbox.Web.Services;
|
||||
@@ -15,12 +17,20 @@ public class OwnershipElevationService : IOwnershipElevationService
|
||||
if (string.IsNullOrWhiteSpace(loginName))
|
||||
{
|
||||
tenantAdminCtx.Load(tenantAdminCtx.Web.CurrentUser, u => u.LoginName);
|
||||
await tenantAdminCtx.ExecuteQueryAsync();
|
||||
await ExecuteQueryRetryHelper.ExecuteQueryRetryAsync(tenantAdminCtx, null, ct);
|
||||
loginName = tenantAdminCtx.Web.CurrentUser.LoginName;
|
||||
}
|
||||
|
||||
Log.Information("SetSiteAdmin: granting {Login} site-collection admin on {Site} via admin endpoint {Admin}",
|
||||
loginName, siteUrl, tenantAdminCtx.Url);
|
||||
|
||||
var tenant = new Tenant(tenantAdminCtx);
|
||||
tenant.SetSiteAdmin(siteUrl, loginName, isSiteAdmin: true);
|
||||
await tenantAdminCtx.ExecuteQueryAsync();
|
||||
// Route through the enricher so a denial on the admin endpoint surfaces the real reason
|
||||
// (and gets logged) instead of a bare 403 the caller has to guess at.
|
||||
await ExecuteQueryRetryHelper.ExecuteQueryRetryAsync(tenantAdminCtx, null, ct);
|
||||
|
||||
Log.Information("SetSiteAdmin call accepted for {Site} (login {Login})", siteUrl, loginName);
|
||||
await _audit.LogAsync("ElevateOwnership", tenantAdminCtx.Url, new[] { siteUrl },
|
||||
$"Site admin granted to {loginName}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user