pod update (RT #36062). VERSION fix.
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Authentication / Realm.pm
CommitLineData
e0499ed6 1package Catalyst::Authentication::Realm;
810966b5 2
3use strict;
4use warnings;
2c7d23af 5
810966b5 6use base qw/Class::Accessor::Fast/;
7
8BEGIN {
9 __PACKAGE__->mk_accessors(qw/store credential name config/);
10};
11
9a37ffba 12## Add use_session config item to realm.
13
810966b5 14sub new {
15 my ($class, $realmname, $config, $app) = @_;
16
17 my $self = { config => $config };
18 bless $self, $class;
19
20 $self->name($realmname);
21
9a37ffba 22 if (!exists($self->config->{'use_session'})) {
23 if (exists($app->config->{'Plugin::Authentication'}{'use_session'})) {
24 $self->config->{'use_session'} = $app->config->{'Plugin::Authentication'}{'use_session'};
25 } else {
26 $self->config->{'use_session'} = 1;
27 }
28 }
29 print STDERR "use session is " . $self->config->{'use_session'} . "\n";
810966b5 30 $app->log->debug("Setting up auth realm $realmname") if $app->debug;
8513d51b 31
32 # use the Null store as a default
33 if( ! exists $config->{store}{class} ) {
0f673ca7 34 $config->{store}{class} = '+Catalyst::Authentication::Store::Null';
8513d51b 35 $app->log->debug( qq(No Store specified for realm "$realmname", using the Null store.) );
810966b5 36 }
810966b5 37 my $storeclass = $config->{'store'}{'class'};
38
39 ## follow catalyst class naming - a + prefix means a fully qualified class, otherwise it's
40 ## taken to mean C::P::A::Store::(specifiedclass)
41 if ($storeclass !~ /^\+(.*)$/ ) {
0f673ca7 42 $storeclass = "Catalyst::Authentication::Store::${storeclass}";
810966b5 43 } else {
44 $storeclass = $1;
45 }
810966b5 46
47 # a little niceness - since most systems seem to use the password credential class,
48 # if no credential class is specified we use password.
0f673ca7 49 $config->{credential}{class} ||= '+Catalyst::Authentication::Credential::Password';
810966b5 50
51 my $credentialclass = $config->{'credential'}{'class'};
52
53 ## follow catalyst class naming - a + prefix means a fully qualified class, otherwise it's
0f673ca7 54 ## taken to mean C::A::Credential::(specifiedclass)
810966b5 55 if ($credentialclass !~ /^\+(.*)$/ ) {
0f673ca7 56 $credentialclass = "Catalyst::Authentication::Credential::${credentialclass}";
810966b5 57 } else {
58 $credentialclass = $1;
59 }
60
0f673ca7 61 # if we made it here - we have what we need to load the classes
62
63 ### BACKWARDS COMPATIBILITY - DEPRECATION WARNING:
64 ### we must eval the ensure_class_loaded - because we might need to try the old-style
65 ### ::Plugin:: module naming if the standard method fails.
66
71486cb0 67 ## Note to self - catch second exception and bitch in detail?
68
0f673ca7 69 eval {
70 Catalyst::Utils::ensure_class_loaded( $credentialclass );
71 };
72
73 if ($@) {
74 $app->log->warn( qq(Credential class "$credentialclass" not found, trying deprecated ::Plugin:: style naming. ) );
71486cb0 75 my $origcredentialclass = $credentialclass;
0f673ca7 76 $credentialclass =~ s/Catalyst::Authentication/Catalyst::Plugin::Authentication/;
71486cb0 77
78 eval { Catalyst::Utils::ensure_class_loaded( $credentialclass ); };
79 if ($@) {
80 Carp::croak "Unable to load credential class, " . $origcredentialclass . " OR " . $credentialclass .
81 " in realm " . $self->name;
82 }
0f673ca7 83 }
84
85 eval {
86 Catalyst::Utils::ensure_class_loaded( $storeclass );
87 };
88
89 if ($@) {
90 $app->log->warn( qq(Store class "$storeclass" not found, trying deprecated ::Plugin:: style naming. ) );
71486cb0 91 my $origstoreclass = $storeclass;
0f673ca7 92 $storeclass =~ s/Catalyst::Authentication/Catalyst::Plugin::Authentication/;
71486cb0 93 eval { Catalyst::Utils::ensure_class_loaded( $storeclass ); };
94 if ($@) {
95 Carp::croak "Unable to load store class, " . $origstoreclass . " OR " . $storeclass .
96 " in realm " . $self->name;
97 }
0f673ca7 98 }
810966b5 99
100 # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms
101 # of get_user and add it to the class. this is because the auth routines use find_user,
102 # and rely on it being present. (this avoids per-call checks)
103 if (!$storeclass->can('find_user')) {
104 no strict 'refs';
105 *{"${storeclass}::find_user"} = sub {
106 my ($self, $info) = @_;
107 my @rest = @{$info->{rest}} if exists($info->{rest});
108 $self->get_user($info->{id}, @rest);
109 };
110 }
111
112 ## a little cruft to stay compatible with some poorly written stores / credentials
113 ## we'll remove this soon.
114 if ($storeclass->can('new')) {
115 $self->store($storeclass->new($config->{'store'}, $app, $self));
116 } else {
117 $app->log->error("THIS IS DEPRECATED: $storeclass has no new() method - Attempting to use uninstantiated");
118 $self->store($storeclass);
119 }
120 if ($credentialclass->can('new')) {
121 $self->credential($credentialclass->new($config->{'credential'}, $app, $self));
122 } else {
123 $app->log->error("THIS IS DEPRECATED: $credentialclass has no new() method - Attempting to use uninstantiated");
124 $self->credential($credentialclass);
125 }
126
127 return $self;
128}
129
130sub find_user {
131 my ( $self, $authinfo, $c ) = @_;
132
133 my $res = $self->store->find_user($authinfo, $c);
134
4437366d 135 if (!$res) {
9b840849 136 if ($self->config->{'auto_create_user'} && $self->store->can('auto_create_user') ) {
137 $res = $self->store->auto_create_user($authinfo, $c);
4437366d 138 }
9b840849 139 } elsif ($self->config->{'auto_update_user'} && $self->store->can('auto_update_user')) {
140 $res = $self->store->auto_update_user($authinfo, $c, $res);
4437366d 141 }
810966b5 142
143 return $res;
144}
145
146sub authenticate {
147 my ($self, $c, $authinfo) = @_;
148
149 my $user = $self->credential->authenticate($c, $self, $authinfo);
150 if (ref($user)) {
151 $c->set_authenticated($user, $self->name);
152 return $user;
153 } else {
154 return undef;
155 }
156}
157
71486cb0 158sub user_is_restorable {
159 my ($self, $c) = @_;
160
161 return unless
162 $c->isa("Catalyst::Plugin::Session")
9a37ffba 163 and $self->config->{'use_session'}
71486cb0 164 and $c->session_is_valid;
810966b5 165
71486cb0 166 return $c->session->{__user};
167}
168
169sub restore_user {
170 my ($self, $c, $frozen_user) = @_;
810966b5 171
71486cb0 172 $frozen_user ||= $self->user_is_restorable($c);
173 return unless defined($frozen_user);
174
175 $c->_user( my $user = $self->from_session( $c, $frozen_user ) );
176
177 # this sets the realm the user originated in.
178 $user->auth_realm($self->name);
179
180 return $user;
181}
182
183sub persist_user {
184 my ($self, $c, $user) = @_;
185
186 if (
187 $c->isa("Catalyst::Plugin::Session")
9a37ffba 188 and $self->config->{'use_session'}
71486cb0 189 and $user->supports("session")
190 ) {
191 $c->session->{__user_realm} = $self->name;
192
193 # we want to ask the store for a user prepared for the session.
194 # but older modules split this functionality between the user and the
195 # store. We try the store first. If not, we use the old method.
196 if ($self->store->can('for_session')) {
197 $c->session->{__user} = $self->store->for_session($c, $user);
198 } else {
199 $c->session->{__user} = $user->for_session;
200 }
810966b5 201 }
71486cb0 202 return $user;
203}
204
205sub remove_persisted_user {
206 my ($self, $c) = @_;
207
208 if (
209 $c->isa("Catalyst::Plugin::Session")
9a37ffba 210 and $self->config->{'use_session'}
71486cb0 211 and $c->session_is_valid
212 ) {
213 delete @{ $c->session }{qw/__user __user_realm/};
214 }
215}
216
217## backwards compatibility - I don't think many people wrote realms since they
218## have only existed for a short time - but just in case.
219sub save_user_in_session {
220 my ( $self, $c, $user ) = @_;
221
222 return $self->persist_user($c, $user);
810966b5 223}
224
225sub from_session {
226 my ($self, $c, $frozen_user) = @_;
227
228 return $self->store->from_session($c, $frozen_user);
229}
230
231
232__PACKAGE__;
233
b72f8c2e 234__END__
2c7d23af 235
236=pod
237
238=head1 NAME
239
e0499ed6 240Catalyst::Authentication::Realm - Base class for realm objects.
2c7d23af 241
242=head1 DESCRIPTION
243
d2ca09b8 244=head1 CONFIGURATION
2c7d23af 245
246=over 4
247
d2ca09b8 248=item class
249
71486cb0 250By default this class is used by
251L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> for all
252realms. The class parameter allows you to choose a different class to use for
253this realm. Creating a new Realm class can allow for authentication methods
254that fall outside the normal credential/store methodology.
deebc899 255
d2ca09b8 256=item auto_create_user
2c7d23af 257
deebc899 258Set this to true if you wish this realm to auto-create user accounts when the
259user doesn't exist (most useful for remote authentication schemes).
260
d2ca09b8 261=item auto_update_user
2c7d23af 262
deebc899 263Set this to true if you wish this realm to auto-update user accounts after
264authentication (most useful for remote authentication schemes).
265
d2ca09b8 266=back
267
268=head1 METHODS
2c7d23af 269
71486cb0 270=head2 new( $realmname, $config, $app )
2c7d23af 271
deebc899 272Instantiantes this realm, plus the specified store and credential classes.
273
274=head2 store( )
275
71486cb0 276Returns an instance of the store object for this realm.
deebc899 277
278=head2 credential( )
279
71486cb0 280Returns an instance of the credential object for this realm.
deebc899 281
71486cb0 282=head2 find_user( $authinfo, $c )
d2ca09b8 283
71486cb0 284Retrieves the user given the authentication information provided. This
285is most often called from the credential. The default realm class simply
286delegates this call the store object. If enabled, auto-creation and
287auto-updating of users is also handled here.
deebc899 288
71486cb0 289=head2 authenticate( $c, $authinfo)
d2ca09b8 290
71486cb0 291Performs the authentication process for the current realm. The default
292realm class simply delegates this to the credential and sets
293the authenticated user on success. Returns the authenticated user object;
deebc899 294
84ebeae8 295=head2 save_user_in_session($c, $user)
d2ca09b8 296
71486cb0 297Used to save the user in a session. Saves $user in the current session,
298marked as originating in the current realm. Calls $store->for_session() by
299default. If for_session is not available in the store class, will attempt
300to call $user->for_session().
deebc899 301
71486cb0 302=head2 from_session($c, $frozenuser )
2c7d23af 303
71486cb0 304Triggers restoring of the user from data in the session. The default realm
305class simply delegates the call to $store->from_session($c, $frozenuser);
deebc899 306
2c7d23af 307=cut
308