Problem with authentication on java ws - c#

I have application in C# that consume Java WS. Everything worked fine until WS was configured to use authentication. Now I should user login i password to execute methods from WS but I'm not sure how to do it.
I've try
var client = new MyBeanClient();
client.ClientCredentials.UserName.UserName = "admin";
client.ClientCredentials.UserName.Password = "";
client.addConsumer("whatever", "", "", "");
But I get
SecurityMessageException-{"The HTTP request is unauthorized with client
authentication scheme 'Anonymous'. The authentication header received from
the server was 'Negotiate,NTLM'."}
InnerException - (WebException) - {"The remote server returned an error:
(401) Unauthorized."}.
What's wrong?
Thanks

Try this:
var credentialCache = new CredentialCache();
var credentials = new NetworkCredential("username", "password", "domain");
credentialCache.Add(new Uri(client.Url), "NTLM", credentials);
client.Credentials = credentialCache;
client.addConsumer("whatever", "", "", "");
UPDATE:
Sorry in my first post I thought you were using wsdl.exe to generate the client proxy. For a WCF client you need to configure the endpoint:
var basicHttpBinding = new BasicHttpBinding();
basicHttpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
var endpoint = new EndpointAddress("http://example.com/myWindowsAuthN");
var client = new MyBeanClient(basicHttpBinding, endpoint);
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
client.ChannelFactory.Credentials.Windows.ClientCredential.Domain = "domain";
client.ChannelFactory.Credentials.Windows.ClientCredential.UserName = "username";
client.ChannelFactory.Credentials.Windows.ClientCredential.Password = "password";
UPDATE2:
I've used the following configuration to invoke web services protected with NTLM authentication. In app.config of the client put the following:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="NtlmBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint
address="http://example.com/SomeWindowsAuthenticatedService"
binding="basicHttpBinding"
bindingConfiguration="NtlmBinding"
contract="IOperationContractOfTheService"
name="WSTestSoap" />
</client>
</system.serviceModel>
and then you could set the corresponding credentials before invoking the method:
using (var client = new MyBeanClient())
{
client.ChannelFactory.Credentials.Windows.ClientCredential =
new NetworkCredential("username", "password", "DOMAIN");
client.addConsumer("whatever", "", "", "");
}

Related

Why web services call only succeeds when pre logined through browser atleast once a day on server

I have following bindings on server side,
<bindings>
<basicHttpBinding>
<binding name="my_BasicHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
and client code running in console on same server,
System.Net.NetworkCredential creds = new NetworkCredential("UserName ", "password", "domain");
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows; //.Ntlm; // Basic;
EndpointAddress endpoint = new EndpointAddress("https://example.portal.com + "/_vti_bin/MyServiceFolder/MyService.svc");
ChannelFactory<MyType> factory = new ChannelFactory<MyType>(binding, endpoint);
factory.Credentials.Windows.ClientCredential = creds;
factory.Credentials.UserName.UserName = creds.UserName;
factory.Credentials.UserName.Password = creds.Password;
//factory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
//factory.Credentials.Windows.AllowNtlm = true;
MyType proxy = factory.CreateChannel();
string result = proxy.MyMethod();
Now it usually throws 401 but when I login through browser using same username to view .svc file and try this code again... IT WORKS. BUT again next morning it won't work till I repeat the steps.
Some more details can be found here but with different settings and scenario -
How to make these web services work, man in middle is KEMP too
Could it be related to SharePoint or authentication protocols or the way Kerborse works etc.. got no clue ?

What is the .NET equivalent of this PHP web service call?

I am attempting to utilise an API, and the providers can only offer a PHP sample, which I have summarised as follows (with sensitive data removed):
<?php
ini_set('default_socket_timeout', 1600);
$options = array(
'login' => 'myusername',
'password' => 'mypassword',
'trace' => 1
);
$url = 'https://supplierurl/ws?wsdl';
$soapClient = new \SoapClient($url, $options);
$params = array('12345');
try{
$details = $soapClient->getData($params);
var_dump($details->paramdetails);
}
catch(\Exception $e){
echo "Last request headers:<br>\n".$soapClient->__getLastRequestHeaders()."<br><br>\n";
echo "Last request:<br>\n".$soapClient->__getLastRequest()."<br><br>\n";
echo "Last response headers:<br>\n".$soapClient->__getLastResponseHeaders()."<br><br>\n";
echo "Last response:<br>\n".$soapClient->__getLastResponse()."<br><br>\n";
}
?>
I have successfully run this on my development machine and get back the data as expected.
I have attempted to use this service in .NET by adding a service reference using the url provided, which generates the proxy code as expected, giving me a configuration as below:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="mybinding">
<security mode="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
<binding name="mybinding1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://supplierurl/ws"
binding="basicHttpBinding" bindingConfiguration="mybinding"
contract="API.portType" name="API.port" />
</client>
</system.serviceModel>
And test code as below:
API.portClient client = new API.portClient();
client.ClientCredentials.UserName.UserName = "myusername";
client.ClientCredentials.UserName.Password = "mypassword";
API.GetDataResponse response = client.getData(new string[] { "12345" });
The code executes with no exceptions thrown, but response is null. If I change the username or password to something invalid, I get an exception, indicating that the credentials side of things is working.
If anyone can point me in the right direction, it would be much appreciated!
Some further information, if I add this as a web reference it works, which gets me moving for now, although I'd still like to know how to make it work in the first instance. Code for using a web reference:
WebReference.customerV4Service svc = new WebReference.customerV4Service();
svc.Credentials = new System.Net.NetworkCredential("myusername", "mypassword");
WebReference.GetDataResponse resp = svc.getData(new string[] { "12345" });

Refactoring WCF service client instantiation from app.config to code

I have a WCF service reference which I use with the following client side app.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ManagerService">
<security>
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://myadress:8080/ManagerService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ManagerService"
contract="Service.ManagerService" name="WSHttpBinding_ManagerService">
<identity>
<certificate encodedValue="AwAAAAEAAAAUAAAAaJ8gJ+2BbDC//Nw76gp1Rx4Ii1AgAAAAAQAAACQDAAAwggMgMIICDKADAgECAhB4jlXUsVcUkE45Bq9sj6cdMAkGBSsOAwIdBQAwIzEhMB8GA1UEAxMYc2tpbGxjb25vbXkuY2xvdWRhcHAubmV0MB4XDTA2MTIzMTIyMDAwMFoXDTE5MTIzMTIyMDAwMFowIzEhMB8GA1UEAxMYc2tpbkjsahdjhdjsdhsjhdsjhdjhdsjhdFAAOCAQ8AMIIBCgKCAQEAwHjDPi/A7+4PfvYt40eySE2I6FgVO2Ewco8gJO21TUqHpKbinmsaNTO6wFJy+l3adMRB0dcmAvH938BPgdwbqbVaaG4mRCDpnekEserWmz5ii+ET1xhm0atIg6xW3sgnDOA+41Y0vB8m8AXTfHQYunILQjn/6xGM/RffK32vbR9WGJKEd/okOJ2/vV5dm2UsejlANwK2kCMe9wNRbjaKsH6PIqv26KeHAXxa0tSzoHfrn/lr46+54WzEXFHRzub1JbZk+IsdsdlakasjdksjdjdksjddjskdZZ0Oj0iG0GjvEVbmHWpBM/WhHrqIfGdqiMtXjOtwIDAQAsdsdsdsdsdsdsdaZtgIq+y6hm91EfPUToJ1ZUhWR8z/RG+IVZrs0O93FCMk6WU8OhYxubIgcVSTx0FDCakyOmfu1gnYeEZv53kVPZSmY4KUAUZz+MCQf/OXN2OGv9cRmsWg4iDlHjzDQwucO+rWkclvQo=" />
</identity>
</endpoint>
</client>
</system.serviceModel>
I now need to refactor the instantiation to work with a blank app.config:
Here is what I've tried:
var binding = new WSHttpBinding();
binding.Security = new WSHttpSecurity { Mode = SecurityMode.Message };
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var cers = store.Certificates.Find(X509FindType.FindByThumbprint, "123THUMBPRINTOFCERT", false);
var cer = cers[0];
var identity = new X509CertificateEndpointIdentity(cer);
var endpoint = new EndpointAddress(new Uri("http://myservice:8080/ManagerService.svc"), identity);
var client = new ManagerServiceClient(binding, endpoint);
client.ClientCredentials.UserName.UserName = EMail;
client.ClientCredentials.UserName.Password = Password;
var resultBuilder = new StringBuilder();
var categories = client.Categorize(Text);
This throws an exception:
System.ServiceModel.Security.MessageSecurityException: Client cannot
determine the Service Principal Name based on the identity in the
target address 'http://myservice:8080/ManagerService.svc' for
the purpose of SspiNegotiation/Kerberos. The target address identity
must be a UPN identity (like acmedomain\alice) or SPN identity (like
host/bobs-machine).
I have checked, that the correct certificate is found in the store. I would be very glad to get a hint on what I am missing here and whether the way I'm going here is ok in general...?
you lost row clientCredentialType="UserName"
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;

WCF Consumer not attaching client credentials to header

I have a WCF service that uses username authentication, I have a console app that consumes the service and attempts to access a protected method. I run the code and Fiddler says in the auth tab:
No Proxy-Authorization Header is present.
No Authorization Header is present.
Here is my accessing code:
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic;
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Default;
binding.Security.Transport.Realm = "MyRealm";
ServiceReference1.MobileAPIClient serviceProxy = new ServiceReference1.MobileAPIClient(binding, new EndpointAddress("https://xx.xx.xx.xx/InventoryServices.MobileApi.svc"));
serviceProxy.ClientCredentials.UserName.UserName = "test";
serviceProxy.ClientCredentials.UserName.Password = "test123";
serviceProxy.ChannelFactory.Credentials.UserName.UserName = "test";
serviceProxy.ChannelFactory.Credentials.UserName.Password = "test123";
try
{
serviceProxy.Test();
}
catch (Exception ex)
{
var ex2 = ex;
}
Why are the credentials not being attached to the header?
There is handshaking mode in wcf. So client and service exchange with credentials before first request and then they use only session token.
To disable this mode you should set in web.config
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="false"/>
</security>

With C#, WCF SOAP consumer that uses WSSE plain text authentication?

I have a WCF SOAP consumer that is implemented by Visual Studio 2012 from a WSDL. The WSDL was generated by PeopleTools. The base object is of type System.ServiceModel.ClientBase.
I need the SOAP request to resemble:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://xmlns.oracle.com/Enterprise/Tools/schemas">
<soapenv:Header>
<wsse:Security soap:mustUnderstand="1" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>[plain text username goes here]</wsse:Username>
<wsse:Password>[plain text password goes here]</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<sch:InputParameters>
<Last_Name>Aren</Last_Name>
<First_Name>Cambre</First_Name>
</sch:InputParameters>
</soapenv:Body>
</soapenv:Envelope>
Here's the closest we can get:
<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://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
<a:MessageID>urn:uuid:3cc3f2ca-c647-466c-b38b-f2423462c837</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://[internal URL to soap listener]</a:To>
</s:Header>
<s:Body>
<t:RequestSecurityToken Context="uuid-7db82975-2b22-4236-94a1-b3344a0bf04d-1" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType>
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:KeySize>256</t:KeySize>
<t:BinaryExchange ValueType=" http://schemas.xmlsoap.org/ws/2005/02/trust/tlsnego" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">FgMBAFoBAABWAwFQ9IhUFGUO6tCH+0baQ0n/3us//MMXzQA78Udm4xFj5gAAGAAvADUABQAKwBPAFMAJwAoAMgA4ABMABAEAABX/AQABAAAKAAYABAAXABgACwACAQA=</t:BinaryExchange>
</t:RequestSecurityToken>
</s:Body>
</s:Envelope>
You'll notice two problems:
No plaintext WSSE credentials. Passes a binary form of the credentials that the service won't use.
Authentication is in Body, not Header.
The request omits InputParameters.
Here's the essential C# code:
var service = new ServiceWithBizarreNameFromPeoplesoft();
if (service.ClientCredentials == null)
throw new NullReferenceException();
service.ClientCredentials.UserName.UserName = "test";
service.ClientCredentials.UserName.Password = "password";
var binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential) {Security = new WSHttpSecurity()};
service.Endpoint.Binding = binding;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Mode = SecurityMode.Message;
var input = new InputParameters { Last_Name = "Cambre", First_Name = "Aren" };
var returnData = service.BizarrePeopleSoftNameForMethod(input);
There's no HTTP layer security, and transport is SSL-encrypted. Authentication is only based on the SOAP message.
That is request for WS-SecureConversation token. It is used by WSHttpSecurity by default unless you change its EstablishSecurityContext property to false. Use this binding instead:
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
It will use SOAP 1.1 with UserName token and it will require HTTPS transport.
Edit:
For testing without HTTPS try to use this custom binding:
var securityElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
securityElement.AllowInsecureTransport = true;
var encodingElement = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
var transportElement = new HttpTransportBindingElement();
var binding = new CustomBinding(securityElement, encodingElement, transportElement);
This looks to me like wsHttpBindings with Transport security using basic username password authentication.
These lines look wrong to me:
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Mode = SecurityMode.Message;
Here's how I would expect to see this configured in your app or web.config
<bindings>
<wsHttpBinding>
<binding name="ws" >
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="Basic" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://www.bla.com/webservice" binding="basicHttpBinding" contract="bla.IService" name="ws" />
</client>
Then the code would look like this:
var service = new GeneratedProxyClient("basic");
service.ClientCredentials.UserName.UserName = "test";
service.ClientCredentials.UserName.Password = "password";
var input = new InputParameters { Last_Name = "Cambre", First_Name = "Aren" };
var returnData = service.BizarrePeopleSoftNameForMethod(input);
Might be better explained here --> http://msdn.microsoft.com/en-us/library/ms733775.aspx

Categories

Resources