bump version
[catagits/Catalyst-Authentication-Store-LDAP.git] / lib / Catalyst / Authentication / Store / LDAP.pm
1 package Catalyst::Authentication::Store::LDAP;
2
3 use strict;
4 use warnings;
5
6 our $VERSION = '0.1003_01';
7
8 use Catalyst::Authentication::Store::LDAP::Backend;
9
10 sub new {
11     my ( $class, $config, $app ) = @_;
12     return Catalyst::Authentication::Store::LDAP::Backend->new(
13         $config);
14 }
15
16 1;
17
18 __END__
19
20 =pod
21
22 =head1 NAME
23
24 Catalyst::Authentication::Store::LDAP 
25   - Authentication from an LDAP Directory.
26
27 =head1 SYNOPSIS
28
29     use Catalyst qw(
30       Authentication
31       );
32
33     __PACKAGE__->config(
34       'authentication' => {
35          default_realm => "ldap",
36          realms => {
37            ldap => {
38              credential => {
39                class => "Password",
40                password_field => "password",
41                password_type => "self_check",
42              },
43              store => {
44                binddn              => "anonymous",
45                bindpw              => "dontcarehow",
46                class               => "LDAP",
47                ldap_server         => "ldap.yourcompany.com",
48                ldap_server_options => { timeout => 30 },
49                role_basedn         => "ou=groups,ou=OxObjects,dc=yourcompany,dc=com",
50                role_field          => "uid",
51                role_filter         => "(&(objectClass=posixGroup)(memberUid=%s))",
52                role_scope          => "one",
53                role_search_options => { deref => "always" },
54                role_value          => "dn",
55                start_tls           => 1,
56                start_tls_options   => { verify => "none" },
57                entry_class         => "MyApp::LDAP::Entry",
58                use_roles           => 1,
59                user_basedn         => "ou=people,dc=yourcompany,dc=com",
60                user_field          => "uid",
61                user_filter         => "(&(objectClass=posixAccount)(uid=%s))",
62                user_scope          => "one",
63                user_search_options => { deref => "always" },
64                user_results_filter => sub { return shift->pop_entry },
65              },
66            },
67          },
68        },
69     );
70
71     sub login : Global {
72         my ( $self, $c ) = @_;
73
74         $c->authenticate({
75                           id          => $c->req->param("login"), 
76                           password    => $c->req->param("password") 
77                          });
78         $c->res->body("Welcome " . $c->user->username . "!");
79     }
80
81 =head1 DESCRIPTION
82
83 This plugin implements the L<Catalyst::Authentication> v.10 API. Read that documentation first if
84 you are upgrading from a previous version of this plugin.
85
86 This plugin uses C<Net::LDAP> to let your application authenticate against
87 an LDAP directory.  It has a pretty high degree of flexibility, given the 
88 wide variation of LDAP directories and schemas from one system to another. 
89
90 It authenticates users in two steps:
91
92 1) A search of the directory is performed, looking for a user object that
93    matches the username you pass.  This is done with the bind credentials 
94    supplied in the "binddn" and "bindpw" configuration options.
95
96 2) If that object is found, we then re-bind to the directory as that object.
97    Assuming this is successful, the user is Authenticated.  
98
99 =head1 CONFIGURATION OPTIONS
100
101 =head2 Configuring with YAML
102
103 Set Configuration to be loaded via Config.yml in YourApp.pm
104
105     use YAML qw(LoadFile);
106     use Path::Class 'file';
107
108     __PACKAGE__->config(
109         LoadFile(
110             file(__PACKAGE__->config->{home}, 'Config.yml')
111         )
112     );
113
114 Settings in Config.yml (adapt these to whatever configuration format you use):
115
116     # Config for Store::LDAP
117     authentication:
118         default_realm: ldap
119         realms:
120             ldap:
121                 credential:
122                     class: Password
123                     password_field: password
124                     password_type:  self_check
125                 store:
126                     class: LDAP
127                     ldap_server: ldap.yourcompany.com
128                     ldap_server_options:
129                         timeout: 30
130                     binddn: anonymous
131                     bindpw: dontcarehow
132                     start_tls: 1
133                     start_tls_options:
134                         verify: none
135                     user_basedn: ou=people,dc=yourcompany,dc=com
136                     user_filter: (&(objectClass=posixAccount)(uid=%s))
137                     user_scope: one
138                     user_field: uid
139                     user_search_options:
140                         deref: always
141                     use_roles: 1
142                     role_basedn: ou=groups,ou=OxObjects,dc=yourcompany,dc=com
143                     role_filter: (&(objectClass=posixGroup)(memberUid=%s))
144                     role_scope: one
145                     role_field: uid
146                     role_value: dn
147                     role_search_options:
148                         deref: always
149
150
151 B<NOTE:> The settings above reflect the default values for OpenLDAP. If you
152 are using Active Directory instead, Matija Grabnar suggests that the following
153 tweeks to the example configuration will work:
154
155     user_basedn: ou=Domain Users,ou=Accounts,dc=mycompany,dc=com
156     user_field:  samaccountname
157     user_filter: (sAMAccountName=%s) 
158
159 He also notes: "I found the case in the value of user_field to be significant: 
160 it didn't seem to work when I had the mixed case value there."
161
162 =head2 ldap_server
163
164 This should be the hostname of your LDAP server.
165
166 =head2 ldap_server_options
167
168 This should be a hashref containing options to pass to L<Net::LDAP>->new().  
169 See L<Net::LDAP> for the full list.
170
171 =head2 binddn
172
173 This should be the DN of the object you wish to bind to the directory as
174 during the first phase of authentication. (The user lookup phase)
175
176 If you supply the value "anonymous" to this option, we will bind anonymously
177 to the directory.  This is the default.
178
179 =head2 bindpw
180
181 This is the password for the initial bind.
182
183 =head2 start_tls
184
185 If this is set to 1, we will convert the LDAP connection to use SSL.
186
187 =head2 start_tls_options
188
189 This is a hashref, which contains the arguments to the L<Net::LDAP> start_tls
190 method.  See L<Net::LDAP> for the complete list of options.
191
192 =head2 user_basedn
193
194 This is the basedn for the initial user lookup.  Usually points to the
195 top of your "users" branch; ie "ou=people,dc=yourcompany,dc=com".
196
197 =head2 user_filter
198
199 This is the LDAP Search filter used during user lookup.  The special string 
200 '%s' will be replaced with the username you pass to $c->login.  By default
201 it is set to '(uid=%s)'.  Other possibly useful filters:
202
203     (&(objectClass=posixAccount)(uid=%s))
204     (&(objectClass=User)(cn=%s))
205
206 =head2 user_scope
207
208 This specifies the scope of the search for the initial user lookup.  Valid
209 values are "base", "one", and "sub".  Defaults to "sub".
210
211 =head2 user_field
212
213 This is the attribute of the returned LDAP object we will use for their
214 "username".  This defaults to "uid".  If you had user_filter set to:
215
216     (&(objectClass=User)(cn=%s))
217
218 You would probably set this to "cn". You can also set it to an array,
219 to allow more than one login field. The first field will be returned
220 as identifier for the user.
221
222 =head2 user_search_options
223
224 This takes a hashref.  It will append it's values to the call to
225 L<Net::LDAP>'s "search" method during the initial user lookup.  See
226 L<Net::LDAP> for valid options.
227
228 Be careful not to specify:
229
230     filter
231     scope
232     base
233
234 As they are already taken care of by other configuration options.
235
236 =head2 user_results_filter
237
238 This is a Perl CODE ref that can be used to filter out multiple results
239 from your LDAP query. In theory, your LDAP query should only return one result
240 and find_user() will throw an exception if it encounters more than one result.
241 However, if you have, for whatever reason, a legitimate reason for returning
242 multiple search results from your LDAP query, use C<user_results_filter> to filter
243 out the LDAP entries you do not want considered. Your CODE ref should expect
244 a single argument, a Net::LDAP::Search object, and it should return exactly one
245 value, a Net::LDAP::Entry object.
246
247 Example:
248
249  user_results_filter => sub {
250                           my $search_obj = shift;
251                           foreach my $entry ($search_obj->entries) {
252                               return $entry if my_match_logic( $entry );
253                           }
254                           return undef; # i.e., no match
255                         }
256  
257 =head2 use_roles
258
259 Whether or not to enable role lookups.  It defaults to true; set it to 0 if 
260 you want to always avoid role lookups.
261
262 =head2 role_basedn
263
264 This should be the basedn where the LDAP Objects representing your roles are.
265
266 =head2 role_filter
267
268 This should be the LDAP Search filter to use during the role lookup.  It
269 defaults to '(memberUid=%s)'.  The %s in this filter is replaced with the value
270 of the "role_value" configuration option.
271
272 So, if you had a role_value of "cn", then this would be populated with the cn
273 of the User's LDAP object.  The special case is a role_value of "dn", which
274 will be replaced with the User's DN.
275
276 =head2 role_scope
277
278 This specifies the scope of the search for the user's role lookup.  Valid
279 values are "base", "one", and "sub".  Defaults to "sub".
280
281 =head2 role_field
282
283 Should be set to the Attribute of the Role Object's returned during Role lookup you want to use as the "name" of the role.  Defaults to "CN".
284
285 =head2 role_value
286
287 This is the attribute of the User object we want to use in our role_filter. 
288 If this is set to "dn", we will use the User Objects DN.
289
290 =head2 role_search_options
291
292 This takes a hashref.  It will append it's values to the call to
293 L<Net::LDAP>'s "search" method during the user's role lookup.  See
294 L<Net::LDAP> for valid options.
295
296 Be careful not to specify:
297
298     filter
299     scope
300     base
301
302 As they are already taken care of by other configuration options.
303
304 =head1 METHODS
305
306 =head2 new
307
308 This method will populate
309 L<Catalyst::Plugin::Authentication/default_auth_store> with this object. 
310
311 =head1 AUTHORS
312
313 Adam Jacob <holoway@cpan.org>
314
315 Some parts stolen shamelessly and entirely from
316 L<Catalyst::Plugin::Authentication::Store::Htpasswd>.
317
318 Currently maintained by Peter Karman <karman@cpan.org>.
319
320 =head1 THANKS
321
322 To nothingmuch, ghenry, castaway and the rest of #catalyst for the help. :)
323
324 =head1 SEE ALSO
325
326 L<Catalyst::Authentication::Store::LDAP>,
327 L<Catalyst::Authentication::Store::LDAP::User>,
328 L<Catalyst::Authentication::Store::LDAP::Backend>,
329 L<Catalyst::Plugin::Authentication>, 
330 L<Net::LDAP>
331
332 =head1 COPYRIGHT & LICENSE
333
334 Copyright (c) 2005 the aforementioned authors. All rights
335 reserved. This program is free software; you can redistribute
336 it and/or modify it under the same terms as Perl itself.
337
338 =cut
339
340