This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, visit https://wso2.com/documentation/.

Securing REST APIs

Using a Basic Auth Handler

In most of the real-world use cases of REST, when a consumer attempts to access a privileged resource, credentials must be provided in an Authorization header or the consumer will be refused access. In WSO2 ESB, when we want to secure a REST API, we can simply make it available via HTTPS and let the security handlers validate the credentials. By default, the ESB does not include any REST Security Handlers, but the following example of a primitive security handler serves as a template that can be used to write your own security handler to secure a REST API in the ESB.

You add the REST request handler to the <handlers> element of the API configuration, as follows (you cannot add it through the REST API UI):

<api name="StockQuoteAPI" context="/stockquote">
   <resource uri-template="/view/{symbol}" methods="GET" protocol="https">
      <inSequence>
         <payloadFactory>
        <format>
        <m0:getQuote xmlns:m0="http://services.samples">
                <m0:request>
                   <m0:symbol>$1</m0:symbol>
                </m0:request>
             </m0:getQuote>
        </format>
        <args>
        <arg expression="get-property('uri.var.symbol')"/>
        </args>
     </payloadFactory>
     <send>
        <endpoint>
        <address uri="http://localhost:9000/services/SimpleStockQuoteService" format="soap11"/>
        </endpoint>
     </send>
      </inSequence>
      <outSequence>
     <send/>
      </outSequence>
   </resource>
    <handlers>
       <handler class="org.wso2.rest.BasicAuthHandler"/>
    </handlers>
  </api>

The custom Basic Auth handler in this sample simply verifies whether the request uses username: admin and password: admin. Following is the code for this handler:

package org.wso2.rest;
import org.apache.commons.codec.binary.Base64;
import org.apache.synapse.MessageContext;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.apache.synapse.core.axis2.Axis2Sender;
import org.apache.synapse.rest.Handler;

 
import java.util.Map;

 
public class BasicAuthHandler implements Handler {
    public void addProperty(String s, Object o) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

 
    public Map getProperties() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

 
    public boolean handleRequest(MessageContext messageContext) {

 
        org.apache.axis2.context.MessageContext axis2MessageContext
                = ((Axis2MessageContext) messageContext).getAxis2MessageContext();
        Object headers = axis2MessageContext.getProperty(
                org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);

 
 
        if (headers != null && headers instanceof Map) {
            Map headersMap = (Map) headers;
            if (headersMap.get("Authorization") == null) {
                headersMap.clear();
                axis2MessageContext.setProperty("HTTP_SC", "401");
                headersMap.put("WWW-Authenticate", "Basic realm=\"WSO2 ESB\"");
                axis2MessageContext.setProperty("NO_ENTITY_BODY", new Boolean("true"));
                messageContext.setProperty("RESPONSE", "true");
                messageContext.setTo(null);
                Axis2Sender.sendBack(messageContext);
                return false;

 
            } else {
                String authHeader = (String) headersMap.get("Authorization");
                String credentials = authHeader.substring(6).trim();
                if (processSecurity(credentials)) {
                    return true;
                } else {
                    headersMap.clear();
                    axis2MessageContext.setProperty("HTTP_SC", "403");
                    axis2MessageContext.setProperty("NO_ENTITY_BODY", new Boolean("true"));
                    messageContext.setProperty("RESPONSE", "true");
                    messageContext.setTo(null);
                    Axis2Sender.sendBack(messageContext);
                    return false;
                }
            }
        }
        return true;
    }

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

 
    public boolean processSecurity(String credentials) {
        String decodedCredentials = new String(new Base64().decode(credentials.getBytes()));
        String userName = decodedCredentials.split(":")[0];
        String password = decodedCredentials.split(":")[1];
        if ("admin".equals(userName) && "admin".equals(password)) {
            return true;
        } else {
            return false;
        }
    }
}

You can build the project (mvn clean install) for this handler by accessing its source here:

https://svn.wso2.org/repos/wso2/carbon/platform/branches/4.1.0/products/esb/4.7.0/modules/samples/integration-scenarios/starbucks_sample/BasicAuth-handler

Alternatively, you can download the JAR file from the following location, copy it to the repository/component/lib directory, and restart the ESB:

https://svn.wso2.org/repos/wso2/carbon/platform/branches/4.1.0/products/esb/4.7.0/modules/samples/integration-scenarios/starbucks_sample/bin/WSO2-REST-BasicAuth-Handler-1.0-SNAPSHOT.jar

You can now send a request to the secured API. For example, you can send it using cURL as the REST client:

curl -v -k -H "Authorization: Basic YWRtaW46YWRtaW4="  https://localhost:8243/stockquote/view/IBM

Using an OAuth Base Security Token

You can generate an OAuth base security token using WSO2 Identity Server, and then use that token when invoking your REST API to connect to a REST endpoint. This approach involves the following tasks:

  1. Create a custom handler that will validate the token
  2. Create a REST API that points to the REST endpoint and includes the custom handler
  3. Create an OAuth application in Identity Server and get the access token
  4. Invoke the API with the access token

Creating the Custom Handler

The custom handler must extend AbstractHandler and implement ManagedLifecycle as shown in the following example. You can download the Maven project for this example at: https://github.com/wso2-docs/ESB-OAuthHandler

package org.wso2.handler;
 
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.
    }
}

Creating the API

You will now create a REST API named TestGoogle that connects to the following endpoint: https://www.google.lk/search?q=wso2

  1. In the ESB Management Console, go to Manage -> Service Bus and click Source View.
  2. Insert the following XML configuration into the source view before the closing </definitions> tag to create the TestGoogle API:

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

    Notice that the <handlers> tag contains the reference to the custom handler class.

  3. Copy the custom handler.jar to the <ESB_HOME>/repository/components/libs directory.
  4. Open <ESB_HOME>/repository/conf/axis2/axis2.xml and add 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>
  5. Restart the ESB.

Getting the OAuth Token

You will now use Identity Server to create an OAuth application and generate the security token.

  1. Start WSO2 Identity Server and log into the management console.
  2. Click Manage -> OAuth and create an OAuth application.
  3. Note the access token URL and embed it in a cURL request to get the token. For example:
    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

Identity Server returns the access token, which you can now use when invoking the API. For example:

curl -v -X GET -H “Authorization: Bearer ca1799fc84986bd87c120ba499838a7″ http://10.100.1.198:8280/search