WCF TransportCredentialOnly not sending username and password - wcf

I have the following WCF client configuration:
<basicHttpBinding>
<binding name="basicHttpOCCWS" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="100000000" maxBufferPoolSize="524288"
maxReceivedMessageSize="100000000" messageEncoding="Text"
textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="16384" maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
In code, I am setting the username and password as follows:
client.ClientCredentials.UserName.UserName = _cacledUserId;
client.ClientCredentials.UserName.Password = _cachedPassword;
However, the web service running on Tomcat is returning an error:
"An authentication object was not found in the security context."
When I look at the HTTP header, it is missing credential information as shown below:
POST /occ600webservice/services/OCC_WS HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8; action=""
Host: 192.54.173.130:8080
Content-Length: 2223
Expect: 100-continue
Why are my credentials not being sent?
TIA.
Klaus

For others who run into the same problem, wrap each call to the secured web service resource like this:
var client = new WCClient();
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
var httpRequestProperty = new HttpRequestMessageProperty();
httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] =
"Basic " +
Convert.ToBase64String(Encoding.ASCII.GetBytes(
client.ClientCredentials.UserName.UserName + ":" +
client.ClientCredentials.UserName.Password));
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] =
httpRequestProperty;
client.DoSomething();
}
see the following links:
Inserting headers 1
Inserting headers 2

Try changing the security element to also include the message element specifying the clientCredentialType to be UserName otherwise the transport doesn't know that you want to use the ClientCredentials.UserName object that you filled in.
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" proxyCredentialType="None" />
<message clientCredentialType="UserName"/>
</security>

Related

Programmatically adding an endpoint

I have a WCF service that I am connecting in client application. I am using following in configuration file.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyNameSpace.TestService" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:9100/TestService" binding="basicHttpBinding"
bindingConfiguration="MyNameSpace.TestService" contract="TestService.IService" name="MyNameSpace.TestService" />
</client>
</system.serviceModel>
In the code, I am calling API on this service as follows,
TestServiceClient client = new TestServiceClient()
client.BlahBlah()
Now I want to defined endpoint porgramatically. How can that be done? I commented out section from config file as I was thinking I will have to put some code on TestServiceClient instance to add endpoint dynamically but then it throws following exception at the point where TestServiceClient is instantiated.
Could not find default endpoint element that references contract
'TestService.IService' in the ServiceModel client configuration
section. This might be because no configuration file was found for
your application, or because no endpoint element matching this
contract could be found in the client element.
How can I accomplish this? Also any point on code examples for adding endpoint programmatically will be appreciated.
To create endpoints and bindings programmatically, you could do this on the service:
ServiceHost _host = new ServiceHost(typeof(TestService), null);
var _basicHttpBinding = new System.ServiceModel.basicHttpBinding();
//Modify your bindings settings if you wish, for example timeout values
_basicHttpBinding.OpenTimeout = new TimeSpan(4, 0, 0);
_basicHttpBinding.CloseTimeout = new TimeSpan(4, 0, 0);
_host.AddServiceEndpoint(_basicHttpBinding, "http://192.168.1.51/TestService.svc");
_host.Open();
You could also define multiple endpoints in your service config, and choose which one to connect to dynamically at run time.
On the client program you would then do this:
basicHttpBinding _binding = new basicHttpBinding();
EndpointAddress _endpoint = new EndpointAddress(new Uri("http://192.168.1.51/TestService.svc"));
TestServiceClient _client = new TestServiceClient(_binding, _endpoint);
_client.BlahBlah();
Can you just use:
TestServiceClient client = new TestServiceClient();
client.Endpoint.Address = new EndPointAddress("http://someurl");
client.BlahBlah();
Note that your binding configuration will no longer apply, as you're not using that endpoint configuration in your configuration file. You'll have to override that, too.
You can try:
TestServiceClient client = new TestServiceClient("MyNameSpace.TestService")
client.BlahBlah()
if not recheck namespace in file TestService is correct?

How do I consume a WS-Security service in WCF over HTTPS?

I'm trying to consume a WS-Security enabled service with WCF. Authentication works using a UsernameToken. I'm not very knowledgeable with WCF web service clients, but I think my configuration below works for regular HTTP communication. I (mostly) used this guide to configure it. The main difference is that I used the VS2010 "Add Service Reference" UI instead of a command prompt.
My problem is that I need to do this over HTTPS. When I use <security mode="Message"> in my app.config, I believe my soap envelope contains the needed WS-Security headers. I can't tell for sure because I can't get logging to work. However, I get the following error: The provided URI scheme 'https' is invalid; expected 'http'. Parameter name: via.
Below are the contents of my app.config file, as well as a sample of my client code.
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="Omitted" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Message">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" negotiateServiceCredential="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://omitted.com/service" binding="wsHttpBinding" bindingConfiguration="Omitted" contract="Omitted.Omitted" name="Omitted" />
</client>
</system.serviceModel>
var service = new OmittedClient();
service.ClientCredentials.UserName.UserName = "username";
service.ClientCredentials.UserName.Password = "password";
var response = service.DoSomething(new DoSomethingRequest());
Thanks to 500 - Internal Server error for helping me figure it out. Here are the steps I took:
Generate a proxy using Visual Studio/WCF.
Change the security mode to TransportWithmessageCredential.
Use the following code to specify a username/password.
var client = new WebServiceClient();
client.ClientCredentials.UserName.UserName = "USERNAME";
client.ClientCredentials.UserName.Password = "PASSWORD";
If you get a response back, but WCF complains when processing it, there might be a timestamp missing from the response. If that's the case, try this to fix it.
// WCF complains about a missing timestamp (http://www.west-wind.com/weblog/posts/2007/Dec/09/Tracing-WCF-Messages)
var elements = service.Endpoint.Binding.CreateBindingElements();
elements.Find().IncludeTimestamp = false;
service.Endpoint.Binding = new CustomBinding(elements);

Large file uploads via WSHttpBinding in WCF

I'm working on a WCF file uploader using WSHttpBinding. I am looking to upload files around 10 mb (not playing an exact game on that one, but won't be getting files much larger). Everything works pretty well up to about 5mb. after that, I start getting HTTP 500 errors.
My binding is set up as follows:
wsBinding.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
wsBinding.MaxBufferPoolSize = 52428800;
wsBinding.MaxReceivedMessageSize = 13631488;
wsBinding.ReceiveTimeout = new TimeSpan(0, 3, 0);
My httpRuntime maxRequestLength is 20480kb in web.config
My requests look like:
POST http://mywebsite/FileUploader.svc HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8;action="http://namespace/UploadPhoto"
Content-Length: 13979476
Host: mywebsite
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:fil="http://namespace">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Action>http://namespace/IFileUploaderSvc/UploadPhoto</wsa:Action></soap:Header>
<soap:Body>
<fil:UploadPhoto>
<fil:AuthorizationToken>(Password)</fil:AuthorizationToken>
<fil:ProgramName>AProgram</fil:ProgramName>
<fil:FileName>bigolefile.jpg</fil:FileName>
<fil:File>(base 64 file data)</fil:File>
</fil:UploadPhoto>
</soap:Body>
</soap:Envelope>
It is very important that I use WSHttpBinding, not WebHttpBinding.
Thanks in advance,
Andrew
Try to use the TextMessageEncodingBindingElement or MtomMessageEncodingBindingElement for the messageEncoding property in WSHttpBinding binding.
For instance, the following snippet uses TextMessageEncodingBindingElement. messageEncoding="Text" http://msdn.microsoft.com/en-us/library/ms733742.aspx
<wsHttpBinding>
<binding name="wsHttpWithMessageSecurity" messageEncoding="Text"
closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00"
sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" textEncoding="utf-8"
useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />

LightSwitch application chokes while instantiating a WCF proxy

I'm trying to create a LightSwitch management panel for a web-based app. Thats why I was setting up a WCF RIA service to interface with the WCF service of the web app. While testing the loading of the users, I discovered that LightSwitch said that it couldn't load the resource. The Immediate Window told me that a System.InvalidOperationException had occured within System.ServiceModel.dll but VS didnt actually point me towards the loc where the error would have originated. After some line for line code execution, I discovered it choked at the instantiation of the WCF proxy.
An example of the code on the WCF RIA service Class:
Public Class RIAInterface
Inherits DomainService
Private WCFProxy As New Service.UserClient() '<-- Choke Point
Public Sub New()
WCFProxy.Open()
End Sub
<Query(IsDefault:=True)>
Public Function GetUsers() As IQueryable(Of User)
Dim TempList As New List(Of User)
For Each User As Service.User In WCFProxy.GetUsers()
TempList.Add(New User With {.ID = User.ID, .FullName = User.FullName, .EmailAddress = User.Email, .Username = User.UserName, .Class = User.Class.Name, .AccountType = User.Privilege.Name})
Next
Return TempList.AsQueryable
End Function
End Class
After some fooling arround with the RIA service and LightSwitch, something changed. I ran the app and got an actual exception.
Exception Details:
Could not find endpoint element with name 'EduNetBackEnd_IUser' and contract 'EduNet.IUser' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element.
This is the the ServiceModel configuration in the App.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="EduNetBackEnd_IUser" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:15:00"
enabled="true" />
<security mode="None">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="[Service_Address]"
binding="wsHttpBinding" bindingConfiguration="EduNetBackEnd_IUser"
contract="EduNet.IUser" name="EduNetBackEnd_IUser" />
</client>
</system.serviceModel>

Trying to call WCF service from inside NServiceBus Message Handler, but it hangs when creating the Service Client

Must be doing something awfully wrong here. Here is what I'm trying to do.
I have a Message handler that should get a message from the queue. Make a WCF call, do stuff and when done, send a new message out on the bus.
It is hosted in the NServiceBus.Host.Exe.
But, whenever I create the Service Client, eveything comes to a grinding halt. If I comment out the service call everything works great... Except, I need that call.
Is there a trick I must do to make WCF calls from my Message Handler when hosting it in the NServiceBus.Host.Exe? I have not made any special config in the EndPointConfig class.
public class EndpointConfig :
IConfigureThisEndpoint, AsA_Server { }
public class RequestAccountUpdateMessageHandler : IHandleMessages<RequestAccountUpdateMessage>
{
public void Handle(RequestAccountUpdateMessage message)
{
// The Line below hangs everything
AccountService.AccountServiceClient client =
new AccountService.AccountServiceClient();
resp = client.DoStuff(message.parameter);
Bus.Send<UpdateAccountMessage>(m =>
{
m.info = DoMagicStuffHere(resp);
});
}
...
}
This is what the system.serviceModel looks like in the App.Config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IAccountService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:01:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://yadayafa/accountservice.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IAccountService" contract="AccountService.IAccountService" name="BasicHttpBinding_IAccountService"/>
</client>
</system.serviceModel>