Saturday, September 17, 2016

Enable CORS in WSO2 ESB

Introduction

This post explains concept of Same Origin Policy (SOP) and how Cross-Origin Resource Sharing(CORS) can be used to handle SOP in details. Finally this describe how to implements CORS in WOS2 ESB.

Same origin policy

The same origin policy restricts the browser how a document or script loaded from one origin can interact with resource from another origin. For example if http://example.com tries to retrieve data from (by sending GET request) https://example.com , the browser will disallow access since origins are different.  The origin is everything in the URL before the path . It follows schema/host/port pattern.(for example, http://www.example.com:8080). This policy basically prevents a malicious script on one page from obtaining access to sensitive data on another web page through that page's DOM.

What if your web application want to access third party API or you want to provide API for third-party access?

Cross-Origin Resource Sharing (CORS)

CORS is a mechanism that allows access resources from one origin to another origin. This seems contradiction. How can CORS allow cross-origin requests if the same-origin policy explicitly prohibited them.? The key is that CORS put servers to decide who can make requests, what type of requests allowed and what are the custom headers allowed.

How CORS work?

The browser and the server use HTT headers to communicate how cross-origin requests behave.Using the response headers, the server can indicate which clients can access the API , which HTTP methods or HTTP
headers are allowed, and whether cookies are allowed in the request.

CORS is basically build around following headers.
  1. The Origin request header (Normally added by the browser)
  2. The Access-Control-Allow-Origin response header
These headers must be present on every successful CORS request. Without one or the other, the CORS request will fail.

1.Simple cross-site request 

A simple cross-site request is one that meets all the following conditions:

1. Allowed http methods
  •  GET
  •  HEAD
  •  POST
2. Allowed values for the Content-Type header of POST request
  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain
for eg: Suppose you have a website that running on http://localhost:8080 needs to get some data from CORS-enabled REST API hosted in http://example.com. Then if you observe the request in browser(in this example chrome) you would see following.

General
Request URL: http://example.com/get/posts
Request Method: GET
Status Code: 200 OK

Request Headers
Origin: http:/localhost:8080

Response Headers
Access-Control-Allow-Origin: http:/localhost:8080

Note: Origin Header will be added by browser automatically and 
Access-Control-Allow-Origin should be added by server.

2. Preflight requests

There are some cases where the Access-Control-Allow-Origin header alone is not enough. Certain types of requests , such as DELETE and PUT, need to go a step further and ask for the sever's permission before making the actual request. This is called "preflight" request.
The preflight request is a small request(OPTIONS)  that sent by browser before the actual request. It contains information like which HTTP method is used, any HTTP headers are available.It gives the server a chance to examine what the actual request look like.Then server can decide whether the browser should send the actual request or return an error without sending the actual response.

In particular, a request is preflighted if

1.It uses methods other than GET, HEAD or POST.  Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
2.It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER

for eg: Suppose you need to send POST request with Content-Type application/xml to CORS-enabled http://example.com/add/post from http://localhost:8080. Then you would see two request as follows.

1. Preflight request

General
Request URL: http://example.com/add/post
Request Method: OPTIONS
Status Code: 204 OK

Request Headers
Origin: http:/localhost:8080
Access-Control-Request-Method: POST
Content-Type: application/xml

Response Headers
Access-Control-Allow-Origin: http:/localhost:8080
Access-Control-Allow-Methods: POST

2. Actual request

If preflight request success this would be normal POST request.


HTTP OPTIONS method

The HTTP spec ( RFC2616 ) defines an OPTIONS request as “a request for information about the communication options available on the request/response chain.” This means that even before CORS , clients could use the OPTIONS method to learn more about an endpoint. When used out-side of CORS , the OPTIONS method traditionally conveys which HTTP methods are
supported on a particular URL .

Handle Preflight request in WSO2 ESB

Add a filter to handle "OPTIONS" request and add required headers as in following configurations.

<filter source="get-property('axis2', 'HTTP_METHOD')" regex="OPTIONS">
            <then>
               <property name="Access-Control-Request-Headers" value="authorization,content-type" scope="transport"/>
               <property name="Access-Control-Allow-Headers" value="authorization,Access-Control-Allow-Origin,Content-Type,X-Requested-With,Accept" scope="transport"/>
               <property name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" scope="transport"/>
               <property name="Access-Control-Allow-Origin" value="*" scope="transport"/>
               <property name="RESPONSE" value="true" scope="default" type="STRING"/>
               <respond/>
            </then>
         </filter>

Tuesday, August 9, 2016

Start Service on Boot Ubuntu

In this example we are going to learn how to start tomcat on system startup.

1. Add following shell script to /etc/init.d/tomcat

### BEGIN INIT INFO
# Provides:        solr
# Required-Start:  $network
# Required-Stop:   $network
# Default-Start:   2 3 4 5
# Default-Stop:    0 1 6
# Short-Description: Start/Stop solr server
### END INIT INFO


PATH=/sbin:/bin:/usr/sbin:/usr/bin

start() {
   sh  /opt/apache-tomcat-8.0.36/bin/startup.sh
}

stop() {
    sh /opt/apache-tomcat-8.0.36/bin/shutdown.sh
}

case $1 in
  start|stop) $1;;
  restart) stop; start;;
  *) echo "Run as $0 <start|stop|restart>"; exit 1;;
esac



2. Make the script executable

  
 sudo chmod +x /etc/init.d/tomcat


3. List all the service and find your service in the list
   
service --status-all
 The services that have a [+] - (service name) will start on boot.  The ones with [-] - (service name) will not start on boot.

4. Starting a server

service tomcat start

5. Add service to automatic startup
  
sudo update-rc.d tomcat defaults

5. Remove service from automatic startup

sudo update-rc.d -f tomcat remove
 rm /etc/rc*/*tomcat
6. Ubuntu startup log can be found in following location

/var/log/boot.log

References:

https://wiki.debian.org/LSBInitScripts 
http://www.jcgonzalez.com/linux-java-service-wrapper-example

Thursday, July 7, 2016

Configure Solr Data Import Handler with Neo4j

Overview

This article explain how solr can be configured to fetch data from neo4j database.

Install "movie" sample database in neo4j (3.0.1)

  1. Click "Favourite" icon (star mark)
  2. Click on "Movie Graph" under "Example Graphs"
  3. Run the automatically generated query ":play movie-graph"
  4. Follow the instruction and create the database 

Configuring Solr (6.0.0)

Create a core

You would need to create a core in order to be able to index and search.
To create a core use following command
     solr create -c <name>
     i.e. solr create -c Movie -d  basic_configs

Note that new folder will create as /solr-6.0.0/server/solr/Movie . And solr interface would look like below.

Import solr-dataimporthandler jars 

Add following entry to /solr-6.0.0/server/solr/Movie/conf/solrconfig.xml

<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-dataimporthandler-.*\.jar" /> 

Configure dataImportHandler as a requestHandler

Add following entry to /solr-6.0.0/server/solr/Movie/conf/solrconfig.xml
 
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
    <lst name="defaults">
      <str name="config">db-data-config.xml</str>
    </lst>
  </requestHandler>

Note: db-data-config.xml is responsible for data import handler configurations.

db-data-config.xml configurations

Create db-data-config.xml in /solr-6.0.0/server/solr/Movie/conf/ and add following content


<dataConfig>
    <dataSource driver="org.neo4j.jdbc.Driver" url="jdbc:neo4j://localhost:7474" user="neo4j" password="rahal" />
    <document>
        <entity name="movie"
            query="MATCH (n:Movie) RETURN n.tagline AS tagline, n.title as title, n.released as released">
            <field column="tagline" name="Tagline" />
            <field column="title" name="Title" />
            <field column="released" name="Released" />
           
        </entity>
    </document>
</dataConfig>

Modify the managed-schema file

Add following fields to the /solr-6.0.0/server/solr/Movie/conf/managed-schema

    <uniqueKey>Title</uniqueKey>
    <field name="Tagline" type="string" indexed="true" stored="true"/>
    <field name="Title" type="string" indexed="true" stored="true"/>
    <field name="Released" type="string" indexed="true" stored="true"/>

Remove below two line segments

<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />

<uniqueKey>id</uniqueKey>

Add Neo4j JDBC and dependencies

Get neo4j jdbc and it's dependencies using following maven config.

  <dependencies>
     <dependency>
            <groupId>org.neo4j</groupId>
              <artifactId>neo4j-jdbc</artifactId>
              <version>2.0.0-M06</version>
      </dependency>
  </dependencies>
 
  <repositories>
        <repository>
          <id>neo4j-public</id>
          <url>http://m2.neo4j.org/content/groups/public</url>
        </repository>
    </repositories>

You can find required dependencies using eclipse IDE and by creating a maven project using above maven config.




So following are the required jars.
  1. httpclient-4.3.2.jar
  2. httpcore-4.3.1.jar
  3. httpmime-4.3.jar
  4. jackson-core-asl-1.9.12.jar
  5. jackson-mapper-asl-1.9.12.jar
  6. neo4j-cypher-dsl-1.9.RC2.jar
  7. neo4j-jdbc-2.0.0-M06.jar
  8. org.restlet-2.2.2.jar
  9. org.restlet.ext.httpclient-2.2.2.jar

Importing the data

Use solr interface to import data as follows