其它系统与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. Matlab图形调色

    Matlab图形调色 Simple example var colormap = require('colormap') options = {   colormap: 'jet',   // pic ...

  2. spine 2.1.27 Pro 叠加方式(Blending)

    将spine更新到2.1.27 Pro,发现有更多的叠加方式可用了,如图: 以前则只有Normal和Additive可选. 更多的叠加方式对于用spine做特效动画还是比较有用的.不过我还没试这些叠加 ...

  3. INFINITY的一个坑

    float a=INFINITY; if(a==INFINITY){ cout<<"a is inf"<<endl; }else{ cout<< ...

  4. Oracle中查询表字段基本信息、主键、外键(整理)

    背景 因为项目某些模块的数据结构设计没有严格按照某规范设计,所以只能从数据库中查询数据结构,需要查询的信息如下:字段名称.数据类型.是否为空.默认值.主键.外键等等. 在网上搜索了查询上述信息的方法, ...

  5. paip.中文 分词 ---paoding 3.1 的使用

    paip.中文 分词 ---paoding 3.1 的使用 paoding 3.1 下载: 1 设置字典路径 1 测试代码 1 作者Attilax  艾龙,  EMAIL:1466519819@qq. ...

  6. tornado日志使用详解

    1.需求 将http访问记录,程序自定义日志输出到文件,按天分割,保留最近30天的日志. 2.使用示例 init_logging("%s/QYK.%s.%s.log" % (log ...

  7. ny788 又见Alice and Bob

    又见Alice and Bob 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 集训生活如此乏味,于是Alice和Bob发明了一个新游戏.规则如下:首先,他们得到一个 ...

  8. Linux下安装Python3.6和第三方库

    如果本机安装了python2,尽量不要管他,使用python3运行python脚本就好,因为可能有程序依赖目前的python2环境, 比如yum!!!!! 不要动现有的python2环境! 一.安装p ...

  9. Frosh Week

    Problem Description During Frosh Week, students play various fun games to get to know each other and ...

  10. SQL Injection绕过技巧

    0x00 sql注入的原因 sql注入的原因,表面上说是因为 拼接字符串,构成sql语句,没有使用 sql语句预编译,绑定变量. 但是更深层次的原因是,将用户输入的字符串,当成了 "sql语 ...