Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Implementation of a Java callout that performs WS-Security Decryp and Encrypt is failing

Hello comunity,

 

I'm trying to use this solution to create WSSec decrypt and encrypt policies in Apigee: DinoChiesa/Apigee-Java-WsSec-RsaEncryption: a configurable custom policy for Apigee, which performs ...

But I'm having an error because the jar can't be loaded.

Example of error:

Failed to instantiate the JavaCallout Class com.google.apigee.callouts.wsseccrypto.Decrypt

Maybe the problem is similar to this one: Solved: Implementation of a Java callout that performs WS-... - Google Cloud Community. I suspect it because I was having the same problem with signing/validation until I found this thread and applied the suggested solution.

Example of policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout name="java-wssec-decrypt">
    <DisplayName>WS-Security Decrypt Message</DisplayName>
    <Properties>
        <Property name='debug'>true</Property>
        <Property name="source">message.content</Property>
        <Property name="private-key">{private.key.content}</Property>
    </Properties>
    <ClassName>com.google.apigee.callouts.wsseccrypto.Decrypt</ClassName>
    <ResourceURL>java://apigee-wssec-xmlenc-20210409.jar</ResourceURL>
</JavaCallout>
 
 
Edit: Apigee's debug show the error described as followed:
 
ThiagoSantos_0-1749048909056.png

 

Solved Solved
0 9 258
1 ACCEPTED SOLUTION

Thank you for the support.

I've already contacted the internal team so we can start the conversation with apigee support, although we're using apigee X so I don't think it'll be possible.

Anyway, I've found a patched version of xmlenc here that doesn't cause any security error, and I suppose I can keep it from here at least to finish the MVP. I'll need to address this issue, though, as this version is quite old, some encrypting algorithms are not supported, and it may have some undesirable xploits.

I've prepared a branch with Signature + Encryption+Patched XmlEnc together here: Farenheith/Apigee-Java-WsSec-Signature-2 at merge-encryption-patchedxmlenc

@dchiesa1 It'd be nice to later compatibilize your separate packages, though. I'll open a PR later for RsaEncryption, addressing the XmlUtils conflict to contribute.

View solution in original post

9 REPLIES 9

There are a couple related issues going on here.  Both have the same root cause, which is that Apigee operations have been tightening security controls on what Java callouts can do.  This applies to later versions of OPDK , as well as more recent deployments of X, Edge, and hybrid.  These tighter controls can prevent some existing Java callouts from loading.  Those callouts were written and implemented prior to the stricter controls, and had no problems previously. But now there are some security checks that prevent *some* Java callouts from loading.

We can talk specifics. 

  • The Apigee-Java-WsSec-Signature-2 callout.  You cited a prior thread on that one. The root cause there is that Apigee is now preventing the registration of a Java Security Provider.  LEt me take a step back and provide some background. WS-Security Signed documents work by signing some portion of the SOAP document, and then embedding some sort of reference to the key or credential used to make the signature, inside the document.  This reference is called a Security Token Reference. It can be a public key, or an x509 cert that bundles a key, or various other options.  WS-Security also supports what is known as a "STR-Transform" - which means Transformation of the Security Token Reference.  It just transforms one representation to another, in the SOAP document. Details are not super important for our purposes here; the important thing is, it is just one of the arcane options within WS-Security.  It is not very commonly used, and when it is used, in my experience, it is pointless. But that doesn't matter here.  Some WS-Security Signed documents that STR-Transform option, and in order for a Java program to handle it, the Java app needs to register a "Security Provider" that does the right thing. The "Security provider" is just a small class that manages the transformation during signature processing. 
    Well, adding this Security Provider became a privileged operations recently, so the existing WsSec-Signature-2 Callout no longer can instantiate. This is the reason for that failure. The workaround here is to modify the Java callout to not support STR-Transform, and therefore not need to register the security provider that handles STr-Transform. Everything else in WS-Sec signing still works. That is the approach I took with the "other branch" i referenced in the prior community discussion you cited.
  • The Encryption Callout which you are trying to use, is similarly failing at instantiation time. But this one does not attempt to register a Security Provider, and so that is not the reason the Callout does not instantiate.  The root cause - tighter controls on what Java callouts can do - is the same. But the specific case is different. In THIS case, I think the problem is that the bundled BouncyCastle jar with Apigee is now *different* than the one this JAR was built against.  BouncyCastle is a strange name, but it's a well-known, tested, proven, broadly used security add-on package for Java apps.  Apigee uses it internally, and this callout also uses it for handling key and cert Serialization and de-serialization.  In the past I could build a Callout that referred to BouncyCastle and at runtime, the JVM would satisfy the dependency with the BC that is part of Apigee. I think that is what is not working, with this callout. The solution is to re-build the Callout with the specific version of BC that Apigee uses, which I believe is 1.80 of jdk18on

So can you try that?  Can you rebuild the WS-Sec-RsaEncryption jar with the current BC jar, and see if it works?  Should be no code change required, except the change to the jar to reference the new version of BC.  

LMK

Thank you for such a fast reply to my issue. I'll try out what you suggested, and I'll update this comment with the results

 

Edit:

@dchiesa1 I've tried what you suggested, but I haven't succeeded in making it load yet.
I've changed more than what you asked for, though.


* I've added buildscript.sh, copying it from your other repository, so I could find some missing dependencies (expressions-1.0.0.jar and message-flow-1.0.0.jar);

* I've changed the following piece of code because javax.xml.bind was not being found, I guess it may have been removed from the newer JDK:

ThiagoSantos_0-1749061214948.png

* I've added a .gitignore just to avoid uploading some jar files, I'm afraid that would cause some licensing issues if I do so (not relevant for the problem, though);

Here's a link to the comparison between your repo and my fork if you want to take a look: Comparing DinoChiesa:master...Farenheith:fix-bouncyCastle · DinoChiesa/Apigee-Java-WsSec-RsaEncrypti...

I've tried some approaches based on this attempt:

* I've updated just apigee-wssec-xmlenc-20210409.jar and tested it, still the same error.

* I've added every jar maven fetched. You can see in the image below the list:

ThiagoSantos_1-1749061566821.png

Notice that, in your repository, you have commons-codec-1.15.jar in the resources folder; here I'm using 1.13, though, which was fetched during compilation.

* I've also tried using the same thing above, but with commons-codec-1.15.jar.

All the approaches failed, unfortunately, but I'll keep investigating to see if I can find anything.
If you happen to have any other ideas in the meantime, I'm glad to try it out. I wonder if there's anything I can do to get a more meaningful error from Apigee in that situation, as the current debug output doesn't give much of what's causing the failed loading.

Edit 2: oh, one more thing: to compile it, I need to skip tests because of some incompatibility between newer Java versions and jmockit code.

Edit 3: I changed jmockit to mokito in an attempt to fix the errors I was experiencing during test so I could compile the jar using just `mvn clean package`, as stated in the README. 
With this last attempt, the resources I've uploaded were the following:

ThiagoSantos_0-1749067790050.png

I push a new commit in my fork with these changes. I couldn't make it work, though. I think I'll try to find some other possibility, comparing the encrypt repo with the signature one

 

Edit 4: My last attempt to solve this problem was to add BouncyCastle to the included jars. Still the same error

ThiagoSantos_0-1749073763352.png

 

I don't have a good suggestion for you at this point, beyond logging this with Apigee support. 

They have access to the system logs and will be able to get better diagnostics for this problem. 

Good luck. 

Well. I'm using signature + ecnryption together, maybe there are some conflict between the two? I've noticed that, even when I don't use the decrypt step while sending a nonencrypted message, I was getting an error at the Validade step that wasn't happening before:

Failed to execute JavaCallout. 'java.lang.String com.google.apigee.util.XmlUtils.asString(org.w3c.dom.Node)'

I validated my whole project looking for accidental changes, but found none. Then, I removed all the jars I'd added when trying to decrypt the received message, and the error stopped.

I see that there are a class XmlUtil inside both repositories and they have the same namespace, but only the one from Signature have a "asString" method, so I suppose things are getting mixed up when I try to use both jars together.

I'll do one more test changing the namespace of encryption repo to com.example so no conflict will happen between the two. Maybe I'll have a nice surprise.

Edit: Yeah, the error at Validate step stopped, but when I test a flow where I try to Decrypt a message, I'm still getting the error `Failed to instantiate the JavaCallout Class com.example.apigee.callouts.wsseccrypto.Decrypt`.

I'll do as you said, I'll get in touch with apigee support. I can also try bringing the Decrypt and Encrypt operations to the Signature repository to check if it works.

Edit 2:
I've merged both projects in case I was doing something wrong trying to fix encryption one's dependencies, and the result now is that Validate is still working, Decrypt is not instantiating yet. Here's the comparison with the base branch I've used.
Comparing DinoChiesa:remove-str-transform...Farenheith:merge-encryption · DinoChiesa/Apigee-Java-WsS...

I think it at least narrows down the issues:
* Both callouts uses bouncyCastle, so, I'm sure both are using the same version;
* Just Decrypt callout uses xmlenc. Maybe it's not loading because it can't load xmlenc dependency.
I'm using 3.0.3 version, which is the one I could compatibilize with the current pom.xml jdk version

ThiagoSantos_0-1749133076848.png

I think now I can play around, maybe commenting the part where xmlenc is used to see if the callout will be loaded, to confirm the cause

 

Edit 3:

@dchiesa1 I have finally found the issue.

The problem is happening at this line:
static {
org.apache.xml.security.Init.init();
}

It's throwing an error and, as it's part of static class initialization, it can't be captured properly, resulting in a limited feedback to the user. I changed the moment this code is ran at this commit: refactor: changing initialization moment · Farenheith/Apigee-Java-WsSec-Signature-2@99d4585

Now, it'll run inside the try catch of execute method, making it possible to have a better error trace.
With this new approach, I have the following error detected:

access denied ("java.security.SecurityPermission" "org.apache.xml.security.register")

java.security.AccessControlException: access denied ("java.security.SecurityPermission" "org.apache.xml.security.register") at java.base/java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) at java.base/java.security.AccessController.checkPermission(AccessController.java:897) at java.base/java.lang.SecurityManager.checkPermission(SecurityManager.java:322) at com.apigee.securitypolicy.InternalSecurityManager.checkPermission(InternalSecurityManager.java:90) at org.apache.xml.security.utils.JavaUtils.checkRegisterPermission(JavaUtils.java:219) at org.apache.xml.security.utils.XMLUtils.setDsPrefix(XMLUtils.java:103) at org.apache.xml.security.utils.ElementProxy.setNamespacePrefix(ElementProxy.java:487) at org.apache.xml.security.utils.ElementProxy.registerDefaultPrefixes(ElementProxy.java:500) at org.apache.xml.security.Init.dynamicInit(Init.java:114) at org.apache.xml.security.Init.init(Init.java:87) at com.google.apigee.callouts.wsseccrypto.WssecCalloutBase.initialize(WssecCalloutBase.java:71) at com.google.apigee.callouts.wsseccrypto.Decrypt.execute(Decrypt.java:279) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$ClassLoadWrappedExecution.execute(JavaCalloutStepDefinition.java:277) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution.lambda$execute$0(JavaCalloutStepDefinition.java:383) at java.base/java.security.AccessController.doPrivileged(Native Method) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution.execute(JavaCalloutStepDefinition.java:382) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$CallOutWrapper.execute(JavaCalloutStepDefinition.java:202) at com.apigee.messaging.runtime.steps.StepExecution.execute(StepExecution.java:175) at com.apigee.flow.execution.AbstractAsyncExecutionStrategy$AsyncExecutionTask.call(AbstractAsyncExecutionStrategy.java:117) at com.apigee.flow.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:30) at com.apigee.flow.MessageFlowImpl.execute(MessageFlowImpl.java:636) at com.apigee.flow.MessageFlowImpl.resume(MessageFlowImpl.java:450) at com.apigee.flow.execution.ExecutionContextImpl.lambda$resume$0(ExecutionContextImpl.java:146) at com.apigee.threadpool.RunnableWrapperForMDCPreservation.run(RunnableWrapperForMDCPreservation.java:22) at com.apigee.threadpool.QueueMetricsAwareTask.run(QueueMetricsAwareTask.java:31) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829)

So, it indeed seems to be an issue with recent apigee x update, where security has been improved.

Do you have any suggestions on how I could solve this issue? I'm willing to contribute to your repos if you allow me, but I think you have the expertise on how to deal with this new situation, as you know really well both sides of the coin here, and I'd appreciate very much your guidance.

Edit 4:
I found a similar issue here Java call out access denied "org.apache.xml.securi... - Google Cloud Community

Which seems to be solved by updating xmlenc to 4.0.4, which will also force me to update the target Java version to 11. I'll try it out to see if I can solve the issue.

oh, thank you for the investigation and legwork. 

I agree with your diagnosis ; the permissions error is something new, introduced when the Apigee operations team made some changes I suppose.  You're using Apigee X, is that right?  If so my prior recommendation : get in touch with Apigee support. 

You've diagnosed the issue; your request to support I snot for help diagnosing. It's for help solving.  How can you get a Java callout to avoid the 
access denied ("java.security.SecurityPermission" "org.apache.xml.security.register")

problem.  That is happening due to the security manager  in Apigee X. 

In hybrid, you have control over this, so you can change the security policy file.  In X you cannot.  

The Support people can connect with the right Engineering resources to determine what is possible here.  

 

 

 

Thank you for the support.

I've already contacted the internal team so we can start the conversation with apigee support, although we're using apigee X so I don't think it'll be possible.

Anyway, I've found a patched version of xmlenc here that doesn't cause any security error, and I suppose I can keep it from here at least to finish the MVP. I'll need to address this issue, though, as this version is quite old, some encrypting algorithms are not supported, and it may have some undesirable xploits.

I've prepared a branch with Signature + Encryption+Patched XmlEnc together here: Farenheith/Apigee-Java-WsSec-Signature-2 at merge-encryption-patchedxmlenc

@dchiesa1 It'd be nice to later compatibilize your separate packages, though. I'll open a PR later for RsaEncryption, addressing the XmlUtils conflict to contribute.

Sorry for the double post, @dchiesa1, but I've gotten some new, valuable information on the issue, and I wanted to make sure you'd see the new insights.

I'll need to address this issue, though, as this version is quite old, some encrypting algorithms are not supported, and it may have some undesirable xploits.

Yes, this is the main problem with using those older libraries .  I guess it's a tradeoff you all will have to make.  I am sure I don't understand whether it is possible (or desirable) to modify the current xmlsec source code to remove the permission demands .  Obviously the Architects of Santuario decided that this operation - registering a provider  - ought to be a protected action. But that may not be applicable, or highly important, in your case with this Java callout.  In which case it might be possible to de-restrict the current jar and use in in this Apigee X environment.  That may be more "ownership" than you want to assume, though. It's all tradeoffs.

Just fantasizing here - what may be the ideal resolution is for you is if Apigee Engineering embeds the current xmlsec into the "blessed" set of JARs, or otherwise modifies the permissions on the JVM to include the required  "org.apache.xml.security.register"  permission for Apigee organizations, so any Java callout would be able to use xmlsec (current version). 


@dchiesa1 wrote:

@dchiesa1 It'd be nice to later compatibilize your separate packages, though. I'll open a PR later for RsaEncryption, addressing the XmlUtils conflict to contribute.


yes, I understand that part too.  I'd be interested in working through that on the GitHub repo...   Obviously the copypasta of XmlUtils is not good across Java callouts.  And when you want to have a consolidated Callout, it introduces conflicts.   So I'd like to explore solutions here.  Independent of the permissions issue. (And assuming we'd get to some satisfactory resolution there).

 


Just fantasizing here - what may be the ideal resolution is for you is if Apigee Engineering embeds the current xmlsec into the "blessed" set of JARs, or otherwise modifies the permissions on the JVM to include the required  "org.apache.xml.security.register"  permission for Apigee organizations, so any Java callout would be able to use xmlsec (current version). 

I think allowing xmlsec would be nice, but the security implications of this are beyond my knowledge, as maybe there's a good reason not to allow it. I think, perhaps, the best solution would be for the team responsible for xmlsec to make it compatible for usage in clouds with a more restricted permission set, as they can safely limit the validation scope.

The thing is, as far as I know, WSS body encryption is more used in legacy scenarios nowadays (like in bank applications, which was my case), as HTTPS is as safe and naturally present in every cloud solution, so, from a product management point of view I don't think there's much value on making it embed in Apigee. This is not the case for WSS signing, though, which is still pretty relevant and does not require xmlsec.


yes, I understand that part too.  I'd be interested in working through that on the GitHub repo...   Obviously the copypasta of XmlUtils is not good across Java callouts.  And when you want to have a consolidated Callout, it introduces conflicts.   So I'd like to explore solutions here.  Independent of the permissions issue. (And assuming we'd get to some satisfactory resolution there).

About that, the solution I thought was to put the util folders inside wsseccrypto, changing its package name. This would be enough to avoid any conflicts, even copying and pasting between repos. That's something you could easily do, but I ask you to let me do it, if you agree to the solution. I'd really be glad to be listed as a contributor 😀