WebDAV Issues After Upgrade to Exchange 2003

  • Thread starter Thread starter George Durzi
  • Start date Start date
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:o\" ");
sbPayload.Append("FROM Scope('SHALLOW TRAVERSAL OF \"\"') ");
sbPayload.Append("Where \"DAV:isfolder\" = false AND \"DAV:contentclass\"
");
sbPayload.Append("= 'urn:content-classes:person'");
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.
 
And you're not running forms-based authentication or frontend/backend OWA or
anything like that? See if the Exchange Explorer can access your folders
since that's a WebDAV client as well.

Tom

--
Looking for a good book on programming Exchange, Outlook, ADSI and
SharePoint? Check out http://www.microsoft.com/MSPress/books/5517.asp



George Durzi said:
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:o\" ");
sbPayload.Append("FROM Scope('SHALLOW TRAVERSAL OF \"\"') ");
sbPayload.Append("Where \"DAV:isfolder\" = false AND
\"DAV:contentclass\" ");
sbPayload.Append("= 'urn:content-classes:person'");
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.
 
Tom,
Sorry, I'm not too experienced with administering Exchange. Is the Exchange
Explorer when you actually browse in IE to
http:\\exchserver\exchange\login\Inbox, etc..?

If so, yes it works

Tom Rizzo said:
And you're not running forms-based authentication or frontend/backend OWA
or anything like that? See if the Exchange Explorer can access your
folders since that's a WebDAV client as well.

Tom

--
Looking for a good book on programming Exchange, Outlook, ADSI and
SharePoint? Check out http://www.microsoft.com/MSPress/books/5517.asp



George Durzi said:
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:o\" ");
sbPayload.Append("FROM Scope('SHALLOW TRAVERSAL OF \"\"') ");
sbPayload.Append("Where \"DAV:isfolder\" = false AND
\"DAV:contentclass\" ");
sbPayload.Append("= 'urn:content-classes:person'");
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.
 
Back
Top