I'm a noob to calling WCF web services, so am hoping this is an easy question. When calling a web service with .NET 4 winform client, how do I change the authorization scheme from Anonymous to NTLM?
Right now I'm getting the exception: The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'.
My goal is to build a little tool to help me monitor TFS 2010's data warehouse and cube. TFS provides a WarehouseControlWebService web service. I can call the service via Test mode in a browser when logged on to the server. However I'm trying to call the same web service remotely, from my desktop. My user account is in the local Administrators group on the server.
I've created a .NET 4 WinForm with the canonical Button1 and TextArea1. I then added a service reference to the web service and creatively called it ServiceReference1:
Add Service Reference...
http://tfssvr:8080/tfs/TeamFoundation/Administration/v3.0/WarehouseControlService.asmx
And here's my code behind:
private void button1_Click(object sender, EventArgs e)
{
// Creating a proxy takes about 3-4 seconds
var dwSvc = new ServiceReference1.WarehouseControlWebServiceSoapClient();
// Invoking the method throws an MessageSecurityException
var dwStatus = dwSvc.GetProcessingStatus(null, null, null);
}
I'm getting System.ServiceModel.Security.MessageSecurityException:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'.
I've tried passing my credentials via:
dwSvc.ClientCredentials.Windows.ClientCredential =
new System.Net.NetworkCredential("user", "pass", "domain");
and also ...
dwSvc.ClientCredentials.Windows.ClientCredential =
CredentialCache.DefaultNetworkCredentials;
I'm wading through the WCF documentation but ... oh boy ... there's a lot there. I'm hoping this is something easy??
Thanks in advance.
Set your config bindings
to security mode="TransportCredentialOnly" and transport clientCredentialType="Ntlm"
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WarehouseControlWebServiceSoap" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10: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="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://tfsServer:8080/tfs/TeamFoundation/Administration/v3.0/WarehouseControlService.asmx"
binding="basicHttpBinding" bindingConfiguration="WarehouseControlWebServiceSoap"
contract="TfsWarehouse.WarehouseControlWebServiceSoap" name="WarehouseControlWebServiceSoap" />
</client>
</system.serviceModel>
You are looking in the right direction. This is a good page with some example level information on available authentication methods you need: http://man.ddvip.com/web/bsaspnetapp/LiB0087.html. At least that page should give you some more clues to continue your efforts on.
Related
I am working on a Silverlight 4 application which connects to a claim ware WCF Service. I am using the following code to retrive the claim token in my WCF to perform authorization.
IClaimsPrincipal principal = ( IClaimsPrincipal )Thread.CurrentPrincipal;
IClaimsIdentity identity = ( IClaimsIdentity )principal.Identity;
return string.Format( "You entered: {0} and you are {1}", value, identity.Name );
When I use wsHttpBinding in WCF and try it out with a console app, it works fine. But since Silverlight only supports basicHttp and customeBinding, i cannot use wsHttp, ws2007Http or anyother binding. Becase of which I am not getting the IClaimIdentity token in my WCF from Silverlight.
Is there any way I can use any of the Silverlight suppported binding and still get the ClaimIdentity in my WCF. Is there any tutorial/help text where I can read more abouth this.
My WCF settings are:
<system.serviceModel>
<services>
<service name="ClainAwareWCF.Service" behaviorConfiguration="ClainAwareWCF.ServiceBehavior">
<endpoint address="" binding="basicHttpBinding" contract="ClainAwareWCF.IService" bindingConfiguration="basicbind">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="basicbind">
<security mode="TransportCredentialOnly"></security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ClainAwareWCF.ServiceBehavior" >
<federatedServiceHostConfiguration/>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
Trying to call this directly from the client will never happen because of the binding issues and also because the client auth awareness security of SL (Windows/Forms/WIF/etc.), but one approach is to use RIA Services Domain Authentication Services to authenticate and call the services from the server-side through a WCF RIA Invoke endpoint. The user's security context is proxied to the client and you can tunnel data over the wire in a straight-forward manner.
This may get you in the right direction:
http://archive.msdn.microsoft.com/RiaServices/Release/ProjectReleases.aspx?ReleaseId=5617
Silverlight doesn´t support Claims Based Authorization and WS-Trust out of the box. Microsoft was going to put this into Silverlight 5 but forgot to do so unfortunately.
There is however a very elegant and usable "Silverlight" version of the WIF IdentityModel stuff available in the Identity Training Kit.
The solution consists of a base AuthenticationService that translates WIF authentication tokens to claims server side, and a Silverlight client library "SL.IdentityModel" containing the building blocks such as a Silverlight version of a ClaimsPrincipal.
Get the Identity Training Kit here. Look for the sample Silverlight implementation.
I wrote some WCF application - ( using IIS 7 ).
The client that connect to this service was develop by me in silverlight.
I want to be able to give only the client that i wrote the ability to access the service and use it => if some other client will try to access the the service ( without user name + password ) the service will ignore him.
How can i do it ?
Thanks for any help.
The problem is that current feature set in Silverlight is limited so the way to go is either Windows authentication which doesn't work over internet:
<bindings>
<binding name="authenticatedBinding">
<security mode="TransportCredentialOnly"> <!-- or Transport in case of HTTPS -->
<transport clientCredentialType="Windows" />
</security>
</binding>
</bindings>
Basic authentication which when handled validates user name and password as Windows accounts (here is some article about forcing basic authentication to validate against custom credential store):
<bindings>
<binding name="authenticatedBinding">
<security mode="TransportCredentialOnly"> <!-- or Transport in case of HTTPS -->
<transport clientCredentialType="Basic" />
</security>
</binding>
</bindings>
or UserName token which can be validated either by custom password validator or by membership provider. The disadvantage is that Silverlight supports this only over HTTPS:
<bindings>
<binding name="authenticatedBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</bindings>
In other words: If you need secure protocol the only choice if HTTPS. If you need just authenticate client over HTTP and you have no problem with passing user name and password as the plain text you can try Basic authentication with custom credential store. Any other case requires you to build your own custom solution.
I have a Silverlight 4 application that uses a WCF SOAP service. The authentication/authorization happens per call (quasi RESTful). This is done by using authenticationMode=UserNameOverTransport - this basically means that that username/password is in each WCF call, but is protected by the SSL encryption of each message. The great thing about this scheme is that I can configure a membership provider in my web.config to do the authentication, making it flexible for different installations.
I have a client that would like to set this website up on their network where the scheme is: Internet <= SSL Traffic => External facing SSL enabled forwarding server <= unsecure HTTP in their internal network => server that hosts my application. They assure me this is a common architecture and I believe them, I am not that experienced an internet application developer.
I am not sure what to do about this as my application is set up to be on the SSL enabled server (UserNameWithTransport is over SSL). in plain HTTP I am not sure how I would get the username which I need to provide the user specific application data. WCF does not provide a "UserNameWithNoTransport" authenticationMode as that would mean sending the username/password in plain text, which is silly. Right now my server side code gets the user from the ServiceSecurityContext.Current.PrimaryIdentity.Name, knowing that the web server has already taken care of the SSL encryption and user authentication. How can I have this work in a way that makes sense in an HTTP solution?
I would like a solution that allows me to configure my solution to work in both the HTTP and HTTPS situation from the web.config, if this is not possible than any other advice is appreciated. thanks
I will place a bounty on this question in a few days, if you give a good answer before then you'll get it.
EDIT: here is the web config as requested:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<system.web>
<pages controlRenderingCompatibilityVersion="4.0" clientIDMode="AutoID"/>
<membership defaultProvider="SampleProvider">
<providers>
<add name="SampleProvider" type="MyNamespace.NullMembershipProvider, MyDLL"/>
</providers>
</membership>
</system.web>
<appSettings>
...
</appSettings>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<bindings>
<customBinding>
<binding name="BinaryCustomBinding" sendTimeout="00:10:00">
<security authenticationMode="UserNameOverTransport"/>
<binaryMessageEncoding />
<httpsTransport maxBufferSize="100000" maxReceivedMessageSize="100000" />
</binding>
</customBinding>
</bindings>
<services>
<service name="MyNamespace.MyService">
<endpoint
binding="customBinding" bindingConfiguration="BinaryCustomBinding"
name="MyService" contract="MyNamespace.IServiceContract" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata
httpsGetEnabled="true"
httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"
membershipProviderName="SampleProvider"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<log4net>
...
</log4net>
</configuration>
Allowing UserNameOverTransport over HTTP is possible in .NET 4 but I think it is not possible in Silverlight. You need to set allowInsecureTransport attribute of security element:
<customBinding>
<binding name="BinaryCustomBinding" sendTimeout="00:10:00">
<security authenticationMode="UserNameOverTransport" allowInsecureTranposrt="true"/>
<binaryMessageEncoding />
<httpTransport maxBufferSize="100000" maxReceivedMessageSize="100000" />
</binding>
</customBinding>
The problem is that allowInsecureTranposrt is not available in Silverlight. Without this you can't use UserName token over unsecured channel.
I would like to ask a question. One of my ex-colleague wrote one window azure project and now I need to continue this project. Web Service is in that window azure project and I need to call that web service in silverlight. Therefore, I add new silverlight project at that existing Window azure project. And when I am trying to add Service Reference in silverlight application. It shows "No Endpoint compatible with Silverlight3 were found" and it cannot create ServiceReference.config file.
I am not too family with web service and c#. So , could you tell me step by step of using web service at Silverlight.
I also tried to change "basicHttpBinding" and "customBinding" in Web.config file. But it doesn't allow me to change anything. So, without changing anything at serverside, how can I call webservice in silverlight?
Here is some part of code.
IEventHandler.cs
`[OperationContract]
[WebGet(UriTemplate = "Holidays", ResponseFormat = WebMessageFormat.Xml)]
List<Holidays> GetHolidays();`
EventHandler.svc
`public List<Holidays> GetHolidays()
{
//database declaration for purpose of accessing the db.
Database db = new Database();
//dg.getHolidays is found in the Database class.
List<Holidays> holidays = db.getHolidays();
return holidays;
}`
Web.config
`<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webBinding"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647" >
<readerQuotas
maxArrayLength="2147483647"
maxStringContentLength="2147483647"/>
<!--<security mode="Transport">
</security>-->
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
<enableWebScript/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Rest_EventHandler_WebRole.EventHandlerBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="Rest_EventHandler_WebRole.EventHandlerBehavior"
name="Rest_EventHandler_WebRole.EventHandler">
<endpoint address="" behaviorConfiguration="webBehavior" binding="webHttpBinding"
bindingConfiguration="webBinding" contract="Rest_EventHandler_WebRole.IEventHandler">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>`
For silverlight, how can I call that WebService? I don't have permission to change the serverside part. Do I need to use sisvcutil.exe? Could you kindly help me my problem?
I don't think you can do this. Silverlight only supports basicHttpBinding and customBinding. I suppose one option would be to create a middle WCF service layer where you just call the azure service and pass the result back to Silverlight.
Silverlight client -> Middle WCF layer -> Azure service
But this seems unnecesssary and overkill. Is there no way you can get control over the web service?
I have a WCF service which is set up to use basic authentication over https like this:
<basicHttpBinding>
<binding name="secureTransport">
<security mode ="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
I have also specified a custom username and password validator. When I call this service from a console application, everything works as expected. However, when I call this service from Silverlight 3, I get a login popup. In both cases, the code is the same and is as follows:
SecureRemoteBox.Service1Client client = new SecureRemoteBox.Service1Client();
client.ClientCredentials.UserName.UserName = "test";
client.ClientCredentials.UserName.Password = "pass";
The client security configuration for the console application is
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
The client security configuration for the SL3 application is
<security mode="Transport" />
I have also tried "TransportWithMessageCredential" but with the same issue.
What am I doing wrong? Thanks.
I'm afraid to say Silverlight 3 doesn't support HTTP Basic Authentication (annoying I know). Best option for authentication is to use asp.net membership provider and check for authentication in your WCF services or pass the username and password as arguments into your services.
HTH