I have a basic WCF service project in Visual Studio 2010, which consists of a .svc file, the associated .cs, and Web.config. My problem is that when using the WCF Test Client I can't get a user. OperationContext.Current.ServiceSecurityContext is null, as is HttpContext.Current. I managed to get security set to Transport on the WCF client, but now I'm getting the following error:
The provided URI scheme 'http' is invalid; expected 'https'.
My Web.config is as follows:
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
My WCF Test Client config is as follows:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_MyService">
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:57165/MyService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_MyService" contract="MyService"
name="BasicHttpBinding_MyService" />
</client>
</system.serviceModel>
</configuration>
I'm totally new to writing new services, so the other posts I've seen that supposedly answer the question say to do things but not where to do them. I'm looking for something clear and concise here.
What am I missing here, or am I going about getting the current user all wrong?
The WCF client throws the "The provided URI scheme 'http' is invalid; expected 'https' " error because the basicHttpBinding specifies security mode="Transport"> but the endpoint address currently indicates a non-secure protocol (endpoint address="http://localhost:57165/MyService.svc". Update the endpoint address to match the binding's security to resolve the communication issue.
Once the transport error is resolved, you can then focus on the proper security binding and the code needed to extract the user information. In order to get the username, your binding will need to specify a client credential type of username. Your service can then access the user information by using System.ServiceModel.ServiceSecurityContext through the OperationContext.
The following links may be useful:
http://www.codemag.com/article/0611051
http://msdn.microsoft.com/en-us/library/ms731058%28v=vs.110%29.aspx
http://msdn.microsoft.com/en-us/library/system.servicemodel.servicesecuritycontext(v=vs.110).aspx
In order to get windows credentials out of your wcf webservice, your binding has to be a wsHttpBinding:
<wsHttpBinding>
<binding name="wsHttpBinding_MyService">
<security mode="TransportCredentialOnly" />
</binding>
</wsHttpBinding>
This is an example of a working security that transports the credentials.
Related
I'm seeing strange behavior. My web service stops working when i add a HTTPS binding to IIS. This happens regardless of whether i use my Service, through a URL starting with "http://" or "https://".
Error message from my Service
The authentication schemes configured on the host
('IntegratedWindowsAuthentication') do not allow those configured on
the binding 'BasicHttpsBinding' ('Anonymous'). Please ensure that the
SecurityMode is set to Transport or TransportCredentialOnly.
Additionally, this may be resolved by changing the authentication
schemes for this application through the IIS management tool, through
the ServiceHost.Authentication.AuthenticationSchemes property, in the
application configuration file at the
element, by updating the ClientCredentialType property on the binding,
or by adjusting the AuthenticationScheme property on the
HttpTransportBindingElement.
The HTTPS binding that i added in IIS
Authentication of my Service in IIS
The web.config of my Service
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Questions
What is the cause of this error?
How can i avoid this Tight Coupling?
It looks like IIS assumes a basicHttpsBinding with Anonymous Authentication, by default. I solved it by adding a basicHttpsBinding with Windows Authentication (again nameless so that it overrides the default), below my already existing nameless basicHttpBinding.
<basicHttpsBinding>
<binding name="">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpsBinding>
I used the WCF Configuration Editor, built into Visual Studio for this. In case anyone is wondering where all these settings are coming from:
It now works regardless of there being an HTTPS binding in IIS
Also my Service now works through URLs starting with "http://" or "https://"
Microsoft should have given the web.config the same structure as IIS, where the Authentication is independent of the binding. Even better would have been if they left the configuration to IIS so that the settings can't conflict. They really dropped the ball on this one.
The new web.config of my Service
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
<basicHttpsBinding>
<binding name="">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpsBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
I have made a simple REST service (WCF) that will be using another SOAP service.
My REST service works fine, but when I add the SOAP service (Added as a Service Reference), it adds data to the Web.config file.
One thing I want to highlight is that I do not want to expose the SOAP service, I'll be just consuming it.
But when I try to invoke an operation, I get this error:
The endpoint at www.myaddress.com does not have a Binding with the
None MessageVersion. 'System.ServiceModel.Description.WebHttpBehavior'
is only intended for use with WebHttpBinding or similar bindings.
Looking on the internet, people have issues with the config file, but they're exposing two services. I am just exposing one service, and consuming the other. For now, the REST service I am consuming through localhost, and the SOAP service uses SAML ADFS authentication
This is how my config file look, can someone please suggest a fix?
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2"/>
</system.web>
<system.serviceModel>
<bindings>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding_mySOAPService">
<security mode="TransportWithMessageCredential">
<message>
<issuer address="issuer.address"/>
<issuerMetadata address="issuer.metadata.address" />
<tokenRequestParameters>
.
.
.
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
<ws2007HttpBinding>
<binding name="binding.address">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" establishSecurityContext="false" />
</security>
</binding>
</ws2007HttpBinding>
</bindings>
<client>
<endpoint address="endpoint.address"
binding="ws2007FederationHttpBinding" bindingConfiguration="WS2007FederationHttpBinding_mySOAPService"
contract="ServiceReference1.mySOAPService" name="WS2007FederationHttpBinding_mySOAPService" />
</client>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior>
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<add binding="webHttpBinding" scheme="http" />
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Yep, that's exactly how it will work by default!
But you can override those settings pretty easily.
var soapService = new SoapClass.SoapService(
new BasicHttpBinding(BasicHttpSecurityMode.Transport), //Pick the right mode here
new EndpointAddress(mySoapUrl));
My assumption being you have multiple projects, and the Soap is being added to the wrong config.
The other choice, would be to move the correct config settings to the correct config.
I have a ASP.NET MVC intranet application hosted in IIS that added WCF service reference the WCF resides in another computer and also expect windows authentication.
In my web this code is working great:
proxy = new MyProxyClient("configurationName", "remoteAddress");
proxy.ClientCredentials.Windows.ClientCredential.UserName = "myUserName";
proxy.ClientCredentials.Windows.ClientCredential.Password = "MyPassword";
proxy.SomeMethod(); //work great
but if I want the credential not to be hardcoded like this I am using: CredentialCache.DefaultNetworkCredentials like this:
proxy = new MyProxyClient("configurationName", "remoteAddress");
proxy.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
proxy.SomeMethod(); //not working throw exception
the above code throw SecurityNegotiationException with message: The caller was not authenticated by the service.
and the inner exception is: The request for security token could not be satisfied because authentication failed.
How can I pass the credential of the current user to the WCF service without hardcoded user name and password?
If your organization uses regular Windows authentication (NTLM) you can't do what you want due to "one-hop" restriction: credentials passed from user's computer to your server use "one-hop" (from direct login to one external computer) and such credentials can't be used to authenticate other servers from the first one.
More information can be found using following search term:ntlm one hop,i.e. Why NTLM fails and Kerberos works.
Standard solution:
Kerberos (often requires significant effort to get approval to enable/configure)
Use some other form of authentication than Windows. Consider if OAuth is possible. Don't go basic auth.
Switch WCF service to claims based authentication.
If WCF service can it can trust caller to verify incoming credentials more approaches are possible:
Run code under particular account that signs in locally on server and have permissions to call the service. The easiest approach is what shown in your post, but storing domain passwords (or any passwords) in plain text is not secure. One can also run process account under special credentials that have access to the remote service and temporary revert impersonation after verifying user credentials.
You can also configure WCF service to require client certificate and use such certificate when calling the WCF service. This way WCF service can verify if caller is known.
In the web.config (client and server), in the <system.serviceModel> section add/modify a binding to look something like this:
<basicHttpBinding>
<binding name="MyBasicBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
And, add this to client side web.config <system.web> section:
<identity impersonate="true" />
<authentication mode="Windows" />
The two changes will make the end-user the current user of the web request which will then be sent in the WCF message.
The user can then be retrieved on the server side like this:
ServiceSecurityContext.Current.WindowsIdentity
Please make sure the following configuration is there in service web.config.
<system.serviceModel>
<services>
<service name="MyWcf.Service1" behaviorConfiguration="MySvcBehavior">
<endpoint address="" binding="wsHttpBinding" contract="MyWcf.IService1" bindingConfiguration="MyWsHttpBinding"></endpoint>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="MyWsHttpBinding">
<security mode="Message">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
<basicHttpBinding>
<binding name="MyBasicBinding">
<security mode="Message">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MySvcBehavior">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
And in your client configuration file following should be there.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1">
<security>
<transport clientCredentialType="Windows" />
<message clientCredentialType="Windows" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/MyWcf/Service1.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService1" contract="MyWCFService.IService1"
name="WSHttpBinding_IService1">
</endpoint>
</client>
</system.serviceModel>
I tried by passing System.Net.CredentialCache.DefaultNetworkCredentials using above configuration and working fine for me. If it's not working for you then put debug point on line which passing credential and watch that System.Net.CredentialCache.DefaultNetworkCredentials Domain, UserName & Password values are blank or not. If Blank then it should work.
I assume that if you're looking within your CredentialCache.DefaultNetworkCredentials attribut you won't see the credential information.
From Microsoft website : The authentication informations return by the DefaultNetworkCredentials property will be only available for NTLM, Negotiate or Kerberos authentication.
To get your credential you need to implement this authentication.
You can use it by using impersonation wihtin your intranet application.
Impersonation allow your intranet application to be executed by the user of this one.
More information here :http://technet.microsoft.com/en-us/library/cc961980.aspx
I am developing one windows phone application which upload images zip file to ftp server. But I can't upload it. It gives an error Remote server Not found
Here is my WCF application web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" maxRequestLength="409600" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<!--<binding maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" receiveTimeout="00:10:00" closeTimeout="00:10:00">
<security mode="None" />
</binding>-->
<binding closeTimeout="01:30:00"
openTimeout="01:30:00" receiveTimeout="01:30:00" sendTimeout="01:30:00"
maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646">
<readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646"
maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
<security mode="None">
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
Here is my ServiceReferences.ClientConfig
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" maxBufferSize="2147483647" closeTimeout="01:10:00"
openTimeout="01:10:00" receiveTimeout="01:10:00" sendTimeout="01:10:00" maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://xxx.xx.x.xxx/WebService/Service1.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
contract="MyService.IService1" name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
I have create two project one is windows phone application, second is wcf application. I am sending large byte[] array to wcf server which gives an error Remote server Notfound. It works perfectly when the byte[] size is small but fails when the size is large. I heard that we can send very large file to wcf service near about 4gb. Then where I was wrong? Is there any change I have to do in web.config? I have hosted my wcf service to IIS on local machine.
For sending large data over wcf you have two options:
You may manually break your data into pieces (or read by 2Kb from file for example) and transfer each piece separately. At server side you may save each piece in temp file. This method require some coding (control order of portions for example).
Another option is using transferMode="Streamed", but this mode have some restrictions.
Update
If you can't use Streamed mode for some reasons, you may create in your service some methods:
string BeginSendFile();
This method must gererate id (Guid for example) and return it to client. Also service may create a file in temporary storage with this name.
void SendFilePortion(string id, byte[] data);
You call this method and transfer a little data. Server may find temp file by id and write data to it.
void EndSentFile(string id, string originalName);
Call this method when transfer all data to rename your temp file and replace it in non-temp storage.
I am trying to create a WCF Service with only Transport Security so I do not need SSL.
I keep geting this error message when I run it:
Could not find a base address that matches scheme https for the endpoint with binding
BasicHttpBinding.
My Web.config file looks like this:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Binding1">
<security mode="Transport">
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="AutoSenderWCFService.AutoSenderService">
<endpoint binding="basicHttpBinding" bindingConfiguration="Binding1"
contract="AutoSenderWCFService.IService1" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="AutoSenderWCFService.MyValidator, AutoSenderWCFService"/>
</serviceCredentials>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Transport security means securing your channel with SSL and hence you would need a certificate.
If you dont want to use SSL but want to pass username password over the channel then you can use ClearUsernameBinding that sends the username password over the channel in clear text.
NOTE: Make sure you use this only when you are confident that you client and server channel is secure like behind a firewall that provides security.
I cant see any address in there - add an address to your endpoint and should be ok
so:
<endpoint binding="basicHttpBinding" address="https://address" bindingConfiguration="Binding1"
contract="AutoSenderWCFService.IService1" />
In my case I was trying to test a wcf web service setup on a testing server without ssl. I changed the security mode to none and it started working for me.