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"开发者_如何学Go, 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.
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.
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.
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
精彩评论