using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.IdentityModel.Claims;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk.Client;
namespace AdfsEnabledReportViewerWebRole
{
public static class ActOnBehalfOfHelper
{
// ReSharper disable InconsistentNaming
private const string CRM_CALLERID = "CRM_CALLERID";
// ReSharper restore InconsistentNaming
public static ContextConnection CreateContextAndConnection()
{
var contextConnection = new ContextConnection();
// Connect to CRM with a single named user (i.e. system account / trusted subsystem model) who has the ActOnBehalfOf privelege
contextConnection.Connection =
CrmConnection.Parse("Url=[YOUR_ORG_URL];Username=[YOUR_USERNAME];Password=[YOUR_PASSWORD]");
contextConnection.Context =
new OrganizationServiceContext(new OrganizationService(contextConnection.Connection));
return contextConnection;
}
public static Guid GetCallerId()
{
Guid callerId;
var contextConnection = CreateContextAndConnection();
var ctx = contextConnection.Context;
// NOTE: I am caching the CallerId to minimize calls to the CRM Organization Service.
// For production code, you should not store the CallerId in plain text in a cookie.
// Malicious code, once authenticated, can change the cookie value and execute as another caller.
// You could apply encryption when creating the cookie and decryption when reading
// the cookie value:
// http://msdn.microsoft.com/en-us/library/windowsazure/hh697511.aspx
// You could even encrypt/decrypt the cookie name to obfuscate the purpose of the cookie.
// Alternatively, find a different approach to cache the CallerId value (ASP.NET Session for example)
// or simply don't cache the CallerId.
HttpCookie callerIdCookie = HttpContext.Current.Request.Cookies[CRM_CALLERID];
// If the cookie exists, reuse the Guid string value to execute the call as the current user
// If not, then query CRM to get the Guid of the authenticated user based on the upn claim
if (callerIdCookie == null)
{
ClaimCollection claims = ((IClaimsIdentity) HttpContext.Current.User.Identity).Claims;
IEnumerable<Claim> claimQuery = from c in claims
where
c.ClaimType ==
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"
select c;
Claim upnClaim = claimQuery.FirstOrDefault();
var userQuery = from user in ctx.CreateQuery<SystemUser>()
where user.DomainName == upnClaim.Value
select user.SystemUserId.Value;
callerId = userQuery.FirstOrDefault();
if (callerId == Guid.Empty)
{
// Send HTTP status code of 403
// See http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
HttpContext.Current.Response.StatusCode = 403;
HttpContext.Current.Response.End();
}
string callerIdString = callerId.ToString();
HttpContext.Current.Response.Cookies.Add(new HttpCookie(CRM_CALLERID, callerIdString));
}
else
{
callerId = new Guid(callerIdCookie.Value);
}
return callerId;
}
}
public class ContextConnection
{
public CrmConnection Connection { get; set; }
public OrganizationServiceContext Context { get; set; }
}
}