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