gSOAP HTTP Authentication - c++

I'm working with gSOAP 2.8.15 and I'm trying to implement the HTTP Authentication by following the instructions in section 19.14 of gsoap documentation (http://www.cs.fsu.edu/~engelen/soapdoc2.html#tth_sEc19.14).
The only difference is that the codes introduced in the documentation is written in C but I'am coding in C++.
Here is my codes for client side of the web service
// The variable wsp is a instance of web service proxy generated by soapcpp2.
// The proxy is a sub-class of the class soap
wsp.userid = "user";
wsp.passwd = "password";
// call the function of web service
wsp.get_version(&result);
In the server side, I use these codes to check the authentication:
// The variable wss is the a instance of web service service generated by soapcpp2.
if (wss.userid == NULL || wss.passwd == NULL)
//......
The problem is when I call the function of web service using the client-side code, the userid and passwd is always NULL in server-side. But when I call the same function using soapUI by passing the userid and passwd with preemptive authorisation mode, the server will get the information without problem.
I appreciate if anyone can help me work out the problem. Thanks for your attention.

I have used tcpdump to catch the package sent between web service server and client and I found that there is no http header sent when the client call the function of the web service. So I have done some search in the documentation of gSOAP and found this sentence:
A client may use the http:// prefix. When absent, no HTTP header is
sent and no HTTP-based information will be communicated to the
service.
It solves my problem...

Related

Add certificate to both server and client using WCF and gSOAP

I have WCF web service that need to be secured using SSL/TLS protocol. In the other hand I have C++ client that consume WCF web service using gSOAP library. Already only server needs to have certificate. Now I have tasked to enforce client to have certificate. My earlier implementation for client is like this:
soap_ssl_init();
int soapResult = soap_ssl_client_context(soapPtr, SOAP_SSL_NO_AUTHENTICATION, "client.pem", NULL,
NULL, "cacert.pem", NULL);
if (soapResult)
{
soap_print_fault(soapPtr, stderr);
throw new ClientLogException("Can not use ssl for comminucations!");
}
else
{
}
struct soap mySoap = *soapPtr;
WSHttpBinding_USCOREILogServicesProxy proxy(mySoap);
input.request = &request;
int callCode = proxy.CallWebService(WEB_SERVICE_ADDRESS, NULL, &input, response);
if (callCode != 0)
{
cout << "Web service call code: " + callCode << endl;
throw new ClientLogException("Error in calling web service with call code: " + callCode);
}
which I does it from gSOAP documents. It works fine with only server required to have certificate. I viewed communication using WireShark and connection was completely encrypted.
Now for enforcing client to use certificate, I am going to use Nine simple steps to enable X.509 certificates on WCF article. But the article uses a C# WCF client. I must implement client configuration in my gSOAP C++ client. I can add client certificate in above code when calling soap_ssl_client_context and in third parameter.
I have 2 problem here:
1- I don't know is it possible calling web service that both client and server have certificates and communication be secured when server uses WCF and client uses gSOAP.
2- In the CodeProject article it seems that web service call is using http and I am wonder there is no encryption in communication.
In the end if anyone has better solution, or recommend other tools will be welcome.
HTTPS works out of the box with gsoap if you compile with -DWITH_OPENSSL and link against the OpenSSL libs. The out-of-the-box default settings will encrypt messages with https://, but this does not enforce authentication because you need to register the server certificates first with soap_ssl_client_context() as you point out.
To authenticate both server and client, the gsoap manual suggests the following:
int soapResult = soap_ssl_client_context(soapPtr,
SOAP_SSL_DEFAULT, // requires server to authenticate
"client.pem", // client cert (+public key) to authenticate to server
"password", // you need this when client.pem is encrypted
NULL, // capath to certs, when used
"cacert.pem", // should contain the server cert
NULL);
Also, you may need to convert PEM to CER (or the other way) for windows.

Manually creating a HTTP SOAP Request with Signing SOAP messages using X.509 certificate

I am trying to send a message from NetSuite to another system via http SOAP, but I was told that I have send a signed soap message. NetSuite only has an operation called nlapiRequestURL(url, postdata, headers); I am trying to use this method to send over a manually created SOAP message. What I am having problems with is figuring out how to add the cert to the header. Has anyone does this before?
What I have learned about signing a soap message with the certificate is that I need private key and public in the local keystore. This tutorial in java shows how to do it, but how would I do something similar in NetSuite.
https://dzone.com/articles/signing-soap-messages
One possible solution is you write your own proxy web server in Java
or any other server side language for that matter.
Below is the summary of my suggestion:
1) Send the request details from NetSuite to proxy server using a
Suitelet or scheduled script.
2) In the proxy server create the signed SOAP request and send to the
vendor API
3) Now, to respond back to NetSuite there are two options a) you
keep the connection open with NetSuite until you get the response and
send it back to NetSUite's script b)you respond back to a NetSuite
RESTlet, which makes the design asynchronous and can be good specially
if the turn around time is more than 45 seconds.
Also, I would suggest to write web server using HTTPS, with your server having a trusted CA signed certificate, so, that communication between web server and NetSuite is secure. And this way your communication would be secure (P.S. I can't answer the question that is SSL 100% secure, there are good discussion on http://security.stackexchange.com on that topic).

Unauthorized HTTP request with Anonymous authentication of SAP PI service

I have a .WSDL file from our client company, for which I need to use to call a web service. Their system is SAP (SAP PI). My application is a C# .NET 3.5 client developed in VS 2008. I added a Service Reference in Visual Studio using their provided .WSDL file. This created a reference class for me to use to call their service, and set up several bindings in the app.config file for me.
I did not change anything in the app.config file, but did create code to call their web service. However, when I call their webservice, I receive the following exception:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm="SAP NetWeaver Application Server ..."'.
(I modified slightly the string used in the 'Basic realm' section so as to not give it out.)
Did the app.config not get built correctly from the WSDL? Am I supposed to modify the app.config file somehow?
Things I've tried:
changed authenticationScheme in app.config from Anonymous to Basic
(as well as all the other authentication types)
changed realm string in app.config to match the realm in the exception message
set username/pw fields in the ClientCredentials.Username object in my code
Any pointers or help would be appreciated.
Edit: After some more investigation, I found that Visual Studio has several warnings about the extension element Policy and Policy assertions:
Custom tool warning: The optional WSDL extension element 'Policy'
from namespace 'http://schemas.xmlsoap.org/ws/2004/09/policy' was not
handled.
Custom tool warning: The following Policy Assertions were not Imported:
XPath://wsdl:definitions[#targetNamespace='urn:sap-com:document:sap:rfc:functions']/wsdl:binding[#name='Binding_FieldValidation']
Assertions: ...
I wasnt able to find out if this was related or not to my current issue with the authentication scheme. It does seem to be related, but I havent been able to find any solutions to getting these policy warnings resolved either. It seems WCF doesnt handle the statements in the wsdl very well.
Most SAP services dont support anonymous.
So pass some form of authentication data with the call.
User and password / X.509 Ticket...
If you are sending auth data with the call the try this
Ask the SAP guy to regenerate the WSDL with
No SAP assertions, No policy, SOAP 1.1.
You can also try and edit the WSDL by hand to remove the extra guff...
As a starting point, I'd verify that you can call the service successfully with the provided username and password. Use something like SoapUI to test that everything works correctly - just create a new project, import the WSDL provided by SAP PI, set the username and password and execute the call. You'll probably get some form of exception with an empty payload, but at least that'll verify that the username and password are correct.
Once you've verified that's working, check that your application is calling the service correctly and that the http basic authentication headers are being sent. You can confirm this by using a network monitoring tool and checking that the http request is being generated correctly. Something like netcat for Windows can do it - just make it listen to a port on your local machine and then specify localhost and the port as your SOAP endpoint.
Once you've verified both of those are correct, your call should succeed.
There must be the Basic authentication header missing or something wrong
with the credentials.
SAP PI always defaults to Basic Authentication if a Service is published via it's SOAP Adapter. I would investigate if WCF really does send out that header (e.g. Point your client endpoint to TCP Gateway and let TCP Gateway point to the SAP PI Endpoint from the WSDL).
About the Warnings: AFAIK the WSDL generated by SAP PI will always contain these Policy Tags, you can't really ommit it. What you can do is simply throw them out as they are not really validated

Axis2 multiple connection authentication issue

I have two servlets that access two corresponding Axis2 web services on the same host. One of the servlets is read-only, while the other writes to a database.
Each of the Axis2 web services uses BASIC authentication. The read-only web service uses a system account, while the write web service uses the user's credentials (which are submitted as part of a web form).
The problem I'm running into is that the servlet called second always fails authentication to its web service. For example, I can query the read-only service through it's servlet all I want, but I get a "401: Authorization Required" when I try to use the write service. If I call the write service first, I get the same error when I try to use the read-only service.
Here is how I am setting the credentials for the connections in the servlets:
Stub service = new Stub(serviceUrl);
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setUsername(username);
auth.setPassword(password);
auth.setPreemptiveAuthentication(true);
service._getServiceClient().getOptions().setProperty(HTTPConstants.AUTHENTICATE, auth);
The servlet that accesses the read-only service has this code in it's constructor. The servlet that accesses the write service has this code in it's doGet/doPost method.
It seems that the credentials for the first service called are getting cached somewhere, but I can't find where that could be. I saw a possible solution here, but I can't find where WSClientConstants.CACHED_HTTP_STATE is defined. The comments in this JIRA issue seems to imply that it's part of org.apache.axis2.transport.http.HTTPConstants but it's not there.
Specifics:
Axis version: 1.5.1
Tomcat Version: 6.0.26
Java version: 1.6.0_23
It turns out the connections to the two different services were using the same JSESSIONID. Thus, the connection to the second web service was trying to use a session authenticated for the first web service, causing the error.
My solution for this was to define an HttpClient for each service, done by the following
MultiThreadedHttpConnectionManager manager = new MuliThreadedHttpConnectionManager();
HttpClient client = new HttpClient(manager);
ConfigurationContext context = ConfigurationContextFactory.createDefaultConfigurationContext();
context.setProperty(HTTPConstants.CACHED_HTTP_CLIENT, client);
context.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, true);
Stub service = new Stub(context, serviceUrl);
This allows both servlets to have a separate session for their corresponding services.
The important point is to create a dedicated ConfigurationContext.
I've solved in a simpler way using a default config context when creating the stub without the multithreaded connection factory
stub = new MyStub(ConfigurationContextFactory.createDefaultConfigurationContext(), myServicesUrl);

Automatically pass a cookie with each web-service call

I have a standalone web-service client. When invoking any of the web-methods an additional "cookie" string must be implicitly(not as a web-method parameter) passed to the WS. The WS on the other end must be able to obtain the string and use it. How can this be achieved?
I invoke the service in the following way:
Service srv = Service.create(new URL(WSDL), QNAME);
myClassPort = srv.getPort(MyClass.class);
What I need is to put some code before the first line, which would make the client send this "cookie" string every time I invoke some remote method via myClassPort. Thx.
By default JAX-WS web services and clients are stateless. When a client makes a request, the server responds and sets a cookie on the connection, if it participates in a session. But, the JAX-WS client ignores that cookie and the server treats subsequent requests as new interaction. When the session is enabled, JAX-WS client sends the same cookie with each subsequent request so that server can keep track of the client session.
So you should not be using either cookies or HTTP sessions with web services. Return a token ID as part of the response; then the client can send that along with the next request.
Anyway:
JAX-WS web service clients must be configured to maintain session information (such as cookies), using the javax.xml.ws.session.maintain property.
Other web service stacks may have similar mechanisms.
On the Server Side
JAX-WS uses some handy annotations defined by Common Annotations for the Java Platform (JSR 250), to inject the web service context and declaring lifecycle methods.
WebServiceContext holds the context information pertaining to a request being served.
You don't need to implement javax.xml.rpc.server.ServiceLifecycle. With JAX-WS Web Service all you need to do is mark a field or method with #Resource. The type element MUST be either java.lang.Object or javax.xml.ws.WebServiceContext.
#WebService
public class HelloWorld {
#Resource
private WebServiceContext wsContext;
public void sayHello(){
MessageContext mc = wsContext.getMessageContext();
HttpSession session = ((javax.servlet.http.HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST)).getSession();
}
}
There are some misleading answers to this question, so I will attempt to highlight current best practices. Most of these suggestions are part of the OWASP security guidelines, which I strongly recommend anyone working on web development to review.
1) ALWAYS use temporary (session scoped) cookies.
2) All cookies should be protected and encrypted.
3) Do not pass tokens in request payloads
4) For any requests which return data that may be sent back to the server, include a nonce (single use token) in your responses.
5) later requests should (must) include the nonce and the cookie
Again, my recommendation is to review the OWASP guidelines and proceed accordingly.
You may want to look into using a service provider for authentication - this is much smarter than brewing your own solution as there are literally a million details that all must be correct. Auth0.com is one of these.