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   47538 use Catmandu::Sane;
  1         112487  
  1         5  
4 1     1   209 use Catmandu::Util qw(:is);
  1         2  
  1         239  
5 1     1   4 use Carp qw(confess);
  1         5  
  1         47  
6 1     1   485 use Net::LDAP;
  1         103786  
  1         4  
7 1     1   57 use Moo;
  1         1  
  1         7  
8              
9             with 'Catmandu::Importer';
10              
11             our $VERSION = '0.0104';
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 = $self->has_base
    0          
42             ? $self->has_password
43             ? $ldap->bind($self->base, password => $self->password)
44             : $ldap->bind($self->base)
45             : $ldap->bind;
46              
47 0 0         if ($bind->code != 0) {
48 0           $self->log->error($bind->error);
49 0           return undef;
50             }
51 0           $ldap;
52             }
53              
54             sub _new_search {
55 0     0     my $self = $_[0];
56 0           my %args;
57 0 0         $args{base} = $self->search_base if $self->has_search_base;
58 0 0         $args{filter} = $self->search_filter if $self->has_search_filter;
59 0 0         if (my $attrs = $self->attributes) {
60 0           $args{attrs} = [keys %$attrs];
61             }
62 0           my $search = $self->ldap->search(%args);
63 0 0         if ($search->code != 0) {
64 0           $self->log->error($search->error);
65             }
66 0           $search;
67             }
68              
69             sub generator {
70             my $self = $_[0];
71             sub {
72             state $search = $self->_new_search;
73             my $entry = $search->shift_entry // return;
74             my $data = {};
75             if (my $attrs = $self->attributes) {
76             for my $attr (keys %$attrs) {
77             my $config = $attrs->{$attr};
78             my $val = $entry->get_value($attr, asref => $config->{array}) // next;
79             $data->{$config->{as} // $attr} = $config->{array} ? [@$val] : $val;
80             }
81             } else {
82             for my $attr ($entry->attributes) {
83             my $val = $entry->get_value($attr, asref => 1);
84             $data->{$attr} = [@$val];
85             }
86             }
87             $data;
88             };
89             }
90              
91             =head1 NAME
92              
93             Catmandu::Importer::LDAP - Package that imports LDAP directories
94              
95             =head1 SYNOPSIS
96              
97             # From the command line
98              
99             # Anonymous bind to find all 'Patrick's
100             $ catmandu convert LDAP \
101             --host ldaps://ldaps.ugent.be \
102             --search-filter '(givenName=Patrick)' \
103             --search-base 'dc=ugent, dc=be' to YAML
104              
105             # From Perl
106              
107             use Catmandu;
108              
109             my $importer = Catmandu->importer('LDAP',
110             host => 'ldaps://ldaps.ugent.be' ,
111             search_filter => '(givenName=Patrick)' ,
112             search_base => 'dc=ugent, dc=be'
113             );
114              
115             my $exporter = Catmandu->exporter('YAML');
116              
117             $exporter->add_many($importer);
118              
119             $exporter->commit;
120              
121             =head1 CONFIGURATION
122              
123             =over
124              
125             =item host
126              
127             The LDAP host to connect to
128              
129             =item base
130              
131             The base to bind to (if not specified it is an anonymous bind)
132              
133             =item password
134              
135             The password needed for the bind
136              
137             =item search_base
138              
139             The DN that is the base object entry relative to which the search is to be performed.
140              
141             =item search_filter
142              
143             One or more search filters. E.g.
144              
145             (givenName=Patrick) # search Patrick
146             (&(givenName=Patrick)(postalCode=9000)) # search Patrick AND postalcode=9000
147             (|)(givenName=Patrick)(postalCode=9000)) # search Patrick OR postcalcode=9000
148              
149             =back
150              
151             =head1 METHODS
152              
153             Every Catmandu::Importer is a Catmandu::Iterable all its methods are inherited.
154             The methods are not idempotent: LDAP streams can only be read once.
155              
156             =head1 SEE ALSO
157              
158             L<Catmandu> ,
159             L<Catmandu::Importer> ,
160             L<Catmandu::Iterable>
161              
162             =cut
163              
164             1;