Sunday, January 29, 2017

How to send custom header in soap message when invoking an API in APIM 2.0 without using a client

Introduction :

WSO2 APIM has 2 methods of securing backend. Basic Auth and Digest Auth. So if the backend expects a security like WSSE security Username Authentication, there should be a method to apply security header. 

Possible method is to send the particular authentication credentials via a client. But it is clear that the secured backend credentials cannot be shared with API subscribers when they expose the backend via WSO2 APIM endpoint. So the best thing is to customize the soap message in this scenario in the middle of the mediation. 

This can be achieved via a mediation logic which can be done via a custom mediation handler or  mediation extension

If you do not want to restart the server, best thing is to use a mediation extension which you can also upload via UI, in WSO2 API Manager publisher. 

One more important thing is, configuring these credentials as you can easily change at anypoint.
This is achieved by adding them as a registry property


Below explains a sample Mediation extension written to achieve this.

The client user name and password are encapsulated in a WS-Security <wsse:UsernameToken>. When the Enterprise Gateway receives this token, it can perform one of the following tasks, depending on the requirements:

-Ensure that the timestamp on the token is still valid
-Authenticate the user name against a repository
-Authenticate the user name and password against a repository

The given extension is to enrich this soap request to achieve the 3rd task.

This extension is written to inject username token in the message mediation, when client invokes an API in APIM 2.0 which has a SOAP endpoint which is secured using WS-Security and requires User Name Token header to appear on the SOAP headers.

This is done using Enrich mediator and payload mediator. 
Enrich mediator is used to remove the existing soap header by copying the soap body.
Payload mediator constructs the soap header with username token tag and security header.
Username and password is taken from a registry resource property by an expression.


Pre-Requisites  :


1. Add username and password as properties in registry under resources _system/config/users

username : <username>
password : <password>


Steps : 

1. In this scenario API should be created as api with version 1.0.0 by admin user.

Mediation Extension named as : admin--api:v1.0.0--In



<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="admin--api:v1.0.0--In"> 
   <enrich>
      <source type="body" clone="true"/>
      <target type="property" property="ORIGINAL_BODY"/>
   </enrich> 
   <payloadFactory media-type="xml">
      <format>
         <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                           xmlns:abc="http://localhost/testapi">
            <soapenv:Header>
               <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"
                              soapenv:mustUnderstand="1">
                  <wsse:UsernameToken>
                     <wsse:Username>$1</wsse:Username>
                     <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">$2</wsse:Password>
                  </wsse:UsernameToken>
               </wsse:Security>
            </soapenv:Header>
            <soapenv:Body/>
         </soapenv:Envelope>
      </format>
           <args>
<arg expression="get-property('registry','conf:/users@username')"/>
<arg expression="get-property('registry','conf:/users@password')"/>
</args>
           </payloadFactory>
   <enrich>
      <source type="property" clone="true" property="ORIGINAL_BODY"/>
      <target type="body"/>
   </enrich>
   <log level="full"/>
</sequence>


2. Mediation extension is uploaded during the api creation in publisher in flow.

3. Invoke API endpoint with authorization bearer token provided by WSO2 APIM via SOAP UI.

Reference :

[1] https://docs.oracle.com/cd/E21455_01/common/tutorials/authn_ws_user.html
[2] http://geethwrites.blogspot.com/2014/01/wso2-esb-removing-full-soap-header.html
[3] http://isharapremadasa.blogspot.com/2014/08/wso2-esb-how-to-read-local-entries-and.html