Sending messages with Pre-Authorized http header information in BizTalk Server
Recently one of my customer was getting the following error when trying to send messages to a service:
A message sent to adapter "SOAP" on send port "sndPrt_zzzzz" with URI "https://xxx.com/yyy" is suspended.
Error details: 320 - Security Error
We are using a SOAP adapter with Basic Authentication. The same issue will however occur with WCFWebHttp adapter as well. On checking further in fiddler traces we found out that the server is sending the following response:
HTTP/1.1 500 Authentication Required
X-CorrelationID: xxxxxxxxxxxxxxxxxxxxxx
Connection: keep-alive
Transfer-Encoding: chunked
Server: xxxxx
Date: Fri, 27 Feb 2015 23:02:02 GMT
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US,en;q=0.5
DNT: 1
Host: xxxxxxxx
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
WWW-Authenticate: Basic realm="xxxx.com"
X-P2P-PeerDist: Version=1.1
X-P2P-PeerDistEx: MinContentInformation=1.0, MaxContentInformation=2.0
Content-Type: text/xml; charset="UTF-8"
Ideally the message handshake with basic authentication happens as follows:
Client -> Sends request ->Server
Server -> 401 Unauthorized -> Client
Client -> Authentication -> Server
Here is the catch. The reason why were not able to send is that the server was returning the error code as 500, which means Internal server error. Therefore BizTalk client will never come to know that the server is expecting the authentication information and therefore the handshake fails.
The solution can be to send the basic authentication information in the first request itself. This means that we want to eliminate the handshake and server is not required to send a 401 request.
How can this be done in BizTalk Server?
Answer is; we cannot.
Sending a message with pre-authorization will not be possible using any adapter in BizTalk. As per this msdn link, https://msdn.microsoft.com/en-us/library/aa547980(BTS.20).aspx.
It mentions that we can set some custom headers but authentication header is not allowed.
Therefore the workaround will be to send the message to the web service using a C# library. Here is the code snippet that can help you send the pre-authorized messages to the server side.
public static void CallWebRequest(string message)
{
//Set the URL of the service and creating a request object
string url = https://xxxx.com/yyyyy;
HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest;
//Specifying the logon information
string user = "UserName";
string pwd = "Password";
//Adding the Basic Authentication information to the header
string auth = "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(user + ":" + pwd));
req.PreAuthenticate = true;
req.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested;
req.Headers.Add("Authorization", auth);
//writing the message body to the request
byte[] bytes = Encoding.UTF8.GetBytes(message);
req.Method = "POST";
req.ContentType = "text/xml; encoding='utf-8'";
req.ContentLength = bytes.Length;
Stream requestStream = req.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
//updating action and sending the response
string action = https://xxxx.com/yyyy;
req.Headers.Add("SOAPAction", action);
req.UserAgent = "zzzzzzzz";
WebResponse resp = req.GetResponse();
resp.Close();
}
This method can be called from the expression shape and then the response can be send back to BizTalk for further processing. Once the above code is implemented the outgoing message will look something like this:
POST https://xxx.com/yyyy/1.1
Authorization: Basic aaaaaaaaaaaaaaaaaaaaaaaaaaaaa==
Content-Type: text/xml; encoding='utf-8'
Host: xxxxxxxx
Content-Length: 2382
Expect: 100-continue
<ns0:xxxxxx xmlns:ns0="https://xxxxx.com/yyyy">…..
Hope this will save some time for you… !!!
Written By
Rasika Chaudhary
Reviewed By
Xuehong Gan
Microsoft GTSC
Comments
- Anonymous
January 27, 2017
Hi, we encountered a similar scenario (BizTalk 2013). The authorization header can quite easily be implemented using a custom behavior