Archive for the '技术相关' Category


Cognos 8.3用户权限控制入门

    学习Cognos 8.3入门中,需要实现Cognos与现有业务系统集成,尤其是用户权限部分。官方文档及网上的教程对Cognos用户权限控制的实现机制都语焉不详,迫切需要一个快餐式的Step-By-Step的学习文档。整理一下学习的东西,希望对新手们有所帮助。

    目的:

    1. 采用OpenDS存储组织机构及用户信息,实现OpenDS与Cognos集成

    2. 使用Cognos Framework Manager来实现用户数据过滤控制,实现同一报表用户只能够看见自己的数据

    3. 二次开发实现cognos与业务系统的用户数据集成

  下载《Cognos 8.3用户权限控制入门》

 

Technorati 标签: ,,,,

电子商务平台之“推荐作为服务”

    在亚马逊这样的电子商务标杆企业的示范下,推荐系统对于电子商务网站的价值已被大家所认同,例如:增加网站的访问量,提升销售额;提高网站的交叉销售能力;增加顾客在网店上的停留时间,浏览更多的商品;将网站的浏览者转变为购买者等等。因此大家都希望能够拥有自己的推荐系统。

    但相对于网站开发技术而言,推荐系统由于涉及数据仓库、数据挖掘、统计分析、人工智能等相关技术,因此技术门槛要高得多,对于研发能力相对较弱的中小型的企业而言,要自己研发推荐系统难度很大。于是乎诞生了一些以“推荐作为服务”(Recommendation as a Service)的公司。

1、推荐服务的基本模式

    这些公司拥有推荐系统核心技术,通过SaaS模式对外提供推荐服务,一般的服务方式如下:

    1)、以接口、批量上传等形式导入合作伙伴的产品目录

    2)、在合作伙伴网站页面嵌入用于跟踪用户行为的javascript脚本

    3)、通过对诸如商品信息、历史用户数据、用户行为(包括搜索、网站点击行为、购买历史、喜好、购物车、收藏历史)等行为数据的汇总分析,建立网站相应的推荐模型

    4)、用户登录网站时候,根据用户历史行为数据实时分析预测用户的喜好,产生个性化推荐。

    下图摘自StrandsMybuys 公司的业务流程图,基本上概括了推荐服务的核心模型

recommendation engine,推荐引擎,推荐系统,协同过滤,开放平台,推荐作为服务,recommendation as a service

                                                 Strands的模型

 

recommendation engine,推荐引擎,推荐系统,协同过滤,开放平台,推荐作为服务,recommendation as a service

                                                    Mybuys 的模型

    尽管推荐服务核心算法的理论基础基本上类似,但不同行业推荐对象对应的模型不尽相同(例如电子商务、SNS社区、媒体站点),更为重要的是由于各公司商业模式的不同,不同的公司对于推荐服务有不同的要求,因此推荐服务提供商针对不同行业及不同公司所采用推荐算法及模型实现都会有所不同。   

2、推荐服务提供商

   2.1、国外的“推荐作为服务”提供商:

    StrandsMybuysBaynoteLoomiaAggregrate KnowledgeRichRelevanceOutBrainATGAvail IntelligenceCertona、    ChoicestreamApture

recommendation engine,推荐引擎,推荐系统,协同过滤,开放平台,推荐作为服务,recommendation as a service 

 

2.2、国内的“推荐作为服务”提供商:

    百分点麦路

    麦路最初以“推荐作为服务”作为商业模式,目前重点已经转向运营购物返现联盟发现宝

    而百分点仍然专注在“推荐作为服务”上,相对于麦路更加专业,百分点推荐技术研究中心及电子期刊收集了一些有价值的资料。尽管作为纯技术驱动的公司在国内现实的商业环境下生存相对较难,但随着国内电子商务的繁荣及成熟,相信像百分点这样专业化的公司会有美好的前景。

3、几点思考:

3.1、“推荐作为服务”的商业模式

    1)、独立的推荐服务提供商

    2)、依托于某个电子商务开放平台(例如淘宝开放平台)、SNS开放平台提供推荐服务

    3)、依托于广告联盟

    4)、依托于网络营销、购物返现联盟

    5)、依托于行业垂直搜索引擎公司

    电子商务、SNS社区等互联网新兴应用的高速发展,对个性化推荐的需求越来越强烈,因此那些专注于“推荐作为服务”这一领域的推荐服务提供商会有较大的成长空间,尽管尚有很长的路要走。

   “推荐作为服务”的一种趋势是多种模式的结合,尤其是与开放平台、网络营销联盟、搜索引擎多种模式的结合,因此“推荐作为服务”提供商最终可能变成网路营销服务提供商、垂直搜索引擎公司、广告媒体公司等等。

3.2、、“推荐作为服务”的核心价值

    “推荐作为服务”提供商拥有的最为核心财富不是推荐技术本身,而是通过推荐服务所积累的海量数据,特别是用户数据和项目(item)数据。这正如Google自身最核心的财富不是搜索引擎本身,而是对于用户点击流数据。因此从这点来说,“推荐作为服务”最大的实践者其实是Google。

    用户数据:当下的“推荐作为服务”提供商基本上都围绕一个应用或一个平台来提供服务,并没有以用户网络身份标识为中心来整合各种用户行为数据。如果能够借助opensocial、openid、oauth等开放协议整合用户的网络身份,获得用户各种网络活动的数据,为用户提供更加个性、精准、实时的推荐服务,这样的推荐服务对用户极大的使用价值。

    项目数据:所谓的项目(item)数据的内涵可以是电子商务平台的商品,可以是社会化媒体的一个视频、一篇blog,可以是搜索引擎的搜索关键词,而这些恰恰是那些传统的电子商务、搜索引擎、广告巨头们的关注点。但这并不意味着“推荐作为服务”提供商无法与这些巨头们竞争。“推荐作为服务”之所以能够蓬勃发展,正说明了目前的巨头们所提供的服务在这些领域并不能很好满足用户的需求。例如在实时网络(Real-Time)、开放平台等领域。

    对于用户而言,推荐服务最核心的价值在于更加个性化、精准、实时的推荐,因此推荐服务未来的趋势之一是对用户身份及数据的整合。

    对于众多的中小企业而言,推荐服务最核心的价值在于能够帮助其带来流量、促成交易、创造交易,因此推荐服务未来的趋势之一应该是与网络营销、广告联盟等服务更加的紧密结合。

3.3、“推荐作为服务”的最佳实践

    Strands 的Francisco Martin 在RecSys 2009上的演讲 RecSys 2009 Keynote: Top 10 Lessons Learned Developing, Deploying, and Operating Real-World Recommender Systems 分享了Strands在此方面的经验,很精彩:

  • Lesson 1. Make sure a recommender is really needed! Do you have lots of recommendable items? Many diverse customers?… also think Return-on-Invesment… a more sophisticated recommender may not deliver a better ROI.
  • Lesson 2. Make sure the recommendations make strategic sense. Is the best recommendation for the customer also the best for the business? What is the difference between a good and useful recommendation? Good recommendations vs useful recs; obvious recommendations may not be useful; risky recs may deliver better long-term value.
  • Lesson 3. Choose the right partner! Select the right rec vendor vs hire some #recsys09 students. If you are a big company the best thing you can do is organize a contest.
  • Lesson 4. Forget about cold-start problems (!) …. just be creative. The internet has all the data that you need (somewhere…).
  • Lesson 5. Get the right balance between data and algorithms. 70% of the success of a recommendation system is in the data, the other 30% in the algorithm.
  • Lesson 6. Finding correlated items is easy but deciding what, how, and when to present them to the user is hard… or don’t just recommend for the sake of it. Remember, user attention is a scarce and valuable resource. Use it wisely! … dont make a recommendations to a customer who is just about to pay for items at the checkout! User interface should get at least 50% of your attention.
  • Lesson 7 Don’t waste time computing nearest neighbours (use social connections)… just mine the social graph. Might miss useful connections?
  • Lesson 8 Don’t wait to scale!
  • Lesson 9: Choose the right feedback mechanism. Stars vs thumbs …. the YouTube problem. More research on implicit and other feedback mechanisms is needed. The perfect rating system is no rating system! … focus on the interface.
  • Lesson 10 Measure Everything! … business control and analytics is a big opportunity here.

 

4、参考资料

  RecSys 2009 Keynote: Top 10 Lessons Learned Developing, Deploying, and Operating Real-World Recommender Systems

  5 Problems of Recommender Systems

  Readwriteweb series on recommendation technologies

  Baynote, Strands, RichRelevance — will they survive the “recommendation engine” consolidation?

 

使用CAPICOM实现证书管理

    在基于ejbca搭建CA时候,需要实现如下功能:

    1)、在客户端实现对页面关键数据(例如订单金额等)采用签名、数字信封等方式进行加密

    2)、能够较好支持USB KEY集成

    3)、用户申请数字证书导入浏览器后,能够通过Web页面对浏览器证书进行重新申请(renewal)、删除、显示、查询、验证等功能

    单独依靠XEnroll.dll或CertEnroll.dll控件已经无法满足以上要求。微软的CAPICOM组件封装了Windows CryptAPI的各种操作,可以在Windows环境下各种语言中使用。而且CAPICOM中的大多数接口都是“脚本安全”的,可以直接在网页脚本中安全使用CAPICOM接口所提供的功能。

    需求1)、2)的实现思路:在前台利用CAPICOM组件读取浏览器或USB盘中的用户证书,对页面表单的关键数据进行SHA1签名。将签名后的密文与页面表单中的明文提交到服务器端。服务器从用户请求密文解密得到用户证书及页面关键数据的摘要(利用Bouncycastle、Apache Commons Codec),验证证书的合法性及有效性。然后对提交的页面明文计算SHA1,把得到的结果与从密文是解出摘要进行对比,从而实现数据完整性的校验。

    需求3)的实现思路:关键是要实现证书的删除、查询、验证功能,结合IE中自动安装用户数字证书 IE中自动安装根数字证书 ,可以很容易实现相关功能。

  CAPICOM中常用的类主要包括:StoreCertificatesCertificate 

  基本操作步骤为:创建Store对象->打开Store对象->查找需要操作的证书集合(Certificates)->对单个证书(Certificate)进行操作

 

1、一个简单例子:

<OBJECT id="capicom" codeBase="http://download.microsoft.com/download/E/1/8/E18ED994-8005-4377-A7D7-0A8E13025B94/capicom.cab#version=2,0,0,3" classid="clsid:A996E48C-D3DC-4244-89F7-AFA33EC60679" VIEWASTEXT>
</OBJECT>
<script language="javascript">
var CAPICOM_CURRENT_USER_STORE = 2
var CAPICOM_MY_STORE = "My"
var CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1
var CAPICOM_STORE_OPEN_READ_WRITE=1
var myStore = new ActiveXObject("CAPICOM.Store");
myStore.Open(CAPICOM_CURRENT_USER_STORE,CAPICOM_MY_STORE,CAPICOM_STORE_OPEN_READ_WRITE);
var myStoreCerts = myStore.Certificates;
var info="";
for(i = 1; i<= myStoreCerts.Count; i++)
{            info+=    " Subject Name : "+myStoreCerts.Item(i).SubjectName +"<br/>";
}
document.write(info);
</script>

 

2、一个更复杂的例子:

2.1)、capicomtest.html

<html>
<head>
<title>CAPICOM使用DEMO</title>
<meta http-equiv="no-cache">

</head>
<body onLoad="listCert()">
    <OBJECT id="capicom" codeBase="http://download.microsoft.com/download/E/1/8/E18ED994-8005-4377-A7D7-0A8E13025B94/capicom.cab#version=2,0,0,3" classid="clsid:A996E48C-D3DC-4244-89F7-AFA33EC60679" VIEWASTEXT>
    </OBJECT>
<script language="javascript" src="capicom.js"></script>
<form name="frmStore" method="post" action="">
  1.读取用户证书
    <br>
    <br>
  证书类型:
  <select id="storeName" size="1" name="storeName">
      <option value="my" selected>Personal</option>
      <option value="root">Root</option>
      <option value="AddressBook">Address Book</option>
      <option value="ca">CA</option>
  </select>
  <input type="button" value="获取证书列表" onclick="listCert()">
  </p>
  <p>选择一个证书:<br>
    <select id="allCerts" size="10" name="allCerts" >
    </select>
    <br>
    <input id="delcert" type="button" name="delcert" value="删除选定证书" onclick="deleteCert()" />
        <input id="verifydate" type="button" name="verifydate" value="验证选定证书有效期" onclick="alert(verifyCertValidDate())" />

</form>
</body>
</html>

   

 

2.2)、capicom.js

var CAPICOM_CURRENT_USER_STORE = 2
var CAPICOM_MY_STORE = "My"
var CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1
var CAPICOM_STORE_OPEN_READ_WRITE=1

var myStore = new ActiveXObject("CAPICOM.Store");
myStore.Open(CAPICOM_CURRENT_USER_STORE,CAPICOM_MY_STORE,CAPICOM_STORE_OPEN_READ_WRITE);      

function deleteCert()
{
    var myStore = new ActiveXObject("CAPICOM.Store");
    try{

          var storeName = frmStore.storeName.options(frmStore.storeName.selectedIndex).value;
            myStore.Open(CAPICOM_CURRENT_USER_STORE,storeName,CAPICOM_STORE_OPEN_READ_WRITE);

            var index = frmStore.allCerts.options.selectedIndex;
            var cert = frmStore.allCerts.options[index].value;
          subjectName=getCertCN(cert);

            var myStoreCerts = myStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, subjectName, true);
             for(i = 1; i<= myStoreCerts.Count; i++)
            {
                     if(myStoreCerts.Item(i).HasPrivateKey()){
                         //要删除用户证书,首先要删除私钥,才能够调用Certificates.Remove方法删除证书
                         myStoreCerts.Item(i).PrivateKey.Delete();
                     }

                 myStore.Remove(myStoreCerts.Item(i));
            }
            alert("删除证书成功");
            myStoreCerts=null;
            myStore.Close() ;
            myStore=null;    

    }catch(e){
        alert("删除证书失败,错误码为:"+e.number);

    }
    window.location.reload();
}

function verifyCertValidDate(){
    var myStore = new ActiveXObject("CAPICOM.Store");

 try{
         var storeName = frmStore.storeName.options(frmStore.storeName.selectedIndex).value;
        myStore.Open(CAPICOM_CURRENT_USER_STORE,storeName,CAPICOM_STORE_OPEN_READ_WRITE);
    }
    catch (e)
    {
        alert("打开证书库失败");
        return ;
    }
    var index = frmStore.allCerts.options.selectedIndex;
    var cert = frmStore.allCerts.options[index].value;
  subjectName=getCertCN(cert);

  var myStoreCerts =  myStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, subjectName, true);
    var result="";

    for(i = 1; i<= myStoreCerts.Count; i++)
    {
        var validToDate=new Date(myStoreCerts.Item(i).ValidToDate+"");
        var currentDate=new Date();
        var diff=(validToDate-currentDate)/(3600*24*1000);

        if(diff >31){
            result="证书"+myStoreCerts.Item(i).subjectName+" 有效期为:"+formatDate(validToDate);
        }
        else if(diff<=31 && diff >0){
            result="证书"+myStoreCerts.Item(i).subjectName+" "+diff+"后即将过期,请更新证书";
                alert(result);
            return result;
        }
        else{
                result="证书"+myStoreCerts.Item(i).subjectName+" 已经过期,请更新证书";
                    alert(result);
                return result;
        }
    }
    if(result=="")
        return "没有有效期";
    return result;

}

function listCert()
{
    var myStore = new ActiveXObject("CAPICOM.Store");
    try
    {
        var storeName = frmStore.storeName.options(frmStore.storeName.selectedIndex).value;
        myStore.Open(CAPICOM_CURRENT_USER_STORE, storeName, CAPICOM_STORE_OPEN_READ_WRITE);
    }
    catch (e)
    {
        alert("打开证书库失败");
        return false;
    }    

    var count = frmStore.allCerts.options.length;
    for (i = 1; i <= count; i++)
    {
        frmStore.allCerts.options.remove(count-i);
    }
    while (frmStore.allCerts.options.length) frmStore.allCerts.options[0] = null;    

    //只列出DN中有yeeach.com的证书
    var myStoreCerts = myStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, "yeeach.com", true);
    for(i = 1; i<= myStoreCerts.Count; i++)
    {
         var certInfo = new Option("cert: " + myStoreCerts.Item(i).subjectName );
         certInfo.value=myStoreCerts.Item(i).subjectName ;
        frmStore.allCerts.options.add(certInfo, i);
    }
}

function getCertCN(dn){
    //对于CAPICOM_CA_STORE、CAPICOM_OTHER_STORE、CAPICOM_ROOT_STORE不适用,需要调整
        i=dn.indexOf('CN=');
    if(i==-1){
        return "没有CN";
    }else{
            cn=dn.substr(i+3);
            return cn;
    }
}

function formatDate(inputDate){
    if(null == inputDate){
        return "";
    }
    //var year = 1900+date.getYear();
        var year = inputDate.getYear();
    var month = inputDate.getMonth()+1;
    if(month < 10) month = "0"+month;

    var day = inputDate.getDate();
    if(day < 10) day = "0"+day;

    var hour = inputDate.getHours();
    if(hour < 10) hour = "0"+hour;
    var minute = inputDate.getMinutes();
    if(minute < 10) minute = "0"+minute;
    var second = inputDate.getSeconds();
    if(second < 10) second = "0"+second;
    return year+"-"+month+"-"+day;
}

 

测试代码打包下载

 

3、参考文档:

CAPICOM Reference

How to use Java produce Signature by USBKey under CryptoAPI/CSP

How to create a digital signing solution with only JavaScript

How to obtain signer’s details from a JavaScript signed data

Automatic sign of a text in with a web script using CAPICOM with an ActiveX

数字证书在WEB应用中登录

 

IE中自动安装用户数字证书

    在基于ejbca搭建数字证书时候,需要实现用户自助申请数字证书(Certificate signing request)并自动安装到IE浏览器中的功能(Certificate enrollment)。

    相关的资料极其缺少,好在ejbca中有相关的例子可以参考,尽管不是很完整。整理一下研究的大致成果。

1、基本思路:

    1)、Certificate signing request(CSR)

     证书签发请求(CSR),也叫做证书请求,是从请求者浏览器发送到证书中心来申请一个数字身份证书的一条信息,在公共密钥基础架构系统中。在创建一个 CSR 之前,这个请求者首先产生一个密钥对,为这个私有密钥保密。CSR 包括鉴别请求者一条的信息,和由这个请求者选择的公共密钥。相应的私有密钥不包含在 CSR 中,但是被用于数位签名整个请求。

    在XP、Windows 2003的IE上,通过XEnroll.dll控件的createPKCS10方法来生成CSR(Certificate signing request)。

   在Vista,Windows 2008,Windows 7 的IE上,需要使用CertEnroll.dll的X509Enrollment.CX509CertificateRequestPkcs10方法来生成CSR(Certificate signing request)。

  2)、用户数字证书的自动安装

    要实现用户数字证书在IE浏览器中自动安装,首先要客户端浏览器提交CSR到证书中心服务器,证书中心服务器端根据CSR对用户私钥和公钥进行签名并将签名后的证书返回给客户端。

   在XP、Windows 2003的IE上,通过XEnroll.dll控件的acceptPKCS7方法实现证书自动安装到客户端浏览器,大致步骤如下:


       <object id=”XEnroll” classid=”clsid:127698e4-e730-4e5c-a2b1-21490a70c8a1″ codebase=”xenroll.dll”></object>

        XEnroll.acceptPKCS7

   在Vista,Windows 2008,Windows 7 的IE上,需要使用CertEnroll.dll控件的InstallResponse方法来实现自动安装到客户端浏览器,大致过程如下:

       <object id=”CertEnroll” classid=”clsid:884e2049-217d-11da-b2a4-000e7bbb2b09″ codebase=”CertEnroll.dll”></object>

       var objEnroll = CertEnroll.CreateObject(“X509Enrollment.CX509Enrollment”)

       Call objEnroll.Initialize(1)

       objEnroll.InstallResponse

    此处安装用户数字证书时候并没有自动安装根证书,根证书自动安装的实现方式可以参考:IE中自动安装根数字证书

   3)、服务器端的处理逻辑

      在ejbca中src\java\org\ejbca\ui\web\pub\DemoCertReqServlet.java、src\publicweb\publicweb\templates\certInstTemplate.jsp可以作为例子来理解服务器端对CSR请求处理及服务器响应客户端实现证书自动安装的实现机制。

      以上思路其实应用于openssl的方案也可以。

2、测试页面

<HTML>
<HEAD>
    <meta http-equiv="Content-Type" content="text/html; charset=GBK" />
    <TITLE>VBScript Certificate Enrollment Control Request 例子(使用XEnroll)
    </TITLE>

<OBJECT classid="clsid:127698E4-E730-4E5C-A2b1-21490A70C8A1"
    codebase="xenroll.dll"
    id=XEnroll >
</OBJECT>

<form name="form1" id="form1" action="http://192.168.1.16/ejbca/democertreq" method="post" onsubmit="cert()">  

<center>Certificate Enrollment Control Request 例子<br/><br/>
这里只演示使用XEnroll.dll(XP、Windows 2003的IE)来生成CSR的例子<br/>
在Vista,Windows 2008,Windows 7 的IE上需要使用CertEnroll.dll,与此类似<br/>

    <!--ejbca 中设定的Certificate Profile-->
  <input name="certificateprofile" value="liang" type="hidden">
    <!--ejbca 中设定的End Entity Profile-->
  <input name="entityprofile" value="liang" type="hidden"><br>
  <!-- XEnroll.createPKCS10产生的CSR值 -->
  <input name="pkcs10req" id="pkcs10req"  type="hidden"><br>
  <br>
  <!-- DemoCertReqServlet需要user参数 -->
  <input name="user" value="C=CN,O=yeeach.com,OU=yeeach.com,CN=liang"  type="hidden">
  <table>
      <tr>
          <td align="right">用户DN之Canonical Name(CN):</td><td><input name="canonical_name" value="liang"  type="text"></td>
      </tr>
        <tr>
          <td align="right">用户DN之Organization(O):</td><td><input name="organization" value="yeeach.com"  type="text"></td>
      </tr>
        <tr>
          <td align="right">用户DN之Organization Unit(C):</td><td><input name="organization_unit" value="R&D"  type="text"></td>
      </tr>
        <tr>
          <td align="right">用户DN之County(C):</td><td><input name="country" value="CN"  type="text"></td>
      </tr>
        <tr>
          <td align="right">用户密码:</td><td><input name="password" value="liang" type="password"></td>
      </tr>
        <tr>
          <td align="right">邮箱:</td><td><input name="email" type="text" value="chuanliang@gmail.com"></td>
      </tr>
      <tr><td></td><td></td></tr>
      <tr><td></td><td></td></tr>
      <tr><td align="center" colspan="2"><input value="申请证书" name="submit" type="submit" ></td></tr>
  </table>
  <input name="includeemail" value="true" type="hidden">

 </form>

  <SCRIPT language="VBScript">
  Sub   cert
<!--
' Declare the distinguished name variable.
Dim strDN

' Declare the request variable.
Dim strReq

' Enable error handling.
On Error Resume Next

' Declare consts used by CertRequest object.
const CR_IN_BASE64 = &H1
const CR_IN_PKCS10 = &H100

' Build the DN.

strDN =  "CN="+document.getElementById("canonical_name").value  _
      & ",OU="+document.getElementById("organization_unit").value _
      & ",O="+document.getElementById("organization").value _
      & ",C="+document.getElementById("country").value

' Attempt to use the control, in this case, to create a PKCS #10.
MsgBox("Creating PKCS #10 " & strDN)
document.getElementById("user").value=strDN
strReq = XEnroll.createPKCS10(strDN," ")
' If above line failed, Err.Number will not be 0.
if ( Err.Number <> 0 ) then
    MsgBox("Error in call to createPKCS10 " & Err.Number)
    err.clear
else
    'MsgBox("Submitting request " & strReq)

    ' If the preceding line failed, Err.Number will not be 0.
    if ( Err.Number <> 0 ) then
        MsgBox("Error in Request Submit " & Err.Number)
        err.clear
        return false
    else
        document.getElementById("pkcs10req").value=_
        "-----BEGIN NEW CERTIFICATE REQUEST-----" + _
        CHR(13) + _
        strReq + _
        "-----END NEW CERTIFICATE REQUEST-----"

    end if

end if
  Exit   Sub
  End   Sub
-->
</SCRIPT>
</body>
</html>

 

3、certInstTemplate.jsp

<!-- Header -->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <title>EJBCA Certification Authority</title>
    <link rel="stylesheet" href="styles.css" type="text/css" />
    <script type="text/javascript" src="scripts/functions.js"></script>
    <script type="text/vbscript" src="scripts/functions.vbs"></script>
  </head>
  <body>

    <div class="main">
      <div class="content">
<!-- Header -->

<object classid="$CLASSID" id="g_objClassFactory"></object>
<!-- Updated w CertEnroll for Vista
Class ID: {884e2049-217d-11da-b2a4-000e7bbb2b09}
-->
<!-- New updated enrollment activeX-control 2002-09-02 (Q323172)
New Xenroll.dll information:
Class ID: {127698e4-e730-4e5c-a2b1-21490a70c8a1}
sXEnrollVersion="5,131,3659,0"

New Scrdenrl.dll information:
Class ID: {c2bbea20-1f2b-492f-8a06-b1c5ffeace3b}
sScrdEnrlVersion="5,131,3642,0"
-->
<!-- Old Xenroll.dll information:
Class ID: {43F8F289-7A20-11D0-8F06-00C04FC295E1}

Old Scrdenrl.dll information:
Class ID: {80CB7887-20DE-11D2-8D5C-00C04FC29D45}
-->

    <script language="VBScript" type="text/vbscript">
        cert = "MIICdgYJKoZIhvcNAQcCoIICZzCCAmMCAQExADALBgkqhkiG9w0BBwGgggJLMIIC" & _

        ' This function can be moved to functions.vbs when the header is parsed as jsp
        Sub installcertvista
            Dim objEnroll
            Set objEnroll = g_objClassFactory.CreateObject("X509Enrollment.CX509Enrollment")
            Call objEnroll.Initialize(1)    'EnrollmentContext UserContext
            err.clear
            On Error Resume Next
            Call objEnroll.InstallResponse(0, cert, 6, "")    'AllowNone, , XCN_CRYPT_STRING_BASE64_ANY, pw
            If err.number = -2146762487    Then    ' 0x800b0109 Not trusted root
                r = Msgbox("Could not complete the request since, the CAs' certificates were not properly installed.", , "Certificate Management")
            ElseIf err.number <> 0 Then
                r = Msgbox("The certificate could not be installed", , "Certificate Management")
            Else
                r = Msgbox("A new certificate has been installed", , "Certificate Management")
            End If
        End Sub

        Sub installcert
            Err.Clear
            On Error Resume Next
            g_objClassFactory.acceptPKCS7(cert)
            If Err.Number <> 0 Then
                r = Msgbox("The certificate could not be installed in this web browser", , "Certificate Management")
            Else
                r = Msgbox ("A new certificate has been installed", , "Certificate Management")
            End if
        End Sub

        If InStr(navigator.userAgent, "Windows NT 6") <> 0 Then
            installcertvista
        Else
            installcert
        End If
    </script>

    <h1 class="title">Internet Explorer Certificate enrollment.</h1>
    <p>If the installation was completed without any errors, your certificate has
    been installed in your web browser and you may now start using your certificate.<br />
    You can look at your certificate with &quot;<tt>Tools-&gt;Internet
    Options-&gt;Content-&gt;Certificates</tt>&quot;.</p>

<!-- Footer -->
      </div>
    </div>
  </body>
</html>
<!-- Footer -->

 

4、参考资料

   IE中自动安装根数字证书

   Certificate Enrollment API

   Certificate Web Request/Enrollment on Windows Vista/Server 2008

   Simple PKI

   Browser-generated Certificate Requests

 

IE中自动安装根数字证书

基本思路:

1、在XP、Windows 2003的IE上,通过XEnroll.dll控件来完成根数字证书的自动安装。

2、在Vista,Windows 2008,Windows 7 的IE上,需要使用CertEnroll.dll来自动完成根数字证书的自动安装。

3、XEnroll.InstallPKCS7只适用于自动安装根证书。XEnroll.acceptPKCS7 用于安装用户数字证书,但需要配合CSR(Certificate signing request)才能够使用。要实现自动安装用户证书:

在IE中:需要配合Enroll.createPKCS10CSR来生成CSR(Certificate signing request)

在Firefox中:需要配合使用html的keygen标签来生成CSR

4、如果只需要能够下载证书并安装,而不要在IE浏览器中完成证书注销、证书申请等功能,可以采用下载证书文件的方式,MIME Type可以采用

application/x-pkcs12、application/pkcs-12

几个与PKI证书相关的MIME Type:

application/x-x509-ca-cert、application/x-x509-user-cert、application/pkcs10、application/x-pkcs10、application/pkcs-12、

application/x-pkcs12、application/x-pkcs7-signature、application/pkcs7-mime、application/x-pkcs7-mime、

application/pkcs7-mime、application/x-pkcs7-mime、application/x-pkcs7-certreqresp、application/pkcs7-signature

  测试代码:

<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ page import="java.lang.*,java.io.*" %>
<html>
<head>
<title>IE中自动安装数字证书测试</title>
</head>

<body>
IE中使用XEnroll.InstallPKCS7自动安装根数字证书<br/>
 备注:这里测试的根证书采用Base64编码 X.509格式(CER)<br/>
<%     

StringBuffer server_cert =new StringBuffer();
try {
    String realPath = this.getClass().getClassLoader().getResource("liangchuan.cer").getPath();
    File file = new File(realPath);
    if (!file.exists()) {
        out.println("<HTML><BODY><P>");
        out.println("<h2>根证书文件不存在</h2> <br/>");
        out.println("</P></BODY></HTML>");
        out.flush();
        out.close();
    }else{
        BufferedReader bf=new BufferedReader(new FileReader(file));
        String line=null;
        while((line=bf.readLine())!=null)
            server_cert.append(line);

        bf.close();

    }
}catch(Exception e){
    out.println("<HTML><BODY><P>");
    out.println("<h2>读取证书文件出错</h2> <br/>");
    out.println(e.toString());
    out.println("</P></BODY></HTML>");
    out.flush();
    out.close();
}

String Agent = request.getHeader("User-Agent");
StringTokenizer st = new StringTokenizer(Agent,";");
st.nextToken();
String userBrowser = st.nextToken();
String userOS = st.nextToken();
out.println("你的操作系统为:");
out.println(userOS);
String activexLib="XEnroll";

//检查是否是Windows Vista,Windows 2008,Windows 7,在Vista,Windows 2008,Windows 7上,需要使用 CertEnroll.dll
//Windows 2008 Server, IE7 User-Agent header: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2;...
//Windows Vista, IE7 User-Agent header: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0;...
//Windows 7,IE8 User-Agent header: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1;...

if(userOS.equals("Windows NT 6.0") || userOS.equals("Windows NT 6.1")|| userOS.equals("Windows NT 5.2"))
    activexLib="CertEnroll";

String sPKCS7=server_cert.toString();
%>

<% if(activexLib.equals("XEnroll"))
{ %>
    <object id="XEnroll" classid="clsid:127698e4-e730-4e5c-a2b1-21490a70c8a1" codebase="xenroll.dll"></object>
    <SCRIPT language="VBSCRIPT">
        ON ERROR resume next
        sPKCS7 = "<%= sPKCS7 %>"
        //XEnroll.InstallPKCS7用于安装根证书。
        XEnroll.InstallPKCS7(sPKCS7)

        if err.Number <> 0 then
            if err.number = -2146885628 then
                MsgBox "Keyset does not exist"
            else
                MsgBox "证书下载时出错,错误号="&err.description
            end if
        else
            MsgBox "证书已成功装入"
        end if
</script>
<% } else {%>

//方法来源:
//http://blogs.msdn.com/alejacma/archive/2009/01/28/how-to-create-a-certificate-request-with-certenroll-javascript.aspx
//Vista下由于暂时没有测试环境,方法尚待验证

    <object id="objCertEnrollClassFactory" classid="clsid:884e2049-217d-11da-b2a4-000e7bbb2b09"></object>
    <script language="javascript">
    function InstallCert()
    {
        document.write("<br>Installing certificate...");
        try {
            // Variables
            var objEnroll = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509Enrollment")
            var sPKCS7 = "<%= sPKCS7 %>"
            objEnroll.Initialize(1); // ContextUser
            objEnroll.InstallResponse(0, sPKCS7, 6, ""); // AllowNone = 0, XCN_CRYPT_STRING_BASE64_ANY = 6
        }
        catch (ex) {
            document.write("<br>" + ex.description);
            return false;
        }

    return true;
    }

    InstallCert(); 

    </script>

<% } %>
<%
/*
out.println("用下载方式下载p12格式的文件下载后安装"); 
ClassLoader cl = this.getClass().getClassLoader();
try {
    InputStream is = cl.getResourceAsStream("liangchuan.p12");
    //response.setContentType("application/x-x509-ca-cert");
    response.setContentType("application/x-pkcs12");
    response.addHeader("Content-Disposition", "attachment; filename=liangchuan.p12");
    OutputStream os = response.getOutputStream();
    //InputStream is = new FileInputStream(fileName);
    while (is.available() > 0) {
        char c = (char) is.read();
        os.write(c);
    }
    os.flush();
    is.close(); 
} catch (Exception e) { 

    out.println("<HTML><BODY><P>");
    out.println("<h2>下载证书文件出错</h2> <br/>");
    out.println(e.toString());
    out.println("</P></BODY></HTML>");
    out.flush();
    out.close(); 

}
*/
%>
</body>
</html>

参考资料:

How to create a certificate request with CertEnroll (JavaScript)

Certificate-Related Changes for Windows Vista

How to use Certificate Services Web enrollment pages together with Windows Vista or Windows Server 2008

域名clientHold后的解锁流程

    一个听朋友道听途说的流程,供参考:

    1、 公司写整顿报告提交给DNS提供商所在地公安局

    2、 公安局上报整顿报告到公安部11局(互联网信息中心)

    3、 公安部11局对整顿报告进行审理并批复

    4、 公安部11局把解除域名锁定的批复抄送给工信部

    5、 工信部接到公安部11局的批复后把解除域名锁定的通知下达给通信管理局

    6、 通信管理局通知DNS提供商解锁

 

Technorati 标签: ,,,

使用Varnish+ESI实现静态页面的局部缓存(思路篇)

    页面静态化是搭建高性能网站必用的招式之一,页面静态化可以有效提升系统响应速度,同时也有利于搜索引擎优化。但在页面静态化后,静态页面之间包含(例如所有的静态页面包含页头、页脚)以及静态页面中的局部信息的动态更新又成为新的问题。

    静态页面之间的包含一般有如下一些方案:

   1、Client Side Includes(CSI):通过frame、iframe、javascript、javacript+ajax等方式将另外一个页面的内容动态包含进来。像现在流行的jquery等javascript库对此有较好的支持。

      优点:能够利用浏览器客户端并行处理及装载的机制;通过浏览器缓存机制可以降低网络传输时间,提高性能;计算放在客户端,能够降低服务器端压力

      缺点:搜索引擎优化问题;javascript兼容性问题;客户端缓存可能导致服务器端内容更新后不能及时生效;XSS等安全隐患

   2、Server Side Includes(SSI):

       优点:SSI技术是通用技术,不受具体语言限制,只需要Web服务器或应用服务器支持即可,Ngnix、Apache、Tomcat、Jboss等对此都有较好的支持

       缺点:SSI在语法上不能够直接包含其他服务器的url(当然也可以通过redirect等来变通实现),因此在需要充分利用缓存及负载均衡的环境下相对不是很灵活。    

       当然如果不使用单独的缓存服务器,而是使用Ngnix,利用Ngnix对SSI及Memcached支持,通过NginxHttpSsiModule、NginxHttpMemcachedModule也可以实现页面缓存,但与专业的缓存服务器(例如Varnish)相比较,Ngnix作为缓存服务器只适合于中小规模的场合。

    3、Edge Side Includes (ESI):

        Edge Side Includes(ESI) 和Server Side Includes(SSI)和功能类似。SSI需要特殊的文件后缀(shtml,inc)。ESI可以直接通过URI包含远程服务器文件,ESI更适合用于缓存服务器上,缓存整个页面或页面片段,因此ESI特别适合用于缓存。像当下流行的缓存服务器Varnish对此有所支持。

 

    SSI可以很容易满足让所有静态页面include其他静态页面的需求。

    大部分的网站都有这样的需求:在整个静态页面的局部有需要动态更新的内容片段,包括:

    1、与用户个性化无关的信息,所有用户进来看到的内容都一样。例如最热新闻、最活跃的用户等

    2、与用户个性化信息相关。例如用户登录信息、用户好友等

   以上两种情况,一般情况下都采用ajax方式来实现静态页面局部信息的刷新,ajax直接提交给Web服务器或应用服务器获取动态数据。或者采用Ajax+Memcached的模式,将动态变化的内容放入Memcached中,ajax直接存取Memcached,这样能够缓解Web服务器或应用服务器压力。但采用ajax的方案,直接绕过了缓存服务器,并没有充分利用缓存服务器对于静态页面的缓存支持。

    使用Varnish及其对ESI的支持很容易实现对以上两种需求的较好支持:

   1、与用户个性化无关的信息:直接由Varnish+ESI就可以实现。对于动态变化的局部页面,可以在ESI制定的url地址返回的http header的Cache-Control来指定缓存策略,实现局部页面缓存(fragment caching)。

  2、与用户个性化信息相关:对于整个页面的缓存策略仍然使用Varnish+ESI方式。而需要fragment caching的局部页面,可以根据用户Cookie信息获得用户身份标识信息(例如userid),然后在ESI的URL中带上用户身份信息提交到后端的Web服务器或应用服务器以获取与用户个性化相关的信息。可以参考:Caching logged in users

    简单梳理了一下基于Varnish+ESI实现静态页面缓存的思路,有空再写代码具体测试一下。

    Varnish作为一个高性能的缓存服务器,值得好好研究一下。

    尽管Varnish和Ngnix都具有Load Balancing的功能,但Ngnix只能根据客户端IP进行负载均衡,不支持基于Session状态维护(session persistence)方式,无法维护Session状态;而Varnish的Load Balancing都不支持。而这正是HAproxy的强项。

    由此得到一个相对理想的架构:

      Nginx (用于HTTP compression及https) –> Varnish (用于reverse proxy caching) –>HAProxy(用作Load Balancing)–>Ngnix(Web Server)或Tomcat

 

参考文档:

    http://www.trygve-lie.com/blog/entry/esi_explained_simple

    http://jimmyg.org/blog/2009/ssi-memcached-nginx.html

    http://docs.heroku.com/http-caching

    http://docs.heroku.com/memcached

    http://kovyrin.net/2007/08/05/using-nginx-ssi-and-memcache-to-make-your-web-applications-faster/

    http://www.ibm.com/developerworks/opensource/library/os-php-varnish/index.html

 

下一页 »