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