公司有個系統的用戶賬戶驗證部分有多種可選的認證方式,其中包括AD域認證,創建的用戶名和密碼必須被某個DNS服務器的域所包含。當用戶去登陸這個系統時,系統呼叫openldap的C API連接域服務器去驗證。之前一直使用的API為ldap_simple_bind_s,但是2020年3月后微軟將強制啟用AD域簽名認證,以前一直使用的簡單認證ldap_simple_bind_s方式將失效。
https://support.microsoft.com/zh-cn/help/4520412/2020-ldap-channel-binding-and-ldap-signing-requirement-for-windows
配置服務器使用AD域簽名的方法如下
https://support.microsoft.com/en-us/help/935834/how-to-enable-ldap-signing-in-windows-server-2008
根據微軟的檔案,我寫了個windows平臺的認證測驗程式
/* 未使用UNICODE字符集, 并需要vs工程配置添加依賴庫Wldap32.lib */
#include "stdafx.h"
#include <windows.h>
#include <winldap.h>
#include "stdio.h"
//#define AD_SIGN
#define PORT LDAP_PORT
#define HOST "192.168.0.249"
#define WHO "[email protected]"
#define PASSWD "^YHN7ujm*IK0"
#ifdef AD_SIGN
#define METHOD LDAP_AUTH_NEGOTIATE
#else
#define METHOD LDAP_AUTH_SIMPLE // 識別方法
#endif
int main()
{
LDAP *ld = NULL;
int version = LDAP_VERSION3; // 版本
int rc; //回傳值
struct timeval timeout;
SEC_WINNT_AUTH_IDENTITY_A cred{
(unsigned char*)"songyuhua",
strlen("songyuhua"),
(unsigned char*)"2020test.com",
strlen("2020test.com"),
(unsigned char*)"^YHN7ujm*IK0",
strlen("^YHN7ujm*IK0"),
SEC_WINNT_AUTH_IDENTITY_ANSI
};
// 初始化 LDAP
ld = ldap_init(HOST, PORT);
if (ld == NULL) {
printf("ldap_init failed");
return -1;
}
printf("ldap_init success\n");
// 設定協議版本為 3.0
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (rc != LDAP_SUCCESS) {
printf("ldap_set_protocol: %d, %s\n", rc, ldap_err2string(rc));
return -1;
}
printf("ldap_set_protocol success\n");
//設定超時
timeout.tv_usec = 0;
timeout.tv_sec = 10;
rc = ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &version);
if (rc != LDAP_SUCCESS) {
printf("ldap_set_send_timeout: %d, %s\n", rc, ldap_err2string(rc));
return -1;
}
printf("ldap_set_send_timeout success\n");
#ifdef AD_SIGN
// 設定簽名
rc = ldap_set_option(ld, LDAP_OPT_SIGN, LDAP_OPT_ON);
if (rc != LDAP_SUCCESS) {
printf("ldap_set_sign: %d, %s\n", rc, ldap_err2string(rc));
return -1;
}
printf("ldap_set_sign success\n");
//設定加密
rc = ldap_set_option(ld, LDAP_OPT_ENCRYPT, LDAP_OPT_ON);
if (rc != LDAP_SUCCESS) {
printf("ldap_set_encrypt: %d, %s\n", rc, ldap_err2string(rc));
//return -1;
}
printf("ldap_set_encrypt success\n");
#endif
// 向 LDAP 服務器認證客戶端
#ifdef AD_SIGN
rc = ldap_bind_s(ld, NULL, (PCHAR)&cred, METHOD);
#else
rc = ldap_bind_s(ld, WHO, PASSWD, METHOD);
#endif
if (rc != LDAP_SUCCESS) {
printf("ldap_bind_s: %d, %s\n", rc, ldap_err2string(rc));
return -1;
}
printf("ldap_bind_s success\n");
ldap_unbind_s(ld);
return 0;
}
可以看到當使用LDAP_AUTH_SIMPLE簡單認證時提示需要強身份認證

使用LDAP_AUTH_NEGOTIATE(打開了AD_SIGN宏)則通過了認證

windows平臺的程式通過了認證,之后我又開始著手測驗linux,用的openLDAP庫,介面類似,移植很方便,
但是遇到了問題,使用簡單認證的程式如下:
#define LDAP_DEPRECATED 1
#include <stdio.h>
#include <ldap.h>
#include <lber.h>
//#define AD_SIGN
#define PORT LDAP_PORT
#define HOST "192.168.0.249"
#define WHO "[email protected]"
#define PASSWD "^YHN7ujm*IK0"
#ifdef AD_DESIGN
#define METHOD LDAP_AUTH_NEGOTIATE
#else
#define METHOD LDAP_AUTH_SIMPLE // 識別方法
#endif
int main()
{
LDAP *ld = NULL;
int version = LDAP_VERSION3; // 版本
int rc; //回傳值
// 初始化 LDAP
ld = ldap_init(HOST, PORT);
if (ld == NULL) {
printf("ldap_init failed");
return -1;
}
printf("ldap_init success\n");
// 設定協議版本為 3.0
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
if (rc != LDAP_SUCCESS) {
printf("ldap_set_protocol: %d, %s\n", rc, ldap_err2string(rc));
return -1;
}
printf("ldap_set_protocol success\n");
#ifdef AD_SIGN
// 設定簽名
rc = ldap_set_option(ld, LDAP_OPT_SIGN, LDAP_OPT_ON);
if (rc != LDAP_SUCCESS) {
printf("ldap_set_sign: %d, %s\n", rc, ldap_err2string(rc));
return -1;
}
printf("ldap_set_sign success\n");
//設定加密
rc = ldap_set_option(ld, LDAP_OPT_ENCRYPT, LDAP_OPT_ON);
if (rc != LDAP_SUCCESS) {
printf("ldap_set_encrypt: %d, %s\n", rc, ldap_err2string(rc));
return -1;
}
printf("ldap_set_encrypt success\n");
#endif
// 向 LDAP 服務器認證客戶端
//rc = ldap_bind_s(ld, WHO, PASSWD, METHOD);
rc = ldap_bind_s(ld, WHO, PASSWD, METHOD);
if (rc != LDAP_SUCCESS) {
printf("ldap_bind_s: %d, %s\n", rc, ldap_err2string(rc));
return -1;
}
printf("ldap_bind_s success\n");
}
運行結果如下:
[syh@localhost src]$ gcc ldaptest.c -o ldaptest -lldap
[syh@localhost src]$ ./ldaptest
ldap_init success
ldap_set_protocol success
ldap_bind_s: 8, Strong(er) authentication required
我又開始著手更改使用簽名認證的程式,僅打開AD_SIGN宏,不改動ldap_bind_s,運行結果如下:
[syh@localhost src]$ ./ldaptest
ldap_init success
ldap_set_protocol success
ldap_set_sign: -1, Can't contact LDAP server
測驗時發現 ldap_set_option在設定LDAP_OPT_SIGN和LDAP_OPT_ENCRYPT的時候報Can't contact LDAP server錯誤,這個錯誤很迷,我明明可以連上服務器,查了很長時間,無果,難道這個引數只能在windows中使用?

此外,對于ldap_bind_s(LDAP *ld, const char *who, const char *cred,int method)函式,
在使用 LDAP_AUTH_NEGOTIATE方式時,引數3的傳參方式我沒有查到像windows下面的詳細的說明。windows下面cred引數雖然也是char*型別,但是可以指向一個特定的結構體SEC_WINNT_AUTH_IDENTITY_A, 但我眼拙未在openldap中沒有找到類似的結構體,還請各位大哥賜教。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/151738.html
標籤:工具平臺和程序庫
上一篇:C++逐字輸出函式
