(401) Unauthorized WebException sending calendar item to Exchange

G

Guest

First, apologies for cross-posting. I posted this message originally in
exchange2000.development, but it looks like that's an unmanaged group. At
least it doesn't show up in the list when looking at the managed groups...

Here's the original post:

I'm writing an ASP .net web application that (in part) adds a calendar item
to the user's Exchange mailbox. I "stole" some code that many people seem to
be using, and it works great as long as I run the application from the local
machine. When I hit the application from another machine, I get a 401 when
attempting the post.

I have annonymous turned off, and I'm attempting to add to my own calendar.

Here's my code:

public void SendQuery(string packageXml)
{

Byte[] packageBytes;
Stream requestStream;
Stream responseStream;
StreamReader reader;
string responseText;
System.Uri myUri = new
Uri("http://srvexchbnt01/exchange/KEVIN.SWANSON/Calendar/20040929123012.eml");
WebRequest httpRequest = HttpWebRequest.Create(myUri);

//use Integrated Windows authentication.
httpRequest.Credentials = CredentialCache.DefaultCredentials;

// add the keep-alive header
httpRequest.Headers.Add("HTTP_CONNECTION", "Keep-Alive");

//Set Headers.
httpRequest.Headers.Set("Pragma", "no-cache");
httpRequest.ContentType = "text/xml";
httpRequest.ContentLength = packageXml.Length;

//Set the request timeout to 5 minutes.
httpRequest.Timeout = 10000;

//Set the request method.
httpRequest.Method = "PROPPATCH";

//The data must be stored in a byte array.
packageBytes = System.Text.Encoding.ASCII.GetBytes(packageXml);
httpRequest.ContentLength = packageBytes.Length;
requestStream = httpRequest.GetRequestStream();

//Write the data to be posted to the Request Stream.
requestStream.Write(packageBytes, 0, packageBytes.Length);
requestStream.Close();

//Get Response Stream.
responseStream = httpRequest.GetResponse().GetResponseStream();

//Read the Response Steam.
reader = new StreamReader(responseStream);
responseText = reader.ReadToEnd();

//Close the Stream.
responseStream.Close();

}
 
B

bruce barker

you are probably hitting the 1 hop rule. to test this, logon locally to the
webserver and try. if that doesn't work, you forgot to turn impersonation on
in the web config.

to fix the 1 hop rule, you will need to use kerberos (and enable credentials
delegation) or basic authenication.

-- bruce (sqlwork.com)
 
G

Guest

Bruce,

I just found an article to that effect, and I'm guessing this is my problem.
Before I go to the network guys and ask them to allow delegation, can you
answer this question:

The .Net web app itself needs to be configured in IIS to user Integrated
Windows authentication, else I won't have a user to impersonate. So which
account do I need to give "trusted for delegation" rights to? The aspnet
account? The system account? The machine account?

My test server is Win2K, and the exchange server and target web server are
both 2003 servers, if that makes a difference.

Thanks so much for your help. From what I've seen in my search, many folks
have this problem and haven't found the document at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT05.asp


bruce barker said:
you are probably hitting the 1 hop rule. to test this, logon locally to the
webserver and try. if that doesn't work, you forgot to turn impersonation on
in the web config.

to fix the 1 hop rule, you will need to use kerberos (and enable credentials
delegation) or basic authenication.

-- bruce (sqlwork.com)


Kevin Swanson said:
First, apologies for cross-posting. I posted this message originally in
exchange2000.development, but it looks like that's an unmanaged group. At
least it doesn't show up in the list when looking at the managed groups...

Here's the original post:

I'm writing an ASP .net web application that (in part) adds a calendar item
to the user's Exchange mailbox. I "stole" some code that many people seem to
be using, and it works great as long as I run the application from the local
machine. When I hit the application from another machine, I get a 401 when
attempting the post.

I have annonymous turned off, and I'm attempting to add to my own calendar.

Here's my code:

public void SendQuery(string packageXml)
{

Byte[] packageBytes;
Stream requestStream;
Stream responseStream;
StreamReader reader;
string responseText;
System.Uri myUri = new
Uri("http://srvexchbnt01/exchange/KEVIN.SWANSON/Calendar/20040929123012.eml"
);
WebRequest httpRequest = HttpWebRequest.Create(myUri);

//use Integrated Windows authentication.
httpRequest.Credentials = CredentialCache.DefaultCredentials;

// add the keep-alive header
httpRequest.Headers.Add("HTTP_CONNECTION", "Keep-Alive");

//Set Headers.
httpRequest.Headers.Set("Pragma", "no-cache");
httpRequest.ContentType = "text/xml";
httpRequest.ContentLength = packageXml.Length;

//Set the request timeout to 5 minutes.
httpRequest.Timeout = 10000;

//Set the request method.
httpRequest.Method = "PROPPATCH";

//The data must be stored in a byte array.
packageBytes = System.Text.Encoding.ASCII.GetBytes(packageXml);
httpRequest.ContentLength = packageBytes.Length;
requestStream = httpRequest.GetRequestStream();

//Write the data to be posted to the Request Stream.
requestStream.Write(packageBytes, 0, packageBytes.Length);
requestStream.Close();

//Get Response Stream.
responseStream = httpRequest.GetResponse().GetResponseStream();

//Read the Response Steam.
reader = new StreamReader(responseStream);
responseText = reader.ReadToEnd();

//Close the Stream.
responseStream.Close();

}
 
S

Steven Cheng[MSFT]

Hi Kevin,

As for the question in your last reply , here is my understandings:
================================================
The .Net web app itself needs to be configured in IIS to user Integrated
Windows authentication, else I won't have a user to impersonate. So which
account do I need to give "trusted for delegation" rights to? The aspnet
account? The system account? The machine account?
=================================================

Regardless of all the aboves, we first need to know that we have to give
the "trust for delegation" to the account who run the asp.net applciation's
worker process. By default(not impersonate), is the Machine\ASPNET account,
this is a local account. So we have to change it to the LOCAL SYSTEM or a
domain user account. Then:
1. if use the local system account , we need to give the right to the
computer account
2. if use domain account as the worker process account , we need to give
the domain account that right.

Also, if you're using impersonate in your asp.net web app, you need to give
the right to the client accoutn which maybe impersonated in your web
application.


=======================================================
My test server is Win2K, and the exchange server and target web server are
both 2003 servers, if that makes a difference.
======================================================
One difference between WIN2K and win2k3 is the process Model, on win2k3
with iis6, the default process Model is IIS6's applicaiton pool model. And
the default process Account is the NetworkService which in the IIS_WPG
group. For the process MOdel topic, you can search the related reference in
msdn:

Hope helps. Thanks.

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
G

Guest

Thanks for the clarification, Steven. The impersonated user should already
have adequate rights, since it's his/her mailbox that's being modified.
Creating a service account for the process thread will probably solve the
problem.

I also came up with an alternative solution. Rather than attempting to post
the xml to the exchange server from the web server, I can have the server
simply do the work of creating the package xml. The xml is then written into
an xml data island on the client. The client posts the xml to the exchange
server via the xmlHttp object. That allows the client to authenticate with
the exchange server directly. Here's the client side code:
<script language="javascript">
function SendData()
{

var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

var packageXml = TestXml.xml
var formAction = document.Form1.ExchangeUrl.value;

//alert(packageXml);
//alert(formAction);


try
{
try
{
xmlhttp.Open("PROPPATCH",formAction,false);
xmlhttp.setRequestHeader("Pragma", "no-cache");
xmlhttp.setRequestHeader("Content-Type", "text/xml");


}
catch (ex)
{
alert(ex.message);
}
xmlhttp.send(packageXml);

}
catch (ex)
{
alert(ex.message);
}
}

</script>
....
<form id="Form1" method="post" runat="server">
....
<xml id="TestXml" name="TestXml">
<asp:Xml id="ExchangePackageXml" runat="server"
EnableViewState="False"></asp:Xml>
</xml>

'course I guess this is only going to work reliably on IE...
 
S

Steven Cheng[MSFT]

Hi Kevin,

Thanks for the followup and sharing the other solution. Yes, the XML island
is only compatiable with IE browser. But that's ok if your client users
won't use the other browsers. Anyway, thanks again for posting here. Have
a good day!

Regards,

Steven Cheng
Microsoft Online Support
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,810
Latest member
Kassie0918

Latest Threads

Top