返回列表 发帖

运用 WebSphere Application Server V4 和 V5 在 Web 上启用 Globus 安全性基础结构

引言 安全性是 Globus Toolkit_ Grid 安全性基础结构(Globus Toolkit_ Grid security infrastructure,GSI)的核心,GSI 支持通过计算机网络进行的安全验证和通信。它提供了诸如相互验证和单一登录这样的服务,并且基于公认的标准,比如公钥加密、X.509 认证以及安全套接字层(Secure Sockets Layer,SSL)。 本文旨在解决在使用 IBM 的 WebSphere Application Server 编写支持 Web 的网格应用程序时遇到的兼容性问题。这些问题与 GSI 用来实现各种安全性服务的 Grid 安全性基础结构 Java crypto 扩展密切相关。 Globus Toolkit 安全性库 Globus Toolkit 3.0(GT3)使用一个由 Java CoG Kit 1.1 提供的全新安全性库。这个新的安全性库基于 GSS-API,并且是完全使用开放源码 SSL 和认证处理库实现的。当为需要 X.509 证书和代理(也称为 Globus 凭证)处理的 WebSphere 平台编写支持 Web 的网格应用程序时,冲突就会出现。之所以出现这些冲突,是因为 WebSphere 使用 IBM JCE 作为缺省的安全性提供者,而 GT3 将试图使用它自己的安全性扩展(由 Bouncy Castle 的 Legion 提供)和 SSLv3/TLS 实现(由 Claymore Systems 许可)。 1. 使用 WebSphere 从缺省证书创建代理 我们将首先编写一个简单的 JSP 页面来创建 Globus 凭证(也称为代理),如图 1 所示。 清单 1. 一个用于创建 Globus 凭证的 JSP 文件 <%@ page language="java" contentType="text/html; charset=ISO-8859-1" import= "java.util.Properties, java.io.*, java.security.cert.*, org.globus.gsi.*, org.globus.gsi.bc.*, org.apache.log4j.*" %> <%! public synchronized GlobusCredential gridProxyInit(InputStream inUserCert, InputStream inUserKey , String pwd, int bits, int hours) throws IOException, java.security.GeneralSecurityException { X509Certificate userCert = CertUtil.loadCertificate(inUserCert); OpenSSLKey key = new BouncyCastleOpenSSLKey(inUserKey); System.out.println("gridProxyInit: User Cert=" + userCert + " User key encrypted=" + key.isEncrypted()); if (key.isEncrypted()) { try { key.decrypt(pwd); } catch(java.security.GeneralSecurityException e) { throw new java.security.GeneralSecurityException("Wrong password or other security error"); } } System.out.println("gridProxyInit: User Priv key : " + key.getPrivateKey()); java.security.PrivateKey userKey = key.getPrivateKey(); BouncyCastleCertProcessingFactory factory = BouncyCastleCertProcessingFactory.getDefault(); return factory.createCredential(new X509Certificate[] {userCert}, userKey, bits, hours * 3600, GSIConstants.GSI_2_PROXY, null); } %> <% Logger.getRootLogger().setLevel(Level.DEBUG); String action = (request.getParameter("ACTION") != null) ? request.getParameter("ACTION") : "INIT"; String pwd = request.getParameter("txtPWD"); String bits = request.getParameter("ST"); String hours = request.getParameter("LIFETIME"); String Msg = request.getParameter("MSG"); String subject = "N/A"; // generated proxy subject String issuer = "N/A"; String strength = "N/A"; // proxy strength String sTimeLeft = "N/A"; // proxy time left // Used to load certs from db boolean proxyReady = false; // is the proxy ready? // Init if ( ! action.equalsIgnoreCase("INIT") ) { } try { if ( action.equalsIgnoreCase("CREATE") ) { String path = System.getProperty("user.home") + "/.globus/cog.properties"; org.globus.common.CoGProperties props = new org.globus.common.CoGProperties(); props.load(path); String certPath = props.getProperty("usercert"); String keyPath = props.getProperty("userkey"); System.out.println("test-proxy.jsp::CREATE pwd=" + pwd + " bits=" + bits + " hours=" + hours); System.out.println("test-proxy.jsp::Cert path:" + certPath + "\nKey path: " + keyPath); // create a globus cred. Certs read from def locs InputStream inCert = new FileInputStream(certPath); InputStream inKey = new FileInputStream(keyPath); int stren = Integer.parseInt(bits); int life = Integer.parseInt(hours); // create globus proxy GlobusCredential cred = gridProxyInit(inCert , inKey, pwd , stren, life); subject = cred.getSubject(); issuer = cred.getIssuer(); strength = new Integer(cred.getStrength()).toString(); sTimeLeft = org.globus.util.Util.formatTimeSec(cred.getTimeLeft()); // // save proxy in def location ByteArrayOutputStream bos = new ByteArrayOutputStream(); cred.save(bos); System.out.println("grid-proxy.jsp::Saving proxy into db\n" + bos.toString()); proxyReady = true; Msg ="Proxy created."; } } catch ( Exception e ) { e.printStackTrace(); response.sendRedirect("test-proxy.jsp?MSG=GridProxyInit+Error:" + e.getMessage()); } %> test-proxy.jsp

Grid Proxy Init

Cetificates will be loaded from default locations
<% if ( Msg != null ) { %>
<%=Msg%> <% } %>
Proxy Options
Lifetime 12 h 24 h 1 week 1 month
Strength 512 1024 2048 4096
Pass Phrase
Proxy Info
CN
Subject <%=subject%>
Issuer <%=issuer%>
Time left <%=sTimeLeft%>
Strength <%=strength%>

为了在 WebSphere Studio V5.x 中成功地编译这个 JSP 文件,必须确保下面这些 JAR 文件在您的 WEB-INF/lib 文件夹中: cog-jglobus.jar cryptix-ans1.jar cryptix32.jar jce-jdk13-117.jar jgss.jar log4j-core.jar puretls.jar. 上面所有的文件都包括在 GT3 发行版中。 2. 配置用于测试的本地证书 您必须配置这个 JSP 文件抑或 Java CoG Kit 将要使用的本地证书。文件 cog.properties 必须在您的本机 .globus 文件夹中。因而,如果您以“Administrator”的身份登录到您的 win32 系统,您就必须创建:C:\Documents and Settings\Administrator\.globus\cog.properties。 此文件的样本内容如清单 2 所示: 清单 2. cog.properties 文件 #Tue Aug 26 11:46:58 EDT 2003 usercert=C\:\\Documents and Settings\\Administrator\\.globus\\usercert.pem userkey=C\:\\Documents and Settings\\Administrator\\.globus\\userkey.pem proxy=C\:\\DOCUME~1\\ADMINI~1\\LOCALS~1\\Temp\\x509up_u_vladimir cacert=C\:\\Documents and Settings\\Administrator\\.globus\\simpleCA\\cacert.pem 如果您从 Globus Web 站点 下载并安装 Java CoG Kit 的话,cog.properties 文件将会自动设置。当这一切都准备就绪之后,在您的 Web 浏览器上 JSP 文件看上去会类似于图 1。 图 1. 代理的初始测试 该 JSP 的输出如下: 图 2. 创建 Globus 凭证 到目前为止一切顺利:我们已经成功地从我们的 Web 应用程序创建了一个 Gloubs 代理。 3. 创建证书和私钥 清单 3 中的 JSP 代码创建了用户证书和私钥集。 清单 3. 创建证书和私钥对 <%@ page language="java" contentType="text/html; charset=ISO-8859-1" import= "java.util.*, java.io.*, java.security.*, java.security.cert.*, org.globus.gsi.*, org.globus.gsi.bc.*, org.apache.log4j.*, COM.claymoresystems.cert.*, cryptix.util.mime.*" %> <%! /* * Write bytes into a PEM string */ public static String writePEM (byte[] bytes, String hdr, String ftr) throws IOException { ByteArrayOutputStream bos=new ByteArrayOutputStream(); Base64OutputStream b64os=new Base64OutputStream(bos); b64os.write(bytes); b64os.flush(); b64os.close(); ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray()); InputStreamReader irr=new InputStreamReader(bis); BufferedReader r=new BufferedReader(irr); StringBuffer buff = new StringBuffer(); String line; buff.append(hdr); while((line=r.readLine())!=null){ buff.append(line + "\n"); } buff.append(ftr); return buff.toString(); } /* Create an X509 Name used for cert creation */ private static X509Name makeCertDN(String subject) throws Exception { Vector tdn = new Vector(); Vector elems = new Vector(); StringTokenizer st = new StringTokenizer(subject,","); for (; st.hasMoreTokens() ;) { String s = st.nextToken(); // [key=value] if ( s.indexOf("=") == -1 ) throw new Exception("Invalid subject format: " + subject + " Offending value: " + s); String key = s.substring(0, s.indexOf("=")).trim(); String val = s.substring(s.indexOf("=") + 1).trim(); if ( val == null || val.equals("")) throw new Exception("Invalid subject format: " + subject + " Offending value: " + s); String[] temp = {key, val}; tdn.addElement(temp); } // COM.claymoresystems.cert (puretls.jar) return CertRequest.makeSimpleDN(tdn); } /* Cert/key creation */ public void generateSelfSignedCertAndKey(String subject, int bits, String Pwd, StringWriter swKey, StringWriter swCert ) throws NoSuchAlgorithmException, Exception { X509Name _subject = makeCertDN(subject); System.out.println("generateSelfSignedCertAndKey Cert subject: " + _subject.getNameString() + " Strength=" + bits + " Pwd=" + Pwd); // Generate A Cert RQ //StringWriter sw = new StringWriter(); // wil contain the priv key PEM BufferedWriter bw = new BufferedWriter(swKey); KeyPair kp = CertRequest.generateKey("RSA", bits, Pwd, bw, true); // certs are valid for 1 year: 31536000 secs byte[] certBytes = CertRequest.makeSelfSignedCert(kp, _subject, 31536000); BufferedWriter bw1 = new BufferedWriter(swCert); String _certPEM = writePEM(certBytes, "-----BEGIN CERTIFICATE-----\n", "-----END CERTIFICATE-----\n"); bw1.write(_certPEM); System.out.println("CertKeyGenerator: Signed Cert RQ . signedUserCert\n" + _certPEM); } %> <% org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.DEBUG); String action = (request.getParameter("ACTION") != null) ? request.getParameter("ACTION") : "INIT"; String Msg = request.getParameter("MSG"); try { //Properties args = com.ibm.grid.ogsa.securityextension.gsi.GSIProperties.load(); String msg = ""; if ( action.equalsIgnoreCase("GENERATE") ) { String cn = request.getParameter("txtCN"); String org = request.getParameter("txtORG"); String ou = request.getParameter("txtOU"); String pwd = request.getParameter("txtPWD"); String subject = "O=" + org + "," + "OU="+ ou + ",CN=" + cn; System.out.println("Gen certs. Subject: " + subject); StringWriter swCert = new StringWriter(); // wil contain cert PEM StringWriter swKey = new StringWriter(); // wil contain the priv key PEM generateSelfSignedCertAndKey(subject, 1024, pwd, swKey, swCert); // Private key System.out.println("Private key PEM\n" + swKey.toString()); // cert System.out.println("Certificate PEM\n" + swCert.toString()); response.sendRedirect("test-creds.jsp?MSG=Certs+installed+successfully."); } } catch ( Exception e0 ) { e0.printStackTrace(); response.sendRedirect("test-creds.jsp?MSG=Error+ installing+certs:" + e0.getMessage()); } catch ( InternalError e ) { e.printStackTrace(); response.sendRedirect("test-creds.jsp?MSG=Error+ installing+certs:" + e.getMessage()); } %> setup-gsi.jsp

Setup Certificate/Private key


<% if ( Msg != null ) { %>
<%=Msg%>
<% } %> All fileds are required
Common Name Enter your name or email
Organizational Unit
Organization Organization
Pass phrase Password used to encrypt the private key

这段代码在您的 Web 浏览器上会这样显示: 图 3. 设置证书/私钥 当尝试创建认证/私钥时,WebSphere 将会抛出下面的异常: 清单 4. 由 WebSphere 和 GT3 之间发生的安全提供者冲突所抛出的异常 java.lang.InternalError: java.security.NoSuchAlgorithmException: class configured for Cipher: com.ibm.crypto.provider.DESedeCipher is not a subclass of xjava.security.Cipher at COM.claymoresystems.crypto.PEMData.writePEMObject(PEMData.java:172) at COM.claymoresystems.crypto.EAYEncryptedPrivateKey.writePrivateKey(EAYEncryptedPrivateKey.java:83) at COM.claymoresystems.cert.CertRequest.generateKey(CertRequest.java:102) at jsp.article._test_2D_creds_jsp_0.generateSelfSignedCertAndKey(_test_2D_creds_jsp_0.java:108) at jsp.article._test_2D_creds_jsp_0._jspService(_test_2D_creds_jsp_0.java:210) 通过更仔细地分析这个消息: class configured for Cipher: com.ibm.crypto.provider.DESedeCipher is not a subclass of xjava.security.Cipher; 并且进行栈跟踪,我们可以假定 Java CoG API 内部尝试使用 IBM 的 JCE 作为缺省的提供者,这是不正确的,因为安全性提供者应该为 Cryptix/Bouncy Castle。这个问题在创建私钥时会出现。为了解决这个问题,将需要修改 Java 代码。 4. 更改 GT3 安全性提供者以与 WebSphere 协同工作 在确定了问题之后,就可以通过更改 puretls.jar 和 cryptix32.jar 源码中的几行代码来进行解决。为此,您将需要从 Web 站点下载源码。下表列出了需要进行的实际代码更改。要获得关于下载源码的信息,请参阅参考资料部分。 表 1:对 GT3 安全提供者进行的更改一览 JAR 文件 类/行 原文 更新 注解 Puretls.jar PEMData.java Line 155 Cipher ciph = Cipher.getInstance(algorithm); ((FeedbackCipher)ciph) .setInitializationVector(iv); Cipher ciph = Cipher.getInstance(algorithm,"Cryptix"); 这种更改将强制要求使用 Cryptix 作为安全性提供者。 Cryptix32.jar Cipher.java Line 480 cipherName = IJCE.getStandardName (cipherName, "Cipher"); cipherName = CryptixProperties.getProperty ("Alg.Alias.Cipher." + cipherName); 方法 IJCE. getStandardName 已经受到反对,并且在 WebSphere 中错误地返回 Cipher 名称(对于像 DES-EDE3 这样的密码)。 结束语 本文给 GT3 安全性提供者以及它们与 WebSphere Application Server V4 和 V5 的兼容性提供了有益的见解。如果您正在编写支持 Web 的网格应用程序,并且需要处理或创建证书、密钥和代理,那么这里的信息会帮助解决您在 GT3 和 WebSphere 容器之间可能会遇到的不兼容性问题。

返回列表 回复 发帖