Java 如何使用LTPA令牌中的信息

Java 如何使用LTPA令牌中的信息,java,websphere,single-sign-on,webseal,ltpa,Java,Websphere,Single Sign On,Webseal,Ltpa,请考虑以下设置: 部署在websphereapplicationserver上的webapplication(6.1,如果需要的话) 该应用程序将通过webseal反向代理进行访问 webseal负责身份验证并传递LTPA令牌作为有效身份验证的标志 如果我没有弄错,LTPA令牌包含用户名、角色等信息 问题:如何从java web应用程序中的LTPA令牌访问此信息?您不直接访问LTPA令牌,而是假设WebSphere已根据其身份验证过程为您建立了安全上下文 然后您可以使用 getUserPri

请考虑以下设置:

  • 部署在websphereapplicationserver上的webapplication(6.1,如果需要的话)
  • 该应用程序将通过webseal反向代理进行访问
  • webseal负责身份验证并传递LTPA令牌作为有效身份验证的标志
如果我没有弄错,LTPA令牌包含用户名、角色等信息


问题:如何从java web应用程序中的LTPA令牌访问此信息?

您不直接访问LTPA令牌,而是假设WebSphere已根据其身份验证过程为您建立了安全上下文

然后您可以使用

getUserPrincipal()
在HttpServletRequest对象上访问用户的身份

角色是特定于当前资源(serlvet、ejb…)的,因此您使用HttpServletRequest方法

isUserInRole()
确定用户是否处于角色中

您也可以使用该方法

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

为了获得更多的安全信息,包括组成员身份。

查看LTPA令牌对于调试非常有用,我们使用了很多。您需要ltpa密钥和密码才能使其工作

/* 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); } } /*版权公告 #版权所有(C)2007,Cosmin Stejerean(http://www.offbytwo.com) # #您可以根据知识共享署名许可证的条款自由使用此代码 #可在http://creativecommons.org/licenses/by/3.0/ #只要您包含以下通知“包含来自Cosmin Stejerean的代码”(http://www.offbytwo.com)' */ 导入java.security.Key; 导入java.security.MessageDigest; 导入java.security.spec.KeySpec; 导入java.sql.Date; 导入java.text.simpleDataFormat; 导入java.util.array; 导入java.util.StringTokenizer; 导入javax.crypto.Cipher; 导入javax.crypto.SecretKeyFactory; 导入javax.crypto.spec.DESedeKeySpec; 导入sun.misc.base64解码器; //共享3DES密钥本身使用LTPA密码的SHA哈希值加密(用0x0填充,最多24字节)。 公共类LtpaDecoder { 私有字符串ltpa3DESKey=“JvJRzwdhKk6o40FuATa9acKD2uaXswVHlUsn2c2+MKQ=”; 私有字符串ltpaPassword=“secretpassword”; 私有字符串sUserInfo=“”; 私人约会; 私有字符串sFullToken=“”; 私有字符串sSignature=“”; 公共静态void main(字符串[]args) { 字符串tokenCipher=“vsof5exb990sb2r5hRJ+bnecnmbtulk3xf+…”; 试一试{ LtpaDecoder t=新的LtpaDecoder(令牌密码); System.out.println(“UserInfo:+t.getUserInfo()); System.out.println(“到期:+t.getExpiryDate()); System.out.println(“完整令牌:+t.getFullToken()); } 捕获(例外e){ e、 printStackTrace(); } } 公共LtpaDecoder(字符串fulltoken)引发异常{ 字节[]secretKey=getSecretKey(this.ltpa3DESKey,this.ltpaPassword); String ltpaPlaintext=新字符串(decryptLtpaToken(fulltoken,secretKey)); 提取令牌数据(ltpaPlaintext); } 私有void extractTokenData(字符串标记) { System.out.println(“\n”); StringTokenizer st=新的StringTokenizer(标记,“%”); sUserInfo=st.nextToken(); 字符串sExpires=st.nextToken(); sSignature=st.nextToken(); dExpiry=新日期(Long.parseLong(sExpires)); sFullToken=令牌; } 公共字符串getSignature(){ 返回签名; } 公共字符串getFullToken(){ 返回sFullToken; } 公共字符串getUserInfo(){ 返回sUserInfo; } 公共字符串getExpiryDate(){ SimpleDataFormat sdf=新的SimpleDataFormat(“yyyy-MM-dd HH:MM:ss z”); 返回sdf.format(dExpiry); } 私有字节[]getSecretKey(字符串shared3DES,字符串密码)引发异常 { MessageDigest md=MessageDigest.getInstance(“SHA”); md.update(password.getBytes()); 字节[]hash3DES=新字节[24]; arraycopy(md.digest(),0,hash3DES,0,20); fill(hash3DES,20,24,(字节)0); //解密真正的密钥并返回它 Base64解码器Base64解码器=新的Base64解码器(); 返回解密(base64decoder.decodeBuffer(shared3DES),hash3DES); } 公共字节[]decryptLtpaToken(字符串encryptedLtpaToken,字节[]密钥)引发异常 { Base64解码器Base64解码器=新的Base64解码器(); 最终字节[]ltpaByteArray=base64解码器.decodeBuffer(encryptedLtpaToken); 返回解密(ltpaByteArray,密钥); } 公共字节[]解密(字节[]密文,字节[]密钥)引发异常{ final Cipher=Cipher.getInstance(“DESede/ECB/PKCS5Padding”); 最终KeySpec KeySpec=新的DESedeKeySpec(键); final Key secretKey=SecretKeyFactory.getInstance(“TripleDES”).generateScret(keySpec); cipher.init(cipher.DECRYPT_模式,secretKey); 返回cipher.doFinal(密文); } }
冒着陈述显而易见的风险,think对于在开发环境中进行调试可能很好,但我们并没有将生产应用程序代码建立在这种技术的基础上,对吗?在与IBM产品合作多年后,我认为这种代码在各种环境中都很有用;)虽然我希望我永远不必在生产代码中使用这些东西(或者在那里找到它),但它仍然很有用。在每个终端旁边的便利贴上写下根密码也是很方便的:-)两个要点:1)。正式的、受支持的API应该足以支持应用程序代码。2). 使用硬编码密钥和密码的应用程序存在潜在的安全风险。这应该是相当罕见的,这个“尖锐”的工具是必要的。太好了,正是我所寻找的。塔克斯