LDAP 认证(Windows)

作者: 一去、二三里
个人微信号: iwaleon
微信公众号: 高效程序员

LDAP(Lightweight Directory Access Protocol - 轻量级目录访问协议)是一种目录服务协议,运行在 TCP/IP 栈之上的一层。它提供了一种用于连接、搜索、和修改 Internet 目录的机制。

LDAP 目录服务基于 client-server 模型,LDAP 的功能是允许访问现有目录。

LDAP 的数据模型(数据和命名空间)类似于 X.500 OSI 目录服务,但资源要求较低。相关联的 LDAP API 简化了编写 Internet 目录服务应用程序的过程。

关于 LDAP 的操作,有 C/C++ 的支持,可参考 MSDN 中的 Lightweight Directory Access Protocol,也可使用 OpenLDAP

初始化 LDAP

LDAP* ldap_init(
  UNICODE PTCHAR HostName,
  ULONG PortNumber
);
  • HostName:表示要连接的 LDAP 服务器的主机 IP 地址。
  • PortNumber:表示要连接的 TCP 端口号。设置为 LDAP_PORT 则为默认端口 389,如果主机名包含端口号,将忽略此参数。

如果函数执行成功,将返回一个指向 LDAP 数据结构的指针形式的会话句柄。否则,返回 NULL,可使用 LdapGetLastError 函数检索错误代码。

设置连接块上的选项

ULONG ldap_set_option(
  LDAP* ld,
  int option,
  void* invalue
);
  • ld:会话句柄
  • option:设置的会话选项的名称
  • invalue:指向给定 option 值的指针。此参数的实际类型取决于 option 参数的设置,可以指定具有开或关设置的常量 LDAP_OPT_ON 和 LDAP_OPT_OFF 选项。

如果函数执行成功,返回值为 LDAP_SUCCESS。否则,返回错误代码。有关可能的返回值列表,请参阅 LDAP_RETCODE 枚举。

调用此函数以访问表示 LDAP 会话的 LDAP 结构,不要尝试直接修改 LDAP 数据结构。

要启用签名/密封,必须在调用 ldap_bind_s 之前打开以下选项之一:

#define LDAP_OPT_SIGN      0x95
#define LDAP_OPT_ENCRYPT   0x96

要关闭签名/密封,必须通过调用连接句柄上的 ldap_unbind 函数来关闭连接。

连接 LDAP 服务器

ULONG ldap_connect(
  LDAP* ld,
  PLDAP_TIMEVAL* timeout
);
  • ld:会话句柄
  • timeout:超时前尝试建立连接的秒数

如果函数执行成功,返回值为 LDAP_SUCCESS。否则,返回错误代码。有关可能的返回值列表,请参阅 LDAP_RETCODE 枚举。

通常客户端不调用此函数来建立与服务器的连接。如果连接不存在,其他函数将在内部进行调用。但是,有时可能需要在连接块上指定其他选项。例如,客户端可以调用 ldap_init 来初始化会话,然后调用 ldap_set_option 在连接块上设置超时。客户端然后调用 ldap_connect 以指定的超时连接到服务器。

向 LDAP 服务器认证客户端

ULONG ldap_bind_s(
  LDAP* ld,
  UNICODE PTCHAR dn,
  UNICODE PTCHAR cred,
  ULONG method
);
  • ld:会话句柄
  • dn:用于绑定的条目的可分辨名称
  • cred:要进行身份验证的凭据。可以使用此参数传递任意凭证,凭据的格式和内容取决于机制参数的设置。
  • method:指示要使用的认证方法。

如果函数执行成功,返回值为 LDAP_SUCCESS。否则,返回错误代码。有关可能的返回值列表,请参阅 LDAP_RETCODE 枚举。

基本使用

使用时依赖库 Wldap32.lib(Wldap32.dll),需要包含头文件 Winldap.h。

#include "stdafx.h"
#include "windows.h"
#include "winldap.h"
#include "stdio.h"

int _tmain(int argc, _TCHAR* argv[])
{
	PWSTR host = L"172.18.***.***";  // 主机
	ULONG port = LDAP_PORT;  // 端口

	ULONG version = LDAP_VERSION3;  // 版本

	// 认证信息
	PWSTR dn = L"uid=ldapuser1,ou=People,dc=cloud,dc=com";  // 唯一的识别名
	PWSTR cred = L"password";  // 识别证书
	ULONG method = LDAP_AUTH_SIMPLE;  // 识别方法

	// 搜索结果
	LDAPMessage *res = NULL;
	PWSTR base_dn = L"ou=People,dc=cloud,dc=com";
	PWSTR filter = L"(&(objectClass=person))";

	LDAP *ld = NULL;  // 连接的句柄
	ULONG rc = 0;  // 返回值

	// 初始化 LDAP
	ld = ldap_init(host, port);
	if (ld == NULL) {
		fprintf(stderr, "ldap_init failed");
		return -1;
	}
	printf("ldap_init success\n");

	// 设置协议版本为 3.0(默认 2.0)
	rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
	if (rc != LDAP_SUCCESS) {
		fprintf(stderr, "ldap_set_option: rc: %d\n", rc);
		return -1;
	}
	printf("ldap_set_option success\n");

	// 连接 LDAP 服务器
	rc = ldap_connect(ld, NULL);
	if (rc != LDAP_SUCCESS) {
		fprintf(stderr, "ldap_connect: rc: %d\n", rc);
		return -1;
	}
	printf("ldap_connect success\n");

	// 向 LDAP 服务器认证客户端
	rc = ldap_bind_s(ld, dn, cred, method);
	if (rc != LDAP_SUCCESS) {
		fprintf(stderr, "ldap_bind_s: rc: %d\n", rc);
		return -1;
	}
	printf("ldap_bind_s success\n");

	// 搜索结果
	PWCHAR attrs[6];
	attrs[0] = (WCHAR*)"cn";
	attrs[1] = (WCHAR*)"company";
	attrs[2] = (WCHAR*)"givenName";
	attrs[3] = (WCHAR*)"sn";
	attrs[4] = (WCHAR*)"memberOf";
	attrs[5] = NULL;

	rc = ldap_search_s(
		ld,                 // 会话句柄
		base_dn,            // 指向查询开始处对象的指针,可以作为数的顶端,或者某一个低的点
		LDAP_SCOPE_SUBTREE, // 范围
		filter,             // 过滤器
		attrs,              // 检索属性列表
		0,                  // 设置为 1,只返回属性的类型,通常设定为 0,返回属性类型和值
		&res);              // [输出]搜索结果

	if (rc != LDAP_SUCCESS) {
		fprintf(stderr, "ldap_search_s: rc: %d\n", rc);
		ldap_unbind_s(ld);
		if (res != NULL)
			ldap_msgfree(res);

		return -1;
	}
	printf("ldap_search_s success\n");

	// 获取返回的条目数
	ULONG count = ldap_count_entries(ld, res);
	printf("The number of entries is: %d\n", count);

	return 0;
}

更多参考

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一去丶二三里

有收获,再打赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值