IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  WebSphere  >

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

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Vladimir Silva (vsilva@us.ibm.com), 软件工程师,Internet Technology, IBM

2003 年 12 月 01 日

本文旨在解决在使用 IBM 的 WebSphereApplication Server 编写支持 Web 的网格应用程序时遇到的兼容性问题。这些问题与 GSI 用来实现各种安全性服务的 Grid 安全性基础结构 Java crypto 扩展密切相关。

© Copyright International Business Machines Corporation 2003. All rights reserved.

引言

安全性是 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 文件


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<%@ 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 GlobusCredentialgridProxyInit(InputStream inUserCert, InputStream inUserKey ,
                        Stringpwd, int bits, int hours)
                throwsIOException, java.security.GeneralSecurityException
    {
                X509CertificateuserCert = CertUtil.loadCertificate(inUserCert);
                OpenSSLKeykey           = 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) {
                                thrownew java.security.GeneralSecurityException("Wrong password or othersecurity error");
                        }
                }
                System.out.println("gridProxyInit:User Priv key : " + key.getPrivateKey());

                java.security.PrivateKeyuserKey = key.getPrivateKey();

                BouncyCastleCertProcessingFactoryfactory =
                                BouncyCastleCertProcessingFactory.getDefault();

                returnfactory.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 fromdb
        boolean proxyReady = false;    // is the proxy ready?

        // Init
        if ( ! action.equalsIgnoreCase("INIT")) {
    }

        try {
                if( action.equalsIgnoreCase("CREATE") ) {

                        Stringpath = System.getProperty("user.home") + "/.globus/cog.properties";
                        org.globus.common.CoGPropertiesprops = new org.globus.common.CoGProperties();
                        props.load(path);

                        StringcertPath = props.getProperty("usercert");
                        StringkeyPath = props.getProperty("userkey");

                        System.out.println("test-proxy.jsp::CREATEpwd=" + pwd + " bits=" + bits + " hours=" + hours);
                        System.out.println("test-proxy.jsp::Certpath:" + certPath + "\nKey path: " + keyPath);


                        //create a globus cred. Certs read from def locs
                        InputStreaminCert = new FileInputStream(certPath);
                        InputStreaminKey = new FileInputStream(keyPath);

                        intstren       = Integer.parseInt(bits);
                        intlife        = Integer.parseInt(hours);

                        //create globus proxy
                        GlobusCredentialcred = 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
                    ByteArrayOutputStreambos = new ByteArrayOutputStream();
                    cred.save(bos);
                    System.out.println("grid-proxy.jsp::Savingproxy into db\n" + bos.toString());

          &# 160;         proxyReady= true;
                    Msg="Proxy created.";

                }
        }
        catch ( Exception e ) {
                e.printStackTrace();
                response.sendRedirect("test-proxy.jsp?MSG=GridProxyInit+Error:"+ e.getMessage());
        }
%>

<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="IBM WebSphere Studio">
<META http-equiv="Content-Style-Type" content="text/css">
<LINK href="../../theme/Master.css" rel="stylesheet" type="text/css">
<TITLE>test-proxy.jsp</TITLE>
<STYLE>
        TABLE, lengend {
                font-family:Verdana, Arial;
                font-size:12px;
        }
</STYLE>
<SCRIPT LANGUAGE=javascript>
<!--
var proxyReady = <%=proxyReady%>;

function OnLoad() {
        var f = document.F1;
        if ( document.all &&proxyReady ) {
                f.btnCreate.disabled= true;
              & #160; f.txtPWD.disabled= true;
        }
}

function showMsg(m sg){
        window.status = msg;
}

// fires when create btn is pressed
function Proxy_OnSubmit() {
        var action = "test-proxy.jsp?ACTION=CREATE";
        var f = document.F1;

        if ( f.txtPWD.value =="" ) {
                alert("Allfields are required");
                f.txtCN.focus();
                returnfalse;
        }

        //alert("action="+ action + "\nSubmit vals. cert=" + cert + " key="+ key);
        showMsg("Working.Please wait...");
        if ( document.all )
                document.F1.btnCreate.disabled= true; // IE only

        document.F1.action = action;
        document.F1.submit(); //submit
}

//-->
</SCRIPT>

</HEAD>
<BODY onload="OnLoad()">

<H1>Grid Proxy Init</H1>
<B>Cetificates will be loaded from default locations</B>

<hr>
<% if ( Msg != null ) { %>
        <br>
        <font color=red><%=Msg%></font>
<% } %>

<FORM method="POST" name="F1" onsubmit="return Proxy_OnSubmit()">
<FIELDSET>
<LEGEND>Proxy Options</LEGEND>
        <TABLE width="100%">
                <trclass="smallfont">
                        <TDclass="smallfont">Lifetime</TD>
                        <TDclass="smallfont">
                                <INPUTtype="radio" name="LIFETIME" value="12" checked="true">12h &nbsp;&nbsp;
                                <INPUTtype="radio" name="LIFETIME" value="24">24h &nbsp;&nbsp;
                                <INPUTtype="radio" name="LIFETIME" value="168">1week &nbsp;&nbsp;
                                <INPUTtype="radio" name="LIFETIME" value="720">1month
                        </TD>
                </tr>
                <trclass="smallfont">
                        <TDclass="smallfont">Strength</TD>
                        <TDclass="smallfont">
                                <INPUTtype="radio" name="ST" value="512" checked="true">512&nbsp;&nbsp;
                                <INPUTtype="radio" name="ST" value="1024">1024&nbsp;&nbsp;
                                <INPUTtype="radio" name="ST" value="2048">2048&nbsp;&nbsp;
                                <INPUTtype="radio" name="ST" value="4096">4096
                        </TD>
                </tr>

        </TABLE>
</FIELDSET>

        <TABLE width="100%">
                <TR>
                        <tdclass="smallfont">Pass Phrase</td>
                        <tdclass="smallfont">
                                <INPUTname="txtPWD" type="password" maxlength="20">
                        </td>
                </TR>
                <TR>
                        <TD>&nbsp;</TD>
                        <td>
                                <INPUTname="btnCreate" type="submit" value="Create"align="right">
                                &nbsp;&nbsp;
                        </td>
                </TR>

        </TABLE>

<FIELDSET>
<LEGEND>Proxy Info</LEGEND>
        <TABLE width="100%">
                <TRclass="smallfont">
                        <tdclass="smallfont">CN</td>
                        <tdclass="smallfont">
                                <fontcolor=red></font>
                        </td>
                </TR>
                <TR>
                        <tdclass="smallfont">Subject</td>
                        <tdclass="smallfont"><%=subject%>
                        </td>
                </TR>
                <TR>
                        <tdclass="smallfont">Issuer</td>
                        <tdclass="smallfont"><%=issuer%>
                        </td>
                </TR>
                <TR>
                        <tdclass="smallfont">Time left</td>
                        <tdclass="smallfont"><%=sTimeLeft%>
                        </td>
                </TR>
                <TR>
                        <tdclass="smallfont">Strength</td>
                        <tdclass="smallfont"><%=strength%>
                        </td>
                </TR>
        </TABLE>

</FIELDSET>
<br>
</FORM>
</BODY>
</HTML>

为了在 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. 代理的初始测试
Proxy init test

该 JSP 的输出如下:


图 2. 创建 Globus 凭证
创建 Globus 凭证

到目前为止一切顺利:我们已经成功地从我们的 Web 应用程序创建了一个 Gloubs 代理。





回页首


3. 创建证书和私钥

清单 3 中的 JSP 代码创建了用户证书和私钥集。

清单 3. 创建证书和私钥对


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<HTML>
<HEAD>
<%@ 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 PEMstring
        */
        public static String writePEM(byte[] bytes, String hdr, String ftr)
                        throwsIOException
        {
                ByteArrayOutputStreambos=new ByteArrayOutputStream();
                Base64OutputStreamb64os=new Base64OutputStream(bos);
                b64os.write(bytes);
                b64os.flush();
                b64os.close();

                ByteArrayInputStreambis=new ByteArrayInputStream(bos.toByteArray());
                InputStreamReaderirr=new InputStreamReader(bis);
                BufferedReaderr=new BufferedReader(irr);

                StringBufferbuff = new StringBuffer();
                Stringline;
                buff.append(hdr);

                while((line=r.readLine())!=null){
                        buff.append(line+ "\n");
                }
                buff.append(ftr);
                returnbuff.toString();

        }

        /* Create an X509 Nameused for cert creation */
        private static X509NamemakeCertDN(String subject) throws Exception
        {
                Vectortdn = new Vector();
                Vectorelems = new Vector();
                StringTokenizerst = new StringTokenizer(subject,",");

                for(; st.hasMoreTokens() ;) {
                        Strings = st.nextToken(); // [key=value]
                        if( s.indexOf("=") == -1 )
                                thrownew Exception("Invalid subject format: " + subject + " Offendingvalue: " + s);

                        Stringkey = s.substring(0, s.indexOf("=")).trim();
                        Stringval = s.substring(s.indexOf("=") + 1).trim();

                        if( val == null || val.equals(""))
                                thrownew Exception("Invalid subject format: " + subject + " Offendingvalue: " + s);

                        String[]temp = {key, val};
                        tdn.addElement(temp);
                }
                //COM.claymoresystems.cert (puretls.jar)
                returnCertRequest.makeSimpleDN(tdn);
        }

        /* Cert/key creation */
        public void generateSelfSignedCertAndKey(Stringsubject, int bits,
                        StringPwd, StringWriter swKey, StringWriter swCert )
        throws NoSuchAlgorithmException,Exception
        {
                X509Name_subject = makeCertDN(subject);
                System.out.println("generateSelfSignedCertAndKeyCert subject: " + _subject.getNameString() +
                        "Strength=" + bits + " Pwd=" + Pwd);

                //Generate A Cert RQ
                //StringWritersw = new StringWriter(); // wil contain the priv key PEM
                BufferedWriterbw = new BufferedWriter(swKey);

                KeyPairkp = CertRequest.generateKey("RSA", bits, Pwd, bw, true);

                //certs are valid for 1 year: 31536000 secs
                byte[]certBytes = CertRequest.makeSelfSignedCert(kp, _subject, 31536000);


                BufferedWriterbw1 = new BufferedWriter(swCert);
                String_certPEM = writePEM(certBytes,
                                        "-----BEGINCERTIFICATE-----\n",
                                        "-----ENDCERTIFICATE-----\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 {
                //Propertiesargs = com.ibm.grid.ogsa.securityextension.gsi.GSIProperties.load();
                Stringmsg = "";

                if( action.equalsIgnoreCase("GENERATE") ) {
                        Stringcn       = request.getParameter("txtCN");
                        String org      = request.getParameter("txtORG");
                        Stringou       = request.getParameter("txtOU");
                        Stringpwd      = request.getParameter("txtPWD");

                        Stringsubject = "O=" + org + "," + "OU="+ ou +",CN=" + cn;
                        System.out.println("Gencerts. Subject: " + subject);

                        StringWriterswCert        = new StringWriter();// wil contain cert PEM
                        StringWriterswKey         = new StringWriter();// wil contain the priv key PEM
                        generateSelfSignedCertAndKey(subject,1024, pwd, swKey, swCert);

                        //Private key
                         System.out.println("Privatekey PEM\n" + swKey.toString());
                        //cert
                        System.out.println("CertificatePEM\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());
        }
%>

<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="IBM WebSphere Studio">
<META http-equiv="Content-Style-Type" content="text/css">
<LINK href="../../theme/Master.css" rel="stylesheet" type="text/css">
<TITLE>setup-gsi.jsp</TITLE>

<SCRIPT LANGUAGE=javascript>
<!--
function showMsg(msg){
        window.status = msg;
}

function OnLoad() {
        document.F1.txtCN.focus();
        showMsg("Done");
}

// fires when create btn is pressed
function O nSubmit() {
        var f = document.F1;

        if ( f.txtCN.value == ""|| f.txtPWD.value == "" || f.txtOU.value == "" ) {
                alert("Allfields are required");
                f.txtCN.focus();
                returnfalse;
        }

        showMsg("Working.Please wait...");
        if ( document.all )
                document.F1.btnCreate.disabled= true; // IE only

        document.F1.submit(); //submit
}
//-->
</SCRIPT>

</HEAD>
<BODY onload="OnLoad()">

<H1>Setup Certificate/Private key</H1>

<hr>
<% if ( Msg != null ) { %>
        <br><font color=red><%=Msg%></font><br>
<% } %>
        <B>All fileds arerequired</B>

        <form name="F1"method="POST" action="test-creds.jsp?ACTION=GENERATE"onsubmit="return OnSubmit()">
                <TABLEwidth="100%" class="smallfont">
                        <tr>
                                <td>CommonName</td>
                                <tdwidth="40%">
                                        <INPUTtype="text" name="txtCN" size="20" maxlength="50">
                                </td>
                                <TD>Enteryour name or email</TD>
                        </tr>
                        <tr>
                                <td>OrganizationalUnit</td>
                                <td>
                                        <INPUTtype="text" name="txtOU" size="20" maxlength="50">
                                </td>
                                <TDclass="smallfont"></TD>
                        </tr>
                        <tr>
                                <td>Organization</td>
                                <td>
                                        <INPUTtype="text" name="txtORG" size="20" maxlength="50">
                                </td>
                                <TDclass="smallfont">Organization</TD>
                        </tr>
                        <tr>
                                <td>Passphrase</td>
                                <td>
                                        <INPUTtype="password" name="txtPWD" size="20" maxlength="50">
                                </td>
                                <TDclass="smallfont">Password used to encrypt the private key</TD>
                        </tr>
                </TABLE>
                <hr>
                <INPUTname="btnCreate" type="submit" name="Submit"value="Install Certs">
        </form>

</BODY>
</HTML>

这段代码在您的 Web 浏览器上会这样显示:


图 3. 设置证书/私钥
设置证书/私钥

当尝试创建认证/私钥时,WebSphere 将会抛出下面的异常:

清单 4. 由 WebSphere 和 GT3 之间发生的安全提供者冲突所抛出的异常


java.lang.InternalError: java.security.NoSuchAlgorithmException: classconfigured for Cipher:
                com.ibm.crypto.provider.DESedeCipheris 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 nota subclass of xjava.security.Cipher;

并且进行栈跟踪,我们可以假定 Java CoG API 内部尝试使用 IBM 的 JCE 作为缺省的提供者,这是不正确的,因为安全性提供者应该为 Cryptix/Bouncy Castle。这个问题在创建私钥时会出现。为了解决这个问题,将需要修改 Java 代码。





回页首


4. 更改 GT3 安全性提供者以与 WebSphere 协同工作

在确定了问题之后,就可以通过更改 puretls.jarcryptix32.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 容器之间可能会遇到的不兼容性问题。



参考资料



关于作者

Vladimir Silva 出生在厄瓜多尔的首都基多。他于1994年在 Polytechnic Institute of the Army 获得系统分析师学位。同年,他作为交换学生来到美国,在 Middle Tennessee State University 攻读计算机科学学位。毕业之后,他加入了 IBM“Web-Ahead”技术智囊团。他兴趣广泛,包括网格计算、神经网络以及人工智能。他还拥有众多的 IT 认证,其中包括 OCP、MCSD 和 MCP。为了与 Vladimir 联系或者想要获得本文所述的 puretls.jarcryptix32.jar 的修改版本, 您可以通过 vsilva@us.ibm.com把信息发给他。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款