I'm not very experienced with WCF, as such I'm a little stuck with this one, I allow my WCF service to configure it's own endpoints (my manual attempts have been less than successful). Now this works fine appart from one issue, It adds a second endpoint using the local machine name, and the local windows domain.
My Config file is such:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="https" port="443"/>
</defaultPorts>
</useRequestHeadersForMetadataAddress>
<!-- 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" />
However when adding this WCF to a WPF application, it generates the following config (Url changed for security)
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IAdminService">
<security mode="None">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
<binding name="BasicHttpsBinding_IAdminService">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://machinename.domain.local/PortalServices/AdminService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IAdminService"
contract="AdminService.IAdminService" name="BasicHttpBinding_IAdminService" />
<endpoint address="https://mysite.co.uk/PortalServices/AdminService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpsBinding_IAdminService"
contract="AdminService.IAdminService" name="BasicHttpsBinding_IAdminService" />
</client>
</system.serviceModel>
As you can see, it adds a working URL and a local domain URL
http://machinename.domain.local/PortalServices/AdminService.svc
How can i prevent this from being added? as it becomes a bit of a pain having to remember to manually remove it after every deploy/service update.
As Requested, this is one of the Interface classes.
[ServiceContract]
public interface IAdminService
{
[OperationContract]
List<PortalApp> GetApplications();
[OperationContract]
int AddApplication(string AppName, string Desc, string version, bool enabled);
[OperationContract]
bool EditApplication(int appid, string AppName, string Desc, string version, bool enabled);
[OperationContract]
bool AddAppAccess(int appid, Int16 uid);
[OperationContract]
bool RemAppAccess(int appid, Int16 uid);
[OperationContract]
List<PortalUser> GetUsers();
}
Ok, thanks to Jontatas mentioning the fact the endpoints have seperate binding types it got me thinking.
Turns out i had forgotten to remove the http binding from IIS itself (which is not used). Removing that binding from IIS also removed the incorrect binding in the generated config.
Related
I have a WCF service created with VS2013 on Win8. If I start the service via VS (localhost:port) I'm able to do GET response in json
but same service i am hosted on server (IIS7) then i get 404 Error
localhost URL : http://localhost:43596/abc.svc/LoginUser/abc/abc
Live URL: http://mywwebsite.com:80/abc.svc/LoginUser/abc/abc
In my opionio, there might something amiss with the hosting environment, try to enable WCF feature support in IIS.
Here is my service, wish it is useful to you.
IService1.cs
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet]
string GetData(int value);
Service1.svc.
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
Web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="mybinding">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</webHttpBinding>
</bindings>
<protocolMapping>
<add binding="webHttpBinding" scheme="http"/>
<add binding="webHttpBinding" scheme="https" bindingConfiguration="mybinding"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Since the above configuration support both http and https protocol, we need to add http and https binding in IIS site binding module.
Reference.
How to make WCF Service Use HTTPS protocol
Feel free to let me know if there is anything I can help with.
I have been looking around and checked several answers but I still keep running into the same problem.
I have a WCF-service which receives data as JSON and then processes it.
I have a console-application which calls this service.
But I keep running into the same problem: 'The remote server returned an unexpected response: (413) Request Entity Too Large.
In my console-application config I have :
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IPaymentBehaviorService" allowCookies="true"
maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647">
<readerQuotas maxDepth="32" maxArrayLength="2147483647" maxStringContentLength="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:50068/PaymentBehaviorService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IPaymentBehaviorService"
contract="PaymentBehaviorServiceService.IPaymentBehaviorService"
name="BasicHttpBinding_IPaymentBehaviorService" />
</client>
</system.serviceModel>
My server-config :
<system.serviceModel>
<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" />
One line in the data that is being sent, looks like :
{ \"ReqId\":\"79\",\"TaxNbr\":\"889638963\",\"Amount\":\"29,4\",\"Invoice\":\"10/2330\",\"InvDate\":\"19/04/2018 0:00:00\",\"ExpDate\":\"19/04/2018 0:00:00\" }
I can only send about 450 of those lines in one request.
I need to raise that number of lines to something like 1500 or even more.
How can I do that?
I have found a lot of similar questions but none that gave me a solution.
Have you played around with TransferMode attribute in the basicHttpBinding; setting the mode to "streaming"
I have created a Service with below Service contract
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
With below Custom Authentication (not in App_Code)
public class CustomAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
try
{
if (userName.Equals("user") && password.Equals("pass"))
{
//Good to go
}
}
catch (Exception ex)
{
throw new FaultException("Authentication failed");
}
}
}
My Config on Service. I used basicHttpBinding with Custom User Authentication (I don't want to use wsHttpBinding which makes it mandatory to have certificate)
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="myBasicBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
<transport clientCredentialType="None" proxyCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="TestService.Service1" behaviorConfiguration="customBehavior">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="myBasicBinding" contract="TestService.IService1" />
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="customBehavior">
<!-- 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"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="TestService.CustomAuthenticator,TestService"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
Service is hosted on IIS 8.5 with Anonymous and Forms Authentications enabled. I took a Console application client, added service reference and below config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
<transport clientCredentialType="None" proxyCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://techspider/Service/Service1.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
But, when I call a method on the service, it seems to be accepting any user name / password, which makes me think that it is not going to the custom authentication class I implemented.
If I don't supply any UserName, it is throwing me an error which indicates my setup is correct.
Service1Client client = new Service1Client();
client.GetData(1);
The username is not provided. Specify username in ClientCredentials.
The below code even after supplying wrong credentials, was able to fetch me the output.
Service1Client client = new Service1Client();
client.ClientCredentials.UserName.UserName = "aaaa";
client.ClientCredentials.UserName.Password = "dddd";
client.GetData(1);
Can anyone suggest if I'm missing any Config on Server? How do I ensure my CustomAuthenticator gets executed with every method call. I searched a number of questions online but none of them resolved.
The feeling that each and every username password combination will be accepted is right. That's the case because you're not really validating the credentials.
if (userName.Equals("user") && password.Equals("pass"))
{
//Good to go
}
If these demo-credentials are submitted, you're good to go ;-) But what if this doesn't apply? If any other username password combination is submitted, then nothing happens! And that's exactly the reason why your service is accepting arbitrary credentials. In the catch-block you're throwing an informative FaultException, but it won't be triggered as long as there doesn't occur an exception (which isn't the case in this simple example).
If you take a look at the docs, there's a very important remark and a corresponding code sample:
Override the Validate method to specify how the username and password is validated. If the username and password do not pass validation, then throw a SecurityTokenValidationException.
So instead of doing nothing if the submitted credentials don't match you should throw a SecurityTokenValidationException to reject the login-attempt.
public class CustomAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
try
{
if (userName.Equals("user") && password.Equals("pass"))
{
//Good to go
}
else
{
// add this line
throw new SecurityTokenException("Unknown Username or Password");
}
}
catch (Exception ex)
{
throw new FaultException("Authentication failed");
}
}
}
I have a WCF service that works as expected when providing proper credentials.
When I try to consume the service with wrong credentials, the service sends an MessageSecurityException error as expected, and I receive an error: "MessageSecurityException was unhandled by user code".
I'm not sure how to handle this exception, since it is raised in the Reference.cs file that is auto-generated and not really under my control:
References.cs
public string EndLogin(System.IAsyncResult result) {
object[] _args = new object[0];
string _result = ((string)(base.EndInvoke("Login", _args, result))); //Here is the error raised
return _result;
}
Ideal would be to check if the service has accepted the credentials instead of relying on an error raised, but have no idea how to check this.
Hope someone can help me, so my App don't have to crash on each wrong login ;)
Web.config : 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>
<services>
<service name="BiBasicService.SalesMarketingService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding"
contract="BiBasicService.ISalesMarketingService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpsGetEnabled="true" 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"/>
<!-- To enable custom Role validation -->
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="BiBasicService.Security.AuthorizationPolicy, BiBasicService" />
</authorizationPolicies>
</serviceAuthorization>
<!-- To enable custom Username and Password validator-->
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="BiBasicService.Security.CustomValidator, BiBasicService"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="false" />
</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>
ServiceReferences.ClientConfig : Client:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ISalesMarketingService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://PUBLICDOMAIN/BasicHttp/SalesMarketingService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISalesMarketingService"
contract="ServiceReference1.ISalesMarketingService" name="BasicHttpBinding_ISalesMarketingService" />
</client>
</system.serviceModel>
</configuration>
The MessageSecurityException: it's a binding error.
Make sure the binding configuration on server side and client side must match.
Please post the server side web.config and client side web.config
You may want to look into the IErrorHandler interface, which would allow you to handle the exception at a more “global level”. The IErrorHandler is an extension that allows explicitly control the behavior of the application when an exception is thrown, implement the IErrorHandler interface and add it to the Dispatcher’s ErrorHandlers property. IErrorHandler enables you to explicitly control the SOAP fault generated, decide whether to send it back to the client, and perform associated tasks, such as logging. Error handlers are called in the order in which they were added to the ErrorHandlers property.
http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.aspx
http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/07/wcf-extensibility-ierrorhandler.aspx
I've created a simple WCF Service which is hosted in IIS. Now i want to use my own userName authentication.
My web.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="WcfIIsBasicAuthTest.Service1" behaviorConfiguration="MyBehavior">
<endpoint address=""
binding="basicHttpBinding"
contract="WcfIIsBasicAuthTest.IService1"
bindingConfiguration="MyBinding"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfIIsBasicAuthTest.MyValidator, WcfIIsBasicAuthTest"/>
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
The Validator
namespace WcfIIsBasicAuthTest
{
public class MyValidator :UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if(!(userName == "test" && password == "test"))
{
throw new SecurityTokenException("Validation Failed!");
}
}
}
}
If i start this WCF Service from within visual studio, i get the following error: The authentication schemes configured on the host ('Ntlm, Anonymous') do not allow those configured on the binding 'BasicHttpBinding' ('Basic').
If i try to connect to the service if it is hosted in IIS, i get error messages depending on which authentication type is set, but it doesn't work at all.
Error if only Anonymous authentication is enabled: The authentication schemes configured on the host ('Anonymous') do not allow those configured on the binding 'BasicHttpBinding' ('Basic').
If i set Basic Authentication in IIS, it demands a valid local user which i don't want to provide(since i want to write my own userprovider).
Any hints/links how to setup such a basic auth userprovider with wcf and iis?
Can you set the below configuration for using your own UserNameValidator:
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
For that to work with basicHttpBinding you would need to have HTTPS setup as WCF doesnt allow username password being passed over the channel in clear text. The other alternative is to use wsHttpBinding.