Problem consuming Webservice with certificate - java

I am having problems consuming a SOAP WebService with security that uses a certificate to encrypt the data.
I am using GeneXus 17 (but I did this same test with GeneXus X Evolution 2 and 3) generating Java.
I did all the necessary steps to generate the certificate and the keystore, then I added everything in the KB and in the object as specified there but it gives me the following error when executing it:
"C:\Program Files\Java\jdk1.8.0_241\bin\java.exe" com.rendiciongastos17.aobtnerrendicionespendientessoap
Exception in thread "main" java.lang.RuntimeException: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.(-5)
at com.rendiciongastos17.SdtClients.getrendicionespendientesintegracion(SdtClients.java:386)
at com.rendiciongastos17.aobtnerpendingrendicionessoap.privateExecute(aobtnerpendingrendicionessoap.java:61)
at com.renditionexpenses17.aobtnerpendingrenditionssoap.execute_int(aobtnerpendingrenditionssoap.java:46)
at com.renditionexpenses17.aobtnerrenditionspendingsoap.execute(aobtnerrenditionspendingsoap.java:38)
at com.surrenderpending17.aobtnerrenderpendingsoap.executeCmdLine(aobtnerrenderpendingsoap.java:22)
at com.renditionexpenses17.aobtnerrenditionspendingsoap.main(aobtnerrenditionspendingsoap.java:15)
Failed: Execution
Now if I import the WSDL into SOAPUI and run it, it does fine.
The only code I have is:
java System.setProperty("javax.net.ssl.trustStore", "d:\\caolix");
java System.setProperty("javax.net.ssl.trustStorePassword", "Riogas1710");
&location = GetLocation('Clients')
&location.Authentication = 1
&location.AuthenticationMethod = 0
&location.AuthenticationRealm = "UnRealm"
&location.AuthenticationUser = "riogas"
&location.AuthenticationPassword = "xcrtdymx"
&RendicionesPendientesDeIntegracion = &wsClients.GetRendicionesPendientesIntegracion()
The location of the keystoke is correct and I can't see what it can be.

This error could be related with the SAC numbers #48044, #49588 or #51075, take a look at them before do anything. If it's not, then the error comes because the endpoint is not returning an XML, or something broke in between. You're talking about "a certificate to encrypt the data", but there is no code where you "encrypt the data" itself, setting the property to a trustStore is not enought, you have to use the Security API to encrypt the data.
And last but not least, I do see that the web service provider uses realm-based authentication, check if the parameters are ok. It's very rare to see endpoints with realm-based authentication but, who knows...

Related

Cannot make requests to Walmart API

I'm trying to make a request to the Walmart API here.
https://walmart.io/docs/affiliate/product-lookup
Here are the steps I'm following.
I create my application here on Walmart and uploaded my public key. I created my keys following these instructions on Mac.
https://walmart.io/key-tutorial
I followed this code to generate my signature.
https://walmart.io/docs/affiliate/onboarding-guide
I plug in all these values into the API explorer, but I keep getting the same error.
Is there an extra step I'm missing?
The 401 Unauthorized is an HTTP status code error that represents the request sent by the client to the server lacks valid authentication
Seems like one of the mandatory header params is missing while consuming api.
Request to please kindly cross check whether all of the mandatory header params are there as part of request.
We should have these below mentioned mandatory header params as part of the request.
One or more header params might be missing in the req.
WM_CONSUMER.ID
WM_SEC.KEY_VERSION
WM_CONSUMER.INTIMESTAMP
WM_SEC.AUTH_SIGNATURE
we need all of the header params and we can generate using below mentioned links.
Generating Auth Signature (WM_CONSUMER.INTIMESTAMP, WM_SEC.AUTH_SIGNATURE)
We can generate Auth Signature by using below mentioned link.
We will have to run below mentioned sample code to generate Auth Signature as seen below. This is going to generate timestamp and valid Auth Signature to consume APIs.
Time Stamp will be valid for couple of mins only. If it expires, we will have to regenerate the same
https://www.walmart.io/docs/affiliate/onboarding-guide
Generating consumer ID (WM_CONSUMER_ID)
Request to please kindly follow below steps to generate consumer ID
Create an account on Walmart IO platform - https://walmart.io by clicking on the user icon just before the search box.
Login to the account and accept "Terms of Use"
Click on "Create Your Application" to create a new application and fill in appropriate details.
Use this tutorial to generate two sets of public/private keys - https://walmart.io/key-tutorial
One set will be used for production.
Other set will be used for stage.
Upload both public keys using - https://walmart.io/key-upload?app_name=<your app name>
Consumer ID will be generated for both sets for prod and stage which can be seen on the dashboard - https://walmart.io/dashboard.
Regards,
Firdos
IOSupport

Windows SSPI to Java GSSAPI interoperability to achieve SSO on EJB calls

I have Java client running on Windows machine that calls remote EJB
on JBoss EAP/Wildfly running on Linux machine.
I use Kerberos to achieve SSO. Java client verifies the user against Windows domain
and pass his identity within EJB call to the JBoss server.
I started with JAAS and the builtin com.sun.security.auth.module.Krb5LoginModule.
It works correctly except one thing: user has to type his username and password
again. So, it is not a real SSO.
The problem is that Windows prohibits to export kerberos session key from its LSA credential cache.
It can be fixed by setting a specific Windows registry key on each client machine - but this is not acceptable for the customer.
Therefore I am trying to find an alternative solution.
I learned that Windows provides SSPI that shall be interoperable with GSSAPI used by Java. I use Waffle library to access SSPI from Java on the client. On the server I keep using JAAS, because it runs on Linux so I cannot use Waffle there.
I also learned that I don't need to implement LoginModule, rather I need SASL client.
So, I had a look how com.sun.security.sasl.gsskerb.GssKrb5Client works and I am trying to reimplement it using Waffle.
First step seems to work correctly - I obtain SSPI security context from Waffle,
then get the initial token and send it to the server.
The server accepts the token and respond with its own token.
And now the problem comes. In the original SASL client the 'unwrap' operation is
used to extract data from the server token, and 'wrap' operation is used to create
reply token to be sent to server.
GSSAPI wrap / unwrap operations shall correspond to SSPI EncryptMessage / DecryptMessage
operations according to Microsoft doc. This two methods are not available in Waflle, but are available
in NetAccountClient library.
However, I am not able to use them correctly. If I use a single SECBUFFER_STREAM then the DecryptMessage
is succesfull, however the data part of the token is not extracted and I don't know how to determine
the offset where it begins.
If I use SECBUFFER_STREAM and SECBUFFER_DATA as suggested by Microsoft docs, then I get an error:
com.sun.jna.platform.win32.Win32Exception: The message or signature supplied for verification has been altered
I also tried other combinations of SECBUFFER types as suggested elsewhere, but without success.
Any idea what am I doing wrong ?
To source code of unwrap method:
public byte[] unwrap(byte[] wrapper) throws LoginException {
Sspi.SecBuffer.ByReference inBuffer = new Sspi.SecBuffer.ByReference(Secur32Ext.SECBUFFER_STREAM, wrapper);
Sspi.SecBuffer.ByReference buffer = new Sspi.SecBuffer.ByReference();
buffer.BufferType = Sspi.SECBUFFER_DATA;
Secur32Ext.SecBufferDesc2 buffers = new Secur32Ext.SecBufferDesc2(inBuffer, buffer);
NativeLongByReference pfQOP = new NativeLongByReference();
int responseCode = Secur32Ext.INSTANCE.DecryptMessage(secCtx.getHandle(), buffers, new NativeLong(1), pfQOP);
if (responseCode != W32Errors.SEC_E_OK) {
throw handleError(responseCode);
}
byte[] data = buffer.getBytes();
return data;
}

Adding soap header authentication to wsdl2java generated code

I'm in the process of creating a Java web services client from a wsdl. I used Eclipses's Dynamic Web Project and new Web Services Client to generate the code with wsdl2java with Apache Axis 1.4. I need to add SOAP authentication to this code in order for it to work with the service. I couldn't find a place to do that in the generated code. After copious research I found this, which I've used as the backbone for my code so far.
Adding ws-security to wsdl2java generated classes
Before I was getting a "Error occurred while processing security for the message" or something along those lines. Now I am getting
"Exception: Did not understand "MustUnderstand" header(s):{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security Message: null"
I've tried many things to get past this exception. This is the code I've arrived at now.
javax.xml.namespace.QName headerName = new javax.xml.namespace.QName(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security");
org.apache.axis.message.SOAPHeaderElement header = new org.apache.axis.message.SOAPHeaderElement(headerName);
header.setActor(null);
header.setMustUnderstand(true);
// Add the UsernameToken element to the WS-Security header
javax.xml.soap.SOAPElement utElem = header.addChildElement("UsernameToken");
utElem.setAttribute("Id", "uuid-3453f017-d595-4a5b-bc16-da53e5831cd1-1");
javax.xml.soap.SOAPElement userNameElem = utElem.addChildElement("Username");
userNameElem.setValue("username");
javax.xml.soap.SOAPElement passwordElem = utElem.addChildElement("Password");
passwordElem.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
passwordElem.setValue("password");
header.setProcessed(true);
// Finally, attach the header to the binding.
setHeader(header)
This code is located in my Binding_ServiceStub class (in its' createCall method).
We have created clients in both C# and VB with this wsdl, and there it's as easy as just changing the ClientCredentials variable which is an extension of the proxy class generated. I was hoping for something similar here.
Here's the security policy from the wsdl code as well.
<wsp:Policy><sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:WssUsernameToken10/></wsp:Policy></sp:UsernameToken></wsp:Policy>
Does anyone know what else I can do here? Why this exception is happening? I've tried many different combinations of prefixes and setProcesses and setMustUnderstand values all in vain (and based on my research of this exception).
And if anyone knows a way in which to add Soap header authentication to wsdl2java code I would take that too. Just need this to work and you would think something like this would be a little more straightforward or at least have more examples out there.
Update-
Confirmed that the same header passed using SOAPUI works fine. Must be something with the framework? I created a custom handler to process the SOAP Message but that didn't help. Is Axis 1.4 and JAX-RPC the problem? (I know they're outdated but still...)
Cool. I decided to just use Apache CXF as my framework and using this it's as easy as adding
javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider) port;
bp.getRequestContext().put("ws-security.username", username);
bp.getRequestContext().put("ws-security.password", password);
Wow that's much better. Don't use Axis 1.4 lesson learned.

How to digitally sign SOAP request using Eclipse generated proxy (axis 1.4) via WSS4J?

I have been provided a WSDL for a webservice. I am now required to digitally sign that request. The previous developer utilized the Eclipse feature to generate proxy classes. Add the WSDL to the project, then right click on it, click "Web Service", then "Generate Client".
This worked fine until we were required to digitally sign the request. I did some digging and it looks like Axis 1.4 doesn't allow you to sign requests. You can use WSS4J to do that. I mavened in WSS4j 1.5 into my project.
I'm at a loss on how to digitally sign the request. Here is my existing code that uses the proxy classes:
XiSecureWSServiceLocator service = new XiSecureWSServiceLocator();
service.setXiSecureWSServicePortEndpointAddress(paymetricPortAddress);
XiSecureWSPortType proxy = service.getXiSecureWSServicePort();
((Stub) proxy).setTimeout(paymetricTimeOutinMillisec);
SDecrypt_InputType sdi = new SDecrypt_InputType();
sdi.setStrToken(ccNumber);
sdi.setStrUserID(user);
SDecrypt_OutputType sdo = null;
sdo = proxy.pm_SingleDecrypt(sdi);
What I want to do is something similar to this article. Here is a function they used:
public Message signSOAPEnvelope(SOAPEnvelope
unsignedEnvelope) throws Exception
{
WSSignEnvelope signer = new WSSignEnvelope();
String alias = "16c73ab6-b892-458f-abf5-2f875f74882e";
String password = "security";
signer.setUserInfo(alias, password);
Document doc = unsignedEnvelope.getAsDocument();
Document signedDoc = signer.build(doc, crypto);
// Convert the signed document into a SOAP message.
Message signedSOAPMsg =
(org.apache.axis.Message)AxisUtil.toSOAPMessage(signedDoc);
return signedSOAPMsg;
}
How can i get the Soap Envelope to be signed when all of the code to create it is hidden in the generated proxy classes?
This JavaRanch Thread explains implementing Security and Encryption with WSS4J using Axis handlers.
It looks like you have to do a number of things:
Configure/write a wsdd
Call the web service with an EngineConfiguration pointing to your wsdd file
Write a password callback class
Write a crypto.properties file
ensure the crypto.properties file and the key store containing the certificate are on the class path of the app.
Props to John Farrel on the JavaRanch forum for figuring all this out.
All in all kind of a pain in the butt. If there's a way to obtain the underlying SOAP Message itself from the Axis proxy class, that might be a quicker way to do it, but I don't have a lot of experience with Axis 1.
Hello from /r/java, by the way!
Found this:
Can anyone recommend to me or point me somewhere that describes
a simple, straightforward way to sign a SOAP request with a Digital
Signature within the Axis framework?
"Have a look at the WSS4J project. They provide Axis handlers for signing and encrypting as it is described in WS Security."
http://mail-archives.apache.org/mod_mbox/axis-java-user/200403.mbox/%3CCGEOIPKACAGJDDPKCDIHEEKACCAA.abhinavm#contata.co.in%3E -
Does that help?

Https WebService message: Message did not contain a valid Security Element

I am using axis 2 webservice client.
The first https call to the webservice throws a exception with the message: "Message did not contain a valid Security Element".
I think that the problem could be the security mode: maybe it has to be message level security. In this case, how can I configure it in axis?.
The code:
System.setProperty("javax.net.ssl.keyStore", jksFile);
System.setProperty("javax.net.ssl.keyStorePassword", jksPassword);
MyServicePortProxy proxy = new MyServicePortProxy();
Stub stub = (Stub) proxy.getMyServicePort();
proxy.setEndpoint(endpoint);
stub.setUsername(username);
stub.setPassword(password);
// throws exception with the above message:
proxy.serviceMethod(...);
Take a look at http://ws.apache.org/wss4j/package.html we had to define a client-config.wsdd that told axis to include username/password (if it is ws-security you are using). I am a little bit weak on the different standards and what separates them.
It's possible that in your XML service definition you need to create a service policy -[http://schemas.xmlsoap.org/ws/2004/09/policy/]
Take a look at these articles:
http://www.javaranch.com/journal/200603/Journal200603.jsp#a2
http://www.javaranch.com/journal/200709/web-services-authentication-axis2.html
Watch your clock-skew. If the timestamp in the security element provided by the client is too far into the past or the future from the server's perspective, it may reject it with exactly this message.

Categories