Thursday, September 12, 2019

How to view an LtpaToken2 token

Leave a Comment

If you find this article useful, please let us know in the comments.

The Article

If you use any WebSphere-based applications (DASH, Impact, BPM, ODM, etc.), you're using LTPA Tokens. An LTPA Token is a browser cookie named LtpaToken2. You can see it if you turn on developer tools in your browser (F12) after you log into one of these applications. You'll see it in the "COOKIES" request header. The value of that header will look something like this:

s_vi=[CS]v1|2E7C0CDA8507BB19-4000010FA0013DFE[CE]; s_cc=true; s_sq=%5B%5BB%5D%5D; JSESSIONID=00004FX-3-uu2ZoYHx1t9p8fJIb:52e767f1-e67e-4220-8435-fa54d8776107; CSRFCookie=C9495874E4D5BA23D8E1330E4F76EA5C9495874E4D5BA23D8E1330E4F76EA5; LtpaToken2=i/InlYuq2tm3rPdd/3BEzA8m9BCc8WGNR3q6eu7OfeQ7s1ICiMvPv0QCNQar5cCQlyVH5GE0N0VNbJj1Z6sUGe2S3nb1kwwbzdzPWzCbNPPtN3uiPWnfLyXzi5T4p2Pz/URwCfP6zWW2NOob/yQoG5vYg/JAgJag9CWP5tqd9+6FgInahSj3VaYYvu69O4hY+h6e6D+v7mpLTYBRM33TlVugTxOkx64JTMAdwFAfH553Ob2T+sW4aqyiGc7arLodIMlWjiVbkBBEgYZ0PXMyCPKb7JPa+5lFxfMRBK0P1kMsC34OXnQ1jUaedx44U4I5

Notice that each cookie=value pair is separated by a semicolon (;). The LtpaToken2 cookie and value are in bold above. That cookie contains the "principal" (user) name, the "realm" (a named security policy domain), and the expiration date of the token. This token is used by a WebSphere server (whether it's WebSphere ND, WebSphere Liberty, or any other flavor of WebSphere) to make authorization decisions to determine which resources the user has access to. It's also used for authentication across WebSphere servers if the two servers share the same LTPA keys. This sharing of keys is how one server "trusts" an LTPA token created by another server.

For troubleshooting purposes, sometimes you want/need to see what's inside an LTPA token. I found the best article on the web that provides the code to allow you to do exactly that. The page is found here: http://tech.srij.it/2012/04/how-to-decrypt-ltpa-cookie-and-view.html , but it leaves out some basic steps that I'm including here. I'm also copying the Java code at the bottom of this blog post just in case the linked article disappears.

Once you've copied the code into a file named DecryptLTPA.java (the file MUST have this name to match the name of the class defined in the file), you then need to specify several values in the file. Specifically, you need to provide values for the following variables:


ltpaKey : the com.ibm.websphere.ltpa.3DESKey value from ltpa.keys file. This file already exists if you're using WebSphere Liberty. If you're using "full" WebSphere, you need to create this file (with whatever name you want) by exporting the LTPA keys from the WebSphere Administration Console. In the ltpa.keys file, this value will end with the characters "\=" (backslash equals). When you paste the value into the DecryptLTPA.java, remove that backslash.

ltpaPassword : WebAS  - This is the default password on WebSphere Liberty. If you're using "full" WebSphere, the password will be whatever you specify when you export the LTPA keys using the WebSphere Administration Console.

tokenCipher : the entire value of the ltpatoken2 header from the COOKIES header in the Request.


Once you've done the above, the beginning of the definition of the main() function in the DecryptLTPA.java file should look something like:

 public static void main(String[] args) {
  String ltpaKey = "ADbpPpqPf3bnkj0b34sNaNC2FYHYygub3/cGjIn+mR4=";
  String ltpaPassword = "WebAS";
  String tokenCipher = "i/InlYuq2tm3rPdd/3BEzA8m9BCc8WGNR3q6eu7OfeQ7s1ICiMvPv0QCNQar5cCQlyVH5GE0N0VNbJj1Z6sUGe2S3nb1kwwbzdzPWzCbNPPtN3uiPWnfLyXzi5T4p2Pz/URwCfP6zWW2NOob/yQoG5vYg/JAgJag9CWP5tqd9+6FgInahSj3VaYYvu69O4hY+h6e6D+v7mpLTYBRM33TlVugTxOkx64JTMAdwFAfH553Ob2T+sW4aqyiGc7arLodIMlWjiVbkBBEgYZ0PXMyCPKb7JPa+5lFxfMRBK0P1kMsC34OXnQ1jUaedx44U4I5";

You then need to compile the java file with a command similar to the following:

 javac -cp /opt/IBM/tivoli/impact/wlp/usr/servers/ImpactUI/apps/blaze.war/WEB-INF/lib/commons-codec-1.10.jar DecryptLTPA.java

That command points to the commons-codec.1.10.jar file, which contains the definition of the Base64 class referenced by the code. That command was run on a Netcool Impact version 7.1.0.16 server which uses WebSphere Liberty. If you were to compile the code on a DASH version 3.1.3.0 server, the command would look like this:

javac -cp /opt/IBM/tivoli/JazzSM/profile/installedApps/JazzSMNode01Cell/IBM Cognos.ear/p2pd.war/WEB-INF/lib/commons-codec-1.3.jar DecryptLTPA.java

In both cases, my path includes the Java 1.7 SDK binaries and my JAVA_HOME is set to the Java 1.7 SDK directory.

Once you have the file compiled, you can actually run it, which requires a similar command:

 java -cp /opt/IBM/tivoli/impact/wlp/usr/servers/ImpactUI/apps/blaze.war/WEB-INF/lib/commons-codec-1.10.jar:. DecryptLTPA

Notice that you must include "." (present working directory) in the classpath (-cp flag) in addition to the commons-codec jar file.

Once that runs, you should see output similar to:

Algorithm:[AES]
Full token string:[expire:1568250479184$u:user\:customRealm/impactadmin%1568250479184%zoQ7cb1BSWekvxdd3slUpxmCRlBCBmMO1nu8iztv73PKQN3MIybuCx/C9EdKGwoeoguJHKrj0BOOAeXxVLDgIQL5Jz2Tg6LQcIyTpAtRAVMsqWTPFzDBrs85Zxs9kP0zFEiOvEsDUmRXXm92dN6zxWooEyGz453x1VPmqGoZ0ww=]
Token is for:[expire:1568250479184$u:user\:customRealm/impactadmin]
Token expires at:[2019-09-11-21:07:59 EDT]
Token signature:[zoQ7cb1BSWekvxdd3slUpxmCRlBCBmMO1nu8iztv73PKQN3MIybuCx/C9EdKGwoeoguJHKrj0BOOAeXxVLDgIQL5Jz2Tg6LQcIyTpAtRAVMsqWTPFzDBrs85Zxs9kP0zFEiOvEsDUmRXXm92dN6zxWooEyGz453x1VPmqGoZ0ww=]

As you can see, the user (principal) ID and expiration timestamps are easily visible, which was my goal from the beginning.

Full Java code:

import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.StringTokenizer;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class DecryptLTPA {
 private static final String AES = "AES/CBC/PKCS5Padding";
 private static final String DES = "DESede/ECB/PKCS5Padding";

 public static void main(String[] args) {
  String ltpaKey = "<DES key from ltpa token>";
  String ltpaPassword = "<password used to export ltpa token>";
  String tokenCipher = "<the header text to dercypt>";

  try {
   Base64 b = new Base64();
   byte[] secretKey = null;
   MessageDigest md = MessageDigest.getInstance("SHA");
   md.update(ltpaPassword.getBytes());
   byte[] hash3DES = new byte[24];
   System.arraycopy(md.digest(), 0, hash3DES, 0, 20);
   Arrays.fill(hash3DES, 20, 24, (byte) 0);
   secretKey = decrypt(b.decode(ltpaKey), hash3DES, DES);
   byte[] ltpaByteArray = b.decode(tokenCipher);

   String algorithm, userInfo, expires, signature, ltpaPlaintext;
   try {
    algorithm="DES";
    ltpaPlaintext = new String(decrypt(ltpaByteArray, secretKey, DES));
   } catch (Exception e) {
    algorithm="AES";
    ltpaPlaintext = new String(decrypt(ltpaByteArray, secretKey, AES));
   }

   System.err.println("Algorithm:["+algorithm+"]");
   StringTokenizer st = new StringTokenizer(ltpaPlaintext, "%");
   userInfo = st.nextToken();
   expires = st.nextToken();
   signature = st.nextToken();
   System.err.println("Full token string:[" + ltpaPlaintext + "]");
   Date d = new Date(Long.parseLong(expires));
   SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss z");
   System.err.println("Token is for:[" + userInfo + "]");
   System.err.println("Token expires at:[" + sdf.format(d) + "]");
   System.err.println("Token signature:[" + signature + "]");

  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public static byte[] decrypt(byte[] ciphertext, byte[] key, String algorithm) throws Exception {
  SecretKey sKey = null;

  if (algorithm.indexOf("AES") != -1) {
   sKey = new SecretKeySpec(key, 0, 16, "AES");
  } else {
   DESedeKeySpec kSpec = new DESedeKeySpec(key);
   SecretKeyFactory kFact = SecretKeyFactory.getInstance("DESede");
   sKey = kFact.generateSecret(kSpec);
  }
  Cipher cipher = Cipher.getInstance(algorithm);

  if (algorithm.indexOf("ECB") == -1) {
   if (algorithm.indexOf("AES") != -1) {
    IvParameterSpec ivs16 = generateIvParameterSpec(key, 16);
    cipher.init(Cipher.DECRYPT_MODE, sKey, ivs16);
   } else {
    IvParameterSpec ivs8 = generateIvParameterSpec(key, 8);
    cipher.init(Cipher.DECRYPT_MODE, sKey, ivs8);
   }
  } else {
   cipher.init(Cipher.DECRYPT_MODE, sKey);
  }
  return cipher.doFinal(ciphertext);
 }

 private static IvParameterSpec generateIvParameterSpec(byte key[], int size) {
  byte[] row = new byte[size];

  for (int i = 0; i < size; i++) {
   row[i] = key[i];
  }

  return new IvParameterSpec(row);
 }
}

Tuesday, August 13, 2019

The best easy and free video editing software available is Shotcut

I've never editing a video before, but I needed to yesterday. I found Shotcut, and I couldn't be happier about how easy it is to use. It's free, easy AND it's a portable app, so you don't have to install anything. They've got a very active forum and tons of how-to videos available. If you need to do some video editing (including multiple tracks, audio overlay, and all the high-ed options), give it a try.

Monday, July 15, 2019

JavaScript regular expression trick

Working on a Netcool Impact implementation recently I ran across a feature of JavaScript regular expressions that really impressed me. I'll compare it to a somewhat similar feature/syntax in Perl.

If you need to test a string for a regular expression in Perl, you can do the following:

if ($mystring =~ /my_regular_expression/) ...

That will return true if $string contains the specified regular expression.

In JavaScript, you can invoke the test() method directly on the regular expression (including the leading and trailing "/") with one parameter, which is the string to test. Here's what the equivalent of the above looks like in JavaScript:

if (/my_regular_expression/.test(mystring)) ...

And to test if it doesn't match, the syntax is:

if (!/my_regular_expression/.test(mystring)) ...

That's it. I just thought it was pretty neat.

Wednesday, July 3, 2019

APM historical data without a TEMS

IBM APM only directly supports the storage of up to 32 days of data. You've always had the option to store older data in the ITM 6 data warehouse, but setting up an entire ITM 6 infrastructure has always seemed like a whole lot of work. As it turns out, you don't have to set up the entire infrastructure! You oonly have to set up a warehouse proxy agent, summarization and pruning agent and the warehouse database. No TEMS or TEPS, as the WPA and SPA can work in autonomous mode.

Madhavan Vyk recently posted a great article on DeveloperWorks detailing exactly how to configure this:

https://www.ibm.com/developerworks/community/blogs/0587adbc-8477-431f-8c68-9226adea11ed/entry/Integrating_IBM_Cloud_APM_8_x_with_Tivoli_Data_Warehouse?lang=en

Monday, May 6, 2019

IBM Netcool Agile Service Manager 1.1 is available with new observers

I've been busy, so I only just now saw that ASM 1.1 was released in April with a bunch of new observers. Observers are used to "observe" individual applications to provide additional data to the topology view(s) in ASM. Here's the download document:

https://www-01.ibm.com/support/docview.wss?uid=swg24043717

Below is the list of observers from that link. Some that I believe are new are ITNM, BigFix, ServiceNow, New Relic and DynaTrace.

PartDescription
CC166EN
IBM Netcool Agile Service Manager v1.1 Docker Observer (asm 1.1.4.1) - Linux 64bit English
CC167EN
IBM Netcool Agile Service Manager v1.1 Event Observer (asm 1.1.4.1) - Linux 64bit English
CC168EN
IBM Netcool Agile Service Manager v1.1 ITNM Observer (asm 1.1.4.1) - Linux 64bit English
CC169EN
IBM Netcool Agile Service Manager v1.1 OpenStack Observer (asm 1.1.4.1) - Linux 64bit English
CC16AEN
IBM Netcool Agile Service Manager v1.1 File Observer (asm 1.1.4.1) - Linux 64bit English
CC16BEN
IBM Netcool Agile Service Manager v1.1 ALM Observer (asm 1.1.4.1) - Linux 64bit English
CC16CEN
IBM Netcool Agile Service Manager v.1.1 REST Observer (asm 1.1.4.1) - Linux 64bit English
CC16DEN
IBM Netcool Agile Service Manager v.1.1 TADDM Observer (asm 1.1.4.1) - Linux 64bit English
CC16EEN
IBM Netcool Agile Service Manager v.1.1 VMWare NSX Observer (asm 1.1.4.1) - Linux 64bit English
CC16FEN
IBM Netcool Agile Service Manager v.1.1 VMWare vCenter Observer (asm 1.1.4.1) - Linux 64bit English
CC16GEN
IBM Netcool Agile Service Manager v.1.1 DNS Observer (asm 1.1.4.1) - Linux 64bit English
CC16HEN
IBM Netcool Agile Service Manager v.1.1 Cisco ACI Observer (asm 1.1.4.1) - Linux 64bit English
CC16IEN
IBM Netcool Agile Service Manager v.1.1 Kubernetes Observer (asm 1.1.4.1) - Linux 64bit English
CC16JEN
IBM Netcool Agile Service Manager v.1.1 IBM Cloud Observer (asm 1.1.4.1) - Linux 64bit English
CC16KENIBM Netcool Agile Service Manager v.1.1 Juniper Contrail Observer (asm 1.1.4.1) - Linux 64bit English
CC16LENIBM Netcool Agile Service Manager v.1.1 ServiceNow Observer (asm 1.1.4.1) - Linux 64bit English
CC16MENIBM Netcool Agile Service Manager v.1.1 New Relic Observer (asm 1.1.4.1) - Linux 64bit English 
CC16NENIBM Netcool Agile Service Manager v1.1  BigFix  Inventory Observer (asm 1.1.4.1) - Linux 64bit English
CC16PENIBM Netcool Agile Service Manager v1.1 Dynatrace Observer (asm 1.1.4.1) - Linux 64bit English

Wednesday, March 13, 2019

A Great Application Dependency Discovery and Mapping Tool

I recently ran across www.device42.com and am blown away by the price and capabilities of their offerings. One of the most difficult challenges in IT is to get application dependency maps in your infrastructure. The biggest hurdle is access to the different systems. Device42 helps ease this problem by providing standalone discovery executables that can be given to system administrators to run themselves. This means that credentials don't NEED to be stored centrally (this is the root of the access problem). Each administrator can simply upload the results of the discovery process.

The tool also lets you drag-and-drop servers into rack configurations, so you can get a real-world visualization of your datacenter.

All of the above is standard in the software from the leaders in this space (BMC ADDM, ServiceNow Discovery, IBM TADDM), but Device42's price just blows the others away. Their pricing page is here: https://www.device42.com/pricing/ . If you've done any research in the space, you know that the pricing gives you a terrific amount of value.


* Gulfsoft has no relationship with Device42. This opinion is being provided simply because we're so amazed by this application.