陈天

陈天--只求真实的记录

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

【背景】

在互联网大环境下,企业办公应用近两年呈现出蓬勃发展的态势,这些应用必须兼容企业已有的登录认证系统,LDAP(Lightweight Directory Access Protocol)做为标准的目录服务,广泛被企业使用。本文记录接入到LDAP服务所遇到的问题以及解决办法,希望对刚接触LDAP的初学者有所帮助。

 

【环境、语音和开源库】

linux

c++

OpenLDAP

 

【编译】

从官网ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.44.tgz下载OpenLDAP最新版本

1、解压缩OpenLDAP

定位到openldap-2.4.44.tgz所在目录,执行tar zxvf  openldap-2.4.44.tgz解压缩,在当前目录下生成openldap-2.4.44目录,ll命令查看包含的子目录和文件:

2、vi命令查看INSTALL文件,初步了解编译安装步骤

3、编译配置,执行如下命令:

./configure --prefix=/data/allanchen/opensource/openldap/openldap-2.4.44/build_lib --enable-backends=no --enable-slapd=no --enable-shared=no --with-pic=yes --with-cyrus-sasl=no
--prefix:设置编译生成路径
--enable-backends=no --enable-slapd=no,由于本次项目只是做为客户端,取消服务端相关配置
当看到最后提示为“Please run "make depend" to build dependencies”时,configure执行成功
4、执行make depend,生成依赖项
5、执行make
6、执行make install,最终编译完成,保护include头文件以及lib静态库文件:
 
【用户登录认证】
由ldap_simple_bind_s(ld, dn, pw)函数完成用户登录认证,dn(distinguishedName)为认证用户完整路径,pw为认证用户密码,dn由于对完整路径的要求,使得我们很难配置基础的base dn并由它来拼接用户完整dn,所以,在认证登录前,需设法查询到用户完整dn,ldap_search_s正好提供了相应功能,用户设置base dn,并设置filter(可设置为(&(classobject=user)(sAMAccountName=loginName))),据此查找到用户dn,从而调用ldap_simple_bind_s完成用户登录认证。
#include “ldap.h”
using namespace std;

LDAP * ld;
if ((ld = ldap_init(host.c_str(), LDAP_PORT)) == NULL) {
      cout << "ldap init failed" << endl;
      return 1;
}

int version = LDAP_VERSION3;
if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS) {
    cout << "set protocol version failed" << endl;
    return 1;
}

int max_timeout = 10;
if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT,
    (void *)&max_timeout) != LDAP_SUCCESS) {
    cout << "set time limit failed" << endl;
    return 1;
}

// must do set
if (ldap_set_option(ld,LDAP_OPT_REFERRALS,LDAP_OPT_OFF) != LDAP_SUCCESS) {
    cout << "set referrals off failed" << endl;
    return 1;
}

// dn,pw管理员账户和密码
int ret = LDAP_SUCCESS;
if ((ret = ldap_simple_bind_s(ld, dn_admin, pw_admin)) != LDAP_SUCCESS) {
    cout << "ldap_simple_bind_s failed" << endl;
    cout << "errcode : " << ret << endl;
    cout << "errmsg : " << ldap_err2string(ret) << endl;
    return 1;
}

LDAPMessage *result, *msg;
char * attrs[1];
attrs[0] = "distinguishedName";
char * filter = "(&(objectclass=user)(sAMAccountName=loginName))";
char * base = "DC=MyCompany,DC=com";
if ((ret = ldap_search_s(ld, base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result)) != LDAP_SUCCESS) {
    cout << "ldap_search_s failed" << endl;
    cout << "errcode :" << ret << endl;
    cout << "errmsg : " << ldap_err2string(ret) << endl;
    return 1;
}

char **vals;
if ((msg = ldap_first_entry(ld, result)) != NULL) {
    if ((vals = ldap_get_values(ld, msg, "distinguishedName")) != NULL) {
        char * dn = ldap_get_dn(ld, msg);
        ret = ldap_simple_bind_s(ld, dn, pw)
        if (ret == LDAP_SUCCESS) {
            cout << "auth succ";
        }
        else {
            cout << "auth failed";
        }
}
 
【结论】
重点在于要兼容不同企业LDAP用户dn不同,以及同一企业不同不用不同层级dn。
posted on 2016-05-29 01:35  陈天  阅读(4550)  评论(0编辑  收藏  举报