WCF custom username and password validation is not executed - wcf

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.

Related

Not able to access the methods from secure wcf rest service

I have a running wcf rest service hosted on IIS. I have successfully added the .x509 certificates to the client and the server and it works fine.As it is a secure service it is accessed using https The problem I am facing is that I am not able to access any of the methods from the service it keeps throwing 404 error however when I browse the service from IIS using https link it open the WSDL fine but throws 404 error while accessing any of the methods.
Here is my Interface implementation of a method from the service.
[ServiceContract]
public interface IRestDemo
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "/DoWork/{name}")]
string DoWork(string name);
}
Here is my configuration file:
<system.serviceModel>
<services>
<service name="RestDemo.RestDemo" behaviorConfiguration="serviceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://localhost/RestDemo/RestDemo.svc" />
</baseAddresses>
</host>
<endpoint address="" binding="webHttpBinding" contract="RestDemo.IRestDemo" behaviorConfiguration="web">
<!--<identity>
<dns value="localhost"/>
</identity>-->
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="RestDemo.IRestDemo" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="web" crossDomainScriptAccessEnabled="true">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<!--<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"
trustedStoreLocation="LocalMachine" />
</clientCertificate>
<serviceCertificate findValue="ServerCertificate"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>-->
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" httpsGetUrl="/RestDemo.svc" />
<!-- 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 name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint
crossDomainScriptAccessEnabled="true">
</standardEndpoint>
</webScriptEndpoint>
</standardEndpoints>
</system.serviceModel>
Any suggestions would be really appreciated.

Why Creating new session id every time in wsHttpBinding

I am using following configuration to make my service sessionful, but for each request wcf service is responding me with new session id. Why it so, what I need to make it sessionful for that client so that for each request there should be same session id
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttp">
<readerQuotas maxStringContentLength="10240" />
<reliableSession enabled="true" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="wcfservice.serviceclass" behaviorConfiguration="MyFileServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:51/"/>
<add baseAddress="net.tcp://localhost:52/"/>
</baseAddresses>
</host>
<endpoint address="pqr" binding="wsHttpBinding" bindingConfiguration="wsHttp"
name="b" contract="wcfservice.Iservice" />
<endpoint address="pqr" binding="netTcpBinding"
name="c" contract="wcfservice.Iservice" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyFileServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
By default a session is initiated when channel is opened you can read more about it here in this Sessions in WCF
AS the default value of IsInitiating parameter is true each of your calls started a new session. Read more About it here IsInitiating and IsInitiating
So in your Operation contracts
[OperationContract(
IsInitiating=false,
IsTerminating=false
)]
public void MethodOne()
{
return;
}

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 Service using UserNamePasswordValidation and Sessions

I have a WCF Service that currently uses basicHttpBinding, userNamePasswordValidationMode and TransportWithMessageCredential, Here is my Configuration:
<behavior name="Secure">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Kestrel.MIS3.Server.Services.Security.LoginAuthentication, Kestrel.MIS3.Server.Services" />
</serviceCredentials>
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="Kestrel.MIS3.Server.Services.Security.AuthorizationPolicy, Kestrel.MIS3.Server.Services"/>
</authorizationPolicies>
</serviceAuthorization>
<behaviour>
<services>
<service name="Kestrel.MIS3.Server.Services.UserService" behaviorConfiguration="Secure">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="wsSecure"
contract="Kestrel.MIS3.Server.Services.IUserService" />
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<wsHttpBinding>
<binding name="wsSecure">
<reliableSession enabled="true"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
I want to be able to use a Session so that when an Instance of the Service is created I dont need to look up the user details evertime. Is this possible?
I have marked the Services with the following but with no luck:
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IUserService
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class UserService : ServiceBase, IUserService

WCF 3.5 UserNameAuthentication is not working?

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";