WCF 3.5 UserNameAuthentication is not working? - wcf

What I'm trying to do is to secure my service. To do this I'm using UserNameAuthentication. I did the binding and everything but some reason when I start the service I don't get the Validation prompt! Validate method is not triggered!
Here is my webConfig
I don't know what I'm missing here!
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service behaviorConfiguration="IPhone.Service1Behavior" name="MobileService.IPhone">
<endpoint address="" binding="wsHttpBinding" contract="MobileService.IIPhone" bindingConfiguration="SafeServiceConf">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="IPhone.Service1Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MobileService.CustomValidator, MobileService" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="SafeServiceConf" maxReceivedMessageSize="65536">
<readerQuotas maxStringContentLength="65536" maxArrayLength="65536"
maxBytesPerRead="65536" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
Here is my code in IPhone.svc for validation
I put the CustomValidator class inside the service!
public class CustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName == "test" && password == "test")
return;
throw new SecurityTokenException(
"Unknown Username or Password");
}
}
Any help?

The validation prompt would not come from WCF. The UI is responsible for that (i.e. ASPX web form).
To pass a user name and password from a client to a service, you would do something like this:
proxy.ClientCredentials.UserName.UserName = "myUserName";
proxy.ClientCredentials.UserName.Password = "password";

Related

WCF custom username and password validation is not executed

I have a WCF service hosted on IIS 7.5 with the settings of basicHttpBinding binding and TransportWithMessageCredential security. I would like to send a FaultException to the client in case of failed authentication but unfortunately the Validate method of custom validator class is not executed.
I have read here, that custom validator works only for self-hosting scenario:
Is it true, or I made a mistake somewhere?
public class ServiceUserNamePasswordValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!(userName == MobilApp.Helper.SiteGlobal.UserName && password == MobilApp.Helper.SiteGlobal.Password))
{
throw new FaultException("Unknown Username or Incorrect Password");
}
}
}
web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="True" />
<bindings>
<basicHttpBinding>
<binding name="ServiceBinding" useDefaultWebProxy="false">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Certificate" />
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="Service.TestService" behaviorConfiguration="CustomValidator">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="ServiceBinding"
bindingNamespace="https://service/TestService/"
contract="Service.ITestService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://service/TestService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CustomValidator">
<useRequestHeadersForMetadataAddress/>
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="True" httpsGetUrl="wsdl" />
<serviceDebug includeExceptionDetailInFaults="false" httpHelpPageEnabled="false" httpsHelpPageEnabled="true" />
<serviceCredentials>
<clientCertificate>
<authentication
certificateValidationMode="ChainTrust"
revocationMode="NoCheck" />
</clientCertificate>
<serviceCertificate
findValue="test.com"
x509FindType="FindBySubjectName"
storeLocation="LocalMachine"
storeName="My" />
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="ServiceUserNamePasswordValidator, Service" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Thank you.

Duplication of EndPoint but i cannot see it

I have a web service.
This is (part of my) my web config:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="LicensedBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<behavior name="NetTCPBehaviour">
<serviceTimeouts transactionTimeout="0.00:00:30" />
<serviceDebug includeExceptionDetailInFaults="false" />
<dataContractSerializer maxItemsInObjectGraph="65536" />
<serviceMetadata httpGetEnabled="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="License" behaviorConfiguration="LicensedBehaviour">
<endpoint address="License.svc" binding="basicHttpBinding" bindingConfiguration="NormalHttpBindingEndPoint" contract="ILicense" name="wsLicense" />
</service>
<service name="testme" behaviorConfiguration="NetTCPBehaviour">
<endpoint address="net.tcp://localhost:808/Sync2.svc" binding="netTcpBinding" contract="ISync2" name="wsMotionUploader" bindingConfiguration="NetTCPBindingEndPoint"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="NormalHttpBindingEndPoint" closeTimeout="00:02:00" openTimeout="00:02:00">
<readerQuotas maxArrayLength="32768" maxStringContentLength="2147483647" />
</binding>
</basicHttpBinding>
<netTcpBinding>
<binding name="NetTCPBindingEndPoint" receiveTimeout="00:15:00" sendTimeout="00:15:00" transferMode="Streamed" closeTimeout="00:02:00" openTimeout="00:02:00"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
<readerQuotas maxArrayLength="32768" />
<security mode="None">
<transport clientCredentialType="None" protectionLevel="None" />
<message clientCredentialType="None" />
</security>
</binding>
</netTcpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
This is my service:
public void DoWork(Stream image)
{
var img = System.Drawing.Bitmap.FromStream(image);
}
This is my interface:
[OperationContract(IsOneWay = true)]
void DoWork(Stream image);
This is my client:
wsSyncFastest.Sync2Client client = new wsSyncFastest.Sync2Client();
using (Bitmap bmp = new Bitmap("d:\\bf.jpg"))
{
using (MemoryStream ms = new MemoryStream())
{
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
client.DoWork(ms);
ms.Close();
}
}
This is my error message:
An endpoint configuration section for contract 'wsSyncFastest.ISync2' could not be loaded because more than one endpoint configuration for that contract was found. Please indicate the preferred endpoint configuration section by name.
this is my stack Error:
at System.ServiceModel.Description.ConfigLoader.LookupChannel(ContextInformation configurationContext, String configurationName, ContractDescription contract, EndpointAddress address, Boolean wildcard, Boolean useChannelElementKind, ServiceEndpoint& serviceEndpoint)
at System.ServiceModel.Description.ConfigLoader.LookupEndpoint(String configurationName, EndpointAddress address, ContractDescription contract, ContextInformation configurationContext)
at System.ServiceModel.Description.ConfigLoader.LookupEndpoint(String configurationName, EndpointAddress address, ContractDescription contract)
at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)
at System.ServiceModel.ChannelFactory1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress)
at System.ServiceModel.ChannelFactory1..ctor(String endpointConfigurationName)
at System.ServiceModel.ConfigurationEndpointTrait1.CreateSimplexFactory()
at System.ServiceModel.ConfigurationEndpointTrait1.CreateChannelFactory()
at System.ServiceModel.ClientBase1.CreateChannelFactoryRef(EndpointTrait1 endpointTrait)
at System.ServiceModel.ClientBase1.InitializeChannelFactoryRef()
at System.ServiceModel.ClientBase1..ctor()
at LiteEdition.wsSyncFastest.Sync2Client..ctor() in g:\dev20140604\LiteEdition\LiteEdition\Service References\wsSyncFastest\Reference.cs:line 51
at LiteEdition.StartUp.button1_Click(Object sender, EventArgs e) in g:\dev20140604\LiteEdition\LiteEdition\StartUp.cs:line 2646
I cannot see any probelms but obviously there is.
Can anyone assist?
ADDITIONAL:
My client app.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="wsLicense" />
<binding name="BasicHttpBinding_ISync2" />
</basicHttpBinding>
<netTcpBinding>
<binding name="NetTcpBinding_ISync2" />
</netTcpBinding>
</bindings>
<client>
<endpoint address="http://aurl/License.svc/License.svc"
binding="basicHttpBinding" bindingConfiguration="wsLicense"
contract="wsLicense.ILicense" name="wsLicense" />
<endpoint address="http://www.informedmotion.co.uk/Sync2.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISync2"
contract="wsSyncFastest.ISync2" name="BasicHttpBinding_ISync2" />
<endpoint address="net.tcp://dsvr019492/Sync2.svc" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_ISync2" contract="wsSyncFastest.ISync2"
name="NetTcpBinding_ISync2">
<identity>
<servicePrincipalName value="host/DSVR019492" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Try passing the name of the endpoint in when you create the proxy object and see if that fixes it.
If you intend on using the basicHttpBinding, it will be:
wsSyncFastest.Sync2Client client = new wsSyncFastest.Sync2Client("BasicHttpBinding_ISync2");
If you intend on using the netTcpBinding it will be:
wsSyncFastest.Sync2Client client = new wsSyncFastest.Sync2Client("NetTcpBinding_ISync2");

WCF service worked with windows authentication, switched to use SSL now it wants anonymous

I have created a WCF service with Windows authentication that worked correctly.
Now I am trying to add SSL. After following the steps, it now seems to be using anonymous authentication, giving this error:
The HTTP request was forbidden with client authentication scheme 'Anonymous'.
Any clues would be appreciated.
We are using IIS 7.5 on Windows Server 2008 R2 and .Net version 4
The config file that worked correctly had this service model (server side):
<system.serviceModel>
<bindings />
<client />
<services>
<service name="WCFServiceTest.Service1" behaviorConfiguration="WCFServiceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="WCFServiceTest.WCFService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCFServiceBehavior">
<serviceMetadata httpGetEnabled="True" policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
This is the changed configuration
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="TransportWsSecurity">
<security mode="Transport">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client />
<services>
<service name="WCFServiceTest.Service1" behaviorConfiguration="WCFServiceBehavior">
<endpoint address="" binding="wsHttpsBinding"
bindingConfiguration="TransportWsSecurity"
contract="WCFServiceTest.WCFService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
<host>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCFServiceBehavior">
<serviceMetadata httpsGetEnabled="True" policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
This is the code that calls the service. It never gets to the IgnoreCertificateErrorHandler which just returns true:
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(IgnoreCertificateErrorHandler);
WCFService1Client client = new WCFService1Client();
client.ClientCredentials.Windows.ClientCredential.UserName = Utility1.GetConfig("RemoteLogin");
client.ClientCredentials.Windows.ClientCredential.Password = Utility1.GetConfig("RemotePassword");
try
{
result = client.SendUpdatesFromLocation(temp);
}
catch (FaultException<WCFProcessFault> ex)
{
string op = ex.Detail.Operation;
string err = ex.Detail.Notes;
}
finally
{
client.Close();
}
WCFService1Client client = new WCFService1Client();
client.ClientCredentials.Windows.ClientCredential.UserName = Utility1.GetConfig("RemoteLogin");
client.ClientCredentials.Windows.ClientCredential.Password = Utility1.GetConfig("RemotePassword");
try
{
result = client.SendUpdatesFromLocation(temp);
}
catch (FaultException<WCFProcessFault> ex)
{
string op = ex.Detail.Operation;
string err = ex.Detail.Notes;
}
finally
{
client.Close();
}
<bindings>
<wsHttpBinding>
<binding name="TransportWsSecurity">
<security mode="Transport">
<transport clientCredentialType="Ntlm"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
Try the above changes. This will use Ntlm rather than Negotiate (Kerberos) for auth. It is very very likely you haven't setup your server for Kerberos auth.

WCF Multiple Endpoints is not working

I am trying to let my WCF service to have operations that can be called through a proxy client and through REST call, i am using the following configurations:
<services>
<service behaviorConfiguration="SecureBehavior" name="Payment">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="secureWS" contract="IPayment"/>
<endpoint address="rest" binding="webHttpBinding" behaviorConfiguration="webBehavior" contract="IPayment"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<bindings>
<mexHttpBinding>
<binding name="userMex"/>
</mexHttpBinding>
<wsHttpBinding>
<binding name="secureWS">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
</security>
</binding>
<binding name="publicWS">
<security mode="None"/>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="false"/>
</serviceCredentials>
</behavior>
<behavior name="PublicBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="true"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</services>
and here is my code:
[ServiceContract]
public interface IPayment
{
[OperationContract]
PaymentResult Finalize(string TransactionID, string CertificatePath);
[OperationContract]
[WebGet(UriTemplate = "rest")]
System.IO.Stream GetPayment();
}
Now whenever i run my service i receive this error:
Operation 'Finalize' of contract 'IPayment' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped.
Where here i would like to keep Finalize operation to be only called via .NET client and the GetPayment operation to be called through any browser.
If you do not want your Finalize method to be called from a client connecting via the webhttp endpoint and you don't want GetPayments to be called from a client connecting via wshttp you can simply split your contract in two.
Assuming you are hosting in IIS you might need to do a little trick to make sure that it works. Let me give you an example using the details from the question...
First of all here is the code for the two services...
[ServiceContract]
public interface IPayment
{
[OperationContract]
[WebGet(UriTemplate = "rest")]
System.IO.Stream GetPayment();
}
[DataContract]
public class PaymentResult
{
}
[ServiceContract]
public interface IMakePayment
{
[OperationContract]
PaymentResult Finalize(string TransactionID, string CertificatePath);
}
// Maybe you really should have the two services separate but if you do
// want to implement them both in a single class you can do this
public abstract class PaymentBase : IMakePayment, IPayment
{
// ... Implement both interfaces here
public PaymentResult Finalize(string TransactionID, string CertificatePath)
{
return null;
}
public System.IO.Stream GetPayment()
{
return null;
}
}
public class MakePayment : PaymentBase
{
// Empty
}
public class Payment : PaymentBase
{
// Empty
}
Now create two .svc files like so:
MakePayment.svc
<%# ServiceHost Language="C#" Debug="true" Service="WebApplication1.MakePayment" %>
Payment.svc
<%# ServiceHost Language="C#" Debug="true" Service="WebApplication1.Payment" %>
And finally here is the system.servicemodel configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="SecureBehavior" name="WebApplication1.MakePayment">
<endpoint binding="wsHttpBinding" bindingConfiguration="secureWS" contract="WebApplication1.IMakePayment"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" bindingConfiguration="userMex"/>
</service>
<service behaviorConfiguration="PublicBehavior" name="WebApplication1.Payment">
<endpoint binding="webHttpBinding" behaviorConfiguration="webBehavior" bindingConfiguration="publicWS" contract="WebApplication1.IPayment"/>
</service>
</services>
<bindings>
<mexHttpBinding>
<binding name="userMex"/>
</mexHttpBinding>
<wsHttpBinding>
<binding name="secureWS">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
<webHttpBinding>
<binding name="publicWS">
<security mode="None"/>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="false"/>
</serviceCredentials>
</behavior>
<behavior name="PublicBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="true"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
There you go - if you connect to /MakePayment.svc you will connect via WSHTTP and be able to call FinalizePayment and if you go to /Payments.svc/rest it will call the GetPayment method where you are returning a stream.

Contract requires Session, but Binding ‘WSHttpBinding’ doesn’t support it or isn’t configured properly to support it

I have specified the service contract to require the session.
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ITicketSales
{
}
The service decorated like this:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class TicketSalesService : ITicketSales
{
}
Here is my App.config file:
<system.serviceModel>
<services>
<service name="InternetRailwayTicketSales.TicketSalesImplementations.TicketSalesService" behaviorConfiguration="defaultBehavior">
<host>
<baseAddresses>
<add baseAddress = "https://localhost/TicketSales/"></add>
</baseAddresses>
</host>
<endpoint address="MainService" binding="wsHttpBinding" bindingConfiguration="wsSecureConfiguration"
contract="InternetRailwayTicketSales.TicketSalesInterface.ITicketSales" />
<endpoint address="mex" binding="mexHttpsBinding"
contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="wsSecureConfiguration">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="defaultBehavior">
<serviceThrottling maxConcurrentInstances="5000" maxConcurrentSessions="5000"/>
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
When I press F5 I receive the error message "Contract requires Session, but Binding ‘WSHttpBinding’ doesn’t support it or isn’t configured properly to support it."
I really need the channel which supports SSL and requires session.
You can support sessions by enabling message security:
<binding name="wsHttpSecureSession">
<security>
<message establishSecurityContext="true"/>
</security>
</binding>
If you need to go with transport security you may need to specify a client credential type