Skip to content
This repository was archived by the owner on Dec 17, 2025. It is now read-only.

Commit 8323b62

Browse files
committed
README update with more precision + validation method
1 parent eb92e23 commit 8323b62

File tree

2 files changed

+54
-23
lines changed

2 files changed

+54
-23
lines changed

README.md

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,38 @@
11
# cics-java-liberty-tai-jwt
22
Sample WebSphere Liberty Trust Association Interceptor (TAI) for use with CICS Liberty to validate [JSON web tokens (JWTs)](https://tools.ietf.org/html/rfc7519)
3-
and set the authorized user ID based on the JWT subject claim.
3+
and set the authenticated user ID based on the JWT subject claim. This TAI sample can also be used with z/OS Liberty.
44

55
For detailed configuration instructions see [Configuring TAI in Liberty](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_sec_tai.html) and [Developing a custom TAI for Liberty](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_dev_custom_tai.html).
6-
A TAI can be deployed as a JAR file and added to the Liberty library (as shown in this description) **__OR__** as a Liberty feature (more information in the [Knowledge Center](https://www.ibm.com/support/knowledgecenter/SSEQTP_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_feat_tai.html)).
6+
A TAI can be deployed as a JAR file and added to the Liberty library (as shown in this sample) **__OR__** as a Liberty feature (more information in the [Knowledge Center](https://www.ibm.com/support/knowledgecenter/SSEQTP_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_feat_tai.html)).
77

88
## Introduction
99

10-
You can configure Liberty to integrate with third-party security services by using a TAI. The TAI can be called before or after single sign-on (SSO).
10+
You can configure Liberty to integrate with third-party security services by using a TAI. The TAI can be called before or after single sign-on (SSO), for more configuration options see the [Knowledge Center](https://www.ibm.com/support/knowledgecenter/SSEQTP_liberty/com.ibm.websphere.liberty.autogen.base.doc/ae/rwlp_config_trustAssociation.html).
1111
You can develop a custom TAI class by implementing the [com.ibm.wsspi.security.tai.TrustAssociationInterceptor](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.javadoc.liberty.doc/com.ibm.websphere.appserver.api.security_1.2-javadoc/com/ibm/wsspi/security/tai/TrustAssociationInterceptor.html) interface provided in the Liberty server.
1212

13-
The trust association interface is a service provider API that enables the integration of third-party security services with a Liberty server. When processing the web request, the Liberty server calls out and passes the `HttpServletRequest` and `HttpServletResponse` to the trust association interceptors. The `HttpServletRequest` calls the `isTargetInterceptor` method of the interceptor to see whether the interceptor can process the request. After an appropriate trust association interceptor is selected, the `HttpServletRequest` is processed by the `negotiateValidateandEstablishTrust` method of the interceptor, and the result is returned in a `TAIResult` object. You can add your own logic code to each method of the custom TAI class.
13+
The trust association interface is a service provider API that enables the integration of third-party security services with a Liberty server. When processing the web request, the Liberty server calls out and passes the `HttpServletRequest` and `HttpServletResponse` to the trust association interceptors. The `HttpServletRequest` calls the interceptor `isTargetInterceptor` method to determine whether the interceptor should catch the request. After an appropriate trust association interceptor is selected, the `HttpServletRequest` is processed by the interceptor `negotiateValidateandEstablishTrust` method, and the result is returned in a `TAIResult` object. You can add your own logic code in the TAI methods.
1414

1515
> Note: The use of a TAI should be handled with care, where possible use a standard supported mechanism within Liberty to achieve security architecture and integration goals. For instance, the validation of a JWT can be achieved by using built-in process in Liberty stand-alone v16.0.0.3 and later versions.
1616
1717
This sample JWTTAI Java class provides the following functions:
1818

19-
* JWT validation based on the JWTConsumer API (Liberty JWT feature) - the JWT signature will be checked, and the claims (exp, iss, aud) will be validated against the expected values;
19+
* JWT validation based on the JwtConsumer API (Liberty JWT feature) - the JWT signature will be checked, and the claims (exp, iss, aud) will be validated against the expected values;
2020

2121
* Assign the ***Principal*** identity by retrieving the ***subject*** claim;
2222

2323
## How does it work?
2424

25-
When the Liberty server is launched, it will read the JWTConsumer configuration named `myJWTConsumer` and make it available. The JWTTAI TAI will also be initialized, but in this sample nothing is done during the TAI initialization process.
25+
When the Liberty server is launched, it will read the jwtConsumer configuration named `myJWTConsumer` and make it available. The JWTTAI TAI will also be initialized, but in this sample nothing is done during the TAI initialization process.
2626

2727
JWTTAI will only intercept ***HTTPS*** requests that contain a ***JWT in the `Authorization Bearer` header***.
28-
It will create an instance of a *JWTBuilder* based on the `myJWTConsumer` configuration to validate and parse JWTs.
28+
It will create an instance of a *JwtConsumer* based on the `myJWTConsumer` configuration to validate and parse JWTs.
2929

3030
Once the JWTTAI is selected to handle the authentication, it will validate the JWT signature with the `trustedAlias` certificate taken from `myJWTConsumer` and will parse the JWT to retrieve the claims.
31-
The JWTConsumer only verifies the issuer, audience, expiry claims; to validate the other claims some lines of code need to be written in the `negotiateValidateandEstablishTrust` method.
31+
The JwtConsumer only verifies the issuer, audience and expiry claims; to validate the other claims some lines of code need to be written in the TAI `negotiateValidateandEstablishTrust` method.
3232
If the JWT passes all the checks, the subject claim will be defined as the Principal identity and the request will be processed.
33-
Otherwise the request will be rejected.
33+
Otherwise the request will be rejected.
3434

35-
Be careful, the subject claim needs to match an entry of the user registry.
35+
Be careful, the subject claim needs to match an entry in the user registry.
3636

3737
This sample shows how a TAI can handle a simple JWT use case.
3838

@@ -42,7 +42,7 @@ To use this sample download the code or clone this repository and load the JWTTA
4242

4343
Cutomize the JWTTAI.java class, if necessary.
4444

45-
To compile the JWTTAI.java class and generate the JAR file, the only Java library required is **__WebSphere Liberty libraries__**, available with CICS Explorer SDK
45+
To compile the JWTTAI.java class and generate the JAR file, the only Java library required is **__WebSphere Liberty libraries__**, available with CICS Explorer SDK.
4646

4747
Finally, upload the generated JAR file (as binary) to the appropriate zFS. In the example configuration, we have uploaded the JAR file in the *jars* folder (created manually) located in the server configuration directory (same directory as server.xml).
4848

@@ -53,30 +53,61 @@ To configure the Liberty server, add the following elements to the Liberty serve
5353
```xml
5454
<featureManager>
5555
<feature>cicsts:security-1.0</feature>
56+
<feature>appSecurity-2.0</feature>
5657
<feature>jwt-1.0</feature>
5758
</featureManager>
5859

5960
<library id="myTAIlib">
60-
<fileset dir="${server.config.dir}" includes="jwttai.jar"/>
61+
<fileset dir="${server.config.dir}/jars" includes="jwttai.jar"/>
6162
</library>
6263

63-
<trustAssociation failOverToAppAuthType="false" id="myTrustAssociation" invokeForUnprotectedURI="false">
64-
<interceptors className="com.ibm.cicsdev.tai.JWTTAI" id="JWTTAI" invokeAfterSSO="true" invokeBeforeSSO="false" libraryRef="myTAIlib"/>
64+
<trustAssociation id="myTrustAssociation" failOverToAppAuthType="false" invokeForUnprotectedURI="false">
65+
<interceptors id="JWTTAI" className="com.ibm.cicsdev.tai.JWTTAI" invokeAfterSSO="true" invokeBeforeSSO="false" libraryRef="myTAIlib"/>
6566
</trustAssociation>
6667

67-
<jwtConsumer audiences="zCEE" id="defaultJWTConsumer" issuer="idg" signatureAlgorithm="RS256" trustStoreRef="JWTStore" trustedAlias="DefaultCert.APIC"/>
68-
<keyStore id="JWTStore" .../>
68+
<jwtConsumer id="myJWTConsumer" audiences="catalogManager" issuer="idg" signatureAlgorithm="RS256" trustStoreRef="JWTTrustStore" trustedAlias="<certificate_label_or_alias>"/>
69+
<keyStore id="JWTTrustStore" .../>
6970

7071
```
7172

72-
This modification adds the necessary JAR file to a library that can then be referenced by the `trustAssociation` element.
73+
This modification adds the necessary JAR file to a library that can then be referenced by the `trustAssociation` element. The variable `server.config.dir` points to the folder that contains the server.xml configuration file.
7374
You may need to change the className attribute to match the name of your TAI class.
7475
This also sets the failOverToAppAuthType attribute to false, so the application security is disabled.
7576

76-
More information on the `trustAssocation` and `interceptors` elements can be found on the [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.liberty.autogen.base.doc/ae/rwlp_config_trustAssociation.html).
77-
More information on the `jwtConsumer` element can be found on the [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.liberty.autogen.base.doc/ae/rwlp_config_jwtConsumer.html).
77+
The `jwtConsumer` tag specifies the values that are expected for different claims; update the `audiences` and `issuer` values to match the JWT generator configuration. The tag also specifies which public certificate to use (`trustedAlias`) to validate the JWT signature.
78+
> Note 1: only the public certificate is required, no need to have the private key in the keyStore.
79+
80+
> Note 2: if using a SAF keyring with only a public certificate, do connect the certificate with usage **CERTAUTH**.
81+
82+
More information on the `trustAssocation` and `interceptors` elements can be found on the [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.liberty.autogen.base.doc/ae/rwlp_config_trustAssociation.html).<br/>
83+
More information on the `jwtConsumer` element can be found on the [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.liberty.autogen.base.doc/ae/rwlp_config_jwtConsumer.html).<br/>
84+
More information on the different supported keyStore types on the [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/en/SS7K4U_liberty/com.ibm.websphere.wlp.zseries.doc/ae/rwlp_sec_keystores.html).<br/>
7885

7986
## Testing the TAI
8087

81-
To test the TAI you will invoke an existing application hosted on your Liberty server. The invokation needs to be an HTTPS request containing a JWT in the Authorization header.
82-
Make sure to use a JWT that contains the expected claims and to use the right set of public/private keys. If everything goes well you should see that the transaction is run with the user ID provided in the subject claim.
88+
To test the TAI, invoke an existing application hosted on your Liberty server that requires authentication. The invokation needs to be an HTTPS request containing a JWT in the Authorization header. The easiest way to build and send an HTTPS request is to use a REST client.<br/>
89+
Make sure to use a JWT that contains the expected claims and to use the right set of public/private keys. If everything goes well you should see that the transaction is run with the user ID provided in the subject claim. Otherwise check the messages.log file.
90+
91+
### Generate a JWT with Liberty
92+
93+
If you don't have a JWT generator at hand, you can use the Liberty server to do it for you.<br/>
94+
Simply add the following `jwtBuilder` tag in the server.xml configuration file:
95+
96+
```xml
97+
<jwtBuilder id="myJWTBuilder" audiences="<audiences_list>" issuer="<issuer_value>" keyAlias="<certificate_label_or_alias>" keyStoreRef="<keyStoreID>"/>
98+
<keyStore id="<keyStoreID>" .../>
99+
```
100+
Replace the placeholders with the correct values.
101+
> Note: This time the keyStore needs to contain the private key in order to sign the JWTs. If the keyStore defined earlier does contain the private key, it can be reused here instead of redefining a new keyStore.
102+
103+
More information on the `jwtBuilder` element on the [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/en/SS7K4U_liberty/com.ibm.websphere.liberty.autogen.zos.doc/ae/rwlp_config_jwtBuilder.html).
104+
105+
The JWT feature exposes JWT builders with a REST API. A token can be retrieved by sending the HTTPS request:<br/>
106+
**GET https://&lt;hostname&gt;:&lt;httpsPort&gt;/jwt/ibm/api/myJWTBuilder/token**<br/>
107+
where `myJWTBuilder` is the id used by the configuration.
108+
109+
If the request is sent with a web browser, the browser will prompt for credentials and if the authentication succeeds a JWT will be returned.<br/>
110+
If the request is sent with a REST client, the request needs to contain a Basic Auth header with the credentials.
111+
112+
Once the JWT retrieved, it should be added to the request as an HTTP Authorization header, for instance "Authorization: Bearer &lt;JWT&gt;".
113+

src/com/ibm/cicsdev/tai/JWTTAI.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ public TAIResult negotiateValidateandEstablishTrust(HttpServletRequest req,
6969
// Decode the JWT using the JwtConsumer to obtain the claims
7070
JwtConsumer jwtConsumer;
7171
try {
72-
// Use the defaultJWTConsumer configuration (in server.xml)
73-
jwtConsumer = JwtConsumer.create("defaultJWTConsumer");
72+
// Use the myJWTConsumer configuration (cf. server.xml)
73+
jwtConsumer = JwtConsumer.create("myJWTConsumer");
7474

7575
JwtToken jwtTokenConsumer = jwtConsumer.createJwt(jwtTokenString);
7676
Claims jwtClaims = jwtTokenConsumer.getClaims();

0 commit comments

Comments
 (0)