Friday, October 14, 2016

Amazon API GW integration with WSO2 IS for OAuth 2.0 token validation

In this blog thought of discussing another interesting topic which is relate token validation and how you can register a custom Authorizers via lambda functions to the Amazon API Gateway and use WSO2 Identity Server as authorization server.

  So, Following steps will guide you on how to use WSO2 IS as a custom authorize for Amazon APIs.

Setup WSO2 Identity Server
  • We will be generating tokens in WSO2 IS and using them to call APIs configured in Amazon API Gateway Preparing WSO2 IS And Generating tokens 
  • When testing WSO2 IS for Amazon API Gateway, we used OAuth 2.0 Token Introspection API. You need host  (introspect.war) ​ that you need to deploy in IS. 
  • The source for this is found in [1]
    • Extract the downloaded zip file to a convenient file location. This distributed folder (by default the folder name is wso2is-5.2.0​ ) will be referred to as throughout the document.
    • Copy introspect.war file to /repository/deployment/server/webapps location. In order to generate an access token we need to create an Oauth2 application and get client credentials from there
    • Start the server and login to the management console with admin:admin credentials. Steps to start the product are in [2]. Also you can find the complete installation guide in [3] Note : In order to be accessed by Amazon Gateway Lambda function, this up and running Identity Server should be hosted with a public URL 4. In the main menu in management console, click “Add” under Service Provider
  • Give a Service Provider name and click Register. You will see the Service Provider
    Configuration page.
  • Expand Inbound Authentication Configuration​ panel.
  • Expand the OAuth/OpenID Connect Configuration​ and click Configure.
  • Fill in the form that appears. For the Allowed Grant Types​ you can disable the ones you do not require or wish to block.
  • Use following request to generate tokens with password grant type
 Replace and values with admin. Replace with Base64 encoded values

curl -k -d
"grant_type=password&username=<USERNAME>&password=<PASSWORD>&scope=<SCOPE>"​ ​-H
"Authorization: Basic <ENCODED_KEY>"​ ​-H "Content-Type:
application/x-www-form-urlencoded"
https://<IS_HOST>t:<IS_HTTPS_PORT>/oauth2/token
will have a response similar to,
curl -k -d "grant_type=password&username=admin&password=admin&scope=default "​ ​-H
"Authorization: Basic
X1ZpREJUMWJUSHF5eXFfR1Y0UWJoc0V6X1IwYTpLdzIxV1JPRmYyeTc4RGViMXY0UGpoRkdydGhq"​ ​-H
"Content-Type: application/x-www-form-urlencoded"
https://localhost:9443/oauth2/token
This will have a response similar to,
{
 "scope": "default"
 "token_type": "Bearer"
 "expires_in": 956
 "refresh_token": "23444-dff-32b0-b4cf-7dc7d8fd8205"
 "access_token": "455533ed-d222-3b0e-9512-fec0b94c1592"
}

  • We will use this access_token value when invoking APIs in AWS side.

Configuring Amazon API Gateway

  • Goto Lambda console in Amazon API Gateway and create new Lambda function.

  • This function should call Token Introspection API of WSO2 IS Server. I have attached a sample lambda function (Lambda.js) which is calling this API. You can copy the source of this file and
console.log('starting lambda');
var http = require('http');
exports.handler = function(event, context) {
    var tkn = event.authorizationToken;
 var postData = 'token='+tkn;
 console.log(postData);

 var options = {
   hostname: 'ip.address',
   port: 9763,
   path: '/introspect',
   method: 'POST',
   headers: {
     'Content-Type': 'application/x-www-form-urlencoded'
   }
 };

 var req = http.request(options, (res) => {
   console.log(`STATUS: ${res.statusCode}`);
   console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
   res.setEncoding('utf8');
   res.on('data', (chunk) => {
     console.log(`BODY: ${JSON.stringify(chunk)}`);
  validationReq(chunk,event,context);
   });
   res.on('end', () => {
     console.log('No more data in response.');
   });
 });

 req.on('error', (e) => {
   console.log(`problem with request: ${e.message}`);
 });

 // write data to request body
 req.write(postData);
 req.end();

}

var validationReq = function (obj,evt,ctx) {
    console.log(obj);
    obj = JSON.parse(obj);

    var bool = obj['active'];
 if(bool) {
     console.log('Token verified');
     ctx.succeed(generatePolicy('user', 'Allow', evt.methodArn));
 } else {
     ctx.fail("Unauthorized");
 }
 
}


var generatePolicy = function(principalId, effect, resource) {
    var authResponse = {};
    console.log(resource);
    authResponse.principalId = principalId;
    if (effect && resource) {
        var policyDocument = {};
        policyDocument.Version = '2012-10-17'; // default version
        policyDocument.Statement = [];
        var statementOne = {};
        statementOne.Action = 'execute-api:Invoke'; // default action
        statementOne.Effect = effect;
        statementOne.Resource = resource;
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    }
    return authResponse;
}






  • Copy it as the Lambda function code. Note that you have to replace <host_name of publiclyhosted wso2 is> and <port of publicly hosted wso2 is> values with actual host and port before using it.
  •  Save the Lambda function.
  • Follow Configure Custom Authorizer Using the API Gateway Console ​in [1] When creating the custom authorizer, make sure you give Lamba Region and Lambda Function details according to the function you created in Step 1.







  • After above configurations are done, you should have an API deployed in Amazon API
  • Gateway which is configured to use the custom authorizer which calls WSO2 IS to authorize. 
  • Invoke this API giving the access_token obtained from WSO2 IS as the Identity token source header value you configured when above step.
 Note:- How Please refer OAuth 2.0 Token Introspection API for WSO2 Identity Server to understand how introspect API calls would validate the access tokens and responses
Empty token
curl -k -H 'Content-Type: application/x-www-form-urlencoded' -X POST --data 'token=' https://localhost:9443/introspect
Response: {"active":false} 
Invalid token: 
curl -k -H 'Content-Type: application/x-www-form-urlencoded' -X POST --data 'token=Bjhk98792k9hkjhk' https://localhost:9443/introspect 
Response: {"active":false,"token_type":"bearer"} 
Get a valid token: 
curl -v -X POST --basic -u client_id:client_secret -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" -k -d "grant_type=client_credentials" https://localhost:9443/oauth2/token Validate the token:
curl -k -H 'Content-Type: application/x-www-form-urlencoded' -X POST --data 'token=99f0a7092c71a6e772cbcf77addd39ea' https://localhost:9443/introspect 
   Response: 
   { "username":"admin@carbon.super", 
     "nbf":3272, 
     "active":true, 
     "token_type":"bearer", 
     "client_id":"LUG28MI5yjL5dATxQWdYGhDLSywa" 
   } 

[1] https://github.com/facilelogin/aratuwa/tree/master/api-security/org.wso2.carbon.identity.oauth.introspection
[2] https://docs.wso2.com/display/IS520/Running+the+Product
[3] https://docs.wso2.com/display/IS520/Installation+Guide
[4] http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html

1 comment:

  1. I admire the valuable information you offer in your articles. I will bookmark your blog and have my children check up here often. I am quite sure they will learn lots of new stuff here than anybody else! Regards aws jobs in hyderabad.

    ReplyDelete