如何使用R运行ldap查询?

12

我想要查询LDAP目录,了解员工在部门和群组中的分布情况...

类似于:"给我一个组的所有成员所在的部门名称",然后使用R进行频率分析,但是我找不到任何关于如何连接和运行LDAP查询使用R的示例。

RCurl 似乎提供了某种类型的支持:

  

此外,其底层实现稳健且广泛,支持FTP / FTPS / TFTP(上传和下载),SSL / HTTPS,telnet,dict,ldap,还支持 cookie,重定向,身份验证等。

但我不是R专家,也没有找到使用RCurl(或任何其他R库)来完成这项任务的示例。

现在我正在使用CURL这样的方法来获取组的成员:

curl "ldap://ldap.replaceme.com/o=replaceme.com?memberuid?sub?(cn=group-name)"

这里是否有人知道如何使用RCurl在R中执行相同的操作?


2
我们需要了解更多关于LDAP服务器配置的信息。以下是一个IBM示例中通过curl -u USERNAME 'ldap://192.168.0.66/CN=Users,DC=training,DC=local\?sAMAccountName?sub?(ObjectClass=*)'进行的LDAP查询示例。这个示例对你来说可能不起作用,因为你需要知道正确的搜索参数。通过RCurl运行并处理结果非常简单,但是你应该先从命令行上的curl中使查询工作正常。 - hrbrmstr
1
现在我正在检索组成员列表,如下所示:ldapsearch -t -h ldap.replaceme.com -x -b "o=replaceme.com" "(cn=group-name)" memberuid - Luxspes
@hrbrmstr如果您能够将我的“ldapsearch”翻译成“curl”,然后用“RCurl”将其转换为“R”,那将是我正在寻找的确切答案... - Luxspes
嗨@hrbrmstr,我已经将我的ldapsearch查询翻译成了curl...你能告诉我如何使用RCurl运行它吗? - Luxspes
已经自己完成了...但是非常感谢您的指导 @hrbrmstr :-) - Luxspes
5个回答

12

我自己找到了答案:

首先运行以下命令,确保RCurl已安装(如http://www.programmingr.com/content/webscraping-using-readlines-and-rcurl/中所述):

install.packages("RCurl", dependencies = TRUE)
library("RCurl")

然后,用户使用LDAP URL(如http://www.ietf.org/rfc/rfc2255.txt中描述的那样)通过getURL获取它,尽管在阅读http://docs.oracle.com/cd/E19396-01/817-7616/ldurl.html和看到ldap[s]://hostname:port/base_dn?attributes?scope?filter之前我无法理解它。

getURL("ldap://ldap.replaceme.com/o=replaceme.com?memberuid?sub?(cn=group-name)")

相关的是,这是一份关于RCurl使用的优秀指南:http://www.omegahat.org/RCurl/RCurlJSS.pdf。 - Luxspes

5
我在这里编写了一个函数来将ldap输出解析为数据框,并且我用提供的示例作为启动一切的参考。
希望它能对某些人有所帮助!
library(RCurl)
library(gtools)

parseldap<-function(url, userpwd=NULL)
{
  ldapraw<-getURL(url, userpwd=userpwd)
  # seperate by two new lines
  ldapraw<-gsub("(DN: .*?)\n", "\\1\n\n", ldapraw)
  ldapsplit<-strsplit(ldapraw, "\n\n")
  ldapsplit<-unlist(ldapsplit)
  # init list and count
  mylist<-list()
  count<-0
  for (ldapline in ldapsplit) {
    # if this is the beginning of the entry
    if(grepl("^DN:", ldapline)) {
      count<-count+1
      # after the first 
      if(count == 2 ) {
        df<-data.frame(mylist)
        mylist<-list()
      }
      if(count > 2) {
        df<-smartbind(df, mylist)
        mylist<-list()
      }
      mylist["DN"] <-gsub("^DN: ", "", ldapline)
    } else {
      linesplit<-unlist(strsplit(ldapline, "\n"))
      if(length(linesplit) > 1) {
        for(line in linesplit) {
          linesplit2<-unlist(strsplit(line, "\t"))
          linesplit2<-unlist(strsplit(linesplit2[2], ": "))
          if(!is.null(unlist(mylist[linesplit2[1]]))) {
            x<-strsplit(unlist(mylist[linesplit2[1]]), "|", fixed=TRUE)

            x<-append(unlist(x), linesplit2[2])
            x<-paste(x, sep="", collapse="|")
            mylist[linesplit2[1]] <- x
          } else {
            mylist[linesplit2[1]] <- linesplit2[2]  
          }
        }
      } else {
        ldaplinesplit<-unlist(strsplit(ldapline, "\t"))
        ldaplinesplit<-unlist(strsplit(ldaplinesplit[2], ": "))
        mylist[ldaplinesplit[1]] <- ldaplinesplit[2]
      }

    }

  }
  if(count == 1 ) {
    df<-data.frame(mylist)
  } else {
    df<-smartbind(df, mylist)
  }
  return(df)
}

1
loginLDAP <- function(username, password) {

  ldap_url <- "ldap://SERVER-NAME-01.companyname.com"

  handle <- curl::new_handle(timeout = 10)

  curl::handle_setopt(handle = handle, userpwd = paste0("companyname\\", username, ":", password))

  tryCatch(
    {
      response <- curl::curl_fetch_memory(url = ldap_url, handle = handle)

      if (response$status_code == 0) {
        return(list(success = TRUE, username = username))
      } else {
        print("Invalid login credentials.")
      }
    },
    error = function(e) {
      return(list(success = FALSE, username = username))
    }
  )
}

0
我遵循了这个策略:
  1. 运行一个带有LDAP查询的Perl脚本,将数据以JSON格式写入磁盘。
  2. 使用R读取JSON结构,创建数据框。
对于步骤(1),我使用了以下脚本:
#use Modern::Perl;
use strict;
use warnings;
use feature 'say';
use Net::LDAP;
use JSON;
chdir("~/git/_my/R_one-offs/R_grabbag");
my $ldap = Net::LDAP->new( 'ldap.mydomain.de' ) or die "$@";
my $outfile = "ldapentries_mydomain_ldap.json";
my $mesg = $ldap->bind ;    # an anonymous bind
# get all cn's (= all names)
$mesg = $ldap->search(
                base   => " ou=People,dc=mydomain,dc=de",
                filter => "(cn=*)"
              );

my $json_text = "";
my @entries;

foreach my $entry ($mesg->entries){
 my %entry;
 foreach my $attr ($entry->attributes) {
    foreach my $value ($entry->get_value($attr)) {
      $entry{$attr} = $value;
    }
  }
  push @entries, \%entry;
}

$json_text = to_json(\@entries);
say "Length json_text: " . length($json_text);


open(my $FH, ">", $outfile);
print $FH $json_text;
close($FH);
$mesg = $ldap->unbind;

您可能需要检查LDAP服务器返回的条目的最大大小限制。 请参见https://serverfault.com/questions/328671/paging-using-ldapsearch

对于步骤(2),我使用了这个R代码:

setwd("~/git/_my/R_one-offs/R_grabbag")
library(rjson)
# read into R list, from file, created from perl script
json <- rjson::fromJSON(file="ldapentries_mydomain_ldap.json",method = "C")
head(json)

# create a data frame from list
library(reshape2)
library(dplyr)
library(tidyr)

# not really efficient, maybe thre's a better way to do it
df.ldap <- json %>% melt %>% spread( L2,value)

# optional:
# turn factors into characters
i <- sapply(df.ldap, is.factor)
df.ldap[i] <- lapply(df.ldap[i], as.character)

0

我编写了一个R库,使用openldap库访问ldap服务器。具体来说,searchldap函数是openldap方法searchldap的包装器。 https://github.com/LukasK13/ldapr


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接