Hola ๐
Greetings Everyone ๐ย โฆ
This is another medium on walking ๐ถ and swimming ๐๐ผ through customizing the opaque access tokens using APIM Token Issuer when we do have a requirement issue
The demo is presented and walked-through using WSO2 API Manager v2.6
Whaaaaat? waitโฆ Why?ย ๐ค
You probably now have a question on why do we need to do that and does it actually matterโฆ Let me give you a simple stupid occasion on when and where I actually need that.
RepoDeWS is a developer-management system which has a set of in-built management services in SOAP. These SOAP services are exposed as REST APIs with the help of WSO2 API Manager. Now the RepoDeWS team is having an undergoing process of security maintenance and they are expecting their users to invoke the APIs using access tokens with a "Dev-Hash" value appended to it.
This "Dev-Hash" value will be passed as a Header (devhash) when requesting an Access Token and will be appended during the generation of the opaque access token
Ohโฆ I forgot to mention that the Dev-Hash value is a unique hash value given to a set of top-rated developers to enrich their API responses with the last accessed timestamps ๐
Let's just focus on the implementation and enhancements and will keep our use-cases behind that.
Implementation
To accomplish my simple requirement, We have to extend the implementation of APIMTokenIssuer and push our enhancements.
The APIMTokenIssuer is responsible for generating opaque access tokens and JWT tokens in the WSO2 API Manager platform
First, create a simple maven project and add the following dependency to the POM. This will help us to resolve most of the dependency issues when extending the APIMTokenIssuer class.
<dependencies>
<dependency>
<groupId>org.wso2.carbon.apimgt</groupId>
<artifactId>org.wso2.carbon.apimgt.keymgt</artifactId>
<version>6.5.222</version>
</dependency>
</dependencies>
But, if you encounter any dependency problems or if you are not able to resolve the dependencies in the POM, then add the following as wellย โฆ
<repositories>
<repository>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
</pluginRepository>
</pluginRepositories>
Phew ๐
Managing dependencies is harder than managing expenses bruh ๐ฌ๐ฌ๐ญย โฆ
Now let's jump into the extended implementation. Given below is the piece of code (I) developed to solve my own problem [Am I overreacting ๐ณย ? I think I am ๐]
package com.sample.token;
import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.utils.APIUtil;
import org.wso2.carbon.apimgt.keymgt.issuers.APIMTokenIssuer;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.identity.oauth2.model.RequestParameter;
public class MyAPIMTokenIssuer extends APIMTokenIssuer {
private static final Log log = LoggerFactory.getLog(MyAPIMTokenIssuer.class)
@Override
public String accessToken(OAuthTokenReqMessageContext tokReqMsgCtx) throws OAuthSystemException {
// generate access token using super method
String accessToken = super.accessToken(tokReqMsgCtx);
String clientId = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId();
Application application;
try {
application = APIUtil.getApplicationByClientId(clientId);
String tokenType = application.getTokenType();
// only acceptable for opaque access tokens and not JWT tokens
if (!APIConstants.JWT.equals(tokenType)) {
// retrieve all request parameters sent to the token request
RequestParameter[] reqParams = tokReqMsgCtx.getOauth2AccessTokenreqDTO().getRequestParameters();
for (int i = 0l i < reqParams.length; i++) {
// check for devhash from the request parameters
// and append it to the access token
if ("devhash".equals(reqParams[i].getKey())) {
accessToken += reqParams[i].getValue()[0];
break;
}
}
}
} catch (APIManagementException e) {
log.error("Exception occured ", e);
}
return accessToken;
}
}
I know right, itโs really hard to follow these things up ๐
Therefore, I give you a golden opportunityโฆ Please go and find the sample implementation (gist) from GitHub Gist (save your time on reading this medium) and enjoy enriching it ๐
Your inner voice: Hmmmโฆ Thanks for that. I have gone through the samples and copied everything from the given sources. Now, what should I do next? Where should I put these implementations???
Me: Ummmโฆ I think I heard your inner voice. But thank you for the question.
As of next steps we have to build-up the maven project by executing the following command from a terminal
mvn clean package
And then copy and place the built JAR artifact from the target
folder to the <APIM>/repository/components/lib
directory.
And at last [Whoaโฆ. the magical keyword ๐ค๐], change the APIMTokenIssuer class representation to the MyAPIMTokenIssuer
class by editing the <IdentityOAuthTokenGenerator>
property in the <APIM>/repository/conf/identity/identity.xml
.
<IdentityOAuthTokenGenerator>com.sample.token.MyAPIMTokenIssuer</IdentityOAuthTokenGenerator>
๐ Voila!!! ๐
Letโs do a test-run with our piece of codeโฆ
Keep Stacking!!!
Test Drive
Fire up the WSO2 API Manager server with the artifacts and the above-mentioned configuration changes.
Execute the following CURL command to generate an Opaque Access Token and letโs verify whether it got generated with the specified Dev-Hash value or notโฆ
curl --location --request POST 'https://localhost:8243/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic {Base64<ClientID>:<ClientSecret>} \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=admin' \
--data-urlencode 'password=admin' \
--data-urlencode 'scope=default' \
--data-urlencode 'devhash=af1c4ca13ab7d6c8d2a887d7ce8250a2'
And the response should be as follows with the Dev-Hash value appended to the Access Token
{
"access_token": "25b9ded7-7441-3b69-bb6b-b1f1828bfff9af1c4ca13ab7d6c8d2a887d7ce8250a2",
"refresh_token": "d86ac9b8-a3aa-3664-9d39-090ca49a9435",
"scope": "default",
"token_type": "Bearer",
"expires_in": 3600
}
athiththan11 / Sample-APIMTokenIssuer
A simple custom APIM Token Issuer Implementation
Custom APIM Token Issuer
A sample extended APIMTokenIssuer
implementation to append a custom value to the generated Opaque Access Tokens.
A Medium Blog: Customizing Opaque Access Token Generation
Implementation
This is a sample implementation to demonstrate on how-to extract a custom header sent to with the Token
request and append it to the generate Opaque access token.
The custom header used here is called as devhash
which is a hash value as data-urlencode
with the Token
request.
Given below is a sample /token
requst
POST https://localhost:8243/token
Authorization: Basic <Base64 {Client ID}:{Client Secret}>
Content-Type: application/x-www-form-urlencoded
grant_type=password
username=admin
password=admin
scope=defualt
devhash=af1c4ca13ab7d6c8d2a887d7ce8250a2
curl --location --request POST 'https://localhost:8243/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic <Base64 {Client ID}:{Client Secret}> \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=admin' \
--data-urlencode 'password=admin' \
--data-urlencode 'scope=default' \
--data-urlencode 'devhash=af1c4ca13ab7d6c8d2a887d7ce8250a2'
And the response should be as follows...
Top comments (0)