Creating JWS in SoapUI
(As with all my blog posts), Here is a neat trick someone at showed me today which I thought was absolutely fabulous.
Use Case
I need to create a JWS on the fly during my SoapUI testsuite’s execution. (i.e. I can’t create one in jwt.io or some other tool and then bake it into my tests.) I need to have valid iat and exp claims, and I might need to dynamically/programmatically vary the claims inside the JWS payload. I was also required to use SoapUI (because I was working at SoapUI-heavy organisation), even though generating dynamic JWS’s is much easier in Postman.
In the past I’ve seen people creating HTTP-enabled services that generate custom tokens for their test harnesses however given that requires a whole web-server or application to be spun up just to run a test, that solution feels like using a sledgehammer-to-crack-a-nut to me.
Trying to Use the “Native” SoapUI Function
Soapui’s JWT creation functionality seems to be very unhackable. The first google result from Smartbear seems to tell me that I need to have the paid-for ReadyAPI, and even then the JWS generation is pretty locked-down to inside the OAuth Authorization Options. (N.B. I’m not against the paid-for ReadyAPI option, I think it is pretty good- especially the “composite project” stuff for meshing with Version Control. I just know that a) waiting for an organisation to procure licenses for ANY product is just the worst thing in a software delivery project b) I want something that I can use anywhere, not just places were everyone has ReadyAPI.)
Putting a JWS together using the rsasign.js Library
Here is the solution that I’ve seen work and that I’ve now implemented.
At a high-level, the instructions are:
- Download the rsasign.js library
- Change a Setting on your SoapUI project
- Update the JS library (Rhino) on the default distribution of SoapUI
- Copy-paste some code snippets.
Notes on Rhino
To understand how SoapUI runs JS, it uses Rhino
. I had heard of Rhino before but had never really scratched the surface. Rhino is an implementation of JS in Java. SoapUI-5.5.0 (which is the version I have pulled using brew cask install soapui
) comes with Rhino 1.7R2. You can read more about Rhino on MDN or Github.
Disclaimer on the Javascript-in-SoapUI Ecosystem!
Be aware- JS snippets for SoapUI tests seem to be pretty rare on Google. SoapUI scripting seems to be pretty-much Groovy-focussed so there doesn’t seem to be much in the way of blogs/help. If you are a JS-through-and-through person, you WILL find the Postman route easier. Also check out this compatibility table here if you are a JS aficionado and none of your cool ES6 tricks work (Rhino does not have 100% coverage of ES6).
Detailed Instructions
-
Use the free-ish(MIT and BSD) library
rsasign.js
. Download this explicit file or download a full release and unzip it to your local machine. -
Open SoapUI and create a New Project.
- Set your SoapUI project to run script as Javascript. In the GUI, In the Navigator pane, click your project. Then in the Project Properties pane, change the value of the
Script Language
property from Groovy to Javascript.
-
Restart SoapUI. (I have found that SoapUI doesn’t pick up on the Script Language change without a restart).
-
(Optional) Create a
Groovy TestStepJavascript TestStep and paste in the following snippet (Shamelessly cribbed from this StackOverflow question)
var Context = org.mozilla.javascript.Context,
currentContext = Context.getCurrentContext(),
rhinoVersion = currentContext.getImplementationVersion();
log.info(rhinoVersion);
-
Update the version of Rhino bundled inside SoapUI (these instructions shamelessly cribbed from this Smartbear forum question).
a. Pull down the latest version of Rhino from the Mozilla website here.
b. In the SoapUI
\lib
folder (/Applications/SoapUI-5.5.0.app/Contents/java/app/lib
was my filepath), replacejs-1.7R2.jar
withjs-<rhino version>.jar
from the downloaded zip.c. Restart SoapUI.
d. (Optional) Run the snippet to print out the Rhino version again.
-
Make a Script Teststep and copy-paste the following code, adding the contents of the minified rsasign file as a massive one-liner and pasting in your own secret key.
var navigator = {}; //fake a navigator object for the lib
var window = {}; //fake a window object for the lib
// Minified .js is copy-pasted as a big one-liner
/* * jsrsasign(all) 8.0.12 (2018-04-22) (c) 2010-2018 Kenji Urushima ...snip...
var header = {
"alg": "PS256",
"typ": "JOSE",
"cty": "application/json"
};
var data = {
"Hello": "World"
}
// Paste in the private key
var secret = "-----BEGIN PRIVATE KEY----- MI...snip...== -----END PRIVATE KEY-----";
var algo = "PS256";
var sHeader = JSON.stringify(header);
var sPayload = JSON.stringify(data);
var sJWT = KJUR.jws.JWS.sign(algo, sHeader, sPayload, secret);
log.info(sJWT);
- Adapt to suit your needs! Transfer the JWS to your next teststep, load your own header and payload sections, slice this up as necessary.
Afterword
I’m pretty sure this is one of those scripts that has been cribbed/passed-around/stolen over and over again. The first/earliest place I could find it on Google was on TheKoguryo’s github site, however it seems to appear in many different forms in different snippets over SO and the blogosphere.
It was very interesting googling and seeing how other people had used this!
References
Helen Kosova’s Answer on this Smartbear Forum Post: https://community.smartbear.com/t5/SoapUI-Open-Source/How-to-parse-JSON-in-javascript/td-p/133474
TheKoguryo’s Github Blog where they implement this for Postman, in Korean(?) https://thekoguryo.github.io/oci/chapter14/3/4/