Friday, September 16, 2016

Writing Custom Handler..

How to write custom handler for API Manager 1.10.0  from the scratch 


Users need to provide OAuth2 bearer token to invoke APIs under an application. Its the default authentication mechanism provided by WSO2 API Manager. But we can extend it to support any of the authentication mechanism other than the bearer token authentication.

In this post i'm going to explain  how you can write a custom handler and How to apply it to the API Manager 1.10.0

First we need to create a new maven project from java IDE. For this article i am using eclipse since it is my favorite IDE.
  • Open eclipse and create new project and choose new maven project in wizard, you can give any artifactId and groupId as you prefer.

  • For my project i'm giving Artifact Id and group Id as following for this as i mentioned above  you can give any name  




  • We can write our own authentication handler class by extending 'org.apache.synapse.rest.AbstractHandler' class

 package com.wso2.CustomHeader.CustomeHandler;  
 import org.apache.synapse.MessageContext;  
 import org.apache.synapse.core.axis2.Axis2MessageContext;  
 import org.apache.synapse.rest.AbstractHandler;  
 import java.util.Map;  
 public class CustomAPIAuthenticationHandler extends AbstractHandler{  
  public boolean handleRequest(MessageContext messageContext) {  
     try {  
       if (authenticate(messageContext)) {  
         return true;  
       }  
     } catch (Exception e) {  
       e.printStackTrace();  
     }  
     return false;  
   }  
   public boolean handleResponse(MessageContext messageContext) {  
     return true;   
   }  
   public boolean authenticate(MessageContext synCtx) {  
     Map headers = getTransportHeaders(synCtx);  
     String authHeader = getAuthorizationHeader(headers);  
     if (authHeader.startsWith("userName")) {  
       return true;  
     }  
     return false;  
   }  
   private String getAuthorizationHeader(Map headers) {  
     return (String) headers.get("Authorization");  
   }  
   private Map getTransportHeaders(MessageContext messageContext) {  
     return (Map) ((Axis2MessageContext) messageContext).getAxis2MessageContext().  
         getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);  
   }  
 }  

  • Here i attached my working .pom file

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.wso2.CustomHeader</groupId>  
  <artifactId>CustomeHandler</artifactId>  
  <version>0.0.1-SNAPSHOT</version>  
  <packaging>jar</packaging>  
  <repositories>  
     <repository>  
       <id>wso2-nexus</id>  
       <name>WSO2 internal Repository</name>  
       <url>  
         http://maven.wso2.org/nexus/content/groups/wso2-public/  
       </url>  
       <releases>  
         <enabled>true</enabled>  
         <updatePolicy>daily</updatePolicy>  
         <checksumPolicy>fail</checksumPolicy>  
       </releases>  
     </repository>  
   </repositories>  
  <name>CustomeHandler</name>  
  <url>http://maven.apache.org</url>  
  <dependencies>  
   <dependency>  
    <groupId>junit</groupId>  
    <artifactId>junit</artifactId>  
    <version>3.8.1</version>  
    <scope>test</scope>  
   </dependency>  
   <dependency>  
       <groupId>org.wso2.carbon</groupId>  
       <artifactId>org.wso2.carbon.core</artifactId>  
       <version>4.4.3</version>  
     </dependency>  
     <dependency>  
       <groupId>org.apache.synapse</groupId>  
       <artifactId>synapse-core</artifactId>  
       <version>${synapse.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.wso2.carbon.mediation</groupId>  
       <artifactId>org.wso2.carbon.mediation.registry</artifactId>  
       <version>${carbon.mediation.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>com.googlecode.json-simple.wso2</groupId>  
       <artifactId>json-simple</artifactId>  
       <version>${googlecode.json-simple.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.wso2.carbon.apimgt</groupId>  
       <artifactId>org.wso2.carbon.apimgt.impl</artifactId>  
       <version>${api.mgt.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>io.swagger</groupId>  
       <artifactId>swagger-parser</artifactId>  
       <version>${swagger.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.wso2.carbon</groupId>  
       <artifactId>org.wso2.carbon.logging</artifactId>  
       <version>4.4.3</version>  
     </dependency>  
     <dependency>  
       <groupId>com.fasterxml.jackson.core</groupId>  
       <artifactId>jackson-annotations</artifactId>  
       <version>2.7.2</version>  
     </dependency>  
     <dependency>  
       <groupId>com.fasterxml.jackson.core</groupId>  
       <artifactId>jackson-core</artifactId>  
       <version>2.7.2</version>  
     </dependency>  
     <dependency>  
       <groupId>com.fasterxml.jackson.core</groupId>  
       <artifactId>jackson-databind</artifactId>  
       <version>2.7.2</version>  
     </dependency>  
  </dependencies>  
  <properties>  
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
   <!-- Misc Versions -->  
     <synapse.version>2.1.5-wso2v2</synapse.version>  
     <carbon.mediation.version>4.5.1</carbon.mediation.version>  
     <swagger.version>1.0.17</swagger.version>  
     <api.mgt.version>5.0.3</api.mgt.version>  
     <googlecode.json-simple.version>1.1.wso2v1</googlecode.json-simple.version>  
     <javax.xml.stream.imp.pkg.version>[1.0.1, 1.1.0)</javax.xml.stream.imp.pkg.version>  
     <axis2.osgi.version.range>[1.6.1.wso2v11, 1.7.0)</axis2.osgi.version.range>  
     <axiom.osgi.version.range>[1.2.11.wso2v6, 1.3.0)</axiom.osgi.version.range>  
     <carbon.platform.package.import.version.range>[4.4.1, 4.5.0)  
     </carbon.platform.package.import.version.range>  
     <carbon.registry.imp.pkg.version>[1.0.1, 2.0.0)</carbon.registry.imp.pkg.version>  
     <carbon.apimgt.imp.pkg.version>[5.0.0, 6.0.0)</carbon.apimgt.imp.pkg.version>  
     <javax.xml.soap.imp.pkg.version>[1.0.0, 1.1.0)</javax.xml.soap.imp.pkg.version>  
     <imp.pkg.version.axis2>[1.6.1.wso2v14, 1.7.0)</imp.pkg.version.axis2>  
     <imp.pkg.version.carbon.throttle>[4.2.1, 4.3.0)</imp.pkg.version.carbon.throttle>  
     <imp.pkg.version.carbon.base>[1.0.0, 1.1.0)</imp.pkg.version.carbon.base>  
     <carbon.mediation.imp.pkg.version>[4.0.0, 5.0.0)</carbon.mediation.imp.pkg.version>  
     <imp.pkg.version.org.wso2.carbon.base>[1.0.0, 1.1.0)</imp.pkg.version.org.wso2.carbon.base>  
     <imp.pkg.version.org.wso2.carbon.user.api>[1.0.1, 1.2.0)  
     </imp.pkg.version.org.wso2.carbon.user.api>  
     <imp.pkg.version.axiom>[1.2.11.wso2v6, 1.3.0)</imp.pkg.version.axiom>  
     <carbon.identity.imp.pkg.version>[5.0.0, 6.0.0)</carbon.identity.imp.pkg.version>  
  </properties>  
   <build>  
     <plugins>  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-compiler-plugin</artifactId>  
         <version>2.0</version>  
         <configuration>  
           <encoding>UTF-8</encoding>  
           <source>1.7</source>  
           <target>1.7</target>  
         </configuration>  
       </plugin>  
       <!--  <plugin>  
           <groupId>org.apache.axis2</groupId>  
           <artifactId>axis2-java2wsdl-maven-plugin</artifactId>  
           <executions>  
             <execution>  
               <goals>  
                 <goal>java2wsdl</goal>  
               </goals>  
             </execution>  
           </executions>  
           <configuration>  
             <className>  
               org.wso2.carbon.apimgt.gateway.service.APIGatewayAdmin  
             </className>  
           </configuration>  
         </plugin>-->  
       <plugin>  
         <groupId>org.apache.felix</groupId>  
         <artifactId>maven-scr-plugin</artifactId>  
         <version>1.7.2</version>  
         <executions>  
           <execution>  
             <id>generate-scr-scrdescriptor</id>  
             <goals>  
               <goal>scr</goal>  
             </goals>  
           </execution>  
         </executions>  
       </plugin>  
       <plugin>  
         <groupId>org.apache.felix</groupId>  
         <artifactId>maven-bundle-plugin</artifactId>  
         <version>1.4.0</version>  
         <extensions>true</extensions>  
         <configuration>  
           <instructions>  
             <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>  
             <Bundle-Name>${project.artifactId}</Bundle-Name>  
             <Private-Package></Private-Package>  
             <Export-Package>  
               com.wso2.header.handler.*;version="${project.version}"  
             </Export-Package>  
             <Import-Package>  
               !com.wso2.header.handler.*;version="${project.version}",  
               javax.cache,  
               javax.naming,  
               javax.sql,  
               javax.xml.*;version="0.0.0",  
               org.slf4j,  
               org.w3c.dom,  
               org.xml.sax,  
               org.wso2.carbon.apimgt.api.*;version="${carbon.apimgt.imp.pkg.version}",  
               org.wso2.carbon.apimgt.api.model.xsd;version="${carbon.apimgt.imp.pkg.version}",  
               org.eclipse.equinox.http.helper,  
               com.google.gson,  
               org.apache.axis2.*; version="${imp.pkg.version.axis2}",  
               org.apache.commons.*,  
               org.apache.synapse.*,  
               org.osgi.service.*,  
               org.apache.commons.logging,  
               org.apache.axiom.*; version="${imp.pkg.version.axiom}",  
               org.wso2.carbon.utils;  
               version="${carbon.platform.package.import.version.range}",  
               org.wso2.carbon.registry.core.*;  
               version="${carbon.registry.imp.pkg.version}",  
               org.wso2.carbon.utils.*;  
               version="${carbon.platform.package.import.version.range}",  
               org.wso2.carbon.context;version="${carbon.platform.package.import.version.range}",  
               org.wso2.carbon.user.core.*;version="${carbon.platform.package.import.version.range}",  
               org.wso2.carbon.user.api;version="${imp.pkg.version.org.wso2.carbon.user.api}",  
               org.wso2.carbon.um.ws.api.stub,  
               org.wso2.carbon.registry.*;version="${carbon.registry.imp.pkg.version}",  
               org.apache.axis2.rpc.receivers; version="${axis2.osgi.version.range}",  
               org.apache.axiom.*; version="${axiom.osgi.version.range}",  
               org.apache.axis2; version="${axis2.osgi.version.range}",  
               org.apache.axis2.description; version="${axis2.osgi.version.range}",  
               org.apache.axis2.engine; version="${axis2.osgi.version.range}",  
               org.apache.axis2.rpc.receivers; version="${axis2.osgi.version.range}",  
               org.apache.axis2.context; version="${axis2.osgi.version.range}",  
               org.apache.axis2.transport.base,  
               org.wso2.carbon.core;  
               version="${carbon.platform.package.import.version.range}",  
               org.wso2.carbon.registry.core.service;  
               version="${carbon.registry.imp.pkg.version}",  
               org.wso2.carbon.registry.api;  
               version="${carbon.registry.imp.pkg.version}",  
               org.wso2.carbon.apimgt.impl.*;  
               version="${carbon.apimgt.imp.pkg.version}",  
               javax.xml.soap; version="${javax.xml.soap.imp.pkg.version}",  
               org.wso2.carbon.apimgt.api.*;  
               version="${carbon.apimgt.imp.pkg.version}",  
               org.apache.axis2.*; version="${imp.pkg.version.axis2}",  
               javax.cache,  
               javax.net.ssl,  
               javax.xml.namespace,  
               org.apache.commons.*,  
               org.apache.synapse.*,  
               org.wso2.carbon.registry.core.*;  
               version="${carbon.registry.imp.pkg.version}",  
               org.wso2.carbon.utils;  
               version="${carbon.platform.package.import.version.range}",  
               org.osgi.service.component,  
               org.slf4j,  
               org.wso2.carbon.apimgt.keymgt.stub.validator;  
               version="${carbon.apimgt.imp.pkg.version}",  
               org.wso2.carbon.sequences.stub.types,  
               org.wso2.carbon.context,  
               *;resolution:=optional  
             </Import-Package>  
             <DynamicImport-Package>*</DynamicImport-Package>  
           </instructions>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  
 </project>  

Build Solution if it is successfully build you can see the .jar file on target folder like following

Then you have to copy this jar file to <AM_HOME>/repository/components/lib  folder where <AM_HOME> is the root of the WSO2 API Manager distribution

You have to put the Jars correspond to external dependencies into classpath in order to make them available in the OSGI repository. For that you can copy those to libs directory.

Following articles will show you how to add external jar libraries to wso2 carbon based products[1],[2].

[2]Adding External Libraries


Engaging the custom handler


You can engage a custom handler to all APIs at once or only to selected APIs.
here i used first method engage custom handler to all APIs, so to do this we have to add following modification to velocity_template.xml file which is located on following path  <APIM_HOME>/repository/resources/api_templates/velocity_template.xml 

 <handlers>  
    <!-- <handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">  
      <property name="inline" value="INLINE"/>  
    </handler> -->  
   <handler class="com.wso2.CustomHeader.CustomeHandler.CustomAPIAuthenticationHandler" />  
     #foreach($handler in $handlers)  
      #if(!($handler.className == "com.wso2.CustomHeader.CustomeHandler.CustomAPIAuthenticationHandler"))  
       <handler xmlns="http://ws.apache.org/ns/synapse" class="$handler.className">  
       #if($handler.hasProperties())  
         #set ($map = $handler.getProperties() )  
         #foreach($property in $map.entrySet())  
           <property name="$!property.key" value="$!property.value"/>  
         #end  
       #end  
       </handler>  
      #end  
     #end  
 </handlers>  
However, please note that these changes to velocity_template.xml won't have an effect on already published APIs. So your custom authentication handler will not be engaged in already published APIs, unless you republish them. To engage it with already published APIs, you need to republish those APIs.
  • Login to publisher
  • Select your API and click on Lifecycle tab
  • Change the State to CREATED and click Update
  • Again change the State to PUBLISHED and click Update

Please find sample code here...

Thanks

0 comments:

Post a Comment