Convert everything not actually a plugin to now live in the
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Authentication / Realm.pm
1 package Catalyst::Authentication::Realm;
2
3 use strict;
4 use warnings;
5
6 use base qw/Class::Accessor::Fast/;
7
8 BEGIN {
9     __PACKAGE__->mk_accessors(qw/store credential name config/);
10 };
11
12 sub new {
13     my ($class, $realmname, $config, $app) = @_;
14
15     my $self = { config => $config };
16     bless $self, $class;
17     
18     $self->name($realmname);
19     
20     $app->log->debug("Setting up auth realm $realmname") if $app->debug;
21
22     # use the Null store as a default
23     if( ! exists $config->{store}{class} ) {
24         $config->{store}{class} = '+Catalyst::Authentication::Store::Null';
25         $app->log->debug( qq(No Store specified for realm "$realmname", using the Null store.) );
26     } 
27     my $storeclass = $config->{'store'}{'class'};
28     
29     ## follow catalyst class naming - a + prefix means a fully qualified class, otherwise it's
30     ## taken to mean C::P::A::Store::(specifiedclass)
31     if ($storeclass !~ /^\+(.*)$/ ) {
32         $storeclass = "Catalyst::Authentication::Store::${storeclass}";
33     } else {
34         $storeclass = $1;
35     }
36
37     # a little niceness - since most systems seem to use the password credential class, 
38     # if no credential class is specified we use password.
39     $config->{credential}{class} ||= '+Catalyst::Authentication::Credential::Password';
40
41     my $credentialclass = $config->{'credential'}{'class'};
42     
43     ## follow catalyst class naming - a + prefix means a fully qualified class, otherwise it's
44     ## taken to mean C::A::Credential::(specifiedclass)
45     if ($credentialclass !~ /^\+(.*)$/ ) {
46         $credentialclass = "Catalyst::Authentication::Credential::${credentialclass}";
47     } else {
48         $credentialclass = $1;
49     }
50     
51     # if we made it here - we have what we need to load the classes
52     
53     ### BACKWARDS COMPATIBILITY - DEPRECATION WARNING:  
54     ###  we must eval the ensure_class_loaded - because we might need to try the old-style
55     ###  ::Plugin:: module naming if the standard method fails. 
56     
57     eval {
58         Catalyst::Utils::ensure_class_loaded( $credentialclass );
59     };
60     
61     if ($@) {
62         $app->log->warn( qq(Credential class "$credentialclass" not found, trying deprecated ::Plugin:: style naming. ) );
63         $credentialclass =~ s/Catalyst::Authentication/Catalyst::Plugin::Authentication/;
64         Catalyst::Utils::ensure_class_loaded( $credentialclass );
65     }
66     
67     eval {
68         Catalyst::Utils::ensure_class_loaded( $storeclass );
69     };
70     
71     if ($@) {
72         $app->log->warn( qq(Store class "$storeclass" not found, trying deprecated ::Plugin:: style naming. ) );
73         $storeclass =~ s/Catalyst::Authentication/Catalyst::Plugin::Authentication/;
74         Catalyst::Utils::ensure_class_loaded( $storeclass );
75     }
76     
77     # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms 
78     # of get_user and add it to the class.  this is because the auth routines use find_user, 
79     # and rely on it being present. (this avoids per-call checks)
80     if (!$storeclass->can('find_user')) {
81         no strict 'refs';
82         *{"${storeclass}::find_user"} = sub {
83                                                 my ($self, $info) = @_;
84                                                 my @rest = @{$info->{rest}} if exists($info->{rest});
85                                                 $self->get_user($info->{id}, @rest);
86                                             };
87     }
88     
89     ## a little cruft to stay compatible with some poorly written stores / credentials
90     ## we'll remove this soon.
91     if ($storeclass->can('new')) {
92         $self->store($storeclass->new($config->{'store'}, $app, $self));
93     } else {
94         $app->log->error("THIS IS DEPRECATED: $storeclass has no new() method - Attempting to use uninstantiated");
95         $self->store($storeclass);
96     }
97     if ($credentialclass->can('new')) {
98         $self->credential($credentialclass->new($config->{'credential'}, $app, $self));
99     } else {
100         $app->log->error("THIS IS DEPRECATED: $credentialclass has no new() method - Attempting to use uninstantiated");
101         $self->credential($credentialclass);
102     }
103     
104     return $self;
105 }
106
107 sub find_user {
108     my ( $self, $authinfo, $c ) = @_;
109
110     my $res = $self->store->find_user($authinfo, $c);
111     
112     if (!$res) {
113       if ($self->config->{'auto_create_user'} && $self->store->can('auto_create_user') ) {
114           $res = $self->store->auto_create_user($authinfo, $c);
115       }
116     } elsif ($self->config->{'auto_update_user'} && $self->store->can('auto_update_user')) {
117         $res = $self->store->auto_update_user($authinfo, $c, $res);
118     } 
119     
120     return $res;
121 }
122
123 sub authenticate {
124      my ($self, $c, $authinfo) = @_;
125
126      my $user = $self->credential->authenticate($c, $self, $authinfo);
127      if (ref($user)) {
128          $c->set_authenticated($user, $self->name);
129          return $user;
130      } else {
131          return undef;
132      }
133 }
134
135 sub save_user_in_session {
136     my ( $self, $c, $user ) = @_;
137
138     $c->session->{__user_realm} = $self->name;
139     
140     # we want to ask the store for a user prepared for the session.
141     # but older modules split this functionality between the user and the
142     # store.  We try the store first.  If not, we use the old method.
143     if ($self->store->can('for_session')) {
144         $c->session->{__user} = $self->store->for_session($c, $user);
145     } else {
146         $c->session->{__user} = $user->for_session;
147     }
148 }
149
150 sub from_session {
151     my ($self, $c, $frozen_user) = @_;
152     
153     return $self->store->from_session($c, $frozen_user);
154 }
155
156
157 __PACKAGE__;
158
159 __END__
160
161 =pod
162
163 =head1 NAME
164
165 Catalyst::Authentication::Realm - Base class for realm objects.
166
167 =head1 DESCRIPTION
168
169 =head1 CONFIGURATION
170
171 =over 4
172
173 =item class
174
175 By default this class is the default realm class. You can specify a custom
176 realm class with this config parameter.
177
178 =item auto_create_user
179
180 Set this to true if you wish this realm to auto-create user accounts when the
181 user doesn't exist (most useful for remote authentication schemes).
182
183 =item auto_update_user
184
185 Set this to true if you wish this realm to auto-update user accounts after
186 authentication (most useful for remote authentication schemes).
187
188 =back
189
190 =head1 METHODS
191
192 =head2 new( )
193
194 Instantiantes this realm, plus the specified store and credential classes.
195
196 =head2 store( )
197
198 Holds an instance of the store object for this realm.
199
200 =head2 credential( )
201
202 Holds an instance of the credential object for this realm.
203
204 =head2 find_user( )
205
206 Delegates to the store object. Will also re-delegate auto_create_user and
207 auto_update_user at this time, if necessary.
208
209 =head2 authenticate( )
210
211 Delegates to the credential objects and sets the authenticated user on success.
212
213 =head2 save_user_in_session( )
214
215 Delegates to the store object.
216
217 =head2 from_session( )
218
219 Delegates to the store object.
220
221 =cut
222