安全wcf(使用用户名密码验证器)不能从PHP客户端工作

I have construct a simple secured wcf with wsHttpBinding in .Net C# (framework 4.5) and consume it from .Net C# (also) client and every thing work fine. But when I try to consume It from php (5.5) client by calling a method from the wcs service, the client not work and it has entered in an infinite loop and not showing any error message, just looping.

a. The following is my wcf ServiceContract and OperationContract's:

namespace CenteralServices
{
    [ServiceContract]
    public interface IAdminServices
    {
        [OperationContract]
        int Add(int x, int y);
    }
}


b. The following is the configueration file Web.config for the wcf:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.serviceModel>
        <services>
            <service name= "CentralTicketServicesSystem.AdminSystem" 
                behaviorConfiguration="customBehaviour">
                <endpoint address="AdminServices" 
                        binding="wsHttpBinding" 
              contract="CentralTicketServicesSystem.IAdminServices"
              bindingConfiguration="ServiceBinding"
              behaviorConfiguration="MyEndPointBehavior">
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost:8080/AdminServicesSystem" />
      </baseAddresses>
    </host>
  </service>
</services>

<bindings>
  <wsHttpBinding>
    <binding name="ServiceBinding"
             openTimeout="00:10:00"
             closeTimeout="00:10:00"
             receiveTimeout="00:10:00"
             sendTimeout="00:10:00">
      <security mode="Message" >
        <message clientCredentialType="UserName"/>
      </security>

    </binding>
  </wsHttpBinding>
</bindings>

<behaviors>
  <endpointBehaviors>
    <behavior name="MyEndPointBehavior">
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="customBehaviour">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
      <serviceAuthorization principalPermissionMode="Custom">
        <authorizationPolicies>
          <add policyType="CentralServicesHost.AuthorizationPolicy, CentralServicesHost" />
        </authorizationPolicies>
      </serviceAuthorization>
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom"
           customUserNamePasswordValidatorType="CentralServicesHost.UserAuthentication, CentralServicesHost"/>
        <serviceCertificate findValue="15 63 10 5e b6 4b 4d 85 4b 2e 4d 5b ec 85 02 ec"
                            storeLocation="LocalMachine"
                            x509FindType="FindBySerialNumber"
                            storeName="My"/>
      </serviceCredentials>
    </behavior>
    <behavior name="mexBehaviour" >
      <serviceMetadata httpGetEnabled="true" />
    </behavior>

            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>



c. The following is UserAuthentication class:

namespace CentralServicesHost
{
    public class UserAuthentication : UserNamePasswordValidator
    {

        public override void Validate(string userName, string password)
        {
            if (string.IsNullOrEmpty(userName))
                throw new ArgumentNullException("userName");
            if (string.IsNullOrEmpty(password))
                throw new ArgumentNullException("password");

            if (userName != "test" && password != "test")
                 throw new FaultException("Unknown Username or Incorrect Password.");
        }
    }
}



d. The following is AuthorizationPolicy class:

namespace CentralServicesHost
{
    public class AuthorizationPolicy : IAuthorizationPolicy
    {
        Guid _id = Guid.NewGuid();
        // this method gets called after the authentication stage
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            // get the authenticated client identity
            IIdentity client = GetClientIdentity(evaluationContext);
            // set the custom principal
            evaluationContext.Properties["Principal"] = new CustomPrincipal(client);
            return true;
        }
        private IIdentity GetClientIdentity(EvaluationContext ec)
        {
            object obj;
            if (!ec.Properties.TryGetValue("Identities", out obj))
                throw new Exception("No Identity found");
            IList<IIdentity> identities = obj as IList<IIdentity>;
            if (identities == null || identities.Count <= 0)
                throw new Exception("No Identity found");
            return identities[0];
        }

        public System.IdentityModel.Claims.ClaimSet Issuer
        {
            get { return ClaimSet.System; }
        }

        public string Id
        {
            get { return _id.ToString(); }
        }
    }
}



e. The following is CustomPrincipal class:

namespace CentralServicesHost
{
    class CustomPrincipal : IPrincipal
    {
        IIdentity _identity;
        string[] _roles;

        public CustomPrincipal(IIdentity identity)
        {
            _identity = identity;
        }

        // helper method for easy access (without casting)
        public static CustomPrincipal Current
        {
            get
            {
                return Thread.CurrentPrincipal as CustomPrincipal;
            }
        }

        public IIdentity Identity
        {
            get { return _identity; }
        }

        // return all roles
        public string[] Roles
        {
            get
            {
                EnsureRoles();
                return _roles;
            }
        }

        // IPrincipal role check
        public bool IsInRole(string role)
        {
            EnsureRoles();
            return (_roles != null) ? _roles.Contains(role) : false;
        }

        // read Role of user from database
        protected virtual void EnsureRoles()
        {
            using (var s = new SupportedMaterialsSystemEntities())
            {
                _roles = new string[1] { "admin" };
            }
        }
    }
}

f. The following is my php client code:

<?php
$options = array('soap_version' => SOAP_1_2, 
                  'login'      =>  'test',
                  'password'   =>  'test');
$wsdl = "http://localhost:8080/AdminServicesSystem";
$client = new SoapClient($wsdl, $options);
$obj = new stdClass;
$obj->x = 3;
$obj->y = 3;
$retval = $client->Add($obj);//here the browser loops for infinite without any response.
//var_dump($exc);//THIS POINT NOT REACHED
//die();
$result = $retval->AddResult;
echo $result;

NOTES:
1. My OS is Win. 8.1, and I'm using visual studio 2013 (as adminstrator) and php Wamp Server.
2. I tried both, hosting the wcf service in IIS 6.2 and console application but non of them changes my php client looping.
3. I have Created the self-signed certificate usin the IIS manager that stores it in my local machine.
4. When I change the soap_version in the php code from SOAP_1_2 to SOAP_1_1 I had Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'..

Last Note:
My .Net C# Client code is the following:

 using (var svcProxy = new AdminServiceProxy.AdminServicesSystemClient())
        {
            svcProxy.ClientCredentials.UserName.UserName = "test";
            svcProxy.ClientCredentials.UserName.Password = "test";
            Console.WriteLine(svcProxy.Add(1, 1));//the service works fine and print 2
        }
 }


So agin, What is the right way to call a secured wcf (with wsHttpBinding) service from php.

I believe you need a default WSDL metadata published to use PHP soap client (see abilities here http://php.net/manual/en/intro.soap.php).

Try to add endpoint with basicHttpBinding binding, which can provide WSDL for your client and then use this endpoint.

On the address http://localhost:8080/AdminServicesSystem you have endpoint with mexHttpBinding, which provides metadata int other format (http://www.w3.org/TR/2009/WD-ws-metadata-exchange-20090317/).

Try to see here form more details: https://abhishekdv.wordpress.com/2013/05/24/mexhttpbinding-vs-wsdl/