I keep getting the following error when trying to consume a webservice:
The HTTP request is unauthorized with client authentication scheme 'Basic'. The authentication header received from the server was 'Basic Realm'.
The webservice is REST written with WCF. The authentication is basic over https.
Any help fixing the error would be apreciated.
Here is the code I tried:
WebHttpBinding webBinding = new WebHttpBinding();
webBinding.Security.Mode = WebHttpSecurityMode.Transport;
webBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
ChannelFactory<ServiceReferences.BTService.FLDT_WholesaleService> factory = new ChannelFactory<ServiceReferences.BTService.FLDT_WholesaleService>(webBinding,
new EndpointAddress(
"https://wholesale.fluidata.co.uk/FLDT_BT_wholesale/Service.svc"));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
factory.Credentials.UserName.UserName = "username";
factory.Credentials.UserName.Password = "password";
ServiceReferences.BTService.FLDT_WholesaleService proxy = factory.CreateChannel();
proxy.AvailabilityCheck("123");
As long as you expose RESTful service you may attempt to use Fiddler - http://www.fiddler2.com/fiddler2/ and/or normal HttpRequest/HttpResponse. Did you try anything like that?
Mr. Franek's answer is useful - you WILL be using Fiddler in working with WCF, period. I can add a little bit...what is happening here is that you've specified "Basic" as your authentication scheme as a client. The server is saying "I only allow 'Basic Realm'" as the authentication scheme. What is 'realm'? Basically a credential namespace:
Realm for HTTP basic authentication
Here's another helpful link: Authentication in WinHTTP
I can't find a property or method overload that carries Realm...I would probably try to construct the Authenticate-WWW header manually.
That would go something like this:
request.Headers.Add("WWW-Authenticate", string.Format("basic realm=\"{0}\", realm));
"realm" would be the value of whatever the server is expecting, e.g., "www.targetsite.com".
Related
I'm working with WCF with SOAP message architecture. My services are using BasicHttpBinding for transporting my SOAP messages. I need to add 2 different HTTP headers(Origin and Cache control) to HTTP response. I know that I can do that in Global.asax file in case of enabling aspNetCompatibilityEnabled, but there is a problem - I'm using windows service for hosting my WCF. aspNetCompatibilityEnabled works only under IIS. Can anybody help me with approach?
I believe this article is about what you want to do: here. You can do something like this:
var context = WebOperationContext.Current;
HttpResponseHeader cacheHeader = HttpResponseHeader.CacheControl;
String cacheControlValue = String.Format("max-age={0}, must-revalidate", maxCacheAge);
context.OutgoingResponse.Headers.Add(cacheHeader, cacheControlValue);
I'm working on client application to utilize SOAP web service. Added SOAP web services as Service reference. It connects to IBM server and server requires WS-Security basic authentification.
Called with default settings and got an error(no authentication header)
Modified code to look like so:
var service = new RealTimeOnlineClient();
service.ClientCredentials.UserName.UserName = "xxxxx";
service.ClientCredentials.UserName.Password = "yyyyy";
Now when I look at response in Fiddler - works properly (I get expected envelope from server), I get proper envelope back.
However, I get exception from WCF:
Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.
Quick search and bunch of answers here on SO points me to HotFix from Microsoft where they added new property EnableUnsecuredResponse. Problem is - I can't figure out WHERE to apply this property in my code OR in config. Adding to security tag in web.config doesn't work (errors out can't find property).
I understand hotfix came out for .NET 3.5 and most questions from 2009-2010. It should be in 4.5 already, correct? How do I apply this property to my code?
I had to add following code to alter value of "EnableUnsecureResponse"
var service = new RealTimeOnlineClient();
service.ClientCredentials.UserName.UserName = "xxxxx";
service.ClientCredentials.UserName.Password = "yyyyy";
var elements = service.Endpoint.Binding.CreateBindingElements();
elements.Find<SecurityBindingElement>().EnableUnsecuredResponse = true;
service.Endpoint.Binding = new CustomBinding(elements);
I have some basic questions on HTTP authentication
1) How does client know about Server's authentication type (Basic/Digest/NTLM) of HTTP ? is this configurable at HTTP Server side?
My Answer: Server will be set with which authentication type it has to perform with the client.
So our client API(in C# HttpWebRequest API) will automatically take care of it.
Best use of Wireshrk with applying HTTP filter; you will get source and Destination IP at Internet Protocol layer. And src and dest port at Transmission control protocol and athentication type at http layer.
2) If i place squid linux proxy in between client and Server; is there any need from my client code should know about authentication type of proxy also? or authentication type is only related to the end HTTP server?
My Answer: If squid proxy is placed in between Client and Server; it wont use HTTP authentication. It may use a) DB: Uses a SQL database b) LDAP: Uses the Lightweight Directory Access Protocol. c) RADIUS: Uses a RADIUS server for login validation. and etc..
So we have to mention proxy authentication credentials in HTTP Headers.
3) Using WireShark found that there are three request from Browser to Server to fulfill single request.
a) Browser sends a request without any authentication credentials; So server responded with 401 along with relam and nonce.
WWW-Authenticate: Digest realm="realm", qop="auth", nonce="MTM1OTYyMzkyNDU4MzpiOWM0OWY0NmMzMzZlMThkMDJhMzRhYmU5NjgwNjkxYQ=="\r\n <BR>
b) The second time Browser sends request with credentials, relam, nonce, cnonce; but still server responded with 401;
WWW-Authenticate: Digest realm="realm", qop="auth", nonce="MTM1OTYyMzk0OTAyMTo3Njk3MDNhZTllZDQyYzQ5MGUxYzI5MWY2MGU5ZDg0Yw==", stale="true"\r\n
c) The third time Browser send the same request with same credentials, relam, nonce, cnonce. This time Server sends 200 ok.
My Question is in the second and third time Browser send the same request; why Server failed at second time and success at the third time. Is this because of my server implementation ? (I am having REST Java server with SPRING Security filter).
I have C# HTTP client;
where in the first time HttpWebRequest is sent without credentials though the System.Net.NetworkCredentials is set; so clinet got 407 with relam, and nonce. The second time HttpWebRequest is scuccess. There is no third request from this client like browser.
Why this difference between the browser and C# client?
My Answer: I am still don't know what is happening here: Q3.
4) Now the real issue i am facing is When SQUID LINUX PROXY came in between our Client and HTTP Server, Browser did the same three request authentication and succeeded. However C# HttpWebRequest is failed (401) at the second request and reached the cache(exception){} block and not tried for the third time.
Could you please anyone clarify me how to resolve this issue in C# client when PROXY SERVER is in between?
Below code is doing the GET Request.
HttpWebRequest request = WebRequest.Create("url") as HttpWebRequest;
request.Credentials = new NetworkCredential(loginUserName, password);
WebResponse response = request.GetResponse();
Note that our request to proxy is send via TCP protocol not with HTTP protocol. Then from PROXY to SERVER is communicated with HTTP protocol.
But HTTP request from Proxy has the info about our client ip in the HTTP header X-Forwarded-For.
Below are the possible solutions
These solutions only required if your proxy requires any authentication else ignore it.
Solution 1: working for me
request.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
Solution 2:
IWebProxy proxy = WebRequest.GetSystemWebProxy();
proxy.Credentials = new NetworkCredential(UserName, UserPassword, UserDomain);
request.Proxy = proxy;
Solution 3 given by Martin:
var proxy = new WebProxy ("http://localhost:3128/");
proxy.Credentials = new NetworkCredential (UserName, UserPassword, UserDomain);
request.Proxy = proxy;
Learn more about proxy authentication at
http://wiki.squid-cache.org/Features/Authentication
It's a challenge/response protocol. Usually, the client makes an initial request without any authentication headers (you may set request.PreAuthenticate = true to send the credentials with the first request).
Then, the server responds with a list of authentication methods that it supports.
If the user did not explicitly specify an authentication method using CredentialsCache, the runtime will try them all, from strongest to weakest. Some protocols (NTLM, for instance) require multiple requests from client to server. In theory, Digest should work with a single one, no idea why it's sending the request twice.
Regarding your proxy question, there are two different kinds of authentication:
The target web server's authentication, a proxy simply passes this though and you don't need any special code in your client.
In addition to that, the proxy itself may also require authentication - which may be different from the one of target web server.
You specify these using
var proxy = new WebProxy ("http://localhost:3128/");
proxy.Credentials = new NetworkCredential ("username", "password");
and then
WebRequest.DefaultWebProxy = proxy;
or
request.Proxy = proxy;
Don't set any credentials on the WebProxy if your proxy server doesn't use any authentication.
If you can't get authentication working while using a proxy server, look at the actual requests that are being sent between the three parties (web server, proxy, client) with Wireshark.
I've been struggling to get a WCF client to work through a web proxy. If I manually specify the proxy as below, I can get the http request to work.
WebProxy proxy = new WebProxy("http://x.x.x.x:3128", false);
proxy.Credentials = new NetworkCredential("user", "pass");
WebRequest.DefaultWebProxy = proxy;
However I have the client service proxy set to use ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.ChainTrust;
Inspecting the packets that get sent out, the client successfully connects to the server, but the then tries to validate the certificate that the service provides. This validation attempt fails because the requests for the chain do not have Proxy-Authorization headers (they fail with 407 errors). How can I get these requests to properly use the DefaultWebProxy that's specified?
If I set the validation mode to None, then it all works of course, but I really don't want to have to do that.
this setting only affects message level certificates. for transport level try something like this http://webservices20.blogspot.co.il/2008/12/wcf-gotcha-disabling-ssl-validation.html
We're being really stuck here so I decided to ask your help.
Yesterday I've been asked to help to consume a web service, got the URL to the WSDL, and the user credentials to use.
I've never really had anything to do with web services, but having a general idea about them and seeing a few examples I thought it can't be that bad. Obviously I was wrong as I'm stuck now.
Everything seems to be fine, the proxy class (or client) has been generated, building up requests and sending them are fine too, apart from the authentication part. Which we can't seem to figure out how to do.
Using the:
client.ChannelFactory.Credentials.UserName.UserName = "myusername";
client.ChannelFactory.Credentials.UserName.Password = "mypassword";
doesn't seem to work. (When I check the BindingElementCollection returbed by the client.Endpoint.Binding.CreateBindingElements() there's no SecurityBindingElement)
I've tried so many other ways of doing it, but I think I'm missing something basic and the lack of documentaion is not really helping either.
So the question is: How do I send the username and password when making a call to a web service, using WCF?
Edit:
Just to clarify, the request should contain something similar to this:
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-25763165">
<wsse:Username>username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">1DiaGTkOLk/CZhDaEpbkAaKRfGw=</wsse:Password>
<wsse:Nonce>6ApOnLn5Aq9KSH46pzzcZA==</wsse:Nonce>
<wsu:Created>2009-05-13T18:59:23.309Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
I had the same problem. Instead of the custom token serializer I used a MessageInspector to add the correct UsernameToken in the BeforeSendRequest method. I then used a custom behavior to apply the fix.
The entire process is documented (with a demo project) in my blog post Supporting the WS-I Basic Profile Password Digest in a WCF client proxy. Alternatively, you can just read the PDF.
If you want to follow my progress through to the solution, you'll find it on StackOverflow titled, "Error in WCF client consuming Axis 2 web service with WS-Security UsernameToken PasswordDigest authentication scheme":
I've achieved similar, using a regular HttpCookie.
To create the cookie:
[OperationContract]
public void LoginToApi(string username, string password, string clientName)
{
// authenticate with DB, if successful ...
// construct a cookie
HttpCookie httpCookie = new HttpCookie("SessionID","whateverneeded");
HttpContext.Current.Response.SetCookie(httpCookie);
}
This appears in your regular HttpRequests, too. So you just reverse the process, checking the hash/session ID/username/password whatever you put in the cookie on receipt before doing anything.
var factory = new ChannelFactory<IService>('*');
factory.Credentials.UserName.UserName = 'bob';
factory.Credentials.UserName.Password = 'bob';
var proxy = factory.CreateChannel();
For more information you can explore Authorization In WCF-Based Services*( http ://msdn.microsoft.com/en-us/magazine/cc948343.aspx)*