AD密码与Lotus密码实现同步

AD密码与Lotus密码实现同步

我们主要通过.net编写的程序来实现用户通过web方式更改密码及重置密码,之前是通过在线传输的方式来实现,AD密码与Domino同步,但是我们发现使用后有很多bug,比如+、&特殊字符传输后密码失效的问题,然后还有一个就是当用户在同一时间大量修改或者重置会出现遗漏的问题,比如50个用户同时修改,会有1-2个不生效,其实不生效的原因跟服务器的性能有一定关系,为了解决该问题,我们通过另外一个方式,实现AD密码与Domino密码的同步,我们在后台中添加程序,将用户修改、重置后的信息写入到数据库下(在此我用SQL),然后Domino再通过程序从sql下提取,完成密码重置工作,然后给sql一个回执,这样就实现了AD密码到Domino密码的同步了。

clip_image002

新建SQL服务器,然后创建数据库、表即可。

数据库名称为:PassworInfor

表:PassInfo

clip_image004

表:

clip_image006

简易查询:

clip_image008

然后通过程序设置,将用户在传输过程中的数据,写入到SQL数据库下

clip_image010

Passinfo
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
namespace ChangePassword.Models.Mapping
{
public class PassInfoMap : EntityTypeConfiguration<PassInfo>
{
public PassInfoMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.Username)
.HasMaxLength(50);
this.Property(t => t.Password)
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("PassInfo");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.Username).HasColumnName("Username");
this.Property(t => t.Password).HasColumnName("Password");
this.Property(t => t.DateTime).HasColumnName("DateTime");
this.Property(t => t.Statue).HasColumnName("Statue");
}
}
}

clip_image012

using System;
using System.Collections.Generic;
namespace ChangePassword.Models
{
public partial class PassInfo
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public Nullable<System.DateTime> DateTime { get; set; }
public Nullable<int> Statue { get; set; }
}
}

clip_image014

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using ChangePassword.Models.Mapping;
namespace ChangePassword.Models
{
public partial class PasswordInfoContext : DbContext
{
static PasswordInfoContext()
{
Database.SetInitializer<PasswordInfoContext>(null);
}
public PasswordInfoContext()
: base("Name=PasswordInfoContext")
{
}
public DbSet<PassInfo> PassInfoes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new PassInfoMap());
}
}
}

clip_image016

/// 重置密码
/// </summary>
public void SetPassword()
{
string Rs = "";
string sItCode = (string)Session["VerIDcode"];
Session.Remove("VerIDcode");
string sNewPwd = Request["sNewPwd"];
{
ADOperator ao = new ADOperator();
int y = ao.IsUserExistsByAccount(sItCode);
if (y == 1)
{
string username = ConfigurationManager.AppSettings["AutoRestAdminUser"].ToString(); ;
string password = ConfigurationManager.AppSettings["AutoRestAdminPwd"].ToString(); ;
DirectoryEntry de = ADOperator.GetDirectoryObject(username, password);
//(DirectoryEntry)Session["admin"];
int z = ao.SetPasswordByAccount(de, sItCode, sNewPwd);
if (z == 1)
{
try
{
PassInfo passInfo = new PassInfo();
passInfo.Password = sNewPwd;
passInfo.Statue = 0;
passInfo.Username = sItCode;
passInfo.DateTime = DateTime.Now;
psContext.PassInfoes.Add(passInfo);
psContext.SaveChanges();
}
catch (Exception ex)
{
//处理 数据库错误
}
Rs = "CS";
//调用Domino密码修改
changeDominoPwd(sItCode, sNewPwd);
HttpContext.Cache.Remove(sItCode + "_PrivateEmail");
HttpContext.Cache.Remove(sItCode + "_code");
HttpContext.Cache.Remove(sItCode + "_reset_uid");
HttpContext.Cache.Remove(sItCode + "_reset_uname");
optionLog log = new optionLog();
log.idCode = sItCode;
log.opDateTime = DateTime.Now;
log.opType = "密码重置";
log.opUser = username;
dbContext.optionLogs.Add(log);
dbContext.SaveChanges();
}
else
{
Rs = "FA";
}
}
else
{
Rs = "NU";
}
}
Response.Write(Rs.ToString());
}
#endregion
/// <summary>
/// 验证用户是否登录
/// </summary>
/// <returns></returns>
private bool VerifyIfSignedIn(string itcode)
{
if (itcode == null)
{
return false;
}
string ipAddress = this.GetIPAddress();
isValidate isValidateReq = new isValidate(new isValidateBody(itcode, ipAddress));
var isValidateResponse = soaService.isValidate(isValidateReq);
if (isValidateResponse.Body.isValidateResult)
{
System.Web.HttpContext.Current.Session["itcode"] = itcode;
}
return isValidateResponse.Body.isValidateResult;
}
//服务器获取用户IP
private string GetIPAddress()
{
string user_IP = string.Empty;
if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
{
if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
{
user_IP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
}
else
{
user_IP = System.Web.HttpContext.Current.Request.UserHostAddress;
}
}
else
{
user_IP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"].ToString();
}
return user_IP;
}
// MD5 加密中文
public static string GetMD5(string str)
{
byte[] b = System.Text.Encoding.Default.GetBytes(str);
b = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(b);
string ret = "";
for (int i = 0; i < b.Length; i++)
{
ret += b[i].ToString("x").PadLeft(2, '0');
}
return ret;
}
public JsonResult CheckValidateCode(string idCode,string userNumber,string validateCode)
{
string tempValidateCode = (string)Session["ValidateCode"];
if (validateCode == tempValidateCode)
{
}

clip_image018

add name="PasswordInfoContext" connectionString="Data Source=10.1.1.88;Initial Catalog=PasswordInfo;Persist Security Info=True;User ID=sa;Password=password;MultipleActiveResultSets=True"
      providerName="System.Data.SqlClient" />

clip_image020

接下来准备domino配置环境

新建空的数据库resetpw.nsf,然后我们用来跑试图及代理程序

首先是创建代理:我们需要创建4个代理,分别为:agtOenDataSource、agtSaveDataSource、resetpw、获取用户次数代理

首先是AgtOpenDatasource

%REM
Agent agtOpenDataSource
Created 2014-5-13 by admin/digioa
Description: Comments for Agent
%END REM
OptionPublic
OptionDeclare
Sub Initialize
Dim session AsNew NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
OnErrorGoTo err_line
Set note = session.Documentcontext
Set view = db.Getview("vwDataSource")
Set doc = view.Getfirstdocument()
IfNot doc IsNothingThen
note.strServerIP = doc.strServerIP(0)
note.strUserName = doc.strUserName(0)
note.strPassWord = doc.strPassWord(0)
note.strDataSource = doc.strDataSource(0)
note.strKeyCol = doc.strKeyCol(0)
EndIf
ExitSub
err_line:
MsgBox"agtOpenDataSource Initialize error :"+Error+" at line:"+CStr(Erl)
EndSub

clip_image022

agtSaveDataSource

%REM
Agent agtSaveDataSource
Created 2014-5-13 by admin/digioa
Description: Comments for Agent
%END REM
OptionPublic
OptionDeclare
Sub Initialize
Dim session AsNew NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim note As NotesDocument
OnErrorGoTo err_line
Set note = session.Documentcontext
Set doc = view.Getfirstdocument()
IfNot doc IsNothingThen
doc.strServerIP = note.strServerIP(0)
doc.strUserName = note.strUserName(0)
doc.strPassWord = note.strPassWord(0)
doc.strDataSource = note.strDataSource(0)
doc.strTableName = note.strTableName(0)
doc.strUserCol = note.strUserCol(0)
Call doc.save(False,False)
Else
note.Form = "frmDataSource"
Call note.save(False,False)
EndIf
Print|<script>|
Print|alert("保存成功!");|
Print|window.location.href =
ExitSub
err_line:
MsgBox"agtSaveDataSource Initialize error :"+Error+" at line:"+CStr(Erl)
EndSub

clip_image024

获取用户次数代理

%REM
Agent 修改用户名密码
Created 2013-12-15 by administrator/iiosoft
Description: Comments for Agent
%END REM
OptionPublic
OptionDeclare
Dim session As NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim view As NotesView
Dim strhtml AsString
Sub Initialize
OnErrorGoTo err_handle
Dim i AsInteger
Dim tmp AsInteger
Set session = New NotesSession
Set db = session.Currentdatabase
Set doc = session.Documentcontext
Set view = db.Getview("ListByPsnView")
Set olddoc = view.Getfirstdocument()
WhileNot namesdoc IsNothing
tmp = 0
arr = namesdoc.Getitemvalue("ShortName")
For i = 0ToUBound(arr)
tmp = tmp + dc.Count
EndIf
Next
strhtml = strhtml
Set namesdoc = namesview.Getnextdocument(namesdoc)
Wend
strhtml = |<table><tr><td>用户名</td><td>次数</td></tr>|+strhtml+|</table>|
Call doc.Replaceitemvalue("RTFTable", strhtml)
ExitSub
err_handle:
MsgBox session.Currentdatabase.Filepath + session.Currentagent.name
MsgBoxError
MsgBoxErl
EndSub

clip_image026

接下来是resetpwd,我们定义是java类

clip_image028

首先是SQLServer08.java

import java.sql.Connection;
import java.sql.DriverManager;
public class SQLServer08 {
private static final String MYDBCN="com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static SQLServer08 dbcn=null;
Connection conn=null;
private SQLServer08(){
try {
Class.forName(this.MYDBCN);
}
public static SQLServer08 getSqlDBCN(){
if(dbcn==null)
dbcn=new SQLServer08();
return dbcn;
String SQLUSER = user;
String SQLPASSWORD = password;
conn=DriverManager.getConnection(SQLURL,SQLUSER,SQLPASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}

第二个是javaagent

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import lotus.domino.*;
public static String sqltable = "";
public static String sqlusercol = "";
public static String sqlpwcol = "";
public static String sqltimecol = "";
public static String sqlkeycol = "";
public static String resetString = "密码已重置";
public void NotesMain() {
Document doclog = null;
Name nm = null;
String userinfo = "";
String uname = "";
try {
Session session = getSession();
dbname = session.getDatabase("","names.nsf");
if(dbname != null){
vw1 = dbname.getView("($VIMPeople)"); //按层次名称,如:dev01/local
userinfo = GetUserAndPW();
if(!"".equals(userinfo)){
String[] arrinfo = userinfo.split("\\(###\\)");
boolean resetflag = false;
boolean updsqlflag = false;
boolean logflag = false;
uname = user[0];
if(uname.indexOf("/")!=-1){
docname = vw1.getDocumentByKey(uname,true);
}else{
docname = vw2.getDocumentByKey(uname,true);
}
if(docname!=null){
resetflag = resetUserpw(session,docname,user[1]);
if(resetflag){
updsqlflag = updSqlState(user[3]);
if(updsqlflag){
logflag =
System.out.println("用户["+uname+"]重置密码操作失败!");
}
}else{
System.out.println("重置密码:names库中未找到用户["+uname+"]的文档");
}
}
}
}
}else{
System.out.println("重置密码失败:SQL数据库配置不完整,请检查配置!");
}
}else{
System.out.println("重置用户密码失败:无法获取/打开names库");
}
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
if(dbname != null){
dbname.recycle();
}
if(vw1 != null){
vw1.recycle();
}
if(vw2 != null){
vw2.recycle();
}
if(docname != null){
docname.recycle();
}
if(nm != null){
nm.recycle()
}
if(doclog != null){
doclog.recycle();
}
} catch(Exception e) {
System.out.println(e);
}
}
}
//获取SQL数据库配置
public boolean GetDataSourceConfig(Document docConfig){
boolean gflag = false;
if(docConfig!=null){
try {
sqlserver = docConfig.getItemValueString("strServerIP")
sqlpassword = docConfig.getItemValueString("strPassWord");
sqldatabase = docConfig.getItemValueString("strDataSource");
sqltable = docConfig.getItemValueString("strTableName");
if("".equals(sqlserver) || "".equals(sqluser)
|| "".equals(sqlpassword) || "".equals(sqldatabase) || "".equals(sqltable)
|| "".equals(sqlusercol) || "".equals(sqlpwcol) ||
gflag = false;
}else{
gflag = true;
}
} catch (NotesException e) {
}
}
return gflag;
}
//连接SQL Server2008获取用户名、密码及时间
public String GetUserAndPW(){
String userinfo = "";
String sql = "select * from "+sqltable+" where "+sqlpwcol+"!=?";
Connection cn=null;
PreparedStatement pst=null;
ResultSet rs=null;
try{
cn=DBCNfactory.getSqlDBCN().getConnection(sqlserver,sqldatabase,sqluser,sqlpassword);
if("".equals(userinfo)){
userinfo =
}else{
userinfo = userinfo+rowsp+rs.getString(sqlusercol)+colsp+rs.getString(sqlpwcol)+colsp+rs.getString(sqltimecol)+colsp+rs.getString(sqlkeycol);
}
}
}catch(Exception e){
System.out.println(e);
}
return userinfo;
}
//重置密码
public boolean resetUserpw(Session session,Document docname,String pw){
boolean oflag = false;
if(docname!=null){
String reset = "@Password('"+pw+"')";
try {
docname.replaceItemValue("HTTPPassword",session.evaluate(reset));
docname.computeWithForm(false, false);
docname.save(true,true);
oflag = true;
} catch (Exception e) {
System.out.println(e);
}
}
return oflag;
}
//将用户密码标识为已重置
public boolean updSqlState(String uid){
boolean oflag = false;
try{
Connection cn=DBCNfactory.getSqlDBCN().getConnection(sqlserver,sqldatabase,sqluser,sqlpassword);
String sql="update "+sqltable+" set "+sqlpwcol+"=? where "+sqlkeycol+"=?";
PreparedStatement pst=cn.prepareStatement(sql)
oflag = true;
}catch(Exception e){
e.printStackTrace();
}
return oflag;
}
//记录日志
public boolean recordLog(Database db,Document doc,String un,String pw,String stime){
boolean oflag = false;
try {
doc = db.createDocument();
doc.replaceItemValue("Form","internetpwd");
doc.replaceItemValue("UserName",un);
doc.replaceItemValue("UserPassword",pw);
doc.replaceItemValue("Time",stime);
doc.save(true,true);
oflag = true;
} catch (NotesException e) {
System.out.println(e);
}
return oflag;
}
}

设置完后,我们将resetpwd代理程序定义计划任务:

clip_image030

接下来我们创建表单:

Internetpwd:

<div style="display:none">
当前登录人:
</div>
<h1>邮箱密码重置系统<h1>
<table border="1" cellspacing="0">
<tr>
<td>用户名:</td>
<td></td>
</tr>
<tr>
<td>新密码:</td>
<td></td>
</tr>
<tr>
<td colspan="2">
</td>
</tr>
</table>

clip_image032

SQP数据库配置:

<div style="display:none">
</div>
<table>
<tr>
<td>服务器IP:</td>
<td></td>
</tr>
<tr>
<td>登录名:</td>
<td></td>
</tr>
<tr>
<td>密码:</td>
<td></td>
</tr>
<tr>
<td>数据库名:</td>
<td></td>
</tr>
<tr>
<td>表名:</td>
<td></td>
</tr>
<tr>
<td>用户名列:</td>
<td></td>
</tr>
<tr>
<td>密码列:</td>
<td></td>
</tr>
<tr>
<td>时间列:</td>
<td></td>
</tr>
<tr>
<td>关键字列:</td>
<td></td>
</tr>
<tr>
<td colspan="2">
<input type="button" value="保存" onclick="mysubmit();"/>
</td>
</tr>
</table>

clip_image034

clip_image036

接下来我们配置相关的显示试图:因为我要记录、统计用户修改密码的信息

SQL数据库配置试图

clip_image038

Listview试图

clip_image040

用户修改密码次数统计

clip_image042

创建完,访问效果为:

clip_image044

接下来我们部署配置文档:

1.从Web端打开SQL数据源配置文档,输入如下地址:

http://iio-mail01.iiosoft.com/resetpw.nsf/frmDataSource?openform

2.根据页面提示,填写SQL相关信息(字段均需填写),保存即可。

字段说明:

服务器IP:SQL Server2008 服务器IP地址

登录名:SQL Server2008数据库登录帐户名

密码:SQL Server2008数据库登录帐户的密码

数据库名:SQL Server2008数据库名

表名:SQL Server2008数据库存储用户及密码相关信息的表名

用户名列:表中存储用户名的列名

密码列:表中存储用户密码的列名

时间列:表中存储用户重置密码的时间列名

关键字列:表的关键字列名(标识列id)

clip_image046

接着我们将sqljdbc4.jar包部署至domino安装目录下,路径:Lotus\Domino\jvm\lib\ext

注:配置完后,我们需要重启domino程序,不然不生效。

首先我的AD、domino内分别注册username=user01的用户,第一次我们闲将密码重置为:123456,然后我们将密码修改为123123abc,看看domino的密码是否能同步:

clip_image048

接下来我们查看SQL下的日志

clip_image050

接下来就差domino运行代理了,运行代理后,domino下的user01的密码被重置为:123123abc后,数据库的密码列将标记为已重置。我们有两种方式让代理快速运行:

1:运行该链接http://iio-mail01.iiosoft.com/resetpw.nsf/%20resetpw?openAgent

clip_image052

2.在控制台敲打命令,其实命令跟url的一样

Tell amgr run “resetpw.nsf” ‘resetpw?apenAgent’

代理生效后,我们查看SQL下的密码状态:明文的密码已经标记其他字符

clip_image054

接着我们查看domino的试图记录log,然后user01是否有更改密码的记录

clip_image056

最后我们就得真实测试user01的密码是否正确了。

clip_image058

测试完全正常,最后我们发现SQL数据库配置试图,可以看见敏感信息,密码:我们可以见该列隐藏,这样就不降低危险性了。

clip_image060

我们来隐藏该列:

clip_image062

设置隐藏即可:应藏后,我们通过desinger.nsf还是可以看见的。

clip_image064

我们在通过notes客户端打开查看。我们发现密码那一项没了。

clip_image066

注:附件中的源代码下载后需要将扩展名更改为.7z格式然后解压即可使用。

你可能感兴趣的:(Lotus,ad)