Wednesday, January 10, 2018

[WSO2] [APIM] [Gateway] How to log the Total Request Execution Time for a API Gateway Request

Latency is a major problem we face when working with APIs. When integrating an existing backend with an API manager, we specially concern about latency related issues. There are multiple reason that can cause latency issues; i.e network delays, preprocessing or post processing mediations logics, backend overload etc. In WSO2 API Manager, we can use a custom logger to log the APIM execution latency related information.

Please not that the the component I used in this article is written by Vanjikumaran [1,2]. Following are the steps to configure it with WSO2 API Gateway.

1. Login to the publisher, create and publish a duplicate api which calls the same backend which is being called by the original API we want to investigate.
2. Clone the custom handler from here and build it using maven.
3. Copy org.wso2.carbon.custom.logging-1.0.0.jar in the target directory, into <APIM_HOME>/repository/components/lib directory.
4. Go to <APIM_HOME>/repository/deployment/server/synapse-configs/default/api/ directory and open the XML file which belongs to the new API.
5. Locate handlers section and add following two handles to top and bottom of the handlers list respectively.

<handler class="org.wso2.carbon.custom.logging.CustomInboundLogging"/>
<handler class="org.wso2.carbon.custom.logging.CustomOutboundLogging"/>
Sample:
   <handlers>
      <handler class="org.wso2.carbon.custom.logging.CustomInboundLogging"/>
      <handler class="org.wso2.carbon.apimgt.gateway.handlers.common.APIMgtLatencyStatsHandler"/>
      <handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
         <property name="apiImplementationType" value="ENDPOINT"/>
      </handler>
      <handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>
      <handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.ThrottleHandler"/>
      <handler class="org.wso2.carbon.apimgt.gateway.handlers.analytics.APIMgtUsageHandler"/>
      <handler class="org.wso2.carbon.apimgt.gateway.handlers.analytics.APIMgtGoogleAnalyticsTrackingHandler">
         <property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
      </handler>
      <handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
      <handler class="org.wso2.carbon.custom.logging.CustomOutboundLogging"/>
   </handlers>
6. Restart the server and invoke the API.
7. You will see a log similar to following with the latency information.

[2017-11-15 18:20:59,712] INFO - CustomInboundLogging Inbound API call from client to gateway: correlationID=b9bcb61c-236a-47b6-910d-b2ced692b82f , httpMethod=GET , transactionId=7758369265731758509094 , userAgent=curl/7.54.0 , requestURI=/pizzashack/1.0.0/menu , requestTime=Wed Nov 15 18:20:59 PST 2017 , clientIP=10.10.20.19
[2017-11-15 18:20:59,729] INFO - CustomOutboundLogging Outbound API call from gateway to client: correlationID=b9bcb61c-236a-47b6-910d-b2ced692b82f , httpMethod=GET , appName=DefaultApplication , applicationId=1 , apiName=PizzaShackAPI , apiPublisher=admin , apiConsumerKey=S6efziZ11z4feJE9HaGSFSZxA80a , userName=admin@carbon.super , transactionId=7758369265731758509094 , requestURI=/pizzashack/1.0.0/menu , statusCode=200 , throttlingLatency=1 , roundTripLatency=17 , gatewayLatency=3 , keyManagerLatency=2 , EndPointURL=https://localhost:9443/am/sample/pizzashack/v1/api/

Please note that this approach is only used for dev requirements and not recommended for production as it adds an extra effort to each API call.

[1] https://plus.google.com/+VanjikumaranSivajothy
[2] https://github.com/vanjikumaran/APIMlogginghandlers

[WSO2] [APIM] Configure OAuth2/OpenID Connect Authenticator in API manager server

Please follow the below steps to install OAuth2/OpenID Connect Authenticator in API manager server.
1. Download OpenID Connect Authenticator bundle [1] from the WSO2 Store.
2. Stop the APIM server if it is already running.
3. Copy the downloaded bundle (org.wso2.carbon.identity.application.authenticator.oidc-5.1.2.jar) into {APIM_HOME}/repository/components/dropins/ directory to install.
4. Start the server.
Now you should be able to see the OAuth2/OpenID Connect Authenticator under federated authenticators in the API Manager server.


However, configuring authenticators in APIM server itself is discouraged. The recommended way to achieve this is through a separate identity server.



[1] https://store.wso2.com/store/assets/isconnector/details/2b71e151-4c38-4e8f-b25a-f3a980cf0862

[WSO2] [APIM] How to change the subscription tier of an existing subscription without re-subscribing

WSO2 APIM 2.1.0 does not support tier modifications for existing subscriptions through UI or the Rest API. However, we can do this manually as below.

The subscription information is stored in the AM_SUBSCRIPTION table of the WSO2AM_DB database. We can change the subscription tiers manually through updating the corresponding db entry.

For example, if we want to change all ‘Unlimited’ tiers to ‘Gold’, then we can execute following command:

update AM_SUBSCRIPTION set TIER_ID = 'Gold' where TIER_ID = 'Unlimited';

If we want to change ‘Unlimited’ tiers to ‘Gold’ of a specific subscription, then we can execute following command after identifying the subscription id:

update AM_SUBSCRIPTION set TIER_ID = 'Gold' where SUBSCRIPTION_ID=1 AND TIER_ID= "Unlimited";

This update will take around 15minutes to update the cache. Note that above queries are written for the mysql server.

How to check the processes that cause High Disk Usage (Hign I/O operations)

There can be multiple reasons for the high disk usage (IO). In order to isolate the process that is responsible for the highest IO usage, we can do the following tasks:

1. Install iotop by following [1] and execute iotop --only command to get the list of processes that do I/O operations. We will be able to get an idea about the reason for the high disk usage after identifying the processes with high I/O.
2. When the available physical memory is low, disk usage can also get increased. Therefore, execute free -m command and check the memory usage of the machine.
3. Stop the servers one at the time and check whether stopping of any server significantly decrease the rate of disk usage.

After Identifying the process, we can further troubleshoot the functionalities to identify the root cause of the high disk usage.

[1] https://lintut.com/install-iotop-on-linux/

[WSO2] [APIM] Custom authentication handler for Okta based token validation

When invoking an API published in WSO2 API manager, the user has to send a valid access token (Oauth 2.0 token) in the Authorization header to verify the identity of the invoker. WSO2 API gateway calls the key validation service in the key manager component in order to check the validity of the token. If it is valid, the user can invoke the API and if not, the user will be served with a 401 (Unauthorized) response.
The key manager is usually a WSO2 component (APIM key manager, Identity Server as key manager). However, there can be some usecases where we need to integrate a third part key manager for authorizing API invocation requests. API manager provides an extension point for integrating third part identity providers as the key manager of APIM manager setup. You can follow [1] and integrate a third party key manager to WSO2 API manager deployment.

There can be situations, where the token was issued by a different key manager/Oauth identity provider which is not integrated to APIM and you just need to validate the token against the particular identity provider. In such cases, you can write a custom handler to replace the default Authentication handler which calls the default key validation service.

In this article, I will discuss on how to write a custom authentication handler to validate an access token (issued by Okta) against Okta.

This custom handler will replace the default authentication handler and validate the access token by calling the Okta introspection endpoint [3]. If the introspection endpoint identifies the token as valid, then the handler will authorize the request. If you want to control the API access based on the scopes, this handler can be modified to authorize the requests if and only if the given token was generated with a white listed scope (We have to maintained a set of white listed scopes in the properties file and validate the requests against it).

Following are the steps to configure the Okta based integration.

1. Download the source code here. Open the okta.properties file located at resources directory and provide the values for introspectionEndpoint, client_id and client_secret of the APP you have already created in Okta. You can provide 'NA' (client_secret=NA) if the id and secret values are not available for the app.

 Please enable debug logs if you want to check the requests being sent to the introspection endpoint.
  • open log4j.properties file located at <APIM_HOME>/repository/conf/ directory and add the following line:
     log4j.logger.org.wso2.carbon.authorization=DEBUG

2. Use Maven to build the project (mvn clean install), copy the authorization-1.0.0-SNAPSHOT.jar to <server-home>/repository/components/lib/ folder and restart the server.

 3. Create and publish your API using API publisher UI(Eg: let's assume API name is BlogPost, API version is 1.0.0 and user who published the API is admin)

4. Then go to the following directory
<API_MANAGER_HOME>/repository/deployment/server/synapse-configs/default/api/

5. Open the xml file with the following format

{API Provider}–{API Name}_v{Version}.xml(Eg: admin--BlogPost_v1.0.0.xml)

6. Replace
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>
with
<handler class="org.wso2.carbon.authorization.UserAuthorizationHandler"/>

7. Wait some time until he API get redeployed (Expects following message in <server-home>/repository/logs/wso2carbon.log file

[2017-02-08 11:51:54,988] INFO - API Initializing API: admin--BlogPost:v1.0.0
[2017-02-08 11:51:54,990] INFO - DependencyTracker API : admin--BlogPost:v1.0.0 was updated from the Synapse configuration successfully
[2017-02-08 11:51:54,990] INFO - APIDeployer API: admin-BlogPost:v1.0.0 has been updated from the file: /home/user/demo/setup/wso2am-2.1.0/repository/deployment/server/synapse-configs/default/api/admin--BlogPost_v1.0.0.xml
[2017-02-08 11:51:56,990] INFO - API Destroying API: admin--BlogPost:v1.0.0

8. Now the API is ready to be invoked with a token returned from Okta.

Sample request:

curl -X GET --header 'Accept: application/xml' --header 'Authorization: Bearer <complete token returned from okta>' 'https://10.200.7.41:8243/test/1/*' -k


We configured the custom handler through editing the API xml directly. This change will be overridden by the default handler if your republish the API. Also, your new apis will not be deployed with the custom handler. In order to make this change permanent, please modify the global API template (velocity_template) as follows:

1. Backup existing velocity_template.xml file located at
 <APIM_HOME>/repository/resources/api_templates/ directory and open it in an editor.

2. Replace the <handlers> element with following (this will replace the default handler with the custom handler we wrote):

<handlers xmlns="http://ws.apache.org/ns/synapse">
<handler class="org.wso2.carbon.authorization.UserAuthorizationHandler" />
#foreach($handler in $handlers)
#if(!($handler.className == "org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"))
<handler xmlns="http://ws.apache.org/ns/synapse" class="$handler.className">
#if($handler.hasProperties())
#set ($map = $handler.getProperties() )
#foreach($property in $map.entrySet())
<property name="$!property.key" value="$!property.value"/>
#end
#end
</handler>
#end
#end
</handlers>

3. Save the change and publish a test api to check whether the custom handler is properly placed as bellow in the api xml file located at <APIM_HOME>/repository/deployment/server/synapse-configs/default/api/ directory.


<handlers>
<handler class="org.wso2.carbon.authorization.UserAuthorizationHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.common.APIMgtLatencyStatsHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
<property name="apiImplementationType" value="ENDPOINT"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.ThrottleHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.analytics.APIMgtUsageHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.analytics.APIMgtGoogleAnalyticsTrackingHandler">
<property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
</handlers>


Please note the following limitations as well


1. Since this approach replaces the APIM default key validation flow, you won't be able to create applications, generate access tokens and invoke apis through the WSO2 API store. You will have to pass a valid token retrieved from Okta to invoke the apis.
2. Handler will call the okta introspection endpoint for validating each request since there is no token caching mechanism.
3. API subscription level usage stats and some of the subscription level throttling policies won't work as those are handled by the default authentication handler.