2017年9月

首页2017年9月
29
Sep
0

在python3上实现微软域帐号ldap登陆认证

有任务要实现域帐号认证,分别试用了ldap,python-ldap包后发现都是基于python2的
在python3上试用基本全部失败,ldap网上和官方代码基本跑不了
python-ldap包直接只支持python2安装不上,在改了部分代码后放弃
主要是在win下修改代码,边改边跑这两个包,N多努力后,偶然看见电脑里有ldap3这样一个控件包
并非主动安装,而是在python-ldap包时发现它引用的ldap包,顺腾摸瓜准备改代码时发现的

然后利用ldap3包如愿实现了所需要的功能,过程略折腾,因为网上的代码要么跑不动,要么有些在win下看似可以,实则不行
造成误会, 下面的代码在centos7.2 和python3.6下测试通过
接下来上代码:

from ldap3 import Server, Connection, ALL, NTLM
LDAP_URI = '10.86.87.52'
LDAP_USER = 'geely\\Huang.Xiaogang'  #域和用户之间必须是双斜划线
LDAP_PASS = 'xxx'
BASE_DN = 'OU=GeelyStaff,dc=geely,dc=auto'

1.验证登陆 成功True 反之

server = Server(LDAP_URI, get_info=ALL)
conn = Connection(server, user=LDAP_USER, password=LDAP_PASS, authentication= NTLM)
print(conn.bind())

2.返回基本信息

print(conn.extend.standard.who_am_i())
u:GEELY\Huang.XiaoGang

3.ssl登陆

server = Server('ipa.demo1.freeipa.org', use_ssl=True, get_info=ALL)
conn = Connection(server, 'uid=admin, cn=users, cn=accounts, dc=demo1, dc=freeipa, dc=org', 'Secret123', auto_bind=True)

4.ssl第二种方法

from ldap3 import Server, Connection, Tls
import ssl
tls_configuration = Tls(validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1)
server = Server('ipa.demo1.freeipa.org', use_ssl=True, tls=tls_configuration)
conn = Connection(server)
conn.open()

5.搜索用户

from ldap3 import Server, Connection, ALL
server = Server('ipa.demo1.freeipa.org', get_info=ALL)
conn = Connection(server, 'uid=admin, cn=users, cn=accounts, dc=demo1, dc=freeipa, dc=org', 'Secret123', auto_bind=True)
conn.search('dc=demo1, dc=freeipa, dc=org', '(objectclass=person)')
conn.entries #array

6.检查密码

def check_user(username,password):
    '''
    connection to LDAP and check whether user exists
    return str and '' means password correct, otherwise it means error message
    '''
    _connection.search('ou=users,'+_baseDN,'(&(uid='+username+')(objectclass=person))',attributes=['uid','userPassword'])
    if hasattr(_connection,'entries'):
        ens=_connection.entries
        if len(ens)==1:
            pwd=str(ens[0]['userPassword'])
            if _checkPassword(pwd,password):
                return ''
            else:
                return 'password not correct'
        elif len(ens)>1:
            return 'too many users'
    return 'user not found'


def _makeSecret(password):
    salt = os.urandom(4)
    h = hashlib.sha1(password)
    h.update(salt)
    return "{SSHA}" + encode(h.digest() + salt)

def _checkPassword(challenge_password, password):
    challenge_bytes = decode(challenge_password[6:])
    digest = challenge_bytes[:20]
    salt = challenge_bytes[20:]
    hr = hashlib.sha1(password)
    hr.update(salt)
    return digest == hr.digest()
'''
challenge_password = _makeSecret('testing123')
challenge_password
    '{SSHA}0c0blFTXXNuAMHECS4uxrj3ZieMoWImr'
_checkPassword(challenge_password, 'testing123')
    True
_checkPassword(challenge_password, 'testing124')
    False
'''
28
Sep
0

遍历文件夹及子目录

简单遍历一个文件夹内容

function GetDirectorys(dir: string): TStringList;
var
  SearchRec: TSearchRec;
  i:integer;
  sl:TStringList;
begin
  sl := TStringList.Create;
  if not DirectoryExists(dir) then
    Exit(sl);
  i := FindFirst(dir + '*.*', faDirectory, SearchRec);
  while i = 0 do
  begin
    if (SearchRec.Name<>'.') and (SearchRec.Name<>'..') and (SearchRec.Attr = faDirectory) then
      sl.Add(SearchRec.Name);
    i := FindNext(SearchRec)
  end;
  FindClose(SearchRec);
  Result := sl;
end;

递归

function MakeFileList(Path,FileExt:string):TStringList ;
var
sch:TSearchrec;
begin
Result:=TStringlist.Create;
if rightStr(trim(Path), 1) <> '\' then
    Path := trim(Path) + '\'
else
    Path := trim(Path);
if not DirectoryExists(Path) then
begin
    Result.Clear;
    exit;
end;
if FindFirst(Path + '*', faAnyfile, sch) = 0 then
begin
    repeat
       Application.ProcessMessages;
       if ((sch.Name = '.') or (sch.Name = '..')) then Continue;
       if DirectoryExists(Path+sch.Name) then   // 这个地方加上一个判断,可以区别子文件夹河当前文件夹的操作
       begin
         Result.AddStrings(MakeFileList(Path+sch.Name,FileExt));
       end
       else
       begin
         if (UpperCase(extractfileext(Path+sch.Name)) = UpperCase(FileExt)) or (FileExt='.*') then
         Result.Add(Path+sch.Name);
       end;
    until FindNext(sch) <> 0;
    SysUtils.FindClose(sch);
end;
end;

加入递归 所有子目录遍历

procedure EnumFileInQueue(path: PChar; fileExt: string; fileList: TStringList);  
var 
   searchRec: TSearchRec;  
   found: Integer;  
   tmpStr: string;  
   curDir: string;  
   dirs: TQueue;  
   pszDir: PChar;  
begin 
   dirs := TQueue.Create; //创建目录队列  
   dirs.Push(path); //将起始搜索路径入队  
   pszDir := dirs.Pop;  
   curDir := StrPas(pszDir); //出队  
   {开始遍历,直至队列为空(即没有目录需要遍历)} 
   while (True) do 
   begin 
      //加上搜索后缀,得到类似'c:\*.*' 、'c:\windows\*.*'的搜索路径  
      tmpStr := curDir + '\*.*';  
      //在当前目录查找第一个文件、子目录  
      found := FindFirst(tmpStr, faAnyFile, searchRec);  
      while found = 0 do //找到了一个文件或目录后  
      begin 
          //如果找到的是个目录  
         if (searchRec.Attr and faDirectory) <> 0 then 
         begin 
          {在搜索非根目录(C:\、D:\)下的子目录时会出现'.','..'的"虚拟目录" 
          大概是表示上层目录和下层目录吧。。。要过滤掉才可以} 
            if (searchRec.Name <> '.') and (searchRec.Name <> '..') then 
            begin 
               {由于查找到的子目录只有个目录名,所以要添上上层目录的路径 
                searchRec.Name = 'Windows'; 
                tmpStr:='c:\Windows'; 
                加个断点就一清二楚了 
               } 
               tmpStr := curDir + '\' + searchRec.Name;  
               {将搜索到的目录入队。让它先晾着。 
                因为TQueue里面的数据只能是指针,所以要把string转换为PChar 
                同时使用StrNew函数重新申请一个空间存入数据,否则会使已经进 
                入队列的指针指向不存在或不正确的数据(tmpStr是局部变量)。} 
               dirs.Push(StrNew(PChar(tmpStr)));  
            end;  
         end 
         else //如果找到的是个文件  
         begin 
             {Result记录着搜索到的文件数。可是我是用CreateThread创建线程 
              来调用函数的,不知道怎么得到这个返回值。。。我不想用全局变量} 
            //把找到的文件加到Memo控件  
            if fileExt = '.*' then 
               fileList.Add(curDir + '\' + searchRec.Name)  
            else 
            begin 
               if SameText(RightStr(curDir + '\' + searchRec.Name, Length(fileExt)), fileExt) then 
                  fileList.Add(curDir + '\' + searchRec.Name);  
            end;  
         end;  
          //查找下一个文件或目录  
         found := FindNext(searchRec);  
      end;  
      {当前目录找到后,如果队列中没有数据,则表示全部找到了; 
        否则就是还有子目录未查找,取一个出来继续查找。} 
      if dirs.Count > 0 then 
      begin 
         pszDir := dirs.Pop;  
         curDir := StrPas(pszDir);  
         StrDispose(pszDir);  
      end 
      else 
         break;  
   end;  
   //释放资源  
   dirs.Free;  
   FindClose(searchRec);  
end; 
27
Sep
0

压缩解压单元System.Zip

基本操作

TZipFile.ExtractZipFile()       //解压 Zip 文件到指定文件夹
TZipFile.IsValid()              //判断指定文件是否是有效的 Zip 文件
TZipFile.ZipDirectoryContents() //压缩指定路径下的所有文件

实例代码

uses System.Zip;

{ 把 C:\Temp\TestDir 下的所有文件压缩到 C:\Temp\Test.zip }
procedure TForm1.Button1Click(Sender: TObject);
begin
  TZipFile.ZipDirectoryContents('C:\Temp\Test.zip', 'C:\Temp\TestDir\'); //参数3可以指定压缩算法
end;

{ 把 C:\Temp\Test.zip 解压到 C:\Temp\TestDir2\ }
procedure TForm1.Button2Click(Sender: TObject);
begin
  TZipFile.ExtractZipFile('C:\Temp\Test.zip', 'C:\Temp\TestDir2\');
end;

使用实例化类的方式:

uses System.Zip;

{ 压缩 }
procedure TForm1.Button1Click(Sender: TObject);
var
  zip: TZipFile;
begin
  zip := TZipFile.Create;
  zip.Open('C:\Temp\001.zip', TZipMode.zmWrite); //准备要压缩为 001.zip
  zip.Add('C:\Temp\Test.txt', 'Test.txt');       //参1是要压缩的文件; 参2是要使用的文件名; 参数3可指定压缩算法
//  zip.Add...
//  zip.Close; //Close 时才执行实际压缩过程; 不过在销毁前会调用它
  zip.Free;
end;

{ 解压 }
procedure TForm1.Button2Click(Sender: TObject);
var
  zip: TZipFile;
begin
  zip := TZipFile.Create;
  zip.Open('C:\Temp\001.zip', TZipMode.zmRead);
  zip.ExtractAll('C:\Temp\002\');
  zip.Free;
end;
27
Sep
0

delphi 退出程序的方法

  1. close()
    主界面退出,会退出整个程序. 所有事件都会发生 FromClose FromCloseQuery FromDestory等

2.application.Terminate
结束整个程序,属于正常退出,会御载相应的实例,程序太复杂没有处理好的话,可能无法正常退出

3.halt(0)
强制退出程序,可以加退出码,由于不管御载,期待WINDOWS回收资源,否则内存泄露

27
Sep
0

实现程序只运行一次和打开正在运行的那个

实现程序运行一次的方法有四个:
全部都需要windows,forms单元

  1. 创建互斥对象法 关键函数如下:

    var

    hAppMutex: THandle; //声明互斥变量

    begin

    hAppMutex := CreateMutex(nil, false,’projectname’);
    if ( (hAppMutex <> 0) and (GetLastError() = ERROR_ALREADY_EXISTS)) then
    begin
    MessageBox('程序已经运行, 按确定关闭此窗口!','提示!', MB_OK);
    end

    end;
    

2.查找窗口法(查找要找的窗口,找到就运行了,反之)

Hwnd:=FindWindow(‘TForm1’,’Form1’);
If Hwnd<>0 then
begin
  MessageBox('程序已经运行, 按确定关闭此窗口!','提示!', MB_OK);
end

3.全局原子法,利用WINDOWS内建的全局原子,和互斥比较像,需要手工删除全局原子

const
  iAtom=‘application’; //可以是任意一个唯一标示该程序的原子量
begin
 if GlobalFindAtom(iAtom)=0 then
  begin
    GlobalAddAtom(iAtom); //添加全局原子
    Application.Initialize;
    Application.CreateForm(TForm1,Form1);
    Application.Run;
    GlobalDeleteAtom(GlobalFindAtom(iAtom));//删除添加的全局原子
   end
end

4.共享内存技术(创建内存映射文件,能打开则已经运行,失败则第一次运行)

const
  MapFileName = '{CAF49BBB-AF40-4FDE-8757-51D5AEB5BBBF}';
type
  //共享内存
  PShareMem = ^TShareMem;
  TShareMem = record
    AppHandle: THandle;  //保存程序的句柄
  end;
var
  hMapFile: THandle;
  PSMem: PShareMem;
procedure CreateMapFile;
begin
  hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(MapFileName));
  if hMapFile = 0 then
  begin
    hMapFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
      SizeOf(TShareMem), MapFileName);
    PSMem := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
    if PSMem = nil then
    begin
      CloseHandle(hMapFile);
      Exit;
    end;
    PSMem^.AppHandle := 0;
  end
  else begin
    PSMem := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
    if PSMem = nil then
    begin
      CloseHandle(hMapFile);
    end
  end;
end;
procedure FreeMapFile;
begin
  UnMapViewOfFile(PSMem);
  CloseHandle(hMapFile);
end;

二.打开正在执行的程序 这个和上面的第四种方法结合的完整代码吧 解决了主窗体隐藏,最小化情况下激活的问题

unit wdRunOnce;
interface
function AppHasRun(AppHandle: THandle): Boolean;
implementation
uses
  Windows, Messages;
const
  MapFileName = '{CAF49BBB-AF40-4FDE-8757-51D5AEB5BBBF}';
type
  PShareMem = ^TShareMem;
  TShareMem = record
    AppHandle: THandle;  //保存程序的句柄
  end;
var
  hMapFile: THandle;
  PSMem: PShareMem;
procedure CreateMapFile;
begin
  hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(MapFileName));
  if hMapFile = 0 then
  begin
    hMapFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
      SizeOf(TShareMem), MapFileName);
    PSMem := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
    if PSMem = nil then
    begin
      CloseHandle(hMapFile);
      Exit;
    end;
    PSMem^.AppHandle := 0;
  end
  else begin
    PSMem := MapViewOfFile(hMapFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
    if PSMem = nil then
    begin
      CloseHandle(hMapFile);
    end
  end;
end;

procedure FreeMapFile;
begin
  UnMapViewOfFile(PSMem);
  CloseHandle(hMapFile);
end;

function AppHasRun(AppHandle: THandle): Boolean;
var
  TopWindow: HWnd;
begin
  Result := False;
  if PSMem <> nil then
  begin
    if PSMem^.AppHandle <> 0 then
    begin
      SendMessage(PSMem^.AppHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
      TopWindow := GetLastActivePopup(PSMem^.AppHandle);
      if (TopWindow <> 0) and (TopWindow <> PSMem^.AppHandle) and
        IsWindowVisible(TopWindow) and IsWindowEnabled(TopWindow) then
        SetForegroundWindow(TopWindow);
      Result := True;
    end
    else
      PSMem^.AppHandle := AppHandle;
  end;
end;

initialization
  CreateMapFile;
finalization
  FreeMapFile;
end.

调用如下:

program Project1;
uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1}
  wdRunOnce in 'wdRunOnce.pas',
  Unit2 in 'Unit2.pas' {Form2}
{$R *.res}
begin
  Application.Initialize;
  if not AppHasRun(Application.Handle) then
    Application.CreateForm(TForm1, Form1);
  Application.Run;
end.