RSS

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

05 Apr

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

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.
    }
}

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

  <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>

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.

 
    <!-- 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>

restart the ESB.

Again go to source view and place the following xml to engage the custom handler in to the API element

 
    <handlers>
         <handler class="org.wso2.handler.SimpleOauthHandler"/>
    </handlers>
1

Total configuration looks like this
1
  <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>

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.

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

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

About these ads
 

Tags: , ,

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

  1. Mike Stuart

    August 15, 2013 at 2:53 am

    I downloaded the maven project, but can’t find all the dependencies. Are there any special repositories (from WSO2?) that need to be specified? Also, I’ll go to the WSO2 docs for the info, but at least a note on how to deploy the handler after it is build would be nice. But very helpful and well written, thanks.

     
    • Bhathiya

      February 3, 2014 at 12:25 pm

      pom.xml should be changed as follows.

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0&quot;
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot;
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
      <modelVersion>4.0.0</modelVersion>

      <groupId>handler</groupId>
      <artifactId>handler</artifactId>
      <version>1.0</version>
      <repositories>
      <repository>
      <id>wso2-nexus</id>
      <name>WSO2 internal Repository</name>
      <url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url&gt;
      <releases>
      <enabled>true</enabled>
      <updatePolicy>daily</updatePolicy>
      <checksumPolicy>ignore</checksumPolicy>
      </releases>
      </repository>
      </repositories>
      <dependencies>
      <dependency>
      <groupId>org.apache.synapse</groupId>
      <artifactId>synapse-core</artifactId>
      <version>2.1.1-wso2v1</version>
      </dependency>

      <dependency>
      <groupId>org.apache.axis2.wso2</groupId>
      <artifactId>axis2</artifactId>
      <version>1.6.1.wso2v7</version>
      </dependency>
      <dependency>
      <groupId>org.wso2.carbon</groupId>
      <artifactId>org.wso2.carbon.identity.oauth.stub</artifactId>
      <version>4.0.7</version>
      </dependency>
      </dependencies>
      </project>

       
  2. faisal

    June 12, 2014 at 6:41 am

    Hi,
    I have requirement bit different i get normal header request with username&password need to validate with wso2 esb user-store like username-token done.But username-token has its own message format where as my client is not sending me in that format how would i change header before the proxy.
    please refer this

    http://stackoverflow.com/questions/24177794/how-to-write-custom-handler-axis2-handler-to-read-custom-headers-message-and-v

     

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: