G
George Durzi
We recently upgraded to Exchange2K3/W2K3 from Exchange2K/W2K, and some of my
c# code that I used to access users' contacts using WebDAV has stopped
working. I'm getting a 401 unauthorized error. Hopefully, I can explain this
adequately.
Prior to the upgrade the following code was working properly.
FYI: The site was running in the context of the domain administrator, and
was also using the Administrator account to create a CredentialCache to
access Exchange
This function accepts my URI:
http://myMailServer/exchange/userLogin/contacts/?Cmd=contents
#region FetchContactsXml
private string FetchContactsXml(string sSourceURL)
{
StringBuilder sbPayload = new StringBuilder();
sbPayload.Append("<?xml version=\"1.0\"?>");
sbPayload.Append("<a:searchrequest xmlns:a=\"DAV:\">");
sbPayload.Append("<sql> SELECT \"urn:schemas:contacts:fileas\" ");
sbPayload.Append(", \"urn:schemas:contacts:givenName\" ");
sbPayload.Append(", \"urn:schemas:contacts:sn\" ");
sbPayload.Append(", \"urn:schemas:contacts
\" ");
sbPayload.Append("FROM Scope('SHALLOW TRAVERSAL OF \"\"') ");
sbPayload.Append("Where \"DAV:isfolder\" = false AND \"DAV:contentclass\"
");
sbPayload.Append("= 'urn:content-classes
erson'");
sbPayload.Append(" ORDER BY \"urn:schemas:contacts:fileas\" ASC");
sbPayload.Append("</>");
sbPayload.Append("</>");
// Array to hold Xml Payload
byte[] arPayload = null;
try
{
// Get Payload and Encode it to utf-8
arPayload = Encoding.UTF8.GetBytes((string)sbPayload.ToString());
// Create HTTP Web Request & Set Properties
HttpWebRequest oWebRequest =
(System.Net.HttpWebRequest)HttpWebRequest.Create(sSourceURL);
oWebRequest.Method = "SEARCH";
oWebRequest.ContentType = "text/xml";
oWebRequest.ContentLength = arPayload.Length;
// Inject the Search Payload into the RequestStream
Stream oRequestStream = oWebRequest.GetRequestStream();
oRequestStream.Write(arPayload, 0, arPayload.Length);
oRequestStream.Close();
// Set Credentials to Access Exchange Store
oWebRequest.Credentials = CreateCredentialCache(sSourceURL);
// Create the Web Response Object
System.Net.WebResponse oWebResponse = (System.Net.WebResponse)
oWebRequest.GetResponse();
// Get the Xml Response Stream
Stream oStream = oWebResponse.GetResponseStream();
// utf-8 handle it
Encoding oEncoding = System.Text.Encoding.GetEncoding("utf-8");
StreamReader oStreamReader = new StreamReader(oStream, oEncoding);
// Get the WebDAV Xml into a string
string sXmlData = oStreamReader.ReadToEnd();
// Clean Up
oStreamReader.Close();
oStream.Close();
oWebResponse.Close();
// Return the Xml string
return sXmlData;
}
catch (Exception oException)
{
ExceptionManager.Publish(oException);
throw(oException);
}
}
#endregion
#region CreateCredentialCache
private CredentialCache CreateCredentialCache(string sSourceURL)
{
try
{
CredentialCache oCredentialCache = new CredentialCache();
oCredentialCache.Add(
new System.Uri(sSourceURL),
"NTLM",
new NetworkCredential(
ConfigurationSettings.AppSettings["ExchangeAdminAccount"].ToString(),
@ConfigurationSettings.AppSettings["ExchangeAdminAccountPwd"].ToString(),
ConfigurationSettings.AppSettings["DomainName"].ToString()));
return oCredentialCache;
}
catch (Exception oException)
{
ExceptionManager.Publish(oException);
throw(oException);
}
}
#endregion
As I said, all of this worked perfectly before the upgrade. Now apparently
Exchange 2003 doesn't allow the Administrator account to have permissions on
all other account by default - which is a good thinkg since I shouldn't have
been using that anyway. So our exchange admin created an account for me to
use with the necessary permissions.
I verified that the account he created can access a user's contacts folder
by browsing to http://myMailServer/exchange/userLogin/contacts/?Cmd=contents
and logging in as DOMAIN\account, password. I was able to open any user's
contacts folder that I wanted to.
Ok, so after the upgrade, the code breaks at the following spot:
Stream oRequestStream = oWebRequest.GetRequestStream();
I noticed that this is before I even attached the CredentialCache, so I
tried moving that to above that point in code, but no change.
The exact exception is:
The remote server returned an error: (401) Unauthorized.
When building the CredentialCache in the CreateCredentialCache function, I
am using that new account I noted that our exchange admin created.
Any help is appreciated.
c# code that I used to access users' contacts using WebDAV has stopped
working. I'm getting a 401 unauthorized error. Hopefully, I can explain this
adequately.
Prior to the upgrade the following code was working properly.
FYI: The site was running in the context of the domain administrator, and
was also using the Administrator account to create a CredentialCache to
access Exchange
This function accepts my URI:
http://myMailServer/exchange/userLogin/contacts/?Cmd=contents
#region FetchContactsXml
private string FetchContactsXml(string sSourceURL)
{
StringBuilder sbPayload = new StringBuilder();
sbPayload.Append("<?xml version=\"1.0\"?>");
sbPayload.Append("<a:searchrequest xmlns:a=\"DAV:\">");
sbPayload.Append("<sql> SELECT \"urn:schemas:contacts:fileas\" ");
sbPayload.Append(", \"urn:schemas:contacts:givenName\" ");
sbPayload.Append(", \"urn:schemas:contacts:sn\" ");
sbPayload.Append(", \"urn:schemas:contacts
sbPayload.Append("FROM Scope('SHALLOW TRAVERSAL OF \"\"') ");
sbPayload.Append("Where \"DAV:isfolder\" = false AND \"DAV:contentclass\"
");
sbPayload.Append("= 'urn:content-classes
sbPayload.Append(" ORDER BY \"urn:schemas:contacts:fileas\" ASC");
sbPayload.Append("</>");
sbPayload.Append("</>");
// Array to hold Xml Payload
byte[] arPayload = null;
try
{
// Get Payload and Encode it to utf-8
arPayload = Encoding.UTF8.GetBytes((string)sbPayload.ToString());
// Create HTTP Web Request & Set Properties
HttpWebRequest oWebRequest =
(System.Net.HttpWebRequest)HttpWebRequest.Create(sSourceURL);
oWebRequest.Method = "SEARCH";
oWebRequest.ContentType = "text/xml";
oWebRequest.ContentLength = arPayload.Length;
// Inject the Search Payload into the RequestStream
Stream oRequestStream = oWebRequest.GetRequestStream();
oRequestStream.Write(arPayload, 0, arPayload.Length);
oRequestStream.Close();
// Set Credentials to Access Exchange Store
oWebRequest.Credentials = CreateCredentialCache(sSourceURL);
// Create the Web Response Object
System.Net.WebResponse oWebResponse = (System.Net.WebResponse)
oWebRequest.GetResponse();
// Get the Xml Response Stream
Stream oStream = oWebResponse.GetResponseStream();
// utf-8 handle it
Encoding oEncoding = System.Text.Encoding.GetEncoding("utf-8");
StreamReader oStreamReader = new StreamReader(oStream, oEncoding);
// Get the WebDAV Xml into a string
string sXmlData = oStreamReader.ReadToEnd();
// Clean Up
oStreamReader.Close();
oStream.Close();
oWebResponse.Close();
// Return the Xml string
return sXmlData;
}
catch (Exception oException)
{
ExceptionManager.Publish(oException);
throw(oException);
}
}
#endregion
#region CreateCredentialCache
private CredentialCache CreateCredentialCache(string sSourceURL)
{
try
{
CredentialCache oCredentialCache = new CredentialCache();
oCredentialCache.Add(
new System.Uri(sSourceURL),
"NTLM",
new NetworkCredential(
ConfigurationSettings.AppSettings["ExchangeAdminAccount"].ToString(),
@ConfigurationSettings.AppSettings["ExchangeAdminAccountPwd"].ToString(),
ConfigurationSettings.AppSettings["DomainName"].ToString()));
return oCredentialCache;
}
catch (Exception oException)
{
ExceptionManager.Publish(oException);
throw(oException);
}
}
#endregion
As I said, all of this worked perfectly before the upgrade. Now apparently
Exchange 2003 doesn't allow the Administrator account to have permissions on
all other account by default - which is a good thinkg since I shouldn't have
been using that anyway. So our exchange admin created an account for me to
use with the necessary permissions.
I verified that the account he created can access a user's contacts folder
by browsing to http://myMailServer/exchange/userLogin/contacts/?Cmd=contents
and logging in as DOMAIN\account, password. I was able to open any user's
contacts folder that I wanted to.
Ok, so after the upgrade, the code breaks at the following spot:
Stream oRequestStream = oWebRequest.GetRequestStream();
I noticed that this is before I even attached the CredentialCache, so I
tried moving that to above that point in code, but no change.
The exact exception is:
The remote server returned an error: (401) Unauthorized.
When building the CredentialCache in the CreateCredentialCache function, I
am using that new account I noted that our exchange admin created.
Any help is appreciated.