0

I have a question concerning a webservice written in PHP.

To instantiate a SoapClient using PHP, I'm passing the following parameters on the SoapClient method in PHP like this:

$client = new SoapClient("some.wsdl", 
                         array('login' => "some_name",
                               'password' => "some_password"
                         ));

To invoke methods on the webservice with PHP, this works fine. But my colleague is having trouble with sending the credentials using .NET.

Does anybody knows how this is passed in .NET?

Update, net client configuration

<basicHttpBinding> 
   <binding name="webserviceControllerBinding"> 
       <security mode="TransportCredentialOnly"> 
           <transport clientCredentialType="Basic"/> 
       </security> 
    </binding> 
</basicHttpBinding> 

And in the code:

client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "password";

Update 2:

building the client (in PHP)

$client = new 
SoapClient("http://***.***.***/********/httpdocs/webservice/wsdl?wsdl", 
    array(
        'uri'      => "http://***.***.***/***/httpdocs/webservice/webservice",
        'login'    => "*****",
        'password' => "*****"
));

The server which handles the request and referencing to the class.

public function webservice()
  parent::__construct();
  ini_set( 'soap.wsdl_cache_enabled', 0);
  $this->presenter     = "NONE";
  $server              = new SoapServer("http://***.***.***/***/httpdocs/webservice/wsdl?wsdl", array('uri' => "http://***.***.***/"));

  $server->setClass(   "Model_Webservice");
  $server->handle();

And this piece in the webservice class handles the username and password authentication.

class Model_Webservice extends Object_Database
{

public function __construct()
{
  parent::__construct();

  $accesslog     = Log::factory('file', $this->config->log->access , 'ACCESS LOG');

  if(!isset($_SERVER['PHP_AUTH_USER']) || trim($_SERVER['PHP_AUTH_USER']) == "")
  {
     $accesslog->log("[denied] [soapclient " . $_SERVER['REMOTE_ADDR'] . "] no username supplied");
     throw new SOAPFault("Authentication failed - reason: no username supplied", 401);
  }
  elseif(!isset($_SERVER['PHP_AUTH_PW']) || trim($_SERVER['PHP_AUTH_PW']) == "")
  {
     $accesslog->log("[denied] [soapclient " . $_SERVER['REMOTE_ADDR'] . "] no password supplied");
     throw new SOAPFault("Authentication failed - reason: no password supplied", 401);
  }
  else
  {
     $user = new User(null, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);

     if($user->getId() > 0)
     {
        $accesslog->log("[approved] [soapclient " . $_SERVER['REMOTE_ADDR'] . "] User logged in");
     }
     if(!$user->getId() > 0)
     {
        $accesslog->log("[denied] [soapclient " . $_SERVER['REMOTE_ADDR'] . "] incorrect username and password combination");
        throw new SOAPFault("Authentication failed - reason: incorrect username and password combination", 401);
     }
  }
}

Update 3

I am getting the following error message based on the adjusted config

  <bindings>
        <basicHttpBinding>
            <binding name="webserviceControllerBinding">
                <security mode="Message">                   
                    <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>

BasicHttp binding requires that BasicHttpBinding.Security.Message.ClientCredentialType be equivalent to the BasicHttpMessageCredentialType.Certificate credential type for secure messages. Select Transport or TransportWithMessageCredential security for UserName credentials.'

I don't want to use certificates or https.

4
  • How do they specify the credentials and which authentication mechanism do you use? Commented Jul 5, 2011 at 12:36
  • I must say that if i turn off the security in the PHP server, we can invoke the webservice using .NET. But this is the other programmer using: <basicHttpBinding> <binding name="webserviceControllerBinding"> <security mode="TransportCredentialOnly"> <transport clientCredentialType="Basic"/> </security> </binding> </basicHttpBinding> client.ClientCredentials .UserName.UserName = "username"; client.ClientCredentials.UserName.Password = "password"; Commented Jul 5, 2011 at 12:49
  • Always add code as an update to your question. Or it will be impossible to follow it. Commented Jul 5, 2011 at 12:55
  • What kind of security have you configured in the server? Is it really BASIC authentication? I would strongly recommend you to consider DIGEST auth in that case. BASIC auth sends passwords in clear text. Commented Jul 5, 2011 at 12:57

3 Answers 3

1

I would suggest using a tool like Fiddler to catch the actual SOAP XML data that is being sent by your working PHP client and your non-functional .NET client.

If you compare the two requests, there's a good chance you'll see what the difference is and be able to work out how to fix it.

Hope that helps.

Sign up to request clarification or add additional context in comments.

2 Comments

I have Fiddler installed, but i can't seem to catch the request send to to the server. Only the response is being showed.
weird. if you can see the response I'd have thought you should be able to see the request.
1

I bet that WCF in .NET do not send the authentication header (per default) unless getting a challenge from the webservice.

You should return HTTP status code 401 if no username or password is supplied and http status code 403 if username/password are incorrect.

In other words: Remove the SoapException and return a proper HTTP status code.

Update into response to update 3

Well. The exception has nothing to do with the fact that it's a PHP webservice. It's a completely different question. The errors is thrown since using BASIC auth without a certificate would send the password in CLEAR TEXT.

I would switch to something more secure like DIGEST authentication.

2 Comments

To be honest, it returns SOAPFault: Authentication failed - reason: no username supplied. And this means it didn't get passed the first username/password check. So .NET didn't even send anything to the webservice.
what kind of exception did they get in .NET then? You have to provide all relevant info
0
MessageHeader header= MessageHeader.CreateHeader("My-CustomHeader","http://myurl","Custom Header.");

       using (phptoebiTestclient.ServiceReference1.webserviceControllerPortTypeClient client = new phptoebiTestclient.ServiceReference1.webserviceControllerPortTypeClient())
       {
           using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
           {
               OperationContext.Current.OutgoingMessageHeaders.Add(header);
               HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
               byte[] toEncodeAsBytes    = System.Text.ASCIIEncoding.ASCII.GetBytes("username:password");                       
               httpRequestProperty.Headers.Add("Authorization: Basic "+ System.Convert.ToBase64String(toEncodeAsBytes));                                              
               OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
               string str = client.getVacanciesReference("");
           }                                 
       }

Code above has solved my problem (I used these URLs for reference)

http://caught-in-a-web.blogspot.com/2008/04/how-to-add-custom-http-header-in-wcf.html http://en.wikipedia.org/wiki/Basic_access_authentication

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.