Saturday, September 21, 2013

Plug your own programming language and get syntax highlighted on Notepad++

Lets try to understand how to plug the new programming language. I'm selecting the "Panini" as my new programming language. First we try to understand how to plug the new syntax to Notepad++. This is very easy task but its very useful for the users who is going to develop software by using this language.

1. Notepad++ expose the grate feature to define your own language. Go to Notepad++ and follow the direction.
Language->Define your Language

notepad++

notepad++-1

Here you can define the language as you wish. But most convenient way is import the language settings from out side xml file. why I'm saying that people who are new to the language they don't know how to configure this by them selves but think about this if some one can provide the configuration file then they can import it in simply.

So then I'm going to discuss the second method.

2. First you have to define the userDefineLanguage.xml file with your new syntax as follows.
[code language="xml"]
<?xml version="1.0" encoding="Windows-1252" ?>
<NotepadPlus>
<UserLang name="Panini" ext="java">
<Settings>
<Global caseIgnored="no" />
<TreatAsSymbol comment="no" commentLine="no"/>
<Prefix words1="no" words2="no" words3="yes" words4="yes"/>
</Settings>
<KeywordLists>
<Keywords name="Folder+">{</Keywords>
<Keywords name="Folder-">}</Keywords>
<Keywords name="Operators">- ( ) * , . / : ? @ [ ] + =</Keywords>
<Keywords name="Comment">//</Keywords>
<Keywords name="Words1"></Keywords>
<Keywords name="Words2"></Keywords>
<Keywords name="Words3">instanceof assert if else switch case default break goto return for while do continue new throw throws try catch finally this super extends implements import true false null</Keywords>
<Keywords name="Words4">capsule design package transient strictfp void char short int long double float const static volatile byte boolean class interface native private protected public final abstract synchronized enum</Keywords>
</KeywordLists>
<Styles>
<WordsStyle name="DEFAULT" styleID="11" fgColor="000000" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="9" />
<WordsStyle name="FOLDEROPEN" styleID="12" fgColor="808040" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="14" keywordClass="Folder+"/>
<WordsStyle name="FOLDERCLOSE" styleID="13" fgColor="808040" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="14" keywordClass="Folder-" />
<WordsStyle name="KEYWORD3" styleID="7" fgColor="0000FF" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="" keywordClass="Words3"/>
<WordsStyle name="KEYWORD4" styleID="8" fgColor="8000FF" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="" keywordClass="Words4"/>/>
<WordsStyle name="COMMENT" styleID="1" fgColor="008000" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="" keywordClass="Comment"/>
<WordsStyle name="COMMENT LINE" styleID="2" fgColor="008000" bgColor="FFFFFF" fontName="Comic Sans MS" fontStyle="0" fontSize="" keywordClass="Comment"/>
<WordsStyle name="NUMBER" styleID="4" fgColor="FF0000" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="" />
<WordsStyle name="OPERATOR" styleID="10" fgColor="804000" bgColor="FFFFFF" fontName="" fontStyle="1" fontSize="" />
</Styles>
</UserLang>
</NotepadPlus>

[/code]

In above xml structure there is Keyword list as well as Styles as it is you can define the new keyword and colors. Once you complete your keywords you can import the file and restart the Notepad++ then you can see "Panini" Language is available in the language list as follows.

notepad++-2

3. Create new file and select "Panini" as the language. then feel the "Panini" syntax highlighting feature.

notepad++-3

Thursday, September 12, 2013

Volatile Vs Static in JAVA

Static Variable: If two Threads(suppose Thread 1 and Thread 2) are accessing the same object and updating a variable which is declared as static then it means Thread 1 and Thread 2 can make their own local copy of the same object(including static variables) in their respective cache, so updating by Thread 1 to the static variable in its local cache wont reflect in the static variable for Thread 2 cache . Static variables are used in the Object Context where updating by one object would reflect in all the other objects of the same class but not in the Thread context where updating of one thread to the static variable will reflect the changes immediately to all the threads (in their local cache).

Volatile variable: If two Threads(suppose Thread 1 and Thread 2) are accessing the same object and updating a variable which is declared as volatile then it means Thread 1 and Thread 2 can make their own local cache of the Object except the variable which is declared as a volatile . So the volatile variable will have only one main copy which will be updated by different threads and updating by one thread to the volatile variable will immediately reflect to the other Thread. So the volatile variable is used in the Thread context.

for further understanding refer the following image.

volatileVsStaticinJava

I will handle the concurrency for you - from Panini

Hi all I was talking about the concurrency programming in java with my earlier blog post. Those are very simple examples but if you go to real world software development the concurrency handling will be mess for the developers with their business logic. So if some one can handle the concurrency implicitly then it would be grate for the developers then they do not want to consider the concurrent problems rather mainly focus on their business logic.

Think about there is a software development requirement of "manage the memory but not required to do it manually" so then you can use JAVA to do this because you don't want to handle the memory by manually, JAVA will take care of it.

As it is if you have requirement of "handle the concurrent connections but not required to do it by manually" then you can use capsules-oriented programming provided by Panini

lets talk about little bit of Panini program.
Panini is a new programming style designed to address the challenges of concurrent programming. Main goal is to enable non-concurrency experts to write correct and efficient concurrent programs.

How to set up the Panini to your command line
1. Download panini distribution from here then extract to any place in your computer
2. Set the $Panini/bin folder to the path variable in you Windows computer.
3. Then go to command line and check whether Panini is set to the command line by type "panc"
panc
4. Now create the Simple Panini HelloWorld example as follows and save it as paniniHelloWorld.java
[code language="java"]
capsule HelloWorld {
void run(){
System.out.println("Panini: Hello World!");
long time = System.currentTimeMillis();
System.out.println("Time is now: " + time);
}
}
[/code]
5. Compile the Panini program
pancH

6. Run the program
pancH

You can follow the complex examples given by Panini and feel the difference with implicit concurrent behavior then Feel free to make the feed back about Panini :).

Synchronization and Concurrent programming in Java

Lets look at simple example to understand the concurrency.
Think about you are going to implement the software like stock controlling. Multiple users access the same value at same time that means different threads access the same value and doing some modification on it. if we don't handle the concurrent access correctly then we cannot guaranty visibility of the modification of values to one thread to the other, so will look at how to handle it correctly.

1. I have Stock class that is created only one instance and do the incCount() operation in different threads as follows
[code language="java"]
public class Stock {

private static int count = 0;

public synchronized void incCount() {
System.out.println("Thread name" + Thread.currentThread().getName());
System.out.println("Befor :"+count);
count = count+1;
System.out.println("After :"+count);
}

}

public class StockThread implements Runnable{
//This Stock variable is initializing only the first time
private static final Stock stock = new Stock();

public static void main(String[] args) {
//Here we create the three threads and run at the same time
Thread a = new Thread(new StockThread()," first");
Thread b = new Thread(new StockThread()," second");
Thread c = new Thread(new StockThread()," third");
c.start();
a.start();
b.start();
}

@Override
public void run() {

for(int i=0;i<500;i++){
//increase the count buy using shared Stock
stock.incCount();

}
}
}
[/code]

2. Now if you have multiple instances of the Stock.class and doing the operation incCount() in different threads then above code is not thread safe. so you have to change the code as follows.

[code language="java"]
public class Stock {

private static int count = 0;

public static synchronized void incCount() {
System.out.println("Thread name" + Thread.currentThread().getName());
System.out.println("Befor :"+count);
count = count+1;
System.out.println("After :"+count);
}

}

public class StockThread implements Runnable{

public static void main(String[] args) {
//Here we create the three threads and run at the same time
Thread a = new Thread(new StockThread()," first");
Thread b = new Thread(new StockThread()," second");
Thread c = new Thread(new StockThread()," third");
c.start();
a.start();
b.start();
}

@Override
public void run() {
//multiple Objects
Stock stock = new Stock();
for(int i=0;i<500;i++){
//increase the count buy using shared Stock
stock.incCount();

}
}
}
[/code]

Ok now let me explain the scenario in the example 1,
we used "synchronized" keyword to the local method so that means if you access this method by using same Stock instance with different threads code is in thread safe because its lock the synchronized method with object reference.

So If you run the same method at same time through the different threads by using same Stock object then all operations are going perfectly one after one.

But you access the same method at same time through the different threads by using different Stock objects then your code is not in thread safe.

In the second scenario I have used the "static synchronized" for the operation incCount() then what happens the synchronized method take the lock as Class. So if you came with different object no matter it will smoothly going one after one.

The same goal can achieve with the following code block as well.

[code language="java"]
public class Stock {

private static int count = 0;

public void incCount() {
synchronized(Stock.class){
System.out.println("Thread name" + Thread.currentThread().getName());
System.out.println("Befor :"+count);
count = count+1;
System.out.println("After :"+count);
}
}

}

public class StockThread implements Runnable{

public static void main(String[] args) {
//Here we create the three threads and run at the same time
Thread a = new Thread(new StockThread()," first");
Thread b = new Thread(new StockThread()," second");
Thread c = new Thread(new StockThread()," third");
c.start();
a.start();
b.start();
}

@Override
public void run() {
//multiple Objects
Stock stock = new Stock();
for(int i=0;i<500;i++){
//increase the count buy using shared Stock
stock.incCount();

}
}
}
[/code]

Wednesday, June 26, 2013

WSO2 ESB talk to WSO2 Identity Server and get the authentication decision to invoke the proxy service

This is very good and simple example. let me explain the exact requirement.

If we need to secure the proxy service with UT (Username Token) in WSO2 ESB but all users and roles are maintained in the WSO2 Identity Server so when the users are going to invoke this service it should talk to WSO2 IS and get authenticated. In order to do this we have to implement Password Callback handler as follows.You can checkout total source here

[code language="java"]
package org.wso2.is.callback;


import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.apache.ws.security.WSPasswordCallback;
import org.wso2.carbon.authenticator.stub.AuthenticationAdminStub;
import org.wso2.carbon.um.ws.api.WSUserStoreManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;


public class ISCallBackHandler implements CallbackHandler {
private static final Log log = LogFactory.getLog(ISCallBackHandler.class);
private String serverUrl = "https://localhost:9443/services/";

private AuthenticationAdminStub authstub = null;
private ConfigurationContext ctx;
private String authCookie = null;
private WSUserStoreManager remoteUserStoreManager = null;
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
try {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof WSPasswordCallback) {
WSPasswordCallback passwordCallback = (WSPasswordCallback) callbacks[i];
String username = passwordCallback.getIdentifer();
String receivedPasswd = passwordCallback.getPassword();

ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null, null);
String authEPR = serverUrl + "AuthenticationAdmin";
authstub = new AuthenticationAdminStub(ctx, authEPR);
ServiceClient client = authstub._getServiceClient();
Options options = client.getOptions();
HttpTransportProperties.Authenticator authenticator = new HttpTransportProperties.Authenticator();
authenticator.setUsername("admin");
authenticator.setPassword("admin");
authenticator.setPreemptiveAuthentication(true);
options.setProperty(HTTPConstants.AUTHENTICATE, authenticator);
client.setOptions(options);

boolean status = authstub.login(username,receivedPasswd,"localhost");
if(status){
//Login Successful
} else{
throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
}

}
}

}catch (UnsupportedCallbackException e){
if(log.isDebugEnabled()){
log.debug(e.getMessage(), e); //logging invlaid passwords and attempts
throw e;
}
throw e;
} catch (Exception e){
log.error(e.getMessage(), e);
//can't build an unsupported exception.
throw new UnsupportedCallbackException(null, e.getMessage());
}

}
}

[/code]

1. First of all you have to build the above project and place the created jar file in to $ESB_HOME/repository/components/lib
2. Create the proxy service as follows and secured by UT
esb

esb1

esb2

esb3

2. Now you have to engage the created Password Call back handler. This is simply do with the policy configuration.
Go to policy configuration and insert the following line into the rampart configuration as follows.
"org.wso2.is.callback.ISCallBackHandler"

esb

esb1

esb2

esb3

3. Now you can invoke the service with username and password which is located in WSO2 Identity server.
(If you are going to run ESB and IS on same machine please consider the port offset as well as change the call back handler server url)

Tuesday, May 28, 2013

SCIM Bulk Endpoint Operations in WSO2 Identity Server

SCIM - (System for Cross-Domain Identity Management)
WSO2 Identity server has exposed the three major endpoints for SCIM operation as follows.
/Users , /Groups, /Bulk

Lets look at the SCIM Bulk operations supported by the Identity Server.
1. Create Users
Request -
[code language="java"]
curl -v -k --user admin:admin -H "Accept: application/json" -H "Content-type: application/json" -X POST -d "{\"failOnErrors\":2,\"schemas\":[\"urn:scim:schemas:core:1.0\"],\"Operations\":[{\"data\":{\"schemas\":[\"urn:scim:schemas:core:1.0\"],\"path\":\"/Users\",\"userName\":\"hasini\",\"method\":\"POST\",\"emails\":[{\"value\":\"hasini@gmail.com\"},{\"value\":\"hasinig@yahoo.com\"}],\"phoneNumbers\":[{\"value\":\"0772508354\"}],\"displayName\":\"Hasini\",\"externalId\":\"hasini@wso2.com\",\"password\":\"dummyPW1\",\"preferredLanguage\":\"Sinhala\",\"bulkId\":\"bulkIDUser1\"},\"path\":\"/Users\",\"method\":\"POST\",\"bulkId\":\"bulkIDUser1\"},{\"data\":{\"schemas\":[\"urn:scim:schemas:core:1.0\"],\"path\":\"/Users\",\"userName\":\"dinuka\",\"method\":\"POST\",\"emails\":[{\"value\":\"dinuka.malalanayake@gmail.com\"},{\"value\":\"dinuka_malalanayake@yahoo.com\"}],\"phoneNumbers\":[{\"value\":\"0772508354\"}],\"displayName\":\"Dinuka\",\"externalId\":\"dinukam@wso2.com\",\"password\":\"myPassword\",\"preferredLanguage\":\"Sinhala\",\"bulkId\":\"bulkIDUser2\"},\"path\":\"/Users\",\"method\":\"POST\",\"bulkId\":\"bulkIDUser2\"}]}" https://localhost:9443/wso2/scim/Bulk
[/code]
is

Response -
[code language="java"]
{"schemas":["urn:scim:schemas:core:1.0"],"Operations":[{"status":{"code":"201"},"location":"https://localhost:9443/wso2/scim/Users/bcbc6fed-6519-4eeb-a1ff-9b643fdab1b5","method":"POST","bulkId":"bulkIDUser1"},{"status":{"code":"201"},"location":"https://localhost:9443/wso2/scim/Users/ce6cf606-c4de-4260-bfdf-a751161eeae0","method":"POST","bulkId":"bulkIDUser2"}]}
[/code]
is2

2. Create Groups - Here you need to change the existing user IDs.
Request -
[code language="java"]
curl -v -k --user admin:admin -H "Accept: application/json" -H "Content-type: application/json" -X POST -d "{\"failOnErrors\":2,\"schemas\":[\"urn:scim:schemas:core:1.0\"],\"Operations\":[{\"data\":{\"schemas\":[\"urn:scim:schemas:core:1.0\"],\"path\":\"/Groups\",\"method\":\"POST\",\"displayName\":\"engineer\",\"externalId\":\"engineer\",\"members\":[{\"value\":\"b1b03cf2-470f-4a73-b517-ae4faed8e61b\"},{\"value\":\"8e2c7178-e5bf-4013-b526-1193e0611d9a\"}],\"bulkId\":\"bulkGroup1\"},\"path\":\"/Groups\",\"method\":\"POST\",\"bulkId\":\"bulkGroup1\"},{\"data\":{\"schemas\":[\"urn:scim:schemas:core:1.0\"],\"path\":\"/Groups\",\"method\":\"POST\",\"displayName\":\"doctor\",\"externalId\":\"doctor\",\"members\":[{\"value\":\"8e2c7178-e5bf-4013-b526-1193e0611d9a\"},{\"value\":\"b1b03cf2-470f-4a73-b517-ae4faed8e61b\"}],\"bulkId\":\"bulkGroup2\"},\"path\":\"/Groups\",\"method\":\"POST\",\"bulkId\":\"bulkGroup2\"}]}" https://localhost:9443/wso2/scim/Bulk
[/code]
is

Response -
[code language="java"]
{"schemas":["urn:scim:schemas:core:1.0"],"Operations":[{"status":{"code":"201"},"location":"https://localhost:9443/wso2/scim/Groups/6f008b6c-e990-4f67-9048-0fbcb3b52d5c","method":"POST","bulkId":"bulkGroup1"},{"status":{"code":"201"},"location":"https://localhost:9443/wso2/scim/Groups/1b7c44a8-26b8-4e81-9961-26d90fe68ac5","method":"POST","bulkId":"bulkGroup2"}]}
[/code]
is2

3. Delete Users
Request -
[code language="java"]
{"failOnErrors":2,"schemas":["urn:scim:schemas:core:1.0"],"Operations":[{"path":"/Users/6f3fc3ee-f39c-4d53-bc4d-649775313e29","method":"DELETE"},{"path":"/Users/b75bdb63-a36d-436d-8462-edd1db7e6b29","method":"DELETE"}]}
[/code]
is

Response -
[code language="java"]
{"schemas":["urn:scim:schemas:core:1.0"],"Operations":[{"status":{"code":"200"},"location":"/Users/bcbc6fed-6519-4eeb-a1ff-9b643fdab1b5","method":"DELETE"},{"status":{"code":"200"},"location":"/Users/ce6cf606-c4de-4260-bfdf-a751161eeae0","method":"DELETE"}]}
[/code]
is2

Thursday, May 16, 2013

Analyze java source with "Yasca" and detecting security vulnerabilities

Here I'm going to explain how to analyze the source code by using the "Yasca"

1. First of all you can checkout the Yasca from "https://svn.wso2.org/repos/wso2/people/prabath/yasca"

2. Check whether the php installed in your machine. if not you have to install it first
(In Linux you can do easily "sudo apt-get install php5")

3. Go to the "yasca" directory and write the the following command
"./yasca $Source_Directory_path" for more command refer this
is

4. Go to your desktop the you can see the folder call Yasca and all the generated reports are located there
is

This is very useful for detecting security vulnerabilities and other issues in program source code.

Friday, April 5, 2013

Apply OAuth2.0 base security for Rest endpoint with WSO2ESB 4.6.0 and WSO2IS 4.1.1 alpha

I think this would be good example for applying the security for the simple rest endpoint. Lets think we already have some rest endpoint without security but we need to expose this with the OAuth2.0 base security.

you can achieve this task with the following steps.

1. Create the custom handler to validate the Bearer token.
2. Create API element in the ESB and pointing the rest endpoint that you have
3. Include created handler to the created API element.
4. Go to IS and create the OAuth2.0 application and get the Access token form IS
5. Invoke the API with the valid access token.

Functional Scenario

Rest endpoint with security

1. Creating custom handler (Download the mvn project here)
You need to extends AbstractHandler and implements ManagedLifecycle as follows. as well I'm getting some parameters from the axis2.xml
[sourcecode language="java"]
package org.wso2.handler;

/**
* Created with IntelliJ IDEA.
* User: dinuka
* Date: 4/4/13
* Time: 3:46 PM
* To change this template use File | Settings | File Templates.
*/
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.apache.http.HttpHeaders;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub;
import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO;
import org.apache.synapse.ManagedLifecycle;
import org.apache.synapse.MessageContext;
import org.apache.synapse.core.SynapseEnvironment;
import org.apache.synapse.rest.AbstractHandler;

import java.util.Map;

public class SimpleOauthHandler extends AbstractHandler implements ManagedLifecycle {

private String securityHeader = HttpHeaders.AUTHORIZATION;
private String consumerKeyHeaderSegment = "Bearer";
private String oauthHeaderSplitter = ",";
private String consumerKeySegmentDelimiter = " ";
private String oauth2TokenValidationService = "oauth2TokenValidationService";
private String identityServerUserName = "identityServerUserName";
private String identityServerPw = "identityServerPw";

@Override
public boolean handleRequest(MessageContext messageContext) {
try{
ConfigurationContext configCtx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null, null);
//Read parameters from axis2.xml
String identityServerUrl = messageContext.getConfiguration().getAxisConfiguration().getParameter(oauth2TokenValidationService).getValue().toString();
String username = messageContext.getConfiguration().getAxisConfiguration().getParameter(identityServerUserName).getValue().toString();
String password = messageContext.getConfiguration().getAxisConfiguration().getParameter(identityServerPw).getValue().toString();

OAuth2TokenValidationServiceStub stub = new OAuth2TokenValidationServiceStub(configCtx,identityServerUrl);
ServiceClient client = stub._getServiceClient();
Options options = client.getOptions();
HttpTransportProperties.Authenticator authenticator = new HttpTransportProperties.Authenticator();
authenticator.setUsername(username);
authenticator.setPassword(password);
authenticator.setPreemptiveAuthentication(true);

options.setProperty(HTTPConstants.AUTHENTICATE, authenticator);
client.setOptions(options);
OAuth2TokenValidationRequestDTO dto = new OAuth2TokenValidationRequestDTO();
dto.setTokenType("bearer");
Map headers = (Map) ((Axis2MessageContext) messageContext).getAxis2MessageContext().
getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
String apiKey = null;
if (headers != null) {
apiKey = extractCustomerKeyFromAuthHeader(headers);
}
dto.setAccessToken(apiKey);
//validate passed apiKey(token)
if(stub.validate(dto).getValid()){
return true;
}else{
return false;
}
}catch(Exception e){
e.printStackTrace();
return false;
}
}

public String extractCustomerKeyFromAuthHeader(Map headersMap) {

//From 1.0.7 version of this component onwards remove the OAuth authorization header from
// the message is configurable. So we dont need to remove headers at this point.
String authHeader = (String) headersMap.get(securityHeader);
if (authHeader == null) {
return null;
}

if (authHeader.startsWith("OAuth ") || authHeader.startsWith("oauth ")) {
authHeader = authHeader.substring(authHeader.indexOf("o"));
}

String[] headers = authHeader.split(oauthHeaderSplitter);
if (headers != null) {
for (int i = 0; i < headers.length; i++) {
String[] elements = headers[i].split(consumerKeySegmentDelimiter);
if (elements != null && elements.length > 1) {
int j = 0;
boolean isConsumerKeyHeaderAvailable = false;
for (String element : elements) {
if (!"".equals(element.trim())) {
if (consumerKeyHeaderSegment.equals(elements[j].trim())) {
isConsumerKeyHeaderAvailable = true;
} else if (isConsumerKeyHeaderAvailable) {
return removeLeadingAndTrailing(elements[j].trim());
}
}
j++;
}
}
}
}
return null;
}

private String removeLeadingAndTrailing(String base) {
String result = base;

if (base.startsWith("\"") || base.endsWith("\"")) {
result = base.replace("\"", "");
}
return result.trim();
}

@Override
public boolean handleResponse(MessageContext messageContext) {
return true;
}

@Override
public void init(SynapseEnvironment synapseEnvironment) {
//To change body of implemented methods use File | Settings | File Templates.
}

@Override
public void destroy() {
//To change body of implemented methods use File | Settings | File Templates.
}
}
[/sourcecode]

2. Now I take rest unsecured endpoint as "https://www.google.lk/search?q=wso2"(You can use your own endpoint)
Lets look at how to configure the WSO2 ESB with this endpoint.

Start the ESB 4.6.0 and Sign in as admin.
Then go to Source View.
esb

Insert following xml configuration in to the source view to create the API element name as TestGoogle
[sourcecode language="xml"]
<api name="TestGoogle" context="/search">
<resource methods="GET">
<inSequence>
<log level="custom">
<property name="Test" value="Test"/>
</log>
<send>
<endpoint>
<address uri="https://www.google.lk/search?q=wso2"/>
</endpoint>
</send>
</inSequence>
</resource>
<handlers>
<handler class="org.wso2.handler.SimpleOauthHandler"/>
</handlers>
</api>
[/sourcecode]

esb2

3. We need to add the created custom handler.jar in to $ESB_HOME/repository/components/libs and go to the $ESB_HOME/repository/conf/axis2/axis2.xml and put the following parameters.
[sourcecode language="xml"]
<!-- OAuth2 Token Validation Service -->
<parameter name="oauth2TokenValidationService">https://localhost:9444/services/OAuth2TokenValidationService</parameter>
<!-- Server credentials -->
<parameter name="identityServerUserName">admin</parameter>
<parameter name="identityServerPw">admin</parameter>
[/sourcecode]

restart the ESB.

Again go to source view and place the following xml to engage the custom handler in to the API element
[sourcecode language="xml"]
<handlers>
<handler class="org.wso2.handler.SimpleOauthHandler"/>
</handlers>
[sourcecode]

Total configuration looks like this
[sourcecode language="xml"]
<api name="TestGoogle" context="/search">
<resource methods="GET">
<inSequence>
<log level="custom">
<property name="Test" value="Test"/>
</log>
<send>
<endpoint>
<address uri="https://www.google.lk/search?q=wso2"/>
</endpoint>
</send>
</inSequence>
</resource>
<handlers>
<handler class="org.wso2.handler.SimpleOauthHandler"/>
</handlers>
</api>
[/sourcecode]

4. Start the WSO2 Identity server and create the Oauth2.0 Application

is

Request the access token from IS you need to pass the ClientID and Client Secret with the curl request.
[sourcecode language="console"]
curl -v -X POST --user <strong>R2CNjiq672f6xXQabAfWbYby2nca</strong>:<strong>QhEQi9eJv8BmSinPBnWscCFFDgsa</strong> -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" -k -d "grant_type=password&username=admin&password=admin" https://localhost:9444/oauth2endpoints/token
[/sourcecode]

Then you will receive the access token
cmd

5. Now you can invoke the API with the received access token

curl -v -X GET -H "Authorization: Bearer ca1799fc84986bd87c120ba499838a7" http://10.100.1.198:8280/search
cmd

Thursday, April 4, 2013

Custom JDBC user store manager with Custom properties as Claims in WSO2IS 4.1.1 alpha

In my early blog post I have describe how to write the custom user store manager and plug in to the WSO2 Identity Server. Now I'm going to explain how we can plug the user properties as claims and how to do some authorization with that properties. First of all you need to read my early blog post (How to write Custom JDBC user store manager with WSO2IS 4.1.1 alpha)

I have modify the DB Schema as follows
[sourcecode language="sql"]
CREATE TABLE CUSTOMER_DATA (
CUSTOMER_ID INTEGER NOT NULL AUTO_INCREMENT,
CUSTOMER_NAME VARCHAR(255) NOT NULL,
PASSWORD VARCHAR(255) NOT NULL,
EMAIL VARCHAR(255) NOT NULL,
AGE VARCHAR(255) NOT NULL,
STATUS VARCHAR(255) NOT NULL,
PRIMARY KEY (CUSTOMER_ID),
UNIQUE(CUSTOMER_NAME)
);

INSERT INTO CUSTOMER_DATA (CUSTOMER_NAME, PASSWORD,EMAIL,AGE,STATUS) VALUES("dinuka" ,"dinuka","dinukam@wso2.com","25","ACTIVE");
INSERT INTO CUSTOMER_DATA (CUSTOMER_NAME, PASSWORD,EMAIL,AGE,STATUS) VALUES("malinda" ,"malinda","malinda@gmail.com","25","INACTIVE");
[/sourcecode]

As I mention in the early post we need to create the data sources in master-datasources.xml and plug the newly created JDBCUserStoreManager through the user-mgt.xml

1. Lets look at the modification of JDBCUserStoreManager.

If we need to get some user properties as claims then you need to override the following methods in JDBCUserStoreManager (Download the mvn project here).
[sourcecode language="java"]
@Override
protected String getProperty(Connection dbConnection, String userName, String propertyName,
String profileName) throws UserStoreException {
String sqlStmt = realmConfig.getUserStoreProperty(JDBCRealmConstants.GET_PROPS_FOR_PROFILE);
if (sqlStmt == null) {
throw new UserStoreException("The sql statement for add user property sql is null");
}
PreparedStatement prepStmt = null;
ResultSet rs = null;
String value = null;
try {
prepStmt = dbConnection.prepareStatement(sqlStmt);
prepStmt.setString(1, userName);

rs = prepStmt.executeQuery();
while (rs.next()) {
if(propertyName.equals("EMAIL")){
value = rs.getString(1);
}else if(propertyName.equals("AGE")){
value = rs.getString(2);
}else if(propertyName.equals("STATUS")){
value = rs.getString(3);
}
}
return value;
} catch (SQLException e) {
log.error("Using sql : " + sqlStmt);
throw new UserStoreException(e.getMessage(), e);
} finally {
DatabaseUtil.closeAllConnections(null, rs, prepStmt);
}
}

@Override
public Map<String, String> getUserPropertyValues(String userName, String[] propertyNames,
String profileName) throws UserStoreException {
if (profileName == null) {
profileName = UserCoreConstants.DEFAULT_PROFILE;
}
Connection dbConnection = null;
String sqlStmt = null;
PreparedStatement prepStmt = null;
ResultSet rs = null;
String[] propertyNamesSorted = propertyNames.clone();
Arrays.sort(propertyNamesSorted);
Map<String, String> map = new HashMap<String, String>();
try {
dbConnection = getDBConnection();
sqlStmt = realmConfig.getUserStoreProperty(JDBCRealmConstants.GET_PROPS_FOR_PROFILE);
prepStmt = dbConnection.prepareStatement(sqlStmt);
prepStmt.setString(1, userName);

rs = prepStmt.executeQuery();
while (rs.next()) {
String email = rs.getString(1);
String age = rs.getString(2);
String status = rs.getString(3);
if (Arrays.binarySearch(propertyNamesSorted, "EMAIL") >= 0) {
map.put("EMAIL", email);
}

if(Arrays.binarySearch(propertyNamesSorted, "AGE") >= 0){
map.put("AGE", age);
}

if(Arrays.binarySearch(propertyNamesSorted, "STATUS") >= 0){
map.put("STATUS", status);
}

}

return map;
} catch (SQLException e) {
throw new UserStoreException(e.getMessage(), e);
} finally {
DatabaseUtil.closeAllConnections(dbConnection, rs, prepStmt);
}
}

[/sourcecode]

2. In this code you can see we are using some external sql query as GET_PROPS_FOR_PROFILE (realmConfig.getUserStoreProperty(JDBCRealmConstants.GET_PROPS_FOR_PROFILE);) so we need to pass it from user-mgt.xml as follows.

[sourcecode language="xml"]
<UserManager>
<Realm>
<Configuration>
<AddAdmin>true</AddAdmin>
<AdminRole>admin</AdminRole>
<AdminUser>
<UserName>admin</UserName>
<Password>admin</Password>
</AdminUser>
<EveryOneRoleName>everyone</EveryOneRoleName> <!-- By default users in this role sees the registry root -->
<Property name="dataSource">jdbc/WSO2CarbonDB</Property>
<Property name="MultiTenantRealmConfigBuilder">org.wso2.carbon.user.core.config.multitenancy.SimpleRealmConfigBuilder</Property>
<!-- Use the following MultiTenantRealmConfigBuilder with LDAP based UserStoreManagers-->
<!--Property name="MultiTenantRealmConfigBuilder">org.wso2.carbon.user.core.config.multitenancy.CommonLDAPRealmConfigBuilder</Property-->
</Configuration>

<UserStoreManager class="org.wso2.carbon.user.core.jdbc.JDBCUserStoreManager">
<Property name="ReadOnly">false</Property>
<Property name="dataSource">jdbc/WSO2CarbonDB</Property>
<Property name="MaxUserNameListLength">100</Property>
<Property name="Disabled">false</Property>
<Property name="IsEmailUserName">false</Property>
<Property name="DomainCalculation">default</Property>
<Property name="PasswordDigest">SHA-256</Property>
<Property name="StoreSaltedPassword">true</Property>
<Property name="ReadGroups">true</Property>
<Property name="WriteGroups">true</Property>
<Property name="UserNameUniqueAcrossTenants">false</Property>
<Property name="PasswordJavaRegEx">^[\S]{5,30}$</Property>
<Property name="PasswordJavaScriptRegEx">^[\S]{5,30}$</Property>
<Property name="UsernameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
<Property name="UsernameJavaScriptRegEx">^[\S]{3,30}$</Property>
<Property name="RolenameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
<Property name="RolenameJavaScriptRegEx">^[\S]{3,30}$</Property>
<Property name="UserRolesCacheEnabled">true</Property>
<Property name="MaxRoleNameListLength">100</Property>
<Property name="MaxUserNameListLength">100</Property>
</UserStoreManager>

<UserStoreManager class="org.wso2.carbon.jdbc.sample.SampleJDBCUserStoreManager">
<Property name="ReadOnly">false</Property>
<Property name="dataSource">jdbc/SampleUserStore</Property>
<Property name="MaxUserNameListLength">100</Property>
<Property name="Disabled">false</Property>
<Property name="IsEmailUserName">false</Property>
<Property name="DomainCalculation">default</Property>
<Property name="PasswordDigest">SHA-256</Property>
<Property name="StoreSaltedPassword">true</Property>
<Property name="ReadGroups">true</Property>
<Property name="WriteGroups">true</Property>
<Property name="UserNameUniqueAcrossTenants">false</Property>
<Property name="PasswordJavaRegEx">^[\S]{5,30}$</Property>
<Property name="PasswordJavaScriptRegEx">^[\S]{5,30}$</Property>
<Property name="UsernameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
<Property name="UsernameJavaScriptRegEx">^[\S]{3,30}$</Property>
<Property name="RolenameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
<Property name="RolenameJavaScriptRegEx">^[\S]{3,30}$</Property>
<Property name="UserRolesCacheEnabled">true</Property>
<Property name="MaxRoleNameListLength">100</Property>
<Property name="MaxUserNameListLength">100</Property>
<Property name="DomainName">sample.com</Property>

<Property name="SelectUserSQL">SELECT * FROM CUSTOMER_DATA WHERE CUSTOMER_NAME=?</Property>
<Property name="UserFilterSQL">SELECT CUSTOMER_NAME FROM CUSTOMER_DATA WHERE CUSTOMER_NAME LIKE ? ORDER BY CUSTOMER_ID</Property>
<Property name="GetUserPropertiesForProfileSQL">SELECT EMAIL,AGE,STATUS FROM CUSTOMER_DATA WHERE CUSTOMER_NAME=?</Property>
</UserStoreManager>

<AuthorizationManager
class="org.wso2.carbon.user.core.authorization.JDBCAuthorizationManager">
<Property name="AdminRoleManagementPermissions">/permission</Property>
<Property name="AuthorizationCacheEnabled">true</Property>
</AuthorizationManager>
</Realm>
</UserManager>
[/sourcecode]

3. Same as you did in early post you have to place the mysql-connector-java-5.1.7-bin.jar and Sample_user_store-1.0.jar in to $IS_HOME/repository/component/libs

4. Start the Identity server and Sign in as admin.

5. Go to claim management.
is
Now you can see some Available Claim Dialects here. In the user store manager is using the http://wso2.org/claims so we need to add the new claim mapping on this.

5. Go to http://wso2.org/claims Dialect.
is

6. Add new Claim EMAIL
is1
Here you need to specify the Mapped Attribute (s) as EMAIL because in our custom user store manager check the property name as "EMAIL","AGE","STATUS"

7. Add new Claim AGE
is

8. Add new Claim STATUS
is1

9. Lets look at the users
is

And go to User profile
is

Now you can see the properties in the database is coming under user profile.

10. Now we need to use those properties and do some authorization. So we can easily move to XACML engine coming with the Identity server to do the needful. Here I'm not going to explain the behavior of the XACML Engine in Identity server but you can follow my early blog posts such as
Authentication and Authorization with WSO2ESB and WSO2IS
XACML Authorization

11. Now I'm going to create the XACML policy buy using the claims that we newly added.
is1

You can see the claim names that we mapped early so you can select those from the UI.
is

Click on the policy name and go to source view of XACML policy.
is

is1

and replace the Deny with Permit and update the policy.
is2

12. Now enable the created policy as follows.

is

13. Go to Tryit and test your policy.

is1

is2

This is very basic example but when its coming to the real world example you can do so many things with this user store extensible facility. as well you can do all the above stuff with the use of web services which are exposed by WSO2 Identity Server.

Wednesday, April 3, 2013

How to write Custom JDBC user store manager with WSO2IS 4.1.1 alpha

Download id 4.1.1- alpha here
Lets think about real world business scenario, Simple company has their own database with Customer name and the password. now they need to do some security implementation with WSO2 Identity Server and they cannot duplicate those data as well as cannot change their db schema.

That means we cannot take those users and insert into the WSO2 IS database as well as they cannot change their DB schema to our WSO2 IS database schema. Don't worry WSO2 Identity server has capability to solve this issue. lets look at the solution with mysql DB.

Steps:
1. Plug the external db as secondary user store.
2. Create some roles in Identity Server and assign the users (coming from external DB).
3. Give the permission to the role.
4. Access the Identity server.

Custom DB Schema
[sourcecode language="sql"]
CREATE TABLE CUSTOMER_DATA (
CUSTOMER_ID INTEGER NOT NULL AUTO_INCREMENT,
CUSTOMER_NAME VARCHAR(255) NOT NULL,
PASSWORD VARCHAR(255) NOT NULL,
PRIMARY KEY (CUSTOMER_ID),
UNIQUE(CUSTOMER_NAME)
);
[/sourcecode]


1. First we have to write down the Custom JDBCUserStoreManager to compatible with the above schema. So you need to create a class with any name that you preferred and extends JDBCUserStoreManager. I have created class call SampleJDBCUserStoreManager.java (download mvn project here).

In my custom class I'm not going to override all methods in JDBCUserStoreManager because this user store is going to plug as read only mode.

2. Let's look at the master-datasource.xml
I have created two data source because I'm going to connect to the two user stores as primary and secondary. you bettor read my early blog post call (Multiple User Stores configuration in WSO2 Identity Server) but there is lot of api changes in 4.1.1 alpha.
[sourcecode language="xml"]
<datasources-configuration xmlns:svns="http://org.wso2.securevault/configuration">

<providers>
<provider>org.wso2.carbon.ndatasource.rdbms.RDBMSDataSourceReader</provider>
</providers>

<datasources>

<datasource>
<name>WSO2_CARBON_DB</name>
<description>The datasource used for registry</description>
<jndiConfig>
<name>jdbc/WSO2CarbonDB</name>
</jndiConfig>
<definition type="RDBMS">
<configuration>
<url>jdbc:mysql://localhost:3306/WSO2_CARBON</url>
<username>root</username>
<password>root</password>
<driverClassName>com.mysql.jdbc.Driver</driverClassName>
<maxActive>50</maxActive>
<maxWait>60000</maxWait>
<testOnBorrow>true</testOnBorrow>
<validationQuery>SELECT 1</validationQuery>
<validationInterval>30000</validationInterval>
</configuration>
</definition>

</datasource>

<datasource>
<name>Sample_DB</name>
<description>The datasource used for user manager</description>
<jndiConfig>
<name>jdbc/SampleUserStore</name>
</jndiConfig>
<definition type="RDBMS">
<configuration>
<url>jdbc:mysql://localhost:3306/custom_users</url>
<username>root</username>
<password>root</password>
<driverClassName>com.mysql.jdbc.Driver</driverClassName>
<maxActive>50</maxActive>
<maxWait>60000</maxWait>
<testOnBorrow>true</testOnBorrow>
<validationQuery>SELECT 1</validationQuery>
<validationInterval>30000</validationInterval>
</configuration>
</definition>
</datasource>

</datasources>

</datasources-configuration>
[/sourcecode]

3. Go to user-mgt.xml
Here I have define two user store manages and the first definition pic as primary user store manager form the Identity server.
The secondary one is the custom user store manager that i have written early.
[sourcecode language="xml"]

<UserManager>
<Realm>
<Configuration>
<AddAdmin>true</AddAdmin>
<AdminRole>admin</AdminRole>
<AdminUser>
<UserName>admin</UserName>
<Password>admin</Password>
</AdminUser>
<EveryOneRoleName>everyone</EveryOneRoleName> <!-- By default users in this role sees the registry root -->
<Property name="dataSource">jdbc/WSO2CarbonDB</Property>
<Property name="MultiTenantRealmConfigBuilder">org.wso2.carbon.user.core.config.multitenancy.SimpleRealmConfigBuilder</Property>
<!-- Use the following MultiTenantRealmConfigBuilder with LDAP based UserStoreManagers-->
<!--Property name="MultiTenantRealmConfigBuilder">org.wso2.carbon.user.core.config.multitenancy.CommonLDAPRealmConfigBuilder</Property-->
</Configuration>

<UserStoreManager class="org.wso2.carbon.user.core.jdbc.JDBCUserStoreManager">
<Property name="ReadOnly">false</Property>
<Property name="dataSource">jdbc/WSO2CarbonDB</Property>
<Property name="MaxUserNameListLength">100</Property>
<Property name="Disabled">false</Property>
<Property name="IsEmailUserName">false</Property>
<Property name="DomainCalculation">default</Property>
<Property name="PasswordDigest">SHA-256</Property>
<Property name="StoreSaltedPassword">true</Property>
<Property name="ReadGroups">true</Property>
<Property name="WriteGroups">true</Property>
<Property name="UserNameUniqueAcrossTenants">false</Property>
<Property name="PasswordJavaRegEx">^[\S]{5,30}$</Property>
<Property name="PasswordJavaScriptRegEx">^[\S]{5,30}$</Property>
<Property name="UsernameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
<Property name="UsernameJavaScriptRegEx">^[\S]{3,30}$</Property>
<Property name="RolenameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
<Property name="RolenameJavaScriptRegEx">^[\S]{3,30}$</Property>
<Property name="UserRolesCacheEnabled">true</Property>
<Property name="MaxRoleNameListLength">100</Property>
<Property name="MaxUserNameListLength">100</Property>
</UserStoreManager>

<UserStoreManager class="org.wso2.carbon.jdbc.sample.SampleJDBCUserStoreManager">
<Property name="ReadOnly">false</Property>
<Property name="dataSource">jdbc/SampleUserStore</Property>
<Property name="MaxUserNameListLength">100</Property>
<Property name="Disabled">false</Property>
<Property name="IsEmailUserName">false</Property>
<Property name="DomainCalculation">default</Property>
<Property name="PasswordDigest">SHA-256</Property>
<Property name="StoreSaltedPassword">true</Property>
<Property name="ReadGroups">true</Property>
<Property name="WriteGroups">true</Property>
<Property name="UserNameUniqueAcrossTenants">false</Property>
<Property name="PasswordJavaRegEx">^[\S]{5,30}$</Property>
<Property name="PasswordJavaScriptRegEx">^[\S]{5,30}$</Property>
<Property name="UsernameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
<Property name="UsernameJavaScriptRegEx">^[\S]{3,30}$</Property>
<Property name="RolenameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
<Property name="RolenameJavaScriptRegEx">^[\S]{3,30}$</Property>
<Property name="UserRolesCacheEnabled">true</Property>
<Property name="MaxRoleNameListLength">100</Property>
<Property name="MaxUserNameListLength">100</Property>
<Property name="DomainName">sample.com</Property>

<Property name="SelectUserSQL">SELECT * FROM CUSTOMER_DATA WHERE CUSTOMER_NAME=?</Property>
<Property name="UserFilterSQL">SELECT CUSTOMER_NAME FROM CUSTOMER_DATA WHERE CUSTOMER_NAME LIKE ? ORDER BY CUSTOMER_ID</Property>
</UserStoreManager>

<AuthorizationManager
class="org.wso2.carbon.user.core.authorization.JDBCAuthorizationManager">
<Property name="AdminRoleManagementPermissions">/permission</Property>
<Property name="AuthorizationCacheEnabled">true</Property>
</AuthorizationManager>
</Realm>
</UserManager>

[/sourcecode]

You can see I'm passing the custom SQLs as "SelectUserSQL" and "UserFilterSQL"

4. You need to put following jars in to the $IS_HOME/repository/component/libs
mysql-connector-java-5.1.7-bin.jar and Sample_user_store-1.0.jar

5. Now I'm going to start the Identity server and sign in as admin

6. Go to users then you can see the users coming from secondary user store as read only
is

7. Now we need to create the internal role because we cannot create the roles inside of the secondary user store manager due to read only mode.So you can do it as follows.

is1

you have to give the permission to the created role

is2

Now you can assign the users from secondary user store.

is

8. Login to the IS from the secondary users.

is