Unauthorized error after deploying your custom application

I've been working on deploying an application today. I received the error "Unauthorized" all the time and did not know why. The website was deployed as a new virtual directory within the ISV folder, authentication was set to integrated windows authentication and the password which was supplied was correct. Still I was able to get this error message:


Server Error in '/ISV/CustomApplication' Application.
The request failed with HTTP status 401: Unauthorized. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.Net.WebException: The request failed with HTTP status 401: Unauthorized.Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. Stack Trace:
[WebException: The request failed with HTTP status 401: Unauthorized.]
System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall) +551137
System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) +204
Microsoft.Crm.Metadata.MetadataWebService.GetDataSet() +31
Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadDataSetFromWebService(Guid orgId) +301
Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadCacheFromWebService(LoadMasks masks, Guid organizationId) +40
Microsoft.Crm.Metadata.DynamicMetadataCacheFactory.LoadMetadataCache(LoadMethod method, CacheType type, IOrganizationContext context) +418
Microsoft.Crm.Metadata.MetadataCache.LoadCache(IOrganizationContext context) +324
Microsoft.Crm.Metadata.MetadataCache.GetInstance(IOrganizationContext context) +386
Microsoft.Crm.BusinessEntities.BusinessEntityMoniker..ctor(Guid id, String entityName, Guid organizationId) +115
Microsoft.Crm.Caching.UserDataCacheLoader.LoadCacheData(Guid key, ExecutionContext context) +323
Microsoft.Crm.Caching.ObjectModelCacheLoader`2.LoadCacheData(TKey key, IOrganizationContext context) +389
Microsoft.Crm.Caching.BasicCrmCache`2.CreateEntry(TKey key, IOrganizationContext context) +82
Microsoft.Crm.Caching.BasicCrmCache`2.LookupEntry(TKey key, IOrganizationContext context) +108
Microsoft.Crm.BusinessEntities.SecurityLibrary.GetUserInfoInternal(WindowsIdentity identity, IOrganizationContext context, UserAuth& userInfo) +344
Microsoft.Crm.BusinessEntities.SecurityLibrary.GetCallerAndBusinessGuidsFromThread(WindowsIdentity identity, Guid organizationId) +194
Microsoft.Crm.Authentication.CrmWindowsIdentity..ctor(WindowsIdentity innerIdentity, Boolean publishCrmUser, Guid organizationId) +279
Microsoft.Crm.Authentication.WindowsAuthenticationProvider.Authenticate(HttpApplication application) +605
Microsoft.Crm.Authentication.AuthenticationStep.Authenticate(HttpApplication application) +125
Microsoft.Crm.Authentication.AuthenticationPipeline.Authenticate(HttpApplication application) +66
Microsoft.Crm.Authentication.AuthenticationEngine.Execute(Object sender, EventArgs e) +513
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +92
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64
Version Information: Microsoft .NET Framework Version:2.0.50727.1433; ASP.NET Version:2.0.50727.1433

After quite a search I managed to find this blog. There I learned that CRM is using an HttpModule for multitenancy. The http module will be called with an anonymous user account and will fail when it's requesting the metadata webservice. To make your own app working, you'll need to remove the HttpModule from being loaded. A copy paste piece from Cesar de la Torre's blog:

This is what you have to add to your own web.con file:

<system.web>
<httpModules>
<clear/>
</httpModules>

Also, if you are not using any CRM 4.0 Titan assembly within your app, you can also get rid of all the references, adding also the following:

<assemblies>
<clear/>
<add assembly="*"/>


Personally I prefer the removal of only the exact names instead of a generic "clear". What I ended up using is:

<httpModules>
<remove name ="CrmAuthentication"/>
<remove name ="MapOrg"/>
</httpModules>


If any of you finds a better approach I'm glad to hear that. Until then I'll be using this approach.

13 comments:

Anonymous said...

Thank you! Just the remove-lines did it for me :)

Mira Ghaly said...
This comment has been removed by the author.
Anonymous said...

i have a problem in reading values from my application web.config can u help me with that

Ronald Lemmen said...

Mira, what problem do you have?

Anonymous said...

Hi, what are the effects of removing these two httpModules? We have the same issue on our prod server (dev & systest environments were fine) - our app calls CRM web services, so I'm concerned over what impact removing these modules might have.

Swati Shah said...

Hi,

I need to retreive the picklist items values using MetaData service.
I am not able to connect to the MetaData Service in my production environment which is an IFD deployment.
It gives me an "401 : UnAuthorised Error." . The same code works well in my development environment which is a VPC environment.
Pls find code below for the same.

Also when I look at the log file the error oroiginates from the line
"RetrieveAttributeResponse amRes = (RetrieveAttributeResponse)service.Execute(attribReq);"

The metadata service url created is fine and it returns the meta methods when pasted on a web browser.


public static MetadataService GetMetaDataService()
{
MetadataService service = new MetadataService();
try{
string organization = "PROD"; //ConfigurationManager.AppSettings["OrgName"].ToString();
string server = "PRODUCTION";//ConfigurationManager.AppSettings["ServerName"].ToString();
string domain = "HOSTING";//ConfigurationManager.AppSettings["CRMDomain"].ToString();
string username = "Administrator";//ConfigurationManager.AppSettings["CRMUserName"].ToString();
string password = "XXXXXX";//ConfigurationManager.AppSettings["CRMPassword"].ToString();
string VDBAuthenticationType = "SPLA";//ConfigurationManager.AppSettings["AuthenticationType"].ToString();


service.Credentials = new System.Net.NetworkCredential(username, password,domain);

string Server = "PRODUCTION"; //ConfigurationManager.AppSettings["ServerName"].ToString();
string Port = "80";//ConfigurationManager.AppSettings["PortNumber"].ToString();


service.CrmAuthenticationTokenValue = new MetaSdk.CrmAuthenticationToken();
service.CrmAuthenticationTokenValue.OrganizationName = organization;


if (Port != "")
service.Url = string.Format("http://{0}:{1}/mscrmservices/2007/metadataservice.asmx", Server, Port);
else
service.Url = string.Format("http://{0}/mscrmservices/2007/metadataservice.asmx", Server);



}
catch(SoapException ex)
{
ErrorWriter(ex,"Meta Sevice Error");
}
}


Also the code for Retreiving picklist Values is here
public static int GetPickListItemValue(string entityName, string pickListName, string itemLabel)
{

int itemValue = 0;
try
{

MetadataService service = new MetadataService();

service = GetMetaDataService();

RetrieveAttributeRequest attribReq = new RetrieveAttributeRequest();
attribReq.EntityLogicalName = entityName;
attribReq.LogicalName = pickListName;

// Get the attribute metadata for the pickListName attribute.
RetrieveAttributeResponse amRes = (RetrieveAttributeResponse)service.Execute(attribReq);

AttributeMetadata am = amRes.AttributeMetadata;

PicklistAttributeMetadata listData = (PicklistAttributeMetadata)am;

foreach (Option option in listData.Options)
{
foreach (LocLabel label in option.Label.LocLabels)
{
// Show US English value:label pairs
if (label.LanguageCode.Value == 1033)

if (label.Label.Equals(itemLabel))
{
itemValue = option.Value.Value;
}
}
}
}
catch(SoapException ex)
{
ErrorWriter(ex,"Error in Retreiving PickList Values, Metadata Sevice Error");
}


return itemValue;

}


Pls help me out.
I am stuck with this code as it works fine in mu[y VPC but gives "401 error" in the production.
Also I have verified that the logged in user has the righta for Entity, Relationship and Attribute as he is the administarator of CRM.

I have also added "/clear" tag in the web.config file but no sucess.


Regards
Susan

Anonymous said...

Thanks dude, removing the httpmodules did the trick.

I had no idea what the issue was, and searching for the stack trace got me to your post :)

Ronald Lemmen said...

Susan,

Your question is not relevant to this posting. Please post your question to the forums which you can find here:
http://msdn.microsoft.com/en-us/dynamics/crm/bb501031.aspx

Kind regards,
Ronald

Anonymous said...

hi,

our application is using crmimpersonation, if we remove the modules, we receive:
System.Security.SecurityException: UserId not found
for the current user on the context

when we reach this part of code
on the using(new CrmImpersonator()) {
//...
}

any ideas?

the customer is using an enterprise-crm

Anonymous said...

Pretty nice place you've got here. Thank you for it. I like such topics and anything connected to them. BTW, why don't you change design :).

Kevin said...

Very helpful blog post. I have an application that we are moving from a separate server to the CRM Server. And this helped me zero in on the problem.

Keeping in mind that the application works fine on our other server, I used "remove" and still got 401 errors, when I use clear I get an error saying "Unable to cast object of type 'System.Security.Principal.GenericIdentity' to type 'System.Security.Principal.WindowsIdentity'."

Any thoughts?

darksander said...

Hi,
I tried your advice but no joy. I'll explain my situation a bit: from within the (hosted) crm site I run a custom aspx page which fills a gridview with data relevant to the current logged user; since it's hosted, there's an IFD authentication taking place, and the user running the sql script ends up being the network service (the identity for the app pool). Will it be possible for me to translate the crm user to its windows counterpart?
Thank you

Alex said...

Thank you!
This blog post helped me solve my problem with System.OutOfMemory.Exception in custom web application!