2015/02/10
10 Feb, 2015

How to Write a Web Application Backed by WSO2 Middleware - Part 3

  • Hasitha Abeykoon
  • Associate Technical Lead - WSO2

Applies to

WSO2 Developer Studio Version 3.6.0
WSO2 Application Server Version 5.2.1
WSO2 Identity Server Version 4.6.0
WSO2 Data Services Server Version 3.2.1
WSO2 Enterprise Service Bus Version 4.8.1


Table of Contents

  1. Introduction
  2. Why WSO2 ESB?
  3. Proxing Back End Services
    • Creating a proxy service for WSO2HealthIT service
    • Modifying the web application to use proxy service
    • Testing the web application with ESB
  4. XACML integration with a proxy service at ESB
    • Web application side changes
    • ESB side changes
    • IS side change
  5. Modifying Web Application to handle and Display custom errors
    • Generating custom error messages from ESB
      • When XACML authorization fails
      • When a DSS fail happened
    • Displaying Error Messages at Web Application Side
    • Testing the web application developed so far
  6. Recommendations and best practices
  7. Conclusion and Possible Improvements
  8. References


Introduction

WSO2 Enterprise Service Bus (WSO2 ESB) plays a major role in the WSO2 middleware platform. When designing the back-end of a solution, most times WSO2 ESB helps to bring out a clean architecture plus powerful mediation across different services. In this article, we look at how you could expose back-end services using WSO2 ESB and how to integrate the WSO2 Health Web Application developed so far with the exposed services by WSO2 ESB.

Figure 01



Why ESB?

Even though a solution to a practical problem begins on a small scale, with time, that solution grows to a comprehensive one gathering more features. It is important that solution architects should have a clue as to what degree, and when setting up the basic layouts they would need to consider those aspects. When the solution contains a lot of components wired together, having point-to-point connections between all of them makes the solution less manageable, which also results in less overall performance1.

Figure 02

Having a bus in the middle and plugging the components into the bus is the solution for this. All the message forwarding and transferring happens through the ESB. Moreover, the security integration for services can be done at the ESB layer, so the service consumer applications do not need to worry about the security aspects, and they can just consume the services.

Figure 03

Therefore, most times, whenever a solution tends to become comprehensive in the future, introducing WSO2 ESB to the solution helps to build a clean solution from the beginning.


Proxing back-end services

A proxy service defines virtual services hosted on the ESB that can accept requests, mediate them, and deliver them to an actual service.

  • A proxy service can perform transport or interface switching and expose different semantics from the actual service: WSDL, policies, and QoS aspects like WS-RM, WS-Security, etc.
  • It can mediate the messages before they are delivered to the actual endpoint and mediate the responses before they reach the client.
  • It is also possible to list a combination of tasks to be performed on the messages received by the proxy service and terminate the flow or send a message back to the client even without sending it to the actual service.

This article describes how you can create a proxy service in ESB fronting the data service implemented to expose patient information for WSO2 Health Web Application.


Creating a proxy service for WSO2HealthIT service

  • Download WSO2 ESB pack here and extract it to a preferred location
  • Navigate to /repository/conf/carbon.xml and set an port offset of 3. This is done to stop conflicting ports of the other WSO2 products used to setup the environment
  • Go to /bin folder and start the server by running wso2server.sh script (wso2server.bat for Windows)
  • Log into management console using default username and password “admin”
  • Select Manage >> services >> add >> proxyService

    Figure 04

  • Select custom proxy type
  • Now login to management console of Data Services Server and grab service URL and the WSDL URL of WSO2HealthIT service

    Figure 05

  • Go to the management console of ESB again and continue creating the custom proxy stating the WSDL URL. Specify the proxy name as “WSO2HealthITProxy”

    Figure 06

  • Click next and define an inline sequence. Click Create.

    Figure 07

  • Add a send mediator to the inSequence and give the WSO2HealthIT data service URL as the inline Address Endpoint (test and verify if ESB can connect to the service successfully. Also note that in this article localhost is used instead of IP).

    Figure 08


    Figure 09

  • Click save and close. Save and close the inSequence as well. Click next. Define an outSequence in the same way and for the endpoint in the send mediator there select none.
  • Click finish. You will be navigated to “Deployed Services” page. There you should notice that WSO2HealthITProxy is created and deployed. Click on “Source View” link in front of WSO2HealthITProxy. The row xml view of the proxy service can be found there.
  • To test if the proxy is working, click on WSO2HealthITProxy and then “try this service” link. Send a message to “WSO2HealthITProxyHttpSoap11Endpoint” and you should get a valid response.


Modifying the web application to use proxy service

  • In the WSO2 Health Web Application we have hardcoded the DSS server URL at two points.
    • QueryPatientDetailServlet.java - dataServiceEP

      Let us refactor this to dataServiceProxyEP
    • RegisterPatientServlet.java - DSSServerURL

      Let us refactor this to dataServiceProxyEP

    The URL should be the proxy service end-point URL

    dataServiceProxyEP = https://localhost:8246/services/WSO2HealthITProxy

    This is the only change that’s needed from the web application side.


Testing the web application with ESB

  • Run all the required servers
  • Export the new .war file and upload the new web application after deleting the older one from the WSO2 Application Server
  • Login to web application from user “Hasitha” with approval to read and write
  • Try querying some existing patient. Try to add a new patient and query it. You will notice query information goes to the WSO2 DSS via the WSO2 ESB server
  • If you are having problems try with the attached sources and cross check


XACML integration with a proxy service at ESB

Web application should pass the user information to the proxy service when it calls the proxy service. This can be done by HTTP Headers. When calling the proxy service, the logged in user can be set as the x-Authorization header from the web application side. On the ESB side, we can extract this header and identify the user.


Web application side changes

Web application should pass the user information to the proxy service when it calls the proxy service. This can be done by HTTP Headers. When calling the proxy service, the logged in user can be set as the x-Authorization header from the web application side. On the ESB side, we can extract this header and identify the user.

  
List
headers = new ArrayList
(); Header authHeader = new Header("X-Authorization", (String) request.getSession(false).getAttribute("user")); headers.add(authHeader); opt.setProperty(HTTPConstants.HTTP_HEADERS, headers); serviceclient = new ServiceClient(cc, null); serviceclient.setOptions(opt);
  • doGet() method of QueryPatientDetailServlet.java should be updated with above code segment (please refer attached sources)
  • doGet() method of RegisterPatientServlet.java should be updated with above code segment (please refer attached sources)


ESB side changes

For the WSO2HealthItProxy developed so far we need to engage “Entitlement Mediator”2 at the inSequence of the proxy.

  • First we need to identify the user who should be authorized against the IS server. At the web application, the logged in user was set to the http header “X-Authorization”. At ESB we can extract this value and save it to a property in “Axis2 scope” called “username”. Note that “Axis2 scope property” important because Entitlement Mediator refers that scope.

    “By default, the Entitlement mediator expects to find the XACML subject (user name) in a property called username in the message's Axis2 context. If your authentication mechanism specifies the user name by adding a property of a different name, create a property called xacml_subject_identifier and set it to the name of the property in the message context that contains the subject.”

    Hence, at ESB, the username is set to the context like below inside the inSequence.

      
    <property xmlns:ns="https://org.apache.synapse/xsd"
    name="username"
    expression="$trp:X-Authorization"
    scope="axis2"/>
    
  • Now, adding the entitlement mediator2. This can be done either via the management console of the ESB or directly editing the XML of the proxy service source. This article describes how this can be achieved using the management console. The resultant source for the proxy service is attached with the article. Readers can copy paste it to the source view as XML as well.
    • Go to services and click on WSO2HealthItProxy and click edit. Click next and go to the edit of inSequence.
    • Click on add child >> advanced >> Entitlement

      Figure 10

    • You will see that entitlement mediator is added to the inSequence.

      Figure 11

    • For the entitlement server give the URL of the identity server (https://localhost:9444/services). In addition, it is required to give some user’s username and credential with permissions to log in and manage configurations in the identity server (default admin user). Callback handler should be UT as we set the “username” to the axis2 message context.

      Figure 12

    • Click on “onAccept”. If the authorization is successful, the call should proceed to backend data service. For this, send mediator should be put with an address endpoint having WSO2HealthIT data service.

      Figure 13

      Figure 14

      Save and close to apply changes

    • Click on “onReject”. There we generate a soap fault having the reason to the failure. We need to send it to the client. For that, a property called “Response” should be set to “true” and “to” header should be removed before applying the send mediator.

      Fault : Transform >> Fault

      Figure 15

      Figure 16

      Property mediator: Core >> property

      Figure 17

      Figure 18

      Header mediator: Transform >> Header

      Figure 19

      Figure 20

    • We already have a send mediator there. First remove it by clicking on delete.

      Figure 21

  • After removing “to” header, apply send mediator so that the created fault message is sent back to the client.
  • at The out sequence (where response from Data Services Server reaches ESB) we need to remove the security headers and send the response back, so that the web application can decode the response.

      
    <outSequence>
    <header xmlns:wsse="https://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" name="wsse:Security" action="remove"/>
    <send/>
    </outSequence>
    
  • Refer the WSO2HealthITProxy.xml for complete source. All above steps generates that source.


Identity server side changes

In the new deployment, it is WSO2 ESB that communicates with WSO2 IS. Thus a new XACML policy should be enforced containing proxy service URLs as AttributeValues (e.g. .*/WSO2HealthITProxy/patientDetailsByNumber).

  • Log into the IS server using admin/admin default credentials.
  • Navigate to policy Administration >> Add New Entitlement Policy >> write policy in XML

    Figure 22

  • Copy paste the “dssOperationsProxy” attached with the sources of this article and save (notations and standards writing a XACML policy is out of scope of this article).
  • Click on publish to my PDP.
  • Go to Policy view and enable the policy.

This policy enforces the following;

Permissions user has Access URL Allow/ Deny
read .*/WSO2HealthITProxy/patientDetailsByNumber Allow
read .*/WSO2HealthITProxy/registerPatient Deny
write .*/WSO2HealthITProxy/patientDetailsByNumber Allow
write .*/WSO2HealthITProxy/registerPatient Allow

Now IS is ready to evaluate authorization requests coming from WSO2 ESB.

The additional modification we have done to the proxy was engaging entitlement mediator to handle XACML authorization. Now it is clear that we are doing the XACML authorization at two places in the Web Application. First place is using the application server itself where the web application is deployed (application server communicates with identity server). Second place is at the proxy service using entitlement mediator (ESB communicates with identity server). It is understandable now that the first place where application server involves can be removed.


Modifying web application to handle and display custom errors

Generating custom error messages from ESB

When integrating services together, there is a requirement at times to transform messages and sometimes generate new messages. One such occasion is generating meaningful error messages to be shown in the Front Side for the user. In this article, there are two instances where custom error messages are considered

  1. When XACML authorization fails. This is already discussed under “onReject” of Entitlement Mediator.
  2. In the event of a DSS failure.

Let us discuss how to handle the second occasion where errors might appear.

In the event of a DSS failure

In the scenario discussed, WSO2HealthIT data service is proxied at the ESB. If an error occurs on the DSS side, it will throw a SOAP fault with the reason to fail to the ESB side. This message will contain error codes generated by the data services server as well. On the ESB side, it is possible to generate a custom error message organizing aforesaid information in an appropriate custom manner.

  • First we need to define a “sequence” called “wso2HealthITFaultHandler” to create a custom fault message for the client
  • In the ESB management console, navigate to Service Bus >> Sequences >> add sequence. Give the above name as the sequence name
  • Create a custom log (add child >> core >> Log) to indicate in logs that the fault sequence is hit

    Figure 23

    Figure 24

  • Save the fault code to a property

    Figure 25

  • Then, as shown previously, create a fault (add child >> transform >> fault)

    Figure 26

  • Save the wso2HealthITFaultHandler sequence
  • Now, it is needed to engage this sequence to the “WSO2HealthITProxy” created. For that set the above sequence as the faultSequence for the proxy as below ;

      
    <target faultSequence="wso2HealthITFaultHandler">
    
  • Now ESB will generate the custom message for any synapse error occurrence in the proxy


Displaying error messages on the web application side

  • Servlet that’s sending a request to the ESB will get an exception when the ESB returns a soap fault. Thus, the underlying axis2 client converts soap fault to an exception. Therefore, in order to get the error message, we can query the message in the exception.
  • The following code should go to “QueryPatientDetailServlet.java” class. We wrap doGet method with following try catch.

      
    try {
    	<doGet method>
    }    catch (Exception e)  {
    	RequestDispatcher rd = getServletContext().getRequestDispatcher("/getPatientDetails.jsp");
    	PrintWriter out= response.getWriter();
    	out.println("Error While Querying Records : "+e.getMessage()+"");
    	rd.include(request, response);
    }
    
  • For inserting patients RegisterPatientServlet.java class just fire and forget the request. For correctness, this should also get a response if the operation was successful or not from the BE. This can be considered as an experiment for the reader (refer to attached sources)


Testing the web application developed so far

  • Export the new .war file and upload the new web application after deleting the older one from WSO2 Application Server.
  • Play with different users with different roles and experience if the XACML authorization happens correctly with the entitlement mediator.
  • Go to “query patient details” page and query an empty patient ID. You will see custom error from the back end in Read.

Figure 27: Error when XACML authorization failed


Figure 28: Error when a DSS error occurred (for an empty query)


Recommendations and best practices

  • Rather than hard coding the back-end server URLs and service names, it is better to read them from a configuration file inside the web application.
  • If the front end is designed to handle JSON messages, the ESB can be used to convert XML messages to JSON format and vice versa3
  • If there are many services and combined APIs that should be secured and monitored, rather than using WSO2 ESB to proxy each service, it is better and clean to use WSO2 API Manager. It is possible to have a store of APIs and manage who can consume them.
  • When moving the solution from a test environment to production environment, etc. it is required to change the endpoint URLs, IP addresses and so on. Thus, it is always easy and recommended to keep them at a single place and manage them. WSO2 Governance Registry is designed to serve this purpose.


Conclusion and possible improvements

For a comprehensive deployment, the ESB server can be viewed as a middle person for transforming messages across vivid services and client applications. For integrated security scenarios, the ESB can communicate with WSO2 Identity Server and secure the services so that the applications that consume the service do not need to worry about handling security. The scenario described in this article enhances the aforesaid roles of the ESB clearly and also shows how easy it is to integrate across multiple servers by WSO2 to meet custom requirements.

As an improvement to the web application developed so far, it can be suggested the service monitoring and displaying service statistics part using WSO2 Business Analytic Server (BAM). In the next article of the series, we will discuss how this aspect can be achieved.


References

[1] https://www.slideshare.net/wso2.org/introduction-to-wso2-esb?qid=72142885-0779-4f8d-9586-d096cf9820c4&v=default&b=&from_search=12

[2] https://docs.wso2.org/display/ESB480/Entitlement+Mediator

[3] https://docs.wso2.com/display/ESB480/JSON+Support


Appendix

[2] https://wso2.com/files/How-to-write-a-web-apply-application-backed-by-wso2-middleware-03.zip

 

About Author

  • Hasitha Abeykoon
  • Associate Technical Lead
  • WSO2