6 Catalyst::Authentication::Store::LDAP::User
7 - A User object representing an LDAP object.
11 You should be creating these objects through L<Catalyst::Authentication::Store::LDAP::Backend>'s "get_user" method, or just letting $c->authenticate do
15 my ( $self, $c ) = @_;
17 id => $c->req->param(username),
18 password => $c->req->param(password)
20 $c->log->debug($c->user->username . "is really neat!");
23 If you access just $c->user in a scalar context, it will return the current
28 This wraps up an LDAP object and presents a simplified interface to it's
29 contents. It uses some AUTOLOAD magic to pass method calls it doesn't
30 understand through as simple read only accessors for the LDAP entries
33 It gets grumpy if you ask for an attribute via the AUTOLOAD mechanism
34 that it doesn't know about. Avoid that with using "has_attribute",
35 discussed in more detail below.
37 You can skip all that and just go straight to the L<Net::LDAP::Entry>
38 object through the "ldap_entry" method:
40 my $entry = $c->user->ldap_entry;
42 It also has support for Roles.
46 package Catalyst::Authentication::Store::LDAP::User;
47 use base qw( Catalyst::Authentication::User Class::Accessor::Fast );
51 use Scalar::Util qw/refaddr/;
53 our $VERSION = '1.014';
55 BEGIN { __PACKAGE__->mk_accessors(qw/user store/) }
57 use overload '""' => sub { shift->stringify }, fallback => 1;
59 my %_ldap_connection_passwords; # Store inside-out so that they don't show up
64 =head2 new($store, $user, $c)
66 Takes a L<Catalyst::Authentication::Store::LDAP::Backend> object
67 as $store, and the data structure returned by that class's "get_user"
68 method as $user. The final argument is an instance of your application,
69 which is passed along for those wanting to subclass User and perhaps use
70 models for fetching data.
72 Returns a L<Catalyst::Authentication::Store::LDAP::User> object.
77 my ( $class, $store, $user, $c ) = @_;
81 bless { store => $store, user => $user, }, $class;
86 Returns the results of the "stringify" method.
92 return $self->stringify;
97 Uses the "user_field" configuration option to determine what the "username"
98 of this object is, and returns it.
100 If you use the special value "dn" for user_field, it will return the DN
101 of the L<Net::LDAP::Entry> object.
107 my $userfield = $self->store->user_field;
108 $userfield = $$userfield[0] if ref $userfield eq 'ARRAY';
109 if ( $userfield eq "dn" ) {
110 my ($string) = $self->user->ldap_entry->dn;
114 my $val = $self->$userfield;
115 return ref($val) eq 'ARRAY' ? $val->[0] : $val;
119 =head2 supported_features
121 Returns hashref of features that this Authentication::User subclass supports.
125 sub supported_features {
127 password => { self_check => 1, },
129 roles => { self_check => 0, },
133 =head2 check_password($password)
135 Bind's to the directory as the DN of the internal L<Net::LDAP::Entry> object,
136 using the bind password supplied in $password. Returns 1 on a successful
142 my ( $self, $password ) = @_;
144 = $self->store->ldap_bind( undef, $self->ldap_entry->dn, $password,
146 if ( defined($ldap) ) {
147 if ($self->store->role_search_as_user) {
148 # FIXME - This can be removed and made to use the code below..
149 # Have to do the role lookup _now_, as this is the only time
150 # that we have the user's password/ldap bind..
153 # Stash a closure which can be used to retrieve the connection in the users context later.
154 $_ldap_connection_passwords{refaddr($self)} = $password;
164 Returns the results of L<Catalyst::Authentication::Store::LDAP::Backend>'s "lookup_roles" method, an array of roles that are valid for this user.
171 $self->{_roles} ||= [$self->store->lookup_roles($self, $ldap)];
172 return @{$self->{_roles}};
177 Returns the User object, stringified.
183 return $self->stringify;
188 Returns the raw ldap_entry.
194 return $self->user->{'ldap_entry'};
197 =head2 attributes($type)
199 Returns an array of attributes present for this user. If $type is "ashash",
200 it will return a hash with the attribute names as keys. (And the values of
201 those attributes as, well, the values of the hash)
206 my ( $self, $type ) = @_;
207 if ( $type eq "ashash" ) {
208 return $self->user->{'attributes'};
211 return keys( %{ $self->user->{'attributes'} } );
217 Returns the values for an attribute, or undef if that attribute is not present.
218 The safest way to get at an attribute.
223 my ( $self, $attribute ) = @_;
224 if ( !defined($attribute) ) {
225 Catalyst::Exception->throw(
226 "You must provide an attribute to has_attribute!");
228 if ( $attribute eq "dn" ) {
229 return $self->ldap_entry->dn;
231 elsif ( $attribute eq "username" ) {
232 return $self->user->{'attributes'}->{$self->store->user_field};
234 elsif ( exists( $self->user->{'attributes'}->{$attribute} ) ) {
235 return $self->user->{'attributes'}->{$attribute};
244 A simple wrapper around has_attribute() to satisfy the Catalyst::Authentication::User API.
248 sub get { return shift->has_attribute(@_) }
252 Satisfies the Catalyst::Authentication::User API and returns the contents of the user()
257 sub get_object { return shift->user }
259 =head2 ldap_connection
261 Re-binds to the auth store with the credentials of the user you logged in
262 as, and returns a L<Net::LDAP> object which you can use to do further queries.
266 sub ldap_connection {
268 $self->store->ldap_bind( undef, $self->ldap_entry->dn,
269 $_ldap_connection_passwords{refaddr($self)} );
272 =head2 AUTOLOADed methods
274 We automatically map the attributes of the underlying L<Net::LDAP::Entry>
275 object to read-only accessor methods. So, if you have an entry that looks
278 dn: cn=adam,ou=users,dc=yourcompany,dc=com
281 homeDirectory: /home/adam
285 mail: adam@yourcompany.com
289 objectClass: inetOrgPerson
290 objectClass: organizationalPerson
293 objectClass: posixAccount
297 $c->user->homedirectory
299 And you'll get the value of the "homeDirectory" attribute. Note that
300 all the AUTOLOADed methods are automatically lower-cased.
302 =head2 Special Keywords
304 The highly useful and common method "username" will map to the configured
305 value of user_field (uid by default.)
307 $c->user->username == $c->user->uid
313 # Don't leak passwords..
314 delete $_ldap_connection_passwords{refaddr($self)};
318 my ($self, $method) = @_;
320 return $self->SUPER::can($method) || do {
321 return unless $self->has_attribute($method);
322 return sub { $_[0]->has_attribute($method) };
329 ( my $method ) = ( our $AUTOLOAD =~ /([^:]+)$/ );
331 if ( $method eq "DESTROY" ) {
335 if ( my $attribute = $self->has_attribute($method) ) {
339 Catalyst::Exception->throw(
340 "No attribute $method for User " . $self->stringify );
350 Adam Jacob <holoway@cpan.org>
352 Some parts stolen shamelessly and entirely from
353 L<Catalyst::Plugin::Authentication::Store::Htpasswd>.
355 Currently maintained by Peter Karman <karman@cpan.org>.
359 To nothingmuch, ghenry, castaway and the rest of #catalyst for the help. :)
363 L<Catalyst::Authentication::Store::LDAP>, L<Catalyst::Authentication::Store::LDAP::Backend>, L<Catalyst::Plugin::Authentication>, L<Net::LDAP>
365 =head1 COPYRIGHT & LICENSE
367 Copyright (c) 2005 the aforementioned authors. All rights
368 reserved. This program is free software; you can redistribute
369 it and/or modify it under the same terms as Perl itself.