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