views:

639

answers:

3

Consider the following setup:

  • A webapplication deployed on a Websphere Application Server (6.1 if it matters)
  • the app will get accessed through a webseal reverse proxy
  • the webseal takes care of the authentication and passes on an LTPA token as sign of valid authentication

If I got it right, the LTPA token contains information like username, roles and so on.

Question: how do I access this information from the LTPA token in my java web application?

+2  A: 

You don't directly access the LTPA token, rather you assume that WebSphere has established a security context for you on the basis of its authentication procedures.

You can then use

getUserPrincipal()

on your HttpServletRequest object to access the user's identity.

Roles are particular to the current resource (serlvet, ejb ...) and hence you use the HttpServletRequest method

isUserInRole()

to determine whether a user is in a role.

You can also use the method

 public static javax.security.auth.Subject getCallerSubject()

to obtain further security information including group membership.

djna
Great, exactly what I was looking for. Thanx
Jens Schauder
+2  A: 

Looking inside LTPA tokens is great for debugging, we use this alot. You'll need the ltpa-key and password for this to work

/* Copyright notice
# Copyright (C) 2007, Cosmin Stejerean (http://www.offbytwo.com)
#
# You are free to use this code under the terms of the Creative Commons Attribution license
# available at http://creativecommons.org/licenses/by/3.0/
# so long as you include the following notice 'includes code from Cosmin Stejerean (http://www.offbytwo.com)'
*/

import java.security.Key;
import java.security.MessageDigest;
import java.security.spec.KeySpec;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.StringTokenizer;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

import sun.misc.BASE64Decoder;


//The shared 3DES key is itself encrypted using the SHA hash value of the LTPA password (padded with 0x0 upto 24 bytes).

public class LtpaDecoder
{
    private String ltpa3DESKey = "JvJRzwdhKk6o40FuATa9acKD2uaXswVHlUsn2c2+MKQ=";
    private String ltpaPassword = "secretpassword";

    private String sUserInfo = "";
    private Date dExpiry;
    private String sFullToken = ""; 
    private String sSignature = "";

    public static void main(String[] args)
    {
          String tokenCipher = "vsof5exb990sb2r5hRJ+bneCnmBTuLQ3XF+......";

          try {
            LtpaDecoder t = new LtpaDecoder(tokenCipher);
            System.out.println("UserInfo: " + t.getUserInfo());
            System.out.println("Expiry: " + t.getExpiryDate());
            System.out.println("Full token: " + t.getFullToken());
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }

    public LtpaDecoder(String fulltoken) throws Exception {
        byte[] secretKey = getSecretKey(this.ltpa3DESKey, this.ltpaPassword);
        String ltpaPlaintext = new String(decryptLtpaToken(fulltoken, secretKey));

        extractTokenData(ltpaPlaintext);
    }

    private void extractTokenData(String token)
    {
        System.out.println("\n");
        StringTokenizer st = new StringTokenizer(token, "%");

        sUserInfo = st.nextToken();
        String sExpires = st.nextToken();
        sSignature = st.nextToken();
        dExpiry = new Date(Long.parseLong(sExpires));
        sFullToken = token;
    }

    public String getSignature() {
        return sSignature;
    }

    public String getFullToken() {
        return sFullToken;
    }

    public String getUserInfo() {
        return sUserInfo;
    }

    public String getExpiryDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
        return sdf.format(dExpiry);
    }

    private byte[] getSecretKey(String shared3DES, String password) throws Exception
    {
        MessageDigest md = MessageDigest.getInstance("SHA");
        md.update(password.getBytes());
        byte[] hash3DES = new byte[24];
        System.arraycopy(md.digest(), 0, hash3DES, 0, 20);
        Arrays.fill(hash3DES, 20, 24, (byte) 0);
        // decrypt the real key and return it
        BASE64Decoder base64decoder = new BASE64Decoder();
        return decrypt(base64decoder.decodeBuffer(shared3DES), hash3DES);
    }

    public byte[] decryptLtpaToken(String encryptedLtpaToken, byte[] key) throws Exception 
    {
        BASE64Decoder base64decoder = new BASE64Decoder();
        final byte[] ltpaByteArray = base64decoder.decodeBuffer(encryptedLtpaToken);
        return decrypt(ltpaByteArray, key);
    }

    public byte[] decrypt(byte[] ciphertext, byte[] key) throws Exception {
        final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        final KeySpec keySpec = new DESedeKeySpec(key);
        final Key secretKey = SecretKeyFactory.getInstance("TripleDES").generateSecret(keySpec);

        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(ciphertext);
    }
}
Tommy
At the risk of stating the obvious, think may be nice for debugging in a development environment, but we don't base production application code on this technique, right?
djna
Having worked with IBM-products for some years i'd say this code comes in handy on all kinds of environments ;)
Tommy
While I hopefully never have to use such stuff in production code (or find it there) it is still useful.
Jens Schauder
It's also handy to have the root password written down on a post-it note beside every terminal :-) Two serious points: 1). The formal, supported, APIs should be sufficient for application code. 2). Applications with hard-coded secret keys and passwords are a potential security risk. It should be pretty rare that this "sharp" tool is needed.
djna
A: 

delete me please

Andreas