I'm new to WCF service. I wanted to create a WCF service with basichttpbinding to create a custom authentication mechanism before giving access to my WCF service. I have used
security mode = Transport and clientcredentialtype = basic. I have written a custom validator function for validating my username and password.
validator function
namespace CustomValidator
{
public class MyCustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
// This isn't secure, though!
if ((userName != "check") || (password != "check"))
{
throw new SecurityTokenException("Validation Failed!");
}
}
}
}
This is my service config file
< ?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<identity impersonate="false" />
</system.web>
<system.serviceModel>
<diagnostics>
<endToEndTracing activityTracing="true" messageFlowTracing="true" propagateActivity="true"></endToEndTracing>
</diagnostics>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpEndpointBinding">
<security mode="Transport">
<transport clientCredentialType="Basic" />
<!-- <message clientCredentialType="UserName" />-->
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<endpoint address="" binding="basicHttpBinding" name="BasicHttpEndpoint" bindingConfiguration="BasicHttpEndpointBinding" contract="IService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="false" />
<!-- 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="CustomValidator.MyCustomValidator, App_Code" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<security>
<authentication>
<basicAuthentication enabled="true" />
<anonymousAuthentication enabled="false" />
<windowsAuthentication enabled="false" />
</authentication>
</security>
</system.webServer>
</configuration>
So the problem here is that whenever I run my service, I get a login dialog were I enter username and password(my validator expects both username and password to be same), I'm not getting my service details page, which used to come up in normal case (without authentication mechanism). I don't know what I'm missing, I do feel like its all in configurations which matters in my case but still I can't find out the mistake.
Have Created and Shared a Demo Project for Username Password Authentication.Its Working Fine.
Pls Check
https://onedrive.live.com/redir?resid=3FE322C74D6AA4D1%21169
You can use SelfCert,given inside,to Create a Certificate with name TrustedPeople , Store Location LocalMachine
Related
I am trying to set up a WCF webservice with BasicHttpBinding and authentication using username/password. I made custom authentication class. However, it is never called (verified by debugging). This is my web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Compareware_WebApp.webservices.AuthenticationValidator, Compareware_WebApp" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding">
<security mode="TransportCredentialOnly">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="Compareware_WebApp.webservices.Accounts">
<endpoint address="/webservices/Accounts.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding" name="BasicEndpoint"
contract="Compareware_WebApp.webservices.IAccounts" />
</service>
</services>
<client />
This is my authentication class:
namespace Compareware_WebApp.webservices
{
public class AuthenticationValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!Membership.ValidateUser(userName, password))
{
// This throws an informative fault to the client.
throw new FaultException("Unknown Username or Incorrect Password");
}
}
}
}
What am I doing wrong?
I also stuck in this problem, And I got the solutions. If you want to call the Validate method of the UserNamePasswordValidator So, you must be have to use the TransportWithMessageCredential security.
NOTE: You must be have to host the WCF Services at the IIS server and have to enable the SSL for you website otherwise it will be not work. If we use the TransportWithMessageCredential than we have to enable the SSL for the our website.
WCF Server Web.config file
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttp">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="TransportWithMessageCredential.Service1" behaviorConfiguration="wsHttpBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttp" contract="TransportWithMessageCredential.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="https://localhost:8080/WCFDemo"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="wsHttpBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="TransportWithMessageCredential.ServiceAuthanticator, TransportWithMessageCredential"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration>
Service Authentication class
public class ServiceAuthanticator : UserNamePasswordValidator
{
/// <summary>
///
/// </summary>
/// <param name="userName"></param>
/// <param name="password"></param>
public override void Validate(string userName, string password)
{
if (String.IsNullOrEmpty(userName) || String.IsNullOrEmpty(password))
{
throw new FaultException("Please, Provide the username and password!!!");
}
if (userName != "abc" || password != "abc")
{
throw new FaultException("Sorry, Invalid username or password!!!");
}
}
}
WCF Client app.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://kalpesh-pc/WCFAuth/Service1.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
name="WSHttpBinding_IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
Client Program to call the WCF Services
try
{
Service1Client objClient = new Service1Client();
objClient.ClientCredentials.UserName.UserName = "abc";
objClient.ClientCredentials.UserName.Password = "abc";
objClient.Open();
string strData = objClient.GetData(10);
}
catch (FaultException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
Happy Coding...
:)
Transport, as far as I understand, requires HTTPS to encrypt credentials and throws an exception if there is no SSL. TransportCredentialOnly will send the credentials in plain text and unencrypted and is recommended for testing ONLY.
Therefore, your credentials are send via transport. So <Transport> tag must be adjusted, not <Message>.
The following works for me:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
I'm trying to create WCF applications with username authentication. And this error occurring.
This is the service configuration:
Web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Jsl.BureauInf.Services.BureauInfSVC" behaviorConfiguration="ServiceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="Jsl.BureauInf.Contracts.ICliente" bindingConfiguration="ServiceBinding"/>
<endpoint address="" binding="wsHttpBinding" contract="Jsl.BureauInf.Contracts.IMotorista" bindingConfiguration="ServiceBinding"/>
<endpoint address="" binding="wsHttpBinding" contract="Jsl.BureauInf.Contracts.ITransportadora" bindingConfiguration="ServiceBinding"/>
<endpoint address="" binding="wsHttpBinding" contract="Jsl.BureauInf.Contracts.IVeiculo" bindingConfiguration="ServiceBinding"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="ServiceBinding">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="True"/>
<serviceCredentials>
<serviceCertificate findValue="Uareubinf"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Jsl.BureauInf.Security.Autenticacao, Jsl.BureauInf.Security" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<system.net>
<defaultProxy useDefaultCredentials="true"/>
</system.net>
</configuration>
Class Autentication
namespace Jsl.BureauInf.Security
{
public class Autenticacao : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName != "yaron")
throw new SecurityTokenException("Unknown Username or Password");
}
}
}
Client
BureauService.TransportadoraClient service = new BureauService.TransportadoraClient();
service.ClientCredentials.UserName.UserName = "xxx";
service.ClientCredentials.UserName.Password = "xxx";
service.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
BureauService.RESPOSTADTC rep = service.ConsultarTransportadora(consulta);
When the client makes request for service triggers the following error:
InnerException.Message: An error occurred when processing the security tokens in the message.
Message: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.
What should I do to fix this error?
This response can happen for a several reasons. The two that I suspect the most are:
You are sending the incorrect client credentials to the server. I see you are sending a UserName and Password as "xxx". However, your server is expecting a UserName of "yaron". This is the expected response from the server in that case.
The client machine has an invalid time or one that is more than 5 minutes different from the server. The default MaxClockSkew value for the WSHttpBinding is 5 minutes.
I am trying to create a call out to a WCF Service using the Channel Factory. But I am getting the error above in the title. If I take out the mode of transport then I get an "Access is Denied" error. I have been working with this for 3 days now.
What I have is one WCF lets call that WCF1 and that calls WCF2. WCF1 has a config file that pertains to WCF2. Now, I want to call WCF1 from another application (NopCommerce). When I call WCF1 from NopCommerce don't I just need to provide the web.config information for WCF1 and not WCF2?
So what I have done so far is I have written this code to invoke the WCF1 Service:
AddressService.Address verifiedAddress = null;
AddressService.VerifyThisAddressKeys keys = new AddressService.VerifyThisAddressKeys();
keys.LicenseId = new Guid("LicenseKey");
var myBinding = new BasicHttpBinding();
var myEndpoint = new EndpointAddress("http://www.verifythisaddress.com/AddressVerification/AddressVerificationService.svc");
myBinding.Security.Mode = BasicHttpSecurityMode.Transport;
var myChannelFactory = new ChannelFactory<AddressService.IAddressVerificationService>(myBinding, myEndpoint);
AddressService.IAddressVerificationService client = null;
try
{
client = myChannelFactory.CreateChannel();
verifiedAddress = client.VerifyThisAddress(address.FirstName, address.LastName, address.Company, address.Address1, address.Address2, address.City, address.StateProvince.Abbreviation, address.ZipPostalCode, address.Country.TwoLetterIsoCode, address.PhoneNumber, address.Email, keys);
((ICommunicationObject)client).Close();
}
catch(Exception ex)
{
if (client != null)
{
((ICommunicationObject)client).Abort();
Console.WriteLine(ex.Message);
}
}
My goal is not to use a Web.Config file if I don't have to.
Here is the WCF Config file I am trying to communicate with:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="DBCS" connectionString="Data Source=Server" providerName="System.Data.SqlClient"/>
</connectionStrings>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
<trust level="Full" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService">
<security mode="Transport" />
</binding>
<binding name="soapEndpointGlobalAddressCheck">
<security mode="Transport" />
</binding>
<binding name="soapSSLEndpointGlobalAddressCheck">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://addresscheck.melissadata.net/v2/SOAP/Service.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService"
contract="MelissaDataService.IService" name="BasicHttpBinding_IService" />
<endpoint address="http://address.melissadata.net/v3/SOAP/GlobalAddress"
binding="basicHttpBinding" bindingConfiguration="soapSSLEndpointGlobalAddressCheck"
contract="globalcheck.AddressCheckSoap" name="soapEndpointGlobalAddressCheck" />
<endpoint address="https://address.melissadata.net/v3/SOAP/GlobalAddress"
binding="basicHttpBinding" bindingConfiguration="soapSSLEndpointGlobalAddressCheck"
contract="globalcheck.AddressCheckSoap" name="soapSSLEndpointGlobalAddressCheck" />
</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="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>
Can't Sleep!
I've been struggling with this for a couple of days now - I cannot get this WCF service configured correctly to use a custom membership provider. When I fire up the test client I get this error:
The username/password Membership provider MidlandsCoop.MembersWcfService.Business.UserAuthentication specified in the configuration is invalid. No such provider was found registered under system.web/membership/providers.
I have been following this MSDN link to no avail. Can anyone tell me where I'm going wrong?
Here's my web.config:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="MyCS" connectionString="Data Source=my server;Initial Catalog=MyDB;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBinding">
<security>
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="MidlandsCoop.MembersWcfService.MembersService" behaviorConfiguration="Service_Behaviour">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration=""
name="basicHttpBinding" contract="MidlandsCoop.MembersWcfService.IMembersService" />
<endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpBinding"
name="wsHttpBinding" contract="MidlandsCoop.MembersWcfService.IMembersService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Service_Behaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
membershipProviderName="MidlandsCoop.MembersWcfService.Business.UserAuthentication" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
</configuration>
My user authentication class is as follows:
public class UserAuthentication : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
var db = new PetaPoco.Database("MyDB");
db.Fetch<dynamic>("SELECT Username, Password FROM MyTable WHERE Username=#0 AND Password =#1",
userName, password);
}
}
Any suggestions would be greatly appreciated.
the link that you have provided mentions customUserNamePasswordValidatorType to specify custom authentication type, UserAuthentication in your case. I think MembershipProviderName should be a class derived from MembershipProvider Class.
Server config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceCredentialsBehavior">
<serviceCredentials>
<serviceCertificate findValue="cn=cool" storeName="TrustedPeople" storeLocation="CurrentUser" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceCredentialsBehavior" name="Service">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MessageAndUserName" name="SecuredByTransportEndpoint" contract="IService"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="MessageAndUserName">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client/>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
My client config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="LocalCertValidation">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="CurrentUser" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService" >
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:48097/WCFServer/Service.svc"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService"
contract="ServiceReference1.IService"
name="WSHttpBinding_IService" behaviorConfiguration="LocalCertValidation">
<identity>
<dns value ="cool" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Service:
public string TestAccess()
{
return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
}
Client:
ServiceClient client = new ServiceClient();
client.ClientCredentials.UserName.UserName = "Admin";
client.ClientCredentials.UserName.Password = "123";
Console.WriteLine(client.TestAccess());
Console.ReadLine();
Error:
An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.
Inner exception:
At least one security token in the message could not be validated.
How do I resolve this exception?
I think the problem is your user name and password. With default configuration user name and password is validated as windows account. If you want other validation you must either use membership provider or custom user name password validator.
Since the error message is rather obscure, thought I would put it out there as another possible solution.
My environment uses Single Sign On (or STS if you prefer) to authenticate a user through ASP.NET MVC site. MVC site in turn makes a service call to my service endpoint by passing bearer token which it requested from STS server with Bootstrap token previously. The error I got was when I made a service call from MVC site.
In my case, this is caused by my Service's configuration as stated below. Particularly audienceUris node, it must exactly match the service endpoint:
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="https://localhost/IdpExample.YService/YService.svc" />
</audienceUris>
....
</identityConfiguration>
</system.identityModel>
HTH.