其它系统与domino系统单点登录的实现方式

  • 【背景】

随着企业中业务不断增多,用户处理不同的业务则须要频繁的切换不同的系统进行操作。而用户则须要记住各个系统的username、password,频繁的登录。假设各个系统间可以进行单点登录。无疑会大大降低用户反复输入password的困扰。

因为domino系统相对照较封闭。其它系统想相对安全的单点domino系统并不是易事。

或许有些人会说通过这个方案。通过模拟用户登录的方式就能够实现:

Names.nsf?login&username=xxx&password=xxx

可是。这样实现显然不太安全。一个须要单独记录用户的明文password(domino httppassword是不可逆算法)。

我知道两种实现方式相对安全:DSAPI和模拟LTPAToken。

本文介绍一种,通过dominoLTPAToken的生成方式实现单点登录的方法。

  • 【实现原理】

输入參数

1.
username;

2.
登录系统时间;

3.
登录到期时间。

4. Domino密钥

输出參数

加密后的LTPAToken加密串

创建cookie

document.cookie= "LtpaToken="+ token + ";expires=" + exp.toGMTString() +";path=/;domain=.xxx.com";

token:加密token

expires:cookie到期时间

domain:单点域名,与dominoSSO配置文档同样,格式:.xxx.com

  • 【參考代码】
  • java代码

    import java.io.PrintWriter;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties; import lotus.domino.*; public class JavaAgent extends AgentBase { public void NotesMain() {
    Session session = null;
    AgentContext agentContext = null;
    Document doc = null;
    PrintWriter pw = null;
    String token = "";
    String sReturn = "false";
    String sJson = "";
    try {
    pw = getAgentOutput();
    session = getSession();
    agentContext = session.getAgentContext();
    doc = agentContext.getDocumentContext();
    String sPara = doc.getItemValueString("query_string_decoded");
    // 单点usernameloginName
    String canonicalUser = sPara.substring(sPara.indexOf("sPara=")+6); // 单点起始时间
    Date tokenCreation = new Date(new Date().getTime() - 60000 * 10);
    String timeLimit="720";
    // 单点到期时间
    Date tokenExpires = new Date(tokenCreation.getTime() + Long.parseLong(timeLimit) * 60000);
    // domino SSO 密钥(domino SSO配置文档的LTPA_DominoSecret域值)
    String dominoSecret = "9BY2oinn1FmI42i3oNEnL3nNVPQ=";
    token = LtpaToken.generate(canonicalUser, tokenCreation, tokenExpires, dominoSecret).getLtpaToken();
    //System.out.println("token==ssobak==="+token);
    sReturn = "true";
    DominoTokenParser tokenParser = new DominoTokenParser();
    System.out.println("username:"+tokenParser.parse(token,dominoSecret)); } catch(Exception e) {
    e.printStackTrace();
    }finally{
    pw.println("Content-type: text/plain;charset=GB2312");
    sJson = "{\"oResult\":\""+sReturn+"\",\"token\":\""+token+"\"}";
    System.out.println("sJson="+sJson);
    pw.println(sJson); //回收domino对象
    fnRecycle(doc);
    fnRecycle(agentContext);
    fnRecycle(session); if(pw!=null){
    pw.close();
    }
    }
    } public void fnRecycle(Base object){
    if(object != null){
    try {
    object.recycle();
    } catch (NotesException e) {
    // TODO 自己主动生成 catch 块
    e.printStackTrace();
    }
    }
    }
    }
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.Properties; /**
    * Lightweight Third Party Authentication. Generates and validates ltpa tokens used in Domino single sign on
    * environments. Does not work with WebSphere SSO tokens. You need a properties file named LtpaToken.properties which
    * holds two properties.
    *
    * <pre>
    * ) domino.secret=The base64 encoded secret found in the field LTPA_DominoSecret in the SSO configuration document.
    * ) cookie.domain=The domain you want generated cookies to be from. e.g. '.domain.com' (Note the leading dot)
    *</pre>
    *
    * @author $Author: rkelly $
    * @version $Revision: 1.1 $
    * @created $Date: 2003/04/07 18:22:14 $
    */
    public final class LtpaToken {
    private byte[] creation;
    private Date creationDate;
    private byte[] digest;
    private byte[] expires;
    private Date expiresDate;
    private byte[] hash;
    private byte[] header;
    private String ltpaToken;
    private Properties properties = null;
    private byte[] rawToken;
    private byte[] user; /**
    * Constructor for the LtpaToken object
    *
    * @param token
    * Description of the Parameter
    */
    public LtpaToken(String token) {
    init();
    ltpaToken = token;
    rawToken = Base64.decode(token);
    user = new byte[(rawToken.length) - 40];
    for (int i = 0; i < 4; i++) {
    header[i] = rawToken[i];
    }
    for (int i = 4; i < 12; i++) {
    creation[i - 4] = rawToken[i];
    }
    for (int i = 12; i < 20; i++) {
    expires[i - 12] = rawToken[i];
    }
    for (int i = 20; i < (rawToken.length - 20); i++) {
    user[i - 20] = rawToken[i];
    }
    for (int i = (rawToken.length - 20); i < rawToken.length; i++) {
    digest[i - (rawToken.length - 20)] = rawToken[i];
    }
    creationDate = new Date(Long.parseLong(new String(creation), 16) * 1000);
    expiresDate = new Date(Long.parseLong(new String(expires), 16) * 1000);
    } /**
    * Constructor for the LtpaToken object
    */
    private LtpaToken() {
    init();
    } /**
    * Gets the creationDate attribute of the LtpaToken object
    *
    * @return The creationDate value
    */
    public Date getCreationDate() {
    return creationDate;
    } /**
    * Gets the expiresDate attribute of the LtpaToken object
    *
    * @return The expiresDate value
    */
    public Date getExpiresDate() {
    return expiresDate;
    } /**
    * Gets the user attribute of the LtpaToken object
    *
    * @return The user value
    */
    public String getCanonicalUser() {
    return new String(user);
    } public String getUser(String prefix, String suffix) {
    String userName = new String(user);
    if (prefix !=null && !prefix.equals("")) {
    userName = userName.substring(userName.indexOf(prefix) + prefix.length());
    }
    if (suffix ==null || suffix.equals("")) {
    suffix = "/";
    }
    return userName.substring(0, userName.indexOf("/"));
    } public String getUser() {
    return new String(user);
    } /**
    * Validates the SHA-1 digest of the token with the Domino secret key.
    *
    * @return Returns true if valid.
    */
    public boolean isValid(LtpaTokenConfig config) {
    boolean validDigest = false;
    boolean validDateRange = false;
    byte[] newDigest;
    byte[] bytes = null;
    Date now = new Date(); MessageDigest md = getDigest(); bytes = concatenate(bytes, header); bytes = concatenate(bytes, creation); bytes = concatenate(bytes, expires); bytes = concatenate(bytes, user); bytes = concatenate(bytes, Base64.decode(config.getDominoSecret())); newDigest = md.digest(bytes); validDigest = MessageDigest.isEqual(digest, newDigest); validDateRange = now.after(creationDate) && now.before(expiresDate); return validDigest & validDateRange;
    } /**
    * String representation of LtpaToken object.
    *
    * @return Returns token String suitable for cookie value.
    */
    public String toString() {
    return ltpaToken;
    } /**
    * Creates a new SHA-1 <code>MessageDigest</code> instance.
    *
    * @return The instance.
    */
    private MessageDigest getDigest() {
    try {
    return MessageDigest.getInstance("SHA-1");
    } catch (NoSuchAlgorithmException nsae) {
    nsae.printStackTrace();
    }
    return null;
    } /**
    * Description of the Method
    */
    private void init() { creation = new byte[8];
    digest = new byte[20];
    expires = new byte[8];
    hash = new byte[20];
    header = new byte[4]; } /**
    * Validates the SHA-1 digest of the token with the Domino secret key.
    *
    * @param ltpaToken
    * Description of the Parameter
    * @return The valid value
    */
    public static boolean isValid(String ltpaToken,LtpaTokenConfig config) {
    LtpaToken ltpa = new LtpaToken(ltpaToken);
    return ltpa.isValid(config);
    } /**
    * Generates a new LtpaToken with given parameters.
    *
    * @param canonicalUser
    * User name in canonical form. e.g. 'CN=Robert Kelly/OU=MIS/O=EBIMED'.
    * @param tokenCreation
    * Token creation date.
    * @param tokenExpires
    * Token expiration date.
    * @return The generated token.
    */
    public static LtpaToken generate(String canonicalUser, Date tokenCreation, Date tokenExpires,String secret) {
    LtpaToken ltpa = new LtpaToken();
    System.out.println("Generating token for " + canonicalUser);
    Calendar calendar = Calendar.getInstance();
    MessageDigest md = ltpa.getDigest();
    ltpa.header = new byte[] { 0, 1, 2, 3 };
    byte[] token = null;
    calendar.setTime(tokenCreation);
    ltpa.creation = Long.toHexString(calendar.getTimeInMillis() / 1000).toUpperCase().getBytes();
    calendar.setTime(tokenExpires);
    ltpa.expires = Long.toHexString(calendar.getTimeInMillis() / 1000).toUpperCase().getBytes();
    //try {
    // canonicalUser = new String(canonicalUser.getBytes(), "GB2312");
    //} catch (UnsupportedEncodingException e) {
    // TODO 自己主动生成 catch 块
    // e.printStackTrace();
    //}
    ltpa.user = canonicalUser.getBytes();
    //ltpa.user = canonicalUser.getBytes(Charset.forName("GB18030")); token = concatenate(token, ltpa.header);
    token = concatenate(token, ltpa.creation);
    token = concatenate(token, ltpa.expires);
    token = concatenate(token, ltpa.user);
    md.update(token);
    ltpa.digest = md.digest(Base64.decode(secret));
    token = concatenate(token, ltpa.digest); return new LtpaToken(new String(Base64.encodeBytes(token,Base64.DONT_BREAK_LINES)));
    } /**
    * Helper method to concatenate a byte array.
    *
    * @param a
    * Byte array a.
    * @param b
    * Byte array b.
    * @return a + b.
    */
    private static byte[] concatenate(byte[] a, byte[] b) {
    if (a == null) {
    return b;
    } else {
    byte[] bytes = new byte[a.length + b.length]; System.arraycopy(a, 0, bytes, 0, a.length);
    System.arraycopy(b, 0, bytes, a.length, b.length);
    return bytes;
    }
    } public String getLtpaToken() {
    return ltpaToken;
    } public void setLtpaToken(String ltpaToken) {
    this.ltpaToken = ltpaToken;
    }
    }

  • js代码

    function fnSSO(){
    if(document.getElementById("username").value==""){
    alert("请输入登录名!");
    document.getElementById("username").focus();
    return false;
    }
    var objHTTP= new ActiveXObject("Microsoft.XMLHTTP");
    var sDbPath = document.getElementById("DbFilePath").value;
    var sPara = document.getElementById("username").value;
    var vurl = "/"+sDbPath+"/"+"ajaxSSO" + "? openagent&sPara=" + sPara;
    objHTTP.open("GET", vurl, false, "", "");
    objHTTP.setRequestHeader("If-Modified-Since","0");
    objHTTP.send(false);
    var getOptions = objHTTP.responseText;
    getOptions = getOptions.replace(/\n/ig,"");
    var oOptions = eval("(" + getOptions + ")");
    var sReturn = "";
    if(oOptions && oOptions.oResult=="true"){
    var Days = 30;
    var exp = new Date();
    exp.setTime(exp.getTime() + Days*24*60*60*1000);
    var token = oOptions.token;
    if(token!=""){
    // 创建单点cookie
    document.cookie = "LtpaToken="+ token + ";expires=" + exp.toGMTString() + ";path=/;domain=.xxx.com";
    }
    sReturn = sPara + ":单点登录成功!"
    }else{
    sReturn = sPara + ":单点失败。"
    } document.getElementById("ssoinfo").innerHTML = "<font color='red'>" + sReturn + "</font>";
    // 页面跳转
    location.href = "http://xxx.com/xxx.nsf/xxx? openform";
    }

  • 【实现效果】 

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvR2F2aWQwMTI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

其它系统与domino系统单点登录的实现方式的更多相关文章

  1. B/S系统间跨域单点登录设计思路

    基于B/S系统间单点登录 此处说的单点登录的概念,即不同系统公用一个登录界面.一处系统通过登录验证,在接入的各系统均为登录状态.一般有两种情景: 1)  一级域名相同 例如:tieba.baidu.c ...

  2. 系统的讲解 - SSO单点登录

    目录 概念 好处 技术实现 小结 扩展 概念 SSO 英文全称 Single Sign On,单点登录. 在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统. 比如:淘宝网(www.t ...

  3. 单点登录系统(SSO)的开发思路

    单点登录并不是一个新鲜的玩意儿,比较官方的解释是企业业务整合的解决方案之一,通俗来讲SSO就是一个通用的用户中心,国内比较流行的UCenter就是一套单点登录解决方案.而近期以CSDN明文存储用户密码 ...

  4. 单点登录系统CAS筹建及取得更多用户信息的实现

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  5. 多系统实现单点登录方案:SSO 单点登录

    一.什么是单点登录SSO(Single Sign-On) SSO是一种统一认证和授权机制,指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后,再访问其他应用 ...

  6. 单点登录系统实现基于SpringBoot

    今天的干货有点湿,里面夹杂着我的泪水.可能也只有代码才能让我暂时的平静.通过本章内容你将学到单点登录系统和传统登录系统的区别,单点登录系统设计思路,Spring4 Java配置方式整合HttpClie ...

  7. 多平台的网站实现单点登录系统(SSO)的开发思路 让你的会员中心更加统一(参考资料)

    单点登录并不是一个新鲜的玩意儿,比较官方的解释是企业业务整合的解决方案之一,通俗来讲SSO就是一个通用的用户中心,国内比较流行的UCenter就是一套单点登录解决方案.而近期以CSDN明文存储用户密码 ...

  8. 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第十天】(单点登录系统实现)

    https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 ...

  9. SpringCloud微服务实战——搭建企业级开发框架(四十):使用Spring Security OAuth2实现单点登录(SSO)系统

    一.单点登录SSO介绍   目前每家企业或者平台都存在不止一套系统,由于历史原因每套系统采购于不同厂商,所以系统间都是相互独立的,都有自己的用户鉴权认证体系,当用户进行登录系统时,不得不记住每套系统的 ...

随机推荐

  1. 常见的web负载均衡方法总结

    Web负载均衡的方法有很多,下面介绍几种常见的负载均衡方法. 1.用户手动选择方法 这是一种较为古老的方式.通过在主站首页入口提供不同线路.不同服务器连接的方式,来实现负载均衡.这种方式在一些提供下载 ...

  2. git的全局变量

    git的全局变量可以用在命令行设置: git config --global user.name "litifeng" git config --global user.email ...

  3. Eclipse最新版注释模板设置详解

    /** * HassCMS (http://www.hassium.org/) * * @link http://github.com/hasscms for the canonical source ...

  4. 【转】Hive优化总结

    优化时,把hive sql当做map reduce程序来读,会有意想不到的惊喜. 理解Hadoop的核心能力,是hive优化的根本.这是这一年来,项目组所有成员宝贵的经验总结.   长期观察hadoo ...

  5. PLSQL连接本机oracle 11g 64 数据库的步骤

    1.登录PL/SQL Developer 这里省略Oracle数据库和PL/SQL Developer的安装步骤,注意在安装PL/SQL Developer软件时,不要安装在Program Files ...

  6. python字符串转换成变量的几种方法

    个人比较喜欢用第三种方法 var = "This is a string" varName = 'var' s= locals()[varName] s2=vars()[varNa ...

  7. 【Java】Collection与Map接口总结

    Collection     -----List                -----LinkedList    非同步                 ----ArrayList      非同 ...

  8. java timer timertask mark

    其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了run方法的一个类,而具体的TimerTask需要由你自己来实现,例如这样: 1 2 3 4 5 6 Timer timer = ...

  9. python2.7执行shell命令

    python学习——python中执行shell命令 2013-10-21 17:44:33 标签:python shell命令 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者 ...

  10. [转]SQL Server 「逾时过期」的处理方式

    基本上 SQL Server 只要在处理大量数据的指令,如 INSERT INTO A SELECT * FROM B 在数据量很大的时候,很容易发生 Timeout ,也就是常见的「逾期过时」错误. ...