Sunday, June 1, 2014

How to configure LDAP with WSO2 Identity Server with SCIM support - The easy way

If you want to setup your user store in a LDAP and want to integrate it with WSO2 Identity Server which support SCIM operations, you need to do claim mapping as described in this post http://sureshatt.blogspot.com/2013/06/scim-user-provisioning-with-wso2.html. But if you are going to support lot of user attributes in your user store and complex user operations with SCIM, this mapping and configuration will be a headache for you.

Thus I will show you a easy way to setup your own LDAP and WSO2 Identity Server to support all these. I am using the configurations in built in LDAP of WSO2 Identity Server.

What you need,
As  you know the attributes assigned to LDAP users are defined in object classes of LDAP. If you want to add more attributes, You need to add your own object classes. You can find mroe details about those in these articles,

http://hasini-gunasinghe.blogspot.com/2011/02/how-to-introduce-custom-attributes-to.html
http://hasini-gunasinghe.blogspot.com/2011/04/how-to-introduce-custom-object-class-to.html

After adding these classes you need do lot of mapping to integrate LDAP with SCIM and other complex operation support in WSO2 Identity Server. Believe me its hectic. So what we can do? What we can do is setting up our LDAP with the built in LDAP object classes of WSO2 Identity Server. Those classes define the necessary attributes to support complex operation like SCIM etc. You can find these classes here,
You can import to these classes to your ApacheDS LDAP using  Apache Directory Studio. In the 'LDAP Browser' window in Apache Directory Studio, Right click on the 'ou=schema' context entry, select 'Import->LDIF Import' and point to above files and import them.After that your LDAP will support all the user attributes as we see in built in LDAP of WSO2 Identity Server.

After that integrate the LDAP to WSO2 Identity Server by changing user-mgt.xml in WSO2 Identity Server Home/repository/conf. You have to use the read-write ldap mode like this,

        <UserStoreManager class="org.wso2.carbon.user.core.ldap.ReadWriteLDAPUserStoreManager">
            <Property name="TenantManager">org.wso2.carbon.user.core.tenant.CommonHybridLDAPTenantManager</Property>
            <Property name="ConnectionURL">ldap://IP:10389</Property>
            <Property name="Disabled">false</Property>                       
            <Property name="ConnectionName">uid=admin,ou=system</Property>
            <Property name="ConnectionPassword">your_password</Property>
            <Property name="passwordHashMethod">PLAIN_TEXT</Property>
            <Property name="UserNameListFilter">(objectClass=person)</Property>
            <Property name="UserEntryObjectClass">identityPerson</Property>
            <Property name="UserSearchBase">ou=Users,dc=example,dc=com</Property>
            <Property name="UserNameSearchFilter">(&amp;(objectClass=person)(uid=?))</Property>
            <Property name="UserNameAttribute">uid</Property>
            <Property name="UsernameJavaRegEx">[a-zA-Z0-9._-|//]{3,30}$</Property>
            <Property name="UsernameJavaScriptRegEx">^[\S]{3,30}$</Property>
            <Property name="RolenameJavaScriptRegEx">^[\S]{3,30}$</Property>
            <Property name="RolenameJavaRegEx">[a-zA-Z0-9._-|//]{3,30}$</Property>
            <Property name="PasswordJavaScriptRegEx">^[\S]{5,30}$</Property>
            <Property name="ReadGroups">true</Property>
            <Property name="WriteGroups">true</Property>
            <Property name="EmptyRolesAllowed">false</Property>
            <Property name="GroupSearchBase">ou=Groups,dc=example,dc=com</Property>
            <Property name="GroupNameListFilter">(objectClass=groupOfNames)</Property>
            <Property name="GroupEntryObjectClass">groupOfNames</Property>
            <Property name="GroupNameSearchFilter">(&amp;(objectClass=groupOfNames)(cn=? </Property>
            <Property name="GroupNameAttribute">cn</Property>
            <Property name="SharedGroupNameAttribute">cn</Property>
            <Property name="SharedGroupSearchBase">ou=SharedGroups,dc=example,dc=com</Property>
            <Property name="SharedGroupEntryObjectClass">groupOfNames</Property>
            <Property name="SharedGroupNameListFilter">(objectClass=groupOfNames)</Property>
            <Property name="SharedGroupNameSearchFilter">(&amp;(objectClass=groupOfNames)(cn=?))</Property>
            <Property name="SharedTenantNameListFilter">(objectClass=organizationalUnit)</Property>
            <Property name="SharedTenantNameAttribute">ou</Property>
            <Property name="SharedTenantObjectClass">organizationalUnit</Property>
            <Property name="MembershipAttribute">member</Property>
            <Property name="UserRolesCacheEnabled">true</Property>
            <Property name="ReplaceEscapeCharactersAtUserLogin">true</Property>
            <Property name="MaxRoleNameListLength">100</Property>
            <Property name="MaxUserNameListLength">100</Property>
            <Property name="SCIMEnabled">true</Property>
        </UserStoreManager>



Also you need to create a admin user in your user search base. That is to log in to the management console. To understand more about the internal LDAP of WSO2 Identity Server you can connect to it via Apache Directory Studio. You can refer,

http://stackoverflow.com/questions/22494921/wso2-identity-server-ldap-browsing
http://stackoverflow.com/questions/11841761/browsing-internal-ldap-of-wso2-identity-server

Hope this helps you to setup your user store easily.

How to send a custom HTTP header to backend through WSO2 API Manager

When you publish a API using WSO2 API Manager it creates this kind of API configuration in built in service bus.

<api name="admin--Example_Rest_API" context="/exampleAPI" version="1.0.0" version-type="url">
        <resource methods="POST GET DELETE OPTIONS PUT" url-mapping="/*">
            <inSequence>
                <property name="POST_TO_URI" value="true" scope="axis2"/>
                <filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
                    <then>
                        <send>
                            <endpoint name="admin--Emojot_Rest_API_APIproductionEndpoint_0">
                                <http uri-template="http://localhost:3000">
                                    <timeout>
                                        <duration>30000</duration>
                                        <responseAction>fault</responseAction>
                                    </timeout>
                                    <suspendOnFailure>
                                        <errorCodes>-1</errorCodes>
                                        <initialDuration>0</initialDuration>
                                        <progressionFactor>1.0</progressionFactor>
                                        <maximumDuration>0</maximumDuration>
                                    </suspendOnFailure>
                                    <markForSuspension>
                                        <errorCodes>-1</errorCodes>
                                    </markForSuspension>
                                </http>
                            </endpoint>
                        </send>
                    </then>
                    <else>
                        <sequence key="_sandbox_key_error_"/>
                    </else>
                </filter>
            </inSequence>
            <outSequence>                
                <send/>
            </outSequence>
        </resource>
        <handlers>
            <handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>
            <handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.APIThrottleHandler">
                <property name="id" value="A"/>
                <property name="policyKey" value="gov:/apimgt/applicationdata/tiers.xml"/>
            </handler>
            <handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtUsageHandler"/>
            <handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtGoogleAnalyticsTrackingHandler"/>
            <handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
        </handlers>
    </api>

When you want to send a custom HTTP header in the API request, you need to add this property to the out sequence of API. customHeader is the name of the header.

 <property name="Access-Control-Allow-Headers" value="customHeader,authorization,Access-Control-Allow-Origin,Content-Type" scope="transport"/>

               

Monday, July 15, 2013

Communicating with WSO2 CEP through Thrift in NodeJS + JAVA

In our  final year research project we use WSO2 CEP to analyze complex event coming through a JSON stream. That JSON stream is coming form a NodeJS application. In this article I am describing how to send the JSON stream to WSO2 CEP using Thrift.

Initially I have developed a JAVA Thrift client to send JSON events to WSO2 CEP. That can be found in here https://github.com/andunslg/Sith/tree/master/SithCEPPublisher.

SithCEPPublisher is the main communicator class,
package org.sith.cep.publisher;

import org.sith.cep.publisher.config.SithPerceptionPublisherStreamConfig;
import org.sith.cep.publisher.config.StreamConfig;
import org.wso2.carbon.databridge.agent.thrift.DataPublisher;
import org.wso2.carbon.databridge.agent.thrift.exception.AgentException;
import org.wso2.carbon.databridge.commons.exception.*;
import java.net.MalformedURLException;

public class SithCEPPublisher{

    private DataPublisher dataPublisher;
    private StreamConfig streamConfig;

    public SithCEPPublisher(String url, String userName, String password){

        //KeyStoreUtil.setTrustStoreParams();
        System.setProperty("javax.net.ssl.trustStore","wso2carbon.jks");
        System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");

        System.out.println("Key Store is set..");
        //according to the convention the authentication port will be 7611+100= 7711 and its host will be the same

        try{
            dataPublisher = new DataPublisher(url, userName, password);
        }catch(MalformedURLException e){
            e.printStackTrace();
        }catch(AgentException e){
            e.printStackTrace();
        }catch(AuthenticationException e){
            e.printStackTrace();
        }catch(TransportException e){
            e.printStackTrace();
        }

        System.out.println("Logged in..");        
        this.streamConfig=new SithPerceptionPublisherStreamConfig();
        System.out.println("Default Stream Config Added..");
    }

    public SithCEPPublisher(String url, String userName, String password,String streamName, String streamVersion, String streamDefinition){

        //KeyStoreUtil.setTrustStoreParams();
        System.setProperty("javax.net.ssl.trustStore","wso2carbon.jks");
        System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");

        System.out.println("Key Store is set..");
        //according to the convention the authentication port will be 7611+100= 7711 and its host will be the same

        try{
            dataPublisher = new DataPublisher(url, userName, password);
        }catch(MalformedURLException e){
            e.printStackTrace();
        }catch(AgentException e){
            e.printStackTrace();
        }catch(AuthenticationException e){
            e.printStackTrace();
        }catch(TransportException e){
            e.printStackTrace();
        }

        System.out.println("Logged in..");

        this.streamConfig=new StreamConfig(streamName,streamVersion,streamDefinition);
        System.out.println("Stream Config Added..");
    }

    public String publishToCEP(Object[] metaDataArray,Object[] payloadArray) {

        System.out.println("Starting publishing process..");
        String streamId;

        try {
            streamId = dataPublisher.findStream(streamConfig.getStreamName(), streamConfig.getStreamVersion());
        } catch (NoStreamDefinitionExistException e) {
            try{
                streamId = dataPublisher.defineStream(streamConfig.getStreamDefinition());
                System.out.println("Stream Definition created..");
            }catch(AgentException e1){
                e1.printStackTrace();
                return "Failed";
            }catch(MalformedStreamDefinitionException e1){
                e1.printStackTrace();
                return "Failed";
            }catch(StreamDefinitionException e1){
                e1.printStackTrace();
                return "Failed";
            }catch(DifferentStreamDefinitionAlreadyDefinedException e1){
                e1.printStackTrace();
                return "Failed";
            }

        }catch(StreamDefinitionException e){
            e.printStackTrace();
            return "Failed";
        }catch(AgentException e){
            e.printStackTrace();
            return "Failed";
        }

        System.out.println("Stream created..");

        try{
            //dataPublisher.publish(streamId, new Object[]{ipAddress}, null, new Object[]{eventID, userID, percetionValue});
            dataPublisher.publish(streamId, metaDataArray, null, payloadArray);
        }catch(AgentException e){
            e.printStackTrace();
            return "Failed";
        }
        System.out.println("Data published..");
        return "Done";
    }
}
The I have two configuration classes,

StreamConfig class which has the configuration of JSON stream,
package org.sith.cep.publisher.config;

public class StreamConfig{

    private String streamName;
    private String streamVersion;
    private String streamDefinition;

    public StreamConfig(String streamName, String streamVersion, String streamDefinition){
        this.streamName=streamName;
        this.streamVersion=streamVersion;
        this.streamDefinition=streamDefinition;
    }

    public String getStreamName(){
        return streamName;
    }

    public void setStreamName(String streamName){
        this.streamName=streamName;
    }

    public String getStreamVersion(){
        return streamVersion;
    }

    public void setStreamVersion(String streamVersion){
        this.streamVersion=streamVersion;
    }

    public String getStreamDefinition(){
        return streamDefinition;
    }

    public void setStreamDefinition(String streamDefinition){
        this.streamDefinition=streamDefinition;
    }
}


SithPerceptionPublisherStreamConfig class which holds the stream definition,

package org.sith.cep.publisher.config;

public class SithPerceptionPublisherStreamConfig extends StreamConfig{
    private static String sithPerceptionStreamName="sith_Perception_Analytic";
    private static String sithPerceptionStreamVersion="1.0.0";
    private static String sithPerceptionStreamDefinition=

                    "{"+
                    "    'name':'sith_Perception_Analytics',"+
                    "    'version':'1.0.0',"+
                    "    'nickName': 'Sith Analytics',"+
                    "    'description': 'Sith_Perception_Analytics',"+
                    "    'metaData':["+
                    "        {"+
                    "            'name':'ipAdd','type':'STRING'\n"+
                    "        }"+
                    "    ],"+
                    "    'payloadData':["+
                    "        {"+
                    "            'name':'eventID','type':'STRING'"+
                    "        },"+
                    "        {"+
                    "            'name':'userID','type':'STRING'"+
                    "        },"+
                    "        {"+
                    "            'name':'perceptionValue','type':'STRING'"+
                    "        },"+
                    "        {"+
                    "            'name':'comment','type':'STRING'"+
                    "        }"+
                    "    ]"+
                    "}";

    public SithPerceptionPublisherStreamConfig(){
        super(sithPerceptionStreamName,sithPerceptionStreamVersion,sithPerceptionStreamDefinition);
    }

}

Then what I have did was invoking this JAVA code using nodejs application. To do that I have used this nodejs module which provides cross language integration. https://github.com/nearinfinity/node-java. The node JS appication is given below,
exports.publishComment = function(req,res){
    percepManager.publishToCEP(req.body.userID , req.body.eventID , req.body.perceptionValue,req.body.text);
    res.writeHead(200, {'Content-Type': 'application/json'});
      var result = JSON.stringify({response: true });
    res.write(result);
    res.end();
}

var java = require("java");
java.classpath.push("cep-publisher-1.0.jar");
var jClass = java.newInstanceSync("org.sith.cep.publisher.SithCEPPublisher","tcp://192.248.8.246:7611","admin","apst@sith");

exports.publishToCEP = function(userID,eventID,perceptionVal,comment) {
    var metaDataArray = java.newArray("java.lang.Object", ["192.248.8.246"]);
    var payloadArray = java.newArray("java.lang.Object", [eventID,userID,perceptionVal,comment]);
    var result=jClass.publishToCEPSync(metaDataArray,payloadArray);
    console.log("Returned data - "+result);
} 
To run this application what you have to do is run npm install java and then run node app command. After that you can call this method to send the defined JSON stream to CEP.

Wednesday, April 17, 2013

How to show a Jasper report in your web page in PDF format

Jasper is a powerful tool which can be used to generate reports for several data sources. These data sources can be MySQL database, Oracle databases etc. In this article, I will show you how to give report on a MySQL database using Jasper as a PDF in your web site.

Pre - Requisites,

Following software and tools have to be in your pc,
Optional,
Say if you have a MySQL database which has the marks of a particular subject for a set of students.


If you want to give report about students marks as a chart, you can use Jasper for the task. I will show you how to give the student's marks graph as PDF in your web site using Jasper.

First task will be creating a Jasper report File(.jrxml) using iReport designer to generate the student marks chart.

Step 1 - Open iReport Designer and Click File - > New. Then select Report template and click the button Open this template.


Step 2 - Give a name to the report project and click next



Step 3 - The new report will be shown in the iReport designer. Click on the Report Datasources button and then click new button.




Step 4 - Click on the Database JDBC Connection an click next.




Step 5 - Select MySQL as JDBC driver type and enter the details for your database connection. Then click save button to go back to the report.



Step 6 - Click on the Report Query Button on the report and following UI will be shown. In that type the SQL query which you need to add to your report. I have used "select * from Marks".




Step 7 - When we typed the query, all the field will be retrieved automatically. Click the preview data button to view the data. Then click OK.




Step 8 - Drag and drop a Static TextBox from palette to the report and give title to the report. I have used "Student Marks".

Step 9 - Drag and drop a Chart from palette to the report's summary section . It will show following UI. In that select line chart.


Step 10 - In the next dialog click the edit button near the text Dummy Series to edit the name of the data series of the graph. I have used Student Marks as the data series name. An click apply and next.






Step 11 - In the next dialog click the edit button in the category expression to select the value set for the X axis of the chart.


Step 12 - In the next dialog, I have double clicked on the column name to add it as the data series for the X axis.



Step 13 - In the next dialog click the edit button in the value expression to select the value set for the Y axis of the chart. In the next dialog, I have double clicked on the column marks to add it as the data series for the Y axis. And  then click Finish.



Step 14 - Now you have completed your Jasper report. Click on the XML tab to view the jrxml file for the particular report and Preview tab to view the report.





Step 15 - Save your jrxml file in a known location. It will be needed to future steps.

Next step will be adding this report to a web page as PDF which user can view or download. For that I a going to create a web application using intelliJ IDEA. Please follow this tutorial to see how to create a web application and run it in Tomcat Server in IntelliJ IDEA. http://wiki.jetbrains.net/intellij/Creating_a_simple_Web_application_and_deploying_it_to_Tomcat.

Step 16 - Create a new Web Aplication Prject in IDEA

Step 17 - Create a new JSP file in it and name it as marksGraph.jsp.

Step 18 - Change the index.jsp as follows.


<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
  <head>
    <title></title>
  </head>
  <body>
    <a href="marksGraph.jsp">Show Students Marks Graph</a>
  </body>
</html>

Step 19- Download all these jars and add the to the lib folder inside your project - > web folder - > WEB-INF folder. Also add the jasperreports jar to the dependencies folder of your project.
Step 20 - Add the previously saved jrxml file to the web folder of your project.

Step 21 - Change the marksGraph.jsp as follows.

This code is responsible for load the jrxml file and generate the report. Also it writes the report to the web page as a PDF.

<%@ page contentType="application/pdf" %>

<%@ page trimDirectiveWhitespaces="true"%>

<%@ page import="net.sf.jasperreports.engine.*" %>
<%@ page import="java.io.File" %>
<%@ page import="java.io.FileInputStream" %>
<%@ page import="java.io.FileNotFoundException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.SQLException" %>

<%
    Connection conn=null;
     try {
        //Connecting to the MySQL database

        Class.forName("com.mysql.jdbc.Driver");
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/Students?user=root&password=12345");

        //Loading Jasper Report File from Local file system

        String jrxmlFile = session.getServletContext().getRealPath(request.getContextPath())+"/GenerateReport.jrxml";
        InputStream input = new FileInputStream(new File(jrxmlFile));

        //Generating the report

        JasperReport jasperReport = JasperCompileManager.compileReport(input);
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, null, conn);

        //Exporting the report as a PDF

        JasperExportManager.exportReportToPdfStream(jasperPrint, response.getOutputStream());

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (JRException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    finally {
        if(conn!=null){
            conn.close();
        }
    }
%>

Step 22 - Cick on the run button to run this web application in Tomcat Server.



Step 23 - The newly deployed web application will be displyed in the web page like this,



Step 24 - Click on the Show Student Marks Graph link.

Step 25 - The students marks graph will be shown as a PDF like this,




Also please note that after saving the jrxml file using iReport designer, remove all the uuid tags of each and every element. Also you can use this kind of report generation logic in any web application. I have attached the source code of my sample web app here. https://www.dropbox.com/s/d8tk1midq4tdy7e/ReportGenerationWebApp.zip Hope this tutorial helped you. Comments and questions are welcomed.

Sunday, October 14, 2012

Optimized Light Weight XPATH Parser using AXIOM and Antlr Parser Generator

If we talk about parsing a XPath expression we can use the XPath engines like Jaxen or AXIOM XPath which is built on top of AXIOM. These XPath engines supports the full specification of XPath.
But most of the time our use-case is not having the full XPath specification parsing support but a quick and optimized way of parsing XPath. Because most of the time we are parsing XPath expressions like "/data/book/name", which will point to a single element of a XML.
So If we have some-kind of fact that we want the first match of XPath or we have only one match for XPath expression, we don't need to open the full tree of XML.
For a example to parse an XPath expression like "/data/book/author/name" against following XML, we don't have to look at lecturers element at all.

  
       
   Andun
   Sri Lanka
       
  
  
       
           Mr_Thilak_Fernando
           
               108
               328
               568
           
      
      
           Ms_Pivithuru
           
               88
               328
               568
               808
               1048
           
      
      
           Mr_Nisansa
           
               88
               328
               568
               808
               1048
           
      
  
So in this post I will describe a implementation of a High Performance Custom Xpath Parser which will have following conditions,
  • Will return the first match of XPAth expression 
If we have an XPath like, "/data/book/author/name". This parser only return the <name>Andun</name> element only.

    
        
        Andun
        Sri Lanka
    
    
    
        
        Sameera
        Sri Lanka
        
    
  • Only return a single element as result. No Sets are returned. 
If we have an XPath like, "/data/book/author/name". This parser only return the <name>Andun</name> element only. While the XPath Spec defines the result of this expression is <name>Andun</name><name>Sameera</name>.

    
        
        Andun
        Sri Lanka
    
    
    
        
            
            Sameera
            Sri Lanka
            
        
    
  • Only parse absolute XPath expressions. 
This kind of XPath expression are accepted "/data/book/author/@age" while "//author/name" kind of expressions are rejected.
  • Complex XPath expression which have predicates, logical combinations of results etc. will be not be eligible.
To implement this we have used this kind of architecture on top of the AXIOM data model for a XML. Created small components which are responsible to do simple operations to AXIOM data model. For Example,
  • Component to return XML node if it matches some conditions.
  • Component to return set of children of a XML node if it matches some conditions.
  • Component to return an attribute of a XML node.
Each of these components get a OMElement as the input and it will output the result. Also we can specify some conditions to get the result. So joining these components as a chain we can get the result of a XPath expression.


Here the XML is passed to the first component. Then the result of the first component is passed to the second. Like wise the chain is created. So the result of the final component is the result of the XPath expression.
So likewise we can create a simple XPath parser. Here the advantages are, 
  • It will not have to do check the all spec of the XPath spec which is useless for most of the use-case. 
  • It don't have to traverse the all big tree of XML to get the result.
  • AXIOM will not load the XML elements to the memory which are not traversed.
So this new Custom XPath parser will do following,
  • When we give a XPath expression to the parser it will create the component chain which will do the processing to get the result of the XPath.
  • When the parsing happens, the input XML is passed though the component chain and output the result.
To create the component chain we have analyze the given XPATH expression. For that We use Antlr Parser Generator.
  • We have to check weather the given XPath expression can be evaluated using Parser.
  • If the expression can be parsed, we have to create the above dicribed component chain. 
We have used a Antlr Grammar for XPath 1.0. Using that grammar we have generated a Lexer, Parser and Walker for  XPath 1.0. When a XPath expression is given Antlr will analyze the expression using the given Grammar which we have created. Then It will generate a Abstract Syntax tree like the following,


The using this generated tree we are building the  component chain. Each node of this tree is responsible to add some JAVA code to the XPath parser. When the tree is traversed a Java class will be generated. Using that we can parse a XPath expression.
Also when this tree found a XPath expression which cant be evaluated using our Custom Parser it will throw an Exception. So we can develop a logic to catch that exception and call a XPath parser like Jaxen to do processing.
Also to further optimize the processing we can use a input stream of a XML. So AXIOM will only read the necessary part of that stream to process the XPath expression.
Following JAVA class shows the implementation of the XPath parser. Please contact me to further clarifications.

package org.wso2.carbon.custom_xpath;

import org.antlr.runtime.RecognitionException;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.impl.llom.util.AXIOMUtil;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.wso2.carbon.custom_xpath.compiler.CustomXPATHCompiler;
import org.wso2.carbon.custom_xpath.compiler.exception.CustomXPATHCompilerException;
import org.wso2.carbon.custom_xpath.exception.CustomXPATHException;
import org.wso2.carbon.custom_xpath.parser.custom.CustomParser;
import org.wso2.carbon.custom_xpath.parser.custom.components.ParserComponent;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class CustomXPATH {

    private String xPath;
    private CustomParser customParser;
    private HashMap<String,String> prefixNameSpaceMap;

    /**
     * This constructor is responsible For Create a Custom XPATH Parser Object
     * @param xPath is the XPATH String
     * @param prefixNameSpaceMap  Prefix:NameSpace Map
     * @throws CustomXPATHException
     */
    public CustomXPATH(String xPath,HashMap<String,String> prefixNameSpaceMap) throws CustomXPATHException {
        setPrefixNameSpaceMap(prefixNameSpaceMap);
        setxPath(xPath);
        try {
            setCustomParser(CustomXPATHCompiler.parse(getxPath()));
        } catch (RecognitionException e) {
            throw new CustomXPATHException(e);
        }
        catch(CustomXPATHCompilerException exception){
            //Here is the catch clause for XPath expressions which the Custom Parser cant process. So we can call A parser like Jaxen here.
        }
    }

    /**
     * This will return the XPATH expression's result when you provide a Input Stream To a XML
     * @param inputStream for a XML
     * @return  Result of the XPATH expression
     * @throws XMLStreamException
     * @throws CustomXPATHException
     */
    public  String getStringValue(InputStream inputStream) throws XMLStreamException, CustomXPATHException {
        if(customParser!=null){
            return getCustomParser().process(inputStream);
        }
        else{
            //Here the Jaxen will do the processing
        }
    }

    /**
     * This will return the XPATH expression's result when you provide a Input Stream To a XML
     * @param envelope for a XML
     * @return  Result of the XPATH expression
     * @throws XMLStreamException
     * @throws CustomXPATHException
     */
    public  String getStringValue(String envelope) throws XMLStreamException, CustomXPATHException {
        return getStringValue(new ByteArrayInputStream(envelope.getBytes()));
    }

    public String getxPath() {
        return xPath;
    }

    public void setxPath(String xPath) {
        this.xPath = xPath;
    }

    public CustomParser getCustomParser() {
        return customParser;
    }

    public void setCustomParser(CustomParser customParser) {
        this.customParser = customParser;
    }

    public HashMap<String, String> getPrefixNameSpaceMap() {
        return prefixNameSpaceMap;
    }

    public void setPrefixNameSpaceMap(HashMap<String, String> prefixNameSpaceMap) {
        this.prefixNameSpaceMap = prefixNameSpaceMap;
        ParserComponent.setPrefixNameSpaceMap(prefixNameSpaceMap);
    }

}

Tuesday, October 9, 2012

Securing an exisiting WebApp using Entitlement Servlet Filter

Entitlement Servlet Filter is for check the Authorization of the requests which are coming to a webapp. This guide will tel you how to add that to a existing web of yours. You can read more about Entitlement Servlet Filter Here.

The steps to add Entitlement Servlet Filter to your Web App :

  • Add one of J2EE Authentication Mechanism to the WebApp. (Still Entitlement Filter Support Basic Auth Only). To do this task add following to the web.xml of your WebApp.
     <security-constraint>
        <display-name>Example Security Constraint</display-name>
        <web-resource-collection>
            <web-resource-name>Protected Area</web-resource-name>
        <!-- Protected URL -->
            <url-pattern>/protected.jsp</url-pattern>
            <!-- If you list http methods, only those methods are protected -->
            <http-method>DELETE</http-method>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
            <http-method>PUT</http-method>
        </web-resource-collection>
        <auth-constraint>
            <!-- Anyone with one of the listed roles may access this area -->
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

    <!-- Default login configuration uses form-based authentication -->
    <login-config>
        <auth-method>BASIC</auth-method>
        <!--<auth-method>FORM</auth-method>-->
        <realm-name>Example Form-Based Authentication Area</realm-name>
        <form-login-config>
            <form-login-page>/protected.jsp</form-login-page>
        </form-login-config>
    </login-config>

    <!-- Security roles referenced by this web application -->
    <security-role>
        <role-name>everyone</role-name>
    </security-role>
    <security-role>
        <role-name>admin</role-name>
    </security-role>

  • Engage the Entitlement Servlet Filter. To do this task add following to the web.xml of your WebApp.
    <!-- Filter mappings used to configure URLs that need to be authorized  -->
    <filter-mapping>
        <filter-name>EntitlementFilter</filter-name>
        <url-pattern>/protected.jsp</url-pattern>
    </filter-mapping> 

  • Provide necessary parameters to the Entitlement Servlet filter. To do this task add following to the web.xml of your WebApp.
    <!-- The scope in which the subject would be available.  Legal values are basicAuth, request-param, request-attribute, session -->
    <context-param>
        <param-name>subjectScope</param-name>
        <param-value>basicAuth</param-value>
    </context-param>

    <!-- The name of the identifier by which to identify the subject -->
    <context-param>
        <param-name>subjectAttributeName</param-name>
        <param-value>username</param-value>
    </context-param>

    <!-- The username to perform EntitlementService query-->
    <context-param>
        <param-name>userName</param-name>
        <param-value>admin</param-value>
    </context-param>

    <!-- The password to perform EntitlementService query -->
    <context-param>
        <param-name>password</param-name>
        <param-value>admin</param-value>
    </context-param>

    <!-- The URL to perform EntitlementService query-->
    <context-param>
        <param-name>remoteServiceUrl</param-name>
        <param-value>https://localhost:9443/services/</param-value>
    </context-param>
    
    <!-- EntitlementFilter Settings -->
    <filter>
        <filter-name>EntitlementFilter</filter-name>
        <filter-class>org.wso2.carbon.identity.entitlement.filter.EntitlementFilter</filter-class>

        <!--Client Class that extends AbstractEntitlementServiceClient. Legal values are basicAuth, soap and thrift.
        Default is 'thrift'.-->
        <init-param>
            <param-name>client</param-name>
            <param-value>basicAuth</param-value>
        </init-param>

        <!--Decision caching at PEPProxy. Legal values are simple and carbon.-->
        <init-param>
            <param-name>cacheType</param-name>
            <param-value>simple</param-value>
        </init-param>

        <!--Maximum number of cached entries. Legal values are between 0 and 10000 -->
        <init-param>
            <param-name>maxCacheEntries</param-name>
            <param-value>1000</param-value>
        </init-param>

        <!-- Time interval for which cached entry is valid.-->
        <init-param>
            <param-name>invalidationInterval</param-name>
            <param-value>100000</param-value>
        </init-param>

        <!-- URL ro redirect to if authorization fails -->
        <init-param>
            <param-name>authRedirectUrl</param-name>
            <param-value>/index.jsp</param-value>
        </init-param>

    <!-- This will be used if the transport type is thrift. -->
        <init-param>
            <param-name>thriftHost</param-name>
            <param-value>localhost</param-value>
        </init-param>

        <!-- This will be used if the transport type is thrift.-->
        <init-param>
            <param-name>thriftPort</param-name>
            <param-value>10500</param-value>
        </init-param>

    </filter> 


So after following these steps your webApp is successfully secured with Entitlement Filter. You can find a sample project here.
Also make sure that you have to put the org.wso2.carbon.identity.entitlement.filter_4.0.2.jar, org.wso2.carbon.identity.entitlement.proxy_4.0.2  and org.wso2.carbon.identity.entitlement.stub_4.0.0.jar to your java classpath. The links for those jar is here. Also you can build those jars by using these links.

https://svn.wso2.org/repos/wso2/carbon/platform/trunk/service-stubs/org.wso2.carbon.identity.entitlement.stub/
https://svn.wso2.org/repos/wso2/carbon/platform/trunk/components/identity/org.wso2.carbon.identity.entitlement.proxy/
https://svn.wso2.org/repos/wso2/carbon/platform/trunk/components/identity/org.wso2.carbon.identity.entitlement.filter/

Saturday, October 6, 2012

Binary Relay - WSO2 ESB : One Major Feature Behind the Success

WSO2 Enterprise Service Bus have bulk of features and components which will help to have a good Enterprises Level Service Integration. The Architecture and the Components of WSO2 ESB explains that more. The Users of WSO2 ESB can have lot of flexibility in Routing Messages, Security , QoS,Monitoring etc.
When we focus about the Performance of the WSO2 ESB, I have identified a special feature which is behind. That is the Binary Relay of WSO2 ESB. In the common scenario the routing and manipulation of the messages inside WSO2 ESB happens on the details given in the Payload. But that will add a overhead to processing. So that will limit the performance, while having the flexibility of processing messages.
If we can live without this high level of flexibility of message processing we can increase the performance. That is the main fact behind the Binary Relay feature of ESB. In this mod of ESB, message payload is not touched. The routing of messages happen considering transport level headers. The incoming message will be added to a Dummy SOAP message as a Data Stream. Then the dummy message will pass through the processing pipeline of the ESB. Following diagram shows that functionality,



Also we can recreate some functionality which given in the normal mod of the ESB. Those recreated functionality will be good in performance.
These days I am working on such R&D works at WSO2. So I feels really interesting about this feature. You can read more about Binary Relay in these links,