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.
Related
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.
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 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 have a silverlight application which has a WCF in it. when the wcf is called it fails with this exception:
An error occurred while trying to make a request to URI 'http://localhost:4693/MapService.svc'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details.
Both silverlight and WCF are running from local.
My silverlight is running from:
...\SilverlightApplication1\SilverlightApplication1\Bin\Release\SilverlightApplication1TestPage.html
this is the WCF web.config services tag:
<services>
<service behaviorConfiguration="FileUpAndDownload.Web.MapServiceBehavior" name="FileUpAndDownload.Web.MapService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="MapBinding" contract="FileUpAndDownload.Web.IMapService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
and this is the ServiceReference.ClientConfig:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMapService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:4693/MapService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IMapService" contract="MapService.IMapService"
name="BasicHttpBinding_IMapService" />
</client>
</system.serviceModel>
I've placed the clientaccesspolicy.xml in bin\release but doesn't help.
HELP PLEASE!
You need some extra configuration to do a cross domain call see:http://www.dotnetcurry.com/ShowArticle.aspx?ID=208&AspxAutoDetectCookieSupport=1
You probably have the clientaccesspolicy.xml in the wrong place, check your IIS log for file not found errors.
The client access policy file must be in your wwwroot folder
There are issues with running Silverlight locally as opposed to from a web server.
The access permissions are different and Silverlight won't be able to access ANY webservice.
I ran into that issue somne time ago with SL2 I think, it might have changed.
You should create a new WebApplication project in Visual Studio and host Silverlight in it.
Then you SL client will have no problem connecting to the 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