File Coverage

blib/lib/Catmandu/Importer/LDAP.pm
Criterion Covered Total %
statement 15 32 46.8
branch 0 14 0.0
condition 0 3 0.0
subroutine 5 7 71.4
pod n/a
total 20 56 35.7


line stmt bran cond sub pod time code
1             package Catmandu::Importer::LDAP;
2              
3 1     1   60269 use Catmandu::Sane;
  1         182904  
  1         6  
4 1     1   287 use Catmandu::Util qw(:is);
  1         3  
  1         279  
5 1     1   7 use Carp qw(confess);
  1         2  
  1         41  
6 1     1   616 use Net::LDAP;
  1         152684  
  1         5  
7 1     1   59 use Moo;
  1         3  
  1         7  
8              
9             with 'Catmandu::Importer';
10              
11             our $VERSION = '0.0105';
12              
13             has host => (is => 'ro', default => sub {'ldap://127.0.0.1:389'});
14             has base => (is => 'ro', predicate => 1);
15             has password => (is => 'ro', predicate => 1);
16             has search_base => (is => 'ro', predicate => 1);
17             has search_filter => (is => 'ro', predicate => 1);
18             has ldap => (is => 'ro', lazy => 1, builder => '_build_ldap');
19             has attributes => (
20             is => 'ro',
21             coerce => sub {
22             my $attrs = $_[0];
23             if (is_string $attrs) {
24             return {map {$_ => {}} split ',', $attrs};
25             }
26             if (is_array_ref $attrs) {
27             return {map {$_ => {}} @$attrs};
28             }
29             if ($attrs) {
30             for my $attr (keys %$attrs) {
31             $attrs->{$attr} = {} unless ref $attrs->{$attr};
32             }
33             }
34             $attrs;
35             },
36             );
37              
38             sub _build_ldap {
39 0     0     my $self = $_[0];
40 0   0       my $ldap = Net::LDAP->new($self->host, raw => qr/;binary/) || confess $@;
41 0 0         my $bind
    0          
42             = $self->has_base
43             ? $self->has_password
44             ? $ldap->bind($self->base, password => $self->password)
45             : $ldap->bind($self->base)
46             : $ldap->bind;
47              
48 0 0         if ($bind->code != 0) {
49 0           $self->log->error($bind->error);
50 0           return undef;
51             }
52 0           $ldap;
53             }
54              
55             sub _new_search {
56 0     0     my $self = $_[0];
57 0           my %args;
58 0 0         $args{base} = $self->search_base if $self->has_search_base;
59 0 0         $args{filter} = $self->search_filter if $self->has_search_filter;
60 0 0         if (my $attrs = $self->attributes) {
61 0           $args{attrs} = [keys %$attrs];
62             }
63 0           my $search = $self->ldap->search(%args);
64 0 0         if ($search->code != 0) {
65 0           $self->log->error($search->error);
66             }
67 0           $search;
68             }
69              
70             sub generator {
71             my $self = $_[0];
72             sub {
73             state $search = $self->_new_search;
74             my $entry = $search->shift_entry // return;
75             my $data = {};
76             if (my $attrs = $self->attributes) {
77             for my $attr (keys %$attrs) {
78             my $config = $attrs->{$attr};
79             my $val = $entry->get_value($attr, asref => $config->{array})
80             // next;
81             $data->{$config->{as} // $attr}
82             = $config->{array} ? [@$val] : $val;
83             }
84             }
85             else {
86             for my $attr ($entry->attributes) {
87             my $val = $entry->get_value($attr, asref => 1);
88             $data->{$attr} = [@$val];
89             }
90             }
91             $data;
92             };
93             }
94              
95             =head1 NAME
96              
97             Catmandu::Importer::LDAP - Package that imports LDAP directories
98              
99             =head1 SYNOPSIS
100              
101             # From the command line
102              
103             # Anonymous bind to find all 'Patrick's
104             $ catmandu convert LDAP \
105             --host ldaps://ldaps.ugent.be \
106             --search-filter '(givenName=Patrick)' \
107             --search-base 'dc=ugent, dc=be' to YAML
108              
109             # From Perl
110              
111             use Catmandu;
112              
113             my $importer = Catmandu->importer('LDAP',
114             host => 'ldaps://ldaps.ugent.be' ,
115             search_filter => '(givenName=Patrick)' ,
116             search_base => 'dc=ugent, dc=be'
117             );
118              
119             my $exporter = Catmandu->exporter('YAML');
120              
121             $exporter->add_many($importer);
122              
123             $exporter->commit;
124              
125             =head1 CONFIGURATION
126              
127             =over
128              
129             =item host
130              
131             The LDAP host to connect to
132              
133             =item base
134              
135             The base to bind to (if not specified it is an anonymous bind)
136              
137             =item password
138              
139             The password needed for the bind
140              
141             =item search_base
142              
143             The DN that is the base object entry relative to which the search is to be performed.
144              
145             =item search_filter
146              
147             One or more search filters. E.g.
148              
149             (givenName=Patrick) # search Patrick
150             (&(givenName=Patrick)(postalCode=9000)) # search Patrick AND postalcode=9000
151             (|)(givenName=Patrick)(postalCode=9000)) # search Patrick OR postcalcode=9000
152              
153             =back
154              
155             =head1 METHODS
156              
157             Every Catmandu::Importer is a Catmandu::Iterable all its methods are inherited.
158             The methods are not idempotent: LDAP streams can only be read once.
159              
160             =head1 SEE ALSO
161              
162             L<Catmandu> ,
163             L<Catmandu::Importer> ,
164             L<Catmandu::Iterable>
165              
166             =cut
167              
168             1;