Showing posts with label WebSphere. Show all posts
Showing posts with label WebSphere. Show all posts

Friday, August 18, 2023

Updating the bundled Java SDK 8 in WebSphere 8.5.5.x

There are a couple different ways to install Java with WebSphere. The most common way is to simply use the bundled Java SDK. Even with this, sometimes you need to update the Java SDK outside of a Fix Pack. To do that, you need to download an update specifically for the bundled Java SDK. Those can be found here:

https://www.ibm.com/support/pages/node/6209712#Java8B

You can download the appropriate version, unzip it, add it as a repository to Installation Manager, and then click "Update" to update the WAS bundled JVM.

An example scenario is this:

I have a customer with WAS 8.5.5.11 installed in a secure and regulated environment. They were told they needed to install WAS 8.5.5 FP 23 (FP24 is available, but it has not yet been approved for installation in this environment) and Java 8.0.8.5. WAS 8.5.5.23 comes bundled with Java 8.0.7.20. So we needed to apply the 8.5.5.23 Update via Installation Manager, and then apply the Bundled Java SDK 8.0.8.5 Update via Installation Manager, and all was good.

Tuesday, March 21, 2023

Installing .pak Files on WebSphere Application Server 8.5.x

Background

In WAS 7.0 (and possibly earlier), the WebSphere Update Installer was used to install WAS fix packs, which would have a file extension of .pak. Additionally, some other software (IBM Security Identity Manager 6, for example) that runs on WAS decided to package their updates in the same way, with .pak files to be installed with the Update Installer. WAS 8.5 moved to using IBM Installation Manager for its installation and the installation of fix packs. The last version of the WebSphere Update Installer is 7.0.0.45.

Let's say after you installed ISIM 6 on WAS 7, and then later upgraded WAS to 8.5. How do you install an ISIM 6 fixpack onto WAS 8.5?

Solution

You use the WAS 7.0.0.45 Update Installer, of course! 

WebSphere Update Installer is actually a standalone product that isn't reliant on any particular version of WebSphere to be installed. Its version number does its best to throw you off, but it works just fine when run against WAS 8.5 (or even 8.5.5.23 in my latest test).

I couldn't find this spelled out anywhere, so I thought I would share.

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);
 }
}

Friday, September 9, 2016

Adding an additional hostname to Maximo on WebSphere and IBM HTTP Server

When you install Maximo (IBM Control Desk in this case) on IBM HTTP Server and WebSphere, the installation creates all of the virtual hosts you need based on the hostname of the IBM HTTP Server(s) that you include in your environment. However, you may need users to access the application using a different hostname (maybe one that's accessible from the Internet, for example). If you simply add a DNS CNAME record for your web server, you'll get an error when you try to access the application with that hostname.

To fix this problem, you need to add a Host Alias to each of the appropriate Virtual Hosts that you have defined for Maximo, then restart the application server(s). Here's how:

1. In my environment, I want to be able to access Maximo using the URL:

http://icdcommon/maximo

The two servers participating in my cluster are named icd1 and icd2. I'm adding an entry in my /etc/hosts (or \windows\system32\drivers\etc\hosts) file for icdcommon to be an alias for icd1.

(In a real environment, you would be modifying DNS appropriately).

2. Log into the WebSphere admin console at http://dmgr_host:9060/admin

3. Navigate to Environment->Virtual Hosts, where you will see multiple virtual hosts. I have the application configured in a cluster named MXCLUSTER, so the virtual hosts of interest to me are:

MXCLUSTER_host
default_host
webserver1_host

4. For each of the above Virtual Hosts, click on that host then click the Host aliases link.

5. Click the New button to add a new entry and in that entry, specify:

Host Name: icdcommon
Port: 80

6. Click OK, then click the save link at the top of the page (or you can wait until your done to click save).

7. Once you've done the above for each of the three Virtual Hosts, you need to restart all IBM HTTP Servers AND all application servers.

8. Now you should be able to access the application with http://icdcommon/maximo (you may need to restart your browser).

Tuesday, December 21, 2010

Adding a custom Java portlet to the TIP for use with WebTop, WebGUI, TBSM, etc.

REMOVED


This article has been removed because it worked for very specific versions of products, but not for the latest versions, and customers were calling Tivoli support to open PMRs when it didn't work. If you're trying to add a portlet, this is CUSTOM work, for which you should not open a PMR.

So I'll revisit this issue when I have time to test with the latest and greatest versions. Until then, if you would like the article, you can send me an email at frank dawt tate aat gulfsoft dot com.