Monday, April 27, 2015

WS Security - Calling a secured Web Service with nonce from BPEL

Problem:

We had to call a secured web service that required a username token to be sent in the SOAP header, but being a WS Security newbie, I bumped into a lot of issues trying to get it to work. After adding the certificate into the SOA Server trust store, I was getting the following error after applying the oracle/wss_username_token_policy:

oracle.j2ee.ws.client.jaxws.JRFSOAPFaultException: Client received SOAP Fault from server : Exception thrown while trying to deserialize the SOAP message
at oracle.j2ee.ws.client.jaxws.DispatchImpl.throwJAXWSSoapFaultException(DispatchImpl.java:1053)
at oracle.j2ee.ws.client.jaxws.DispatchImpl.invoke(DispatchImpl.java:839)
at oracle.j2ee.ws.client.jaxws.OracleDispatchImpl.synchronousInvocationWithRetry(OracleDispatchImpl.java:235)
at oracle.j2ee.ws.client.jaxws.OracleDispatchImpl.invoke(OracleDispatchImpl.java:106)

After reading this very useful post from the AMIS Technology blog, I was able to attach the WS Security header right into the SOAP message which included the Nonce section, like so:

<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
   <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <wsse:Username>username</wsse:Username>
      <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
      <wsse:Nonce>Gt0q/QzAnQn/KMzhXYgR8Q==</wsse:Nonce>
   </wsse:UsernameToken>
</wsse:Security>

The call to the web service would now complete successfully since the original policy does not include the nonce, but this isn't the best way to do it since it's hardcoded into the BPEL process and it's just not very dynamic. The other, better way to do it is by using the OWSM policies and the credential store. I won't go too much into detail on how to setup the keystore and the credential store (I will do a follow-up post on this later on), but I will explain how I managed to send a nonce in the header using the policies, which...isn't really that hard at all!

Solution:

1) Go to the Oracle Enterprise Manager.

2) Under the farm name, expand the Weblogic Domain folder and right-click on the name of your domain, then select WebServices -> Policies.


3) Filter the policies by Service Clients and scroll down until you find one called oracle/wss_username_token_policy. This is the policy I attached on the webservice I had to call, but by default, this policy does NOT include the Nonce. Select it and click at the top "Create Like". I created a copy of this policy so I wouldn't mess with the original.

4) Give your policy a name (I named mine oracle/wss_username_token_nonce_policy) and then scroll down to the area that says "Assertions", Under the Settings tab, click "Show Advanced Fields":

5) Check the box that says "Nonce Required" and save your new policy. My web service only required the nonce, but if yours also needs a creation time, then go ahead and click that, too.


6) Now go to your composite, and below the composite name click SOA Composite -> Service/Reference Properties -> Web Service that you are calling




7) Here, click the Policies tab, then under Directly Attached Policies, click Attach/Detach.


8) Look for your new policy, click Attach, then OK.

9) Your policy should now appear under Directly Attached Policies. If you click on it, its information will be displayed under Security Configuration Details, including the csf-key. These are the credentials that the web service sends for the Username and Password. They can be configured in the Credential Store. In my case, since I had configured the basic.credentials with the username and password that the web service required, there was no need to override this value so the Current Value is left as blank.


When I tried the Web Service again, the policy did the same job as manually adding the SOAP header and the composite completed successfully! :)

Wednesday, April 8, 2015

XSLT - carriage return not working for text output

Problem:

When deploying an XSLT, the carriage return or line feed for text output would not show up when looking at the style sheet in the MDS repository. This was how I was trying to do the carriage returns:

<xsl:text>&#xd;</xsl:text>
<!-- OR -->
<xsl:variable name='newline'><xsl:text>
</xsl:text></xsl:variable> 

But when I would look at the XSLT in the MDS Repository, it would ignore the line breaks and just close the <xsl:text/> tags:

<xsl:text/>
<xsl:variable name="newline">
<xsl:text/>
</xsl:variable> 

Solution:

I ended up having to do it with a variable like so:

<xsl:variable name="newline" select="'&#xD;&#xA;'" /> 

This would show up correctly in the MDS repository and the text output would give the expected result.

Monday, April 6, 2015

XSLT - transforming to text output and writing to File Adapter

Problem:

I have an XSLT which is supposed to transform an XML (polled by a File adapter) to a plain text file. I tried the transformation in several online XSLT test tools (such as xslttest.appspot.com) and the output is shown as expected, so I was inclined to believe that there was nothing wrong with how I was doing the transformation. I used the mediator to do the transformation and passed it to a File Adapter to write the result in a .txt file.

I had another XSLT which transforms to an HTML file via a Mediator and that one worked as it should, but when I would replace the transformation file with an output method of text, the Mediator wouldn't do the transformation and so the File Adapter would give me the following error:

"JCA Binding execute of Reference operation 'Write' failed due to: Input Source null. Input Source null. Input Source is null. Please make sure that the outbound interaction receives a valid payload. ".

I wasn't sure why the XSLT wasn't working for a text output while the HTML output seemed to work fine with the Mediator.

Solution:

What I eventually had to do was pass the payload to BPEL and do the transformation using the ora:processXSLT function in an Assign activity:

ora:processXSLT('xsl/850-to-POI.xsl',$ReceiveFile_Read_InputVariable.body)

Note: The assign activity HAS to be done using this function and not any other variation (e.g. doXSLTransformForDoc etc.) since otherwise the text output from the XSLT will NOT be properly handled! Also in 12c, with the new folder structure, it is NOT necessary to add the two periods to access the Transformations folder (e.g. ../Transformations/TransformationFile.xsl). Doing so will cause for the XSLT file to not be recognized.

I copied this result to a String variable called "decodedBody", then I used Java to encode the contents to a base64binary variable called "encodedBody" (I tweaked a bit the very useful encoding function found in this blog):

addAuditTrailEntry("Base64encode started");       
    
try     
{       
String input = (String) getVariableData("decodedBody");       
addAuditTrailEntry("Base64decode decoded="+input); 

oracle.soa.common.util.Base64Encoder encoder = new oracle.soa.common.util.Base64Encoder();   
String encoded = encoder.encode(input);       
      
setVariableData("encodedBody",encoded);    
}    
     
catch (Exception e)     
{       
  addAuditTrailEntry("Base64encode Exception: "+e.getMessage());       
}       
    
addAuditTrailEntry("Base64encode ended");

I would then pass the encodedBody to the File Adapter input variable (which had an opaque schema). This would write the positional flat file I needed to a plain .txt. :)

I'm not sure if there is a better way to do this by just using the Mediator, so if anyone has any tips please do let me know in the comments!