locked
secure username/password authentication issue in WCF service application RRS feed

  • Question

  • User404975991 posted

    My web.config of the service is as follows

    <configuration>

    <appSettings>

    <add key="SSLUserName" value="lgxitadmin" />
    <add key="SSLPassword" value="lgxadmin$123" />
    </appSettings>

    <system.serviceModel>
    <bindings>
    <basicHttpBinding>
    <binding name="SafeServiceConf">
    <security mode="TransportWithMessageCredential">
    <transport clientCredentialType="Basic" proxyCredentialType="Basic"
    realm="" />
    <message clientCredentialType="UserName" algorithmSuite="Default" />
    </security>
    </binding>
    </basicHttpBinding>
    </bindings>

    <services>
    <service name="Ramco_LGX_interfaces.LGXService" behaviorConfiguration="metadataBehavior">
    <endpoint address="" binding="" bindingConfiguration="SafeServiceConf" contract="Ramco_LGX_interfaces.ILGXService" />
    <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
    </service>
    </services>

    <behaviors>
    <serviceBehaviors>
    <behavior name="metadataBehavior">
    <serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" suppressAuditFailure="true" />
    <serviceMetadata httpsGetEnabled="true" />
    <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
    <!-- 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>
    <!--<clientCertificate>
    <authentication certificateValidationMode="None" />
    </clientCertificate>-->
    <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Ramco_LGX_interfaces.CustomValidator,Ramco-LGX_interfaces" />
    </serviceCredentials>
    </behavior>
    </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

    </system.serviceModel>

    CustomValidator:

    public class CustomValidator : UserNamePasswordValidator
    {
    public override void Validate(string userName, string password)
    {
    if (null == userName || null == password)
    {
    throw new ArgumentNullException();
    }


    if (!AuthenticateUser(userName, password))
    throw new SecurityTokenValidationException("Invalid Service Credentials");
    else
    {
    // do nothing - they're good
    }
    }
    public bool AuthenticateUser(string userName, string password)
    {
    if (userName != ConfigurationManager.AppSettings["SSLUserName"].ToString() || password != ConfigurationManager.AppSettings["SSLPassword"].ToString())
    {
    return false;
    }
    else
    {
    return true;
    }
    }
    }

    in IIS  Enabled "Basic" Authentication 

    When i test this in SOAP UI with lgxitadmin/lgxadmin$123 credentials as configured in Config file am getting below error

    Getting below error;

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
    <s:Fault>
    <faultcode xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">a:InvalidSecurity</faultcode>
    <faultstring xml:lang="en-AU">An error occurred when verifying security for the message.</faultstring>
    </s:Fault>
    </s:Body>
    </s:Envelope>

    Thanks in advance. 

    Kindly support on this

    Regards

    Raghu

    Thursday, November 2, 2017 4:17 AM

All replies

  • User475983607 posted

    Do not configure Basic Authentication in IIS when implementing a custom username  password validator in WCF.

    This doc explains how to setup and configure a custom username password validator in WCF.

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-a-custom-user-name-and-password-validator

    IIRC, you must use transport security (HTTPS) otherwise WCF will not use the custom validator.  The documentation above explains the details.

    Thursday, November 2, 2017 10:33 AM
  • User404975991 posted

    Thanks mgebhard,

    Changed my web.config bindings as below

    <wsHttpBinding>

    <binding name="SafeServiceConf">
    <security mode="Transport">
    <transport clientCredentialType="Basic" proxyCredentialType="Basic"
    realm="" />
    <message clientCredentialType="UserName" algorithmSuite="Default" />
    </security>
    </binding>
    </wsHttpBinding>

    <serviceBehaviors>
    <behavior name="metadataBehavior">
    <serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" suppressAuditFailure="true" />
    <serviceMetadata httpsGetEnabled="true" httpGetBinding ="true" />
    <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
    <!-- 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>
    <!--<clientCertificate>
    <authentication certificateValidationMode="None" />
    </clientCertificate>-->
    <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Ramco_LGX_interfaces.CustomValidator,Ramco-LGX_interfaces" />
    </serviceCredentials>
    </behavior>
    </serviceBehaviors>

    Disabled IIS Basic Authentication. Now only Anonymous Authentication enabled in IIS.

    Even though am getting below error:

    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
    <s:Header>
    <a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>
    </s:Header>
    <s:Body>
    <s:Fault>
    <s:Code>
    <s:Value>s:Sender</s:Value>
    <s:Subcode>
    <s:Value xmlns:a="http://schemas.xmlsoap.org/ws/2005/02/sc">a:BadContextToken</s:Value>
    </s:Subcode>
    </s:Code>
    <s:Reason>
    <s:Text xml:lang="en-AU">The message could not be processed. This is most likely because the action 'http://tempuri.org/ILGXService/Get_proof_of_delivery_master' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.</s:Text>
    </s:Reason>
    </s:Fault>
    </s:Body>
    </s:Envelope>

    Kindly support on this.

    Thanks in Advance

    Regards

    Raghu

    Thursday, November 2, 2017 12:12 PM
  • User475983607 posted

    The error message indicates the client configuration does not match the server configuration.  Please see the link posted in my previous thread. It explains how to do create a custom username and password validator step-by-step.  The documentation works for me so I assume you missed a step.  Or perhaps you forgot to update the client after making changes to the server configuration.  Or perhaps you are using Soap UI and not formating the request properly?

    You should be able to simply create a web service reference in Visual Studio and add the credentials to the proxy.  

    I use the default WCF template and added the username and password validator found in the linked documentation.

    namespace WcfService1
    {
        public class CustomUserNameValidator : UserNamePasswordValidator
        {
            // This method validates users. It allows in two users, test1 and test2 
            // with passwords 1tset and 2tset respectively.
            // This code is for illustration purposes only and 
            // must not be used in a production environment because it is not secure.	
            public override void Validate(string userName, string password)
            {
                if (null == userName || null == password)
                {
                    throw new ArgumentNullException();
                }
    
                if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
                {
                    // This throws an informative fault to the client.
                    throw new FaultException("Unknown Username or Incorrect Password");
                    // When you do not want to throw an infomative fault to the client,
                    // throw the following exception.
                    // throw new SecurityTokenException("Unknown Username or Incorrect Password");
                }
            }
        }
    }

    The web.config

      <system.serviceModel>
        <services>
          <service name="WcfService1.Service1" behaviorConfiguration="CustomusernamePasswordBehavior">
            <endpoint binding="wsHttpBinding"
                      bindingConfiguration="Binding"
                      contract="WcfService1.IService1" />
          </service>
        </services>
        <bindings>
          <wsHttpBinding>
            <binding name="Binding">
              <security mode="TransportWithMessageCredential">
                <message clientCredentialType="UserName"  />
              </security>
            </binding>
          </wsHttpBinding>
        </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior name="CustomusernamePasswordBehavior">
              <serviceCredentials>
                <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.CustomUserNameValidator, WcfService1" />
              </serviceCredentials>
              <!-- 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"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
      </system.serviceModel>

    Next, I added a console application and adding service reference to the service above.

      <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://localhost:44353/Service1.svc" binding="wsHttpBinding"
            bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
            name="WSHttpBinding_IService1" />
        </client>
      </system.serviceModel>
            static void Main(string[] args)
            {
                ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
                client.ClientCredentials.UserName.UserName = "test1";
                client.ClientCredentials.UserName.Password = "1tset";
                string result = client.GetData(100);
    
                Console.WriteLine(result);
    
            }


    As you can see I used TransportWithMessageCredential and HTTPS otherwise the validator will not fire.  Or you can use a certificate.

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/user-name-password-validator

    Thursday, November 2, 2017 2:26 PM
  • User404975991 posted

    Hi Mgebhard,

    Created simple WcfService1 application as you suggested , executed and got below errors.

    Am not understanding where am doing wrong and am new to WCF. If i remove <bindings> and <services> from <system.serviceModel> its working without credentials(no secure)

    But required to validate with CustomUserNameValidator.cs

    Errors:

    in  Visual Studio 2010 (WCFTestClient) : 

    Cannot obtain Metadata from http://localhost:30626/Service1.svc If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address

     Metadata contains a reference that cannot be resolved: 'http://localhost:30626/Service1.svc'.    The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error

    Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http]

    in SOAP UI:

    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
    <s:Header>
    <a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>
    </s:Header>
    <s:Body>
    <s:Fault>
    <s:Code>
    <s:Value>s:Sender</s:Value>
    <s:Subcode>
    <s:Value xmlns:a="http://schemas.xmlsoap.org/ws/2005/02/sc">a:BadContextToken</s:Value>
    </s:Subcode>
    </s:Code>
    <s:Reason>
    <s:Text xml:lang="en-AU">The message could not be processed. This is most likely because the action 'http://tempuri.org/IService1/GetData' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.</s:Text>
    </s:Reason>
    </s:Fault>
    </s:Body>
    </s:Envelope>

    Web.Config:

    <system.serviceModel>

    <services>
    <service name="WcfService1.Service1" behaviorConfiguration="CustomusernamePasswordBehavior">
    <endpoint binding="wsHttpBinding"
    bindingConfiguration="Binding"
    contract="WcfService1.IService1" />
    </service>
    </services>
    <bindings>
    <wsHttpBinding>
    <binding name="Binding">
    <security mode="TransportWithMessageCredential">
    <message clientCredentialType="UserName" />
    </security>
    </binding>
    </wsHttpBinding>
    </bindings>
    <behaviors>
    <serviceBehaviors>
    <behavior name="CustomusernamePasswordBehavior">
    <serviceCredentials>
    <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.CustomUserNameValidator, WcfService1" />
    </serviceCredentials>
    <!-- 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"/>
    </behavior>
    </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>

    Kindly do needful

    Regards

    Raghu

     

    Saturday, November 4, 2017 7:20 AM
  • User475983607 posted

    Don't use Soap UI.  Create a new console project and add a service reference as instructed above.  Most likely you are not configuring Soap UI correctly.

    Saturday, November 4, 2017 11:50 AM
  • User404975991 posted

    When i run in Visual Studio 2010 am facing below error

    Cannot obtain Metadata from http://localhost:30626/Service1.svc If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address

     Metadata contains a reference that cannot be resolved: 'http://localhost:30626/Service1.svc'.    The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error

    Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http]

    Regards

    Raghu

    Saturday, November 4, 2017 12:09 PM
  • User475983607 posted

    If I recall correctly, in order to implement a custom username and password validator, UserNamePasswordValidator,  the request must be secured wither over HTTPS (transport) or use a certificate know by both the client and service.  If the message is not secured the WCF framework will not invoke UserNamePasswordValidator as the transaction is not secured.

    The following error means the you tried to connect to the server over HTTP and there is no HTTPS endpoint available.

    Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http]

    You must setup the service to use HTTPS.  In VS 2010 you need to create a self-sighed cert and deploy to localhost (IIS). In VS 2017 you can simply set a project property and use IIS Express.  You might consider upgrading to VS 2017 as upgrading will make building the project much easier.

    The WCF documentation explains everything you need to know about WCF.

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/common-security-scenarios

    There is also a samples download that has many pre-configured projects.  This is what I used to learn WCF.

    https://www.microsoft.com/en-us/download/details.aspx?id=21459

    The UserNamePasswordValidator is one of those projects.

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/user-name-password-validator

    WCF is a very vast framework you should not expect to learn WCF over night.

    Saturday, November 4, 2017 1:17 PM
  • User1168443798 posted

    Hi Raghu,

    For this error, you could follow the suggestion from mgebhard to deploy WCF Service to IIS, then enable Https for this service.

    During developing, you could follow select WCF Service project-> Press F4->Set SSL Enabled as True, it will enable Https during developing.

    If you still have any issue about this, please feel free to let us know.

    Best Regards,

    Edward

    Monday, November 6, 2017 2:20 AM
  • User404975991 posted

    Thanks Edward,

    I did what ever the changes/settings suggested by mgebhard and created sample application as given by mgebhard but not working.

    Am searching is any sample application which is working fine WCF Service Application with UserNamePasswordValidator over internet.

    From my end tried many things but no luck and don't know where am doing wrong.

    If possible please share working sample project for  WCF Service Application with UserNamePasswordValidator.

    Regards

    Raghu

    Monday, November 6, 2017 3:10 AM
  • User1168443798 posted

    Hi Raghu,

    With the link from mgebhard’s first reply, you could download User Name Password Validator demo samples from Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4.

    Is there any issue with this project?

    Best Regards,

    Edward

    Monday, November 6, 2017 6:33 AM
  • User404975991 posted

    Thanks Edward for your response.

    Created WcfService1 sample WCF Service Application as  per mgebhard’s first reply, that application not run in VS2010 , faced below error and the same has been informed to him.

    He helped me but i don't have luck. Dont know how to solve this. Demo application not working.

    Searching for any running sample application which work  User Name Password Validator.

    Error:

    Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http

    Reagrds

    Raghu

    Monday, November 6, 2017 11:42 AM
  • User475983607 posted

    If possible please share working sample project for  WCF Service Application with UserNamePasswordValidator.

    I provided two verified working examples and guidance documentation.  I don;t think providing a third example is going to help as the issue is not the source code it is your configuration.

    Created WcfService1 sample WCF Service Application as  per mgebhard’s first reply, that application not run in VS2010 , faced below error and the same has been informed to him.

    He helped me but i don't have luck. Dont know how to solve this.

    Searching for any running sample application which work  User Name Password Validator.

    Error:

    Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http

    For the second time, you making an HTTP request and the configuration requires HTTPS.  Did you read the WCF security docs follow the step by step instructions to create a certificate and deploy the calculator service to IIS? 

    Did you try installing VS 2017 and running the service posted as suggested?  

    Monday, November 6, 2017 11:58 AM
  • User404975991 posted

    Hi mgebhard,

    Gone through UserNamePasswordValidator example documentation  and created sample application step by step as given

    Even though am getting same error. Moreover am shared my configuration in previous discussions. 

    You are saying that am  making an HTTP request and the configuration requires HTTPS,  if this is the case can you pls let me know what needs to be done from my config end.

    Thanks for your support

    Regards

    Raghu

    Monday, November 6, 2017 12:25 PM
  • User475983607 posted

    The error means you have no configured SSL!

    For the third time, did you setup SSL?  Did you install VS 2017 and try the example? 

    Raghu Kiran

    You are saying that am  making an HTTP request and the configuration requires HTTPS,  if this is the case can you pls let me know what needs to be done from my config end.

    You need to read the provided documentation!  Either create a self-signed certificate as explained in the security guidance docs and WCF samples or install VS2017 and use IIS Express to configure the SSL URL.  The later, installing VS 2017, is the easiest path - as stated above - because it's just a project property!  Are you still using Soap UI?

    Monday, November 6, 2017 1:02 PM
  • User404975991 posted

    Hi mgebhard,

    Done below settings for my application

    1. <serviceCredentials>
      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.CustomUserNameValidator, WcfService1" />
      <serviceCertificate findValue="UserNamePasswordValidator" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
      <!--<serviceCertificate findValue="CN=RamcoLgxSSL_test" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>-->
      </serviceCredentials>
      <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />

    2. Created https binding with 443 port and assigned SSL self signed certificate "UserNamePasswordValidator"

    3. in IIS Manager SSL settings checked Accepted option for this site

    Am getting  error, but my IIS showing this certificate

    Cannot find the X.509 certificate using the following search criteria: StoreName 'My', StoreLocation 'LocalMachine', FindType 'FindBySubjectName', FindValue 'UserNamePasswordValidator'.

         Same time please confirm that  is "serviceCertificate" X.509 settings required while working with UserNamePasswordValidator

        Amn't using Soap UI and using VS2010 for this application.(don't have VS 2017 S/W)

    Regards

    Raghu

    Monday, November 6, 2017 1:42 PM
  • User475983607 posted

    WCF is very complex and depending on your level of web experience and might take days, week, or even months before you becoming productive.

    You are configuring the service and client to use Public Private key security and need to install the certificate on both the client and the service.  The samples documentation explains how to do this.  Did you create and install the certificates in the local system and current user cert stores?  Did you follow the setup instruction at the end of the document? Did you follow the troubleshooting steps also in the document?

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/user-name-password-validator

    The error means the certificate is not installed the certificate store or the web application does not have access to the certificate.

    Cannot find the X.509 certificate using the following search criteria: StoreName 'My', StoreLocation 'LocalMachine', FindType 'FindBySubjectName', FindValue 'UserNamePasswordValidator'.

    Open the local computer certificate store.  Go to Personal/Certificates.  Right click the certificate you created and select "all Tasks"  -> "Manage private key".  Grant access to the web application Identity (found in the app pool).  If the cert does not exist or Manage is not an option, then the certificates are not installed properly.

    Have you downloaded the WCF Samples?  Have you gone through the setup instruction for the sample you're using?  Perhaps try one of the more basic examples to get a feel of how the samples work since each samples has a deployment bat files that configure and deploy the samples to IIS.  Basically get the WCF sample environment setup and functioning.

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/set-up-instructions

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/one-time-setup-procedure-for-the-wcf-samples

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/building-the-samples

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/running-the-samples

    IMHO, installing VS 2017, is a lot easier and my sample code above will just work - once you set the project properties to use SSL.   This will, at least, get IIS Express working. Then you can focus on configuring IIS properly using a known "good" working solution.

    Monday, November 6, 2017 2:44 PM