0

I fallowed a tutorial to secure wcf service with username and password, and with certificate. I created and install certificate using pluralsight's self-Cert tool. and override validate method which is inherit from UserNamePasswordValidator. Certificate security is working fine, but validate method is not invoking during a service call. Service can be accessed without a providing username and password.
I read many articles about it, but the same procedure is shown there. I also read other stack overflow question about same problem but i am unable to find the solution for it.

Validation Code

using System;
using System.IdentityModel.Selectors;
using System.ServiceModel;

namespace WcfSecure
{
    public class CredentialValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName == null && password == null)
                throw new ArgumentNullException();
            if (!(userName == "one" && password == "two"))
                throw new FaultException("Wrong Credentials!");
        }
    }
}

Here Service Contract.

using System.ServiceModel;

namespace WcfSecure
{

    [ServiceContract]
    public interface ISecureWebService
    {
        [OperationContract]
        int SecureAdd(int x, int y);

        [OperationContract]
        int UnSecureService(int x, int y);
    }
}

Service Code

namespace WcfSecure
{
    public class SecureWebService : ISecureWebService
    {
        public int SecureAdd(int x, int y)
        {
            return x + y;
        }

        public int UnSecureService(int x, int y)
        {
            return x + y;
        }
    }
}

And the most important 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"/>
  </system.web>


  <system.serviceModel>

     <bindings>
      <wsHttpBinding>
        <binding name="SecureBinding">
          <security mode="Message">
            <message clientCredentialType="UserName" establishSecurityContext="true"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors >
        <behavior name="CustomBehavior">
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceCredentials>
            <serviceCertificate findValue="SecureService"
                                storeLocation="LocalMachine"
                                storeName="My"
                                x509FindType="FindBySubjectName"/>
            <userNameAuthentication  userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfSecure.CredentialValidator, WcfSecure" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <services>
      <service behaviorConfiguration="CustomBehavior" name ="WcfSecure.SecureWebService">
        <endpoint address="" binding="wsHttpBinding" contract="WcfSecure.ISecureWebService"></endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="http://192.168.1.224:84/WcfSecure/SecureWebService"/>
          </baseAddresses>
        </host>
      </service>
    </services>

  </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>
vikrantx
  • 593
  • 5
  • 22
  • I'm not sure why you're implementing your own validator. I have WCF services that area secured by a certificate with username/password validation, and I don't have to touch any of the WCF classes. – DeanOC Mar 25 '14 at 07:51
  • Could you share how it works or a demo code of it. – vikrantx Mar 25 '14 at 08:57

1 Answers1

0

a) I have my certificate installed on both the client and server machines

b) This is the section of the Client config file

  <system.serviceModel>
    <bindings>
      <ws2007HttpBinding>
        <binding name="WS2007HttpBinding_MyAppWCFServices"
                 closeTimeout="00:00:30"
                 openTimeout="00:00:30"
                 receiveTimeout="00:00:30"
                 sendTimeout="00:05:00"
                 bypassProxyOnLocal="false"
                 transactionFlow="false"
                 hostNameComparisonMode="StrongWildcard"
                 maxBufferPoolSize="6000000"
                 maxReceivedMessageSize="6000000"
                 messageEncoding="Text"
                 textEncoding="utf-8"
                 useDefaultWebProxy="true"
                 allowCookies="false">
          <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="6000000" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
          <security mode="Message">
            <transport realm="" />
            <message clientCredentialType="UserName" negotiateServiceCredential="false" />
          </security>
        </binding>
      </ws2007HttpBinding>
    </bindings>

    <behaviors>
      <endpointBehaviors>
        <behavior name="MyAppServiceBehaviour">
          <clientCredentials>
            <serviceCertificate>
              <authentication certificateValidationMode="None" revocationMode="NoCheck"/>
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>

    <client>
      <endpoint address="http://servername:888/MyApp.WCF.Services/WorkFlowService.svc"
        binding="ws2007HttpBinding" bindingConfiguration="WS2007HttpBinding_MyAppWCFServices" behaviorConfiguration="MyAppServiceBehaviour"
        contract="MyApp.WCF.Services.IWorkFlowService" name="WorkFlowServiceEndpoint">
        <identity>
          <certificateReference  storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="AF43F4486E52B225408B252C6479DBD6814FCE5B"/>
        </identity>
      </endpoint>
    </client>
</system.serviceModel>

c) This is the section of the Server config file

<system.serviceModel>
    <bindings>
      <ws2007HttpBinding>
        <binding name="WS2007HttpBinding_MyAppWCFServices"
                 closeTimeout="00:00:30"
                 openTimeout="00:00:30"
                 receiveTimeout="00:01:00"
                 sendTimeout="00:10:00"
                 bypassProxyOnLocal="false"
                 transactionFlow="false"
                 hostNameComparisonMode="StrongWildcard"
                 maxBufferPoolSize="6000000"
                 maxReceivedMessageSize="6000000"
                 messageEncoding="Text"
                 textEncoding="utf-8"
                 useDefaultWebProxy="true"
                 allowCookies="false">
          <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="6000000" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
          <security mode="Message">
            <transport realm="" />
            <message clientCredentialType="UserName" negotiateServiceCredential="false" />
          </security>
        </binding>
      </ws2007HttpBinding>
    </bindings>

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true">
      <serviceActivations>
        <add relativeAddress="MyApp.WCF.Services/WorkflowService.svc" service="MyApp.WCF.Services.WorkFlowService" />
      </serviceActivations>
    </serviceHostingEnvironment>

    <behaviors>
      <serviceBehaviors>
        <behavior name="MyAppServiceBehaviour">
          <!-- 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="true" />
          <serviceCredentials>
            <serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="AF43F4486E52B225408B252C6479DBD6814FCE5B" />
          </serviceCredentials>
        </behavior>
        <behavior name="ExposeMetaDataBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <services>
      <service behaviorConfiguration="MyAppServiceBehaviour" name="MyApp.WCF.Services.WorkFlowService">
        <endpoint address="" binding="ws2007HttpBinding" bindingConfiguration="WS2007HttpBinding_MyAppWCFServices" contract="MyApp.WCF.Services.IWorkFlowService" />
      </service>
    </services>
  </system.serviceModel>

Hope this helps!

DeanOC
  • 7,142
  • 6
  • 42
  • 56