Skip to content

Commit

Permalink
Ensure impersonation was successful
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMpn committed Apr 23, 2024
1 parent cee3566 commit c691fcc
Showing 1 changed file with 45 additions and 11 deletions.
56 changes: 45 additions & 11 deletions MarkMpn.Sql4Cds.Engine/ExecutionPlan/ExecuteAsNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
using System.ComponentModel;
using System.Data.SqlTypes;
using System.Linq;
using System.Net.PeerToPeer;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlServer.TransactSql.ScriptDom;
using Microsoft.Xrm.Sdk;
using System.Reflection;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
#if NETCOREAPP
using Microsoft.PowerPlatform.Dataverse.Client;
#else
Expand Down Expand Up @@ -100,22 +98,58 @@ public override void Execute(NodeExecutionContext context, out int recordsAffect

var userId = (Guid)userIdAccessor(entities[0]);

PropertyInfo callerIdProp;

#if NETCOREAPP
if (dataSource.Connection is ServiceClient svc)
svc.CallerId = userId;
callerIdProp = Expr.GetPropertyInfo(() => svc.CallerId);
#else
if (dataSource.Connection is Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy svcProxy)
svcProxy.CallerId = userId;
callerIdProp = Expr.GetPropertyInfo(() => svcProxy.CallerId);
else if (dataSource.Connection is Microsoft.Xrm.Sdk.WebServiceClient.OrganizationWebProxyClient webProxy)
webProxy.CallerId = userId;
callerIdProp = Expr.GetPropertyInfo(() => webProxy.CallerId);
else if (dataSource.Connection is CrmServiceClient svc)
svc.CallerId = userId;
callerIdProp = Expr.GetPropertyInfo(() => svc.CallerId);
#endif
else
throw new QueryExecutionException("Unexpected organization service type");

recordsAffected = -1;
message = $"Impersonated user {userId}";
// Some application users can't be reliably impersonated - check the impersonation has actually worked and revert it if not
var existingUserId = callerIdProp.GetValue(dataSource.Connection);

callerIdProp.SetValue(dataSource.Connection, userId);

try
{
try
{
var qry = new Microsoft.Xrm.Sdk.Query.QueryExpression("systemuser");
qry.Criteria.AddCondition("systemuserid", ConditionOperator.EqualUserId);
var actualUserId = ((RetrieveMultipleResponse)dataSource.Execute(new RetrieveMultipleRequest { Query = qry })).EntityCollection.Entities.Single().Id;

if (actualUserId != userId)
throw new QueryExecutionException(Sql4CdsError.ImpersonationError(username), new ApplicationException("User was found but the server could not impersonate it"));

recordsAffected = -1;
message = $"Impersonated user {userId}";
}
catch
{
callerIdProp.SetValue(dataSource.Connection, existingUserId);
throw;
}
}
catch (QueryExecutionException ex)
{
if (ex.Errors[0].Number != 15517)
throw new QueryExecutionException(Sql4CdsError.ImpersonationError(username), ex);

throw;
}
catch (Exception ex)
{
throw new QueryExecutionException(Sql4CdsError.ImpersonationError(username), ex);
}
}
}
catch (QueryExecutionException ex)
Expand Down

0 comments on commit c691fcc

Please sign in to comment.