forked from russoz/Net-LDAP-SimpleServer
/
ProtocolHandler.pm
177 lines (124 loc) · 4.47 KB
/
ProtocolHandler.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package Net::LDAP::SimpleServer::ProtocolHandler;
use strict;
use warnings;
# ABSTRACT: LDAP protocol handler used with Net::LDAP::SimpleServer
# VERSION
use Net::LDAP::Server;
use base 'Net::LDAP::Server';
use fields qw(store root_dn root_pw allow_anon);
use Carp;
use Net::LDAP::LDIF;
use Net::LDAP::Util qw{canonical_dn};
use Net::LDAP::FilterMatch;
use Net::LDAP::Constant (
qw/LDAP_SUCCESS LDAP_AUTH_UNKNOWN LDAP_INVALID_CREDENTIALS/,
qw/LDAP_AUTH_METHOD_NOT_SUPPORTED/ );
use Scalar::Util qw{reftype};
use UNIVERSAL::isa;
use Data::Dumper;
sub _make_result {
my $code = shift;
my $dn = shift || '';
my $msg = shift || '';
return {
matchedDN => $dn,
errorMessage => $msg,
resultCode => $code,
};
}
sub new {
my $class = shift;
my $params = shift || croak 'Must pass parameters!';
my $self = $class->SUPER::new( $params->{input}, $params->{output} );
croak 'Parameter must be a HASHREF' unless reftype($params) eq 'HASH';
croak 'Must pass option {store}' unless exists $params->{store};
croak 'Not a LDIFStore'
unless $params->{store}->isa('Net::LDAP::SimpleServer::LDIFStore');
croak 'Must pass option {root_dn}' unless exists $params->{root_dn};
croak 'Option {root_dn} can not be empty' unless $params->{root_dn};
croak 'Invalid root DN'
unless my $canon_dn = canonical_dn( $params->{root_dn} );
$self->{store} = $params->{store};
$self->{root_dn} = $canon_dn;
$self->{root_pw} = $params->{root_pw};
$self->{allow_anon} = $params->{allow_anon};
chomp( $self->{root_pw} );
return $self;
}
sub unbind {
my $self = shift;
$self->{store} = undef;
$self->{root_dn} = undef;
$self->{root_pw} = undef;
return _make_result(LDAP_SUCCESS);
}
sub bind { ## no critic
my ( $self, $request ) = @_;
#print STDERR '=' x 70 . "\n";
#print STDERR Dumper($self);
#print STDERR Dumper($request);
my $ok = _make_result(LDAP_SUCCESS);
if( not $request->{name} and exists $request->{authentication}->{simple} and $self->{allow_anon} ) {
return $ok;
}
#print STDERR qq{not anonymous\n};
# As of now, accepts only simple authentication
return _make_result(LDAP_AUTH_METHOD_NOT_SUPPORTED)
unless exists $request->{authentication}->{simple};
#print STDERR qq{is simple authentication\n};
return _make_result(LDAP_INVALID_CREDENTIALS)
unless my $binddn = canonical_dn( $request->{name} );
#print STDERR qq#binddn is ok ($request->{name}) => ($binddn)\n#;
#print STDERR qq#handler dn is $self->{root_dn}\n#;
return _make_result(LDAP_INVALID_CREDENTIALS)
unless uc($binddn) eq uc( $self->{root_dn} );
#print STDERR qq{binddn is good\n};
my $bindpw = $request->{authentication}->{simple};
chomp($bindpw);
#print STDERR qq|comparing ($bindpw) eq ($self->{root_pw})\n|;
return _make_result(LDAP_INVALID_CREDENTIALS)
unless $bindpw eq $self->{root_pw};
return $ok;
}
sub _match {
my ( $filter_spec, $elems ) = @_;
my $f = bless $filter_spec, 'Net::LDAP::Filter';
return [ grep { $f->match($_) } @{$elems} ];
}
sub search {
my ( $self, $request ) = @_;
my $list = $self->{store}->list;
#my $basedn = $request->{baseObject};
#print STDERR '=' x 50 . "\n";
#print STDERR Dumper($request);
#print STDERR Dumper($list);
my $res = _match( $request->{filter}, $list );
#print STDERR Dumper($res);
return ( _make_result(LDAP_SUCCESS), @{$res} );
}
1; # Magic true value required at end of module
__END__
=head1 SYNOPSIS
use Net::LDAP::SimpleServer::ProtocolHandler;
my $store = Net::LDAP::SimpleServer::LDIFStore->new($datafile);
my $handler =
Net::LDAP::SimpleServer::ProtocolHandler->new({
store => $datafile,
root_dn => 'cn=root',
root_pw => 'somepassword'
}, $socket );
=head1 DESCRIPTION
This module provides an interface between Net::LDAP::SimpleServer and the
underlying data store. Currently only L<Net::LDAP::SimpleServer::LDIFStore>
is available.
=method new( OPTIONS, IOHANDLES )
Creates a new handler for the LDAP protocol, using STORE as the backend
where the directory data is stored. The rest of the IOHANDLES are the same
as in the L<Net::LDAP::Server> module.
=method unbind()
Unbinds the connection to the server.
=method bind( REQUEST )
Handles a bind REQUEST from the LDAP client.
=method search( REQUEST )
Performs a search in the data store.
=cut