line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Catalyst::Authentication::Store::Tangram; |
2
|
1
|
|
|
1
|
|
874
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
32
|
|
3
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
30
|
|
4
|
1
|
|
|
1
|
|
12
|
use base qw/Class::Accessor::Fast/; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
924
|
|
5
|
1
|
|
|
1
|
|
4407
|
use Scalar::Util qw/blessed/; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
108
|
|
6
|
1
|
|
|
1
|
|
650
|
use Catalyst::Authentication::Store::Tangram::User; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use Catalyst::Utils (); |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '0.010'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
__PACKAGE__->mk_accessors(qw/ |
12
|
|
|
|
|
|
|
tangram_model |
13
|
|
|
|
|
|
|
tangram_user_class |
14
|
|
|
|
|
|
|
user_class |
15
|
|
|
|
|
|
|
storage_method |
16
|
|
|
|
|
|
|
use_roles |
17
|
|
|
|
|
|
|
role_relation |
18
|
|
|
|
|
|
|
role_name_field |
19
|
|
|
|
|
|
|
user_results_filter |
20
|
|
|
|
|
|
|
/); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub _get_storage { |
23
|
|
|
|
|
|
|
my ($self, $c) = @_; |
24
|
|
|
|
|
|
|
$c->model($self->tangram_model)->${\$self->storage_method}(); |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub new { |
28
|
|
|
|
|
|
|
my ($class, $config, $app, $realm) = @_; |
29
|
|
|
|
|
|
|
die("tangram_user_class key must be defined in config") |
30
|
|
|
|
|
|
|
unless $config->{tangram_user_class}; |
31
|
|
|
|
|
|
|
$config->{tangram_model} ||= 'Tangram'; |
32
|
|
|
|
|
|
|
$config->{storage_method} ||= 'storage'; |
33
|
|
|
|
|
|
|
$config->{user_class} ||= __PACKAGE__ . '::User'; |
34
|
|
|
|
|
|
|
$config->{use_roles} ||= 0; |
35
|
|
|
|
|
|
|
$config->{use_roles} = 0 if $config->{use_roles} =~ /false/i; |
36
|
|
|
|
|
|
|
die("No role_relation config option set, cannot use roles") |
37
|
|
|
|
|
|
|
if (!length($config->{role_relation}) && $config->{use_roles}); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Catalyst::Utils::ensure_class_loaded($config->{tangram_user_class}); |
40
|
|
|
|
|
|
|
Catalyst::Utils::ensure_class_loaded($config->{user_class}); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
bless { %$config }, $class; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub find_user { |
46
|
|
|
|
|
|
|
my ($self, $authinfo, $c) = @_; |
47
|
|
|
|
|
|
|
my $tangram_class = $self->tangram_user_class; |
48
|
|
|
|
|
|
|
my $storage = $self->_get_storage($c); |
49
|
|
|
|
|
|
|
my $remote = $storage->remote($tangram_class); |
50
|
|
|
|
|
|
|
my $filter; |
51
|
|
|
|
|
|
|
foreach my $key (keys %$authinfo) { |
52
|
|
|
|
|
|
|
if (defined $filter) { |
53
|
|
|
|
|
|
|
$filter = $filter & $remote->{$key} eq $authinfo->{$key}; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
else { |
56
|
|
|
|
|
|
|
$filter = $remote->{$key} eq $authinfo->{$key}; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
my @result = $storage->select($remote, filter => $filter); |
60
|
|
|
|
|
|
|
if ($self->user_results_filter) { |
61
|
|
|
|
|
|
|
@result = grep { $self->user_results_filter->($_) } @result; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
if (@result) { |
64
|
|
|
|
|
|
|
return $self->user_class->new($storage, $result[0], $self); |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
return; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub for_session { |
70
|
|
|
|
|
|
|
my ($self, $user) = @_; |
71
|
|
|
|
|
|
|
return $user->id; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub from_session { |
75
|
|
|
|
|
|
|
my ($self, $id) = @_; |
76
|
|
|
|
|
|
|
my $tangram_class = $self->tangram_user_class; |
77
|
|
|
|
|
|
|
my $tangram_user; |
78
|
|
|
|
|
|
|
eval { $tangram_user = $self->_get_storage->load($id) }; |
79
|
|
|
|
|
|
|
return if $@ or !$tangram_user; |
80
|
|
|
|
|
|
|
return $self->user_class->new($self->_get_storage, $tangram_user, $self); # FIXME - $c arg for get_storage. |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub user_supports { |
84
|
|
|
|
|
|
|
my $class = shift; |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
return Catalyst::Authentication::Store::Tangram::User->supports(@_); |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub lookup_roles { |
90
|
|
|
|
|
|
|
my ($self, $user_ob) = @_; |
91
|
|
|
|
|
|
|
return undef unless $self->use_roles; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
my @roles = $user_ob->${ \$self->role_relation() }(); |
94
|
|
|
|
|
|
|
@roles = @{ $roles[0] } # Deal with either a list or listref return |
95
|
|
|
|
|
|
|
if (1 == scalar(@roles) and 'ARRAY' eq ref($roles[0])); |
96
|
|
|
|
|
|
|
if ($self->role_name_field) { |
97
|
|
|
|
|
|
|
return map { $_->${\$self->role_name_field}() } @roles; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
else { |
100
|
|
|
|
|
|
|
return @roles; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
1; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head1 NAME |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
Catalyst::Authentication::Store::Tangram - A storage class for Catalyst authentication from a class stored in Tangram |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head1 SYNOPSIS |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
use Catalyst qw/ |
113
|
|
|
|
|
|
|
Authentication |
114
|
|
|
|
|
|
|
/; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
__PACKAGE__->config( authentication => { |
117
|
|
|
|
|
|
|
default_realm => 'members', |
118
|
|
|
|
|
|
|
realms => { |
119
|
|
|
|
|
|
|
members => { |
120
|
|
|
|
|
|
|
credential => { |
121
|
|
|
|
|
|
|
class => 'Password', |
122
|
|
|
|
|
|
|
password_field => 'password', |
123
|
|
|
|
|
|
|
password_type => 'clear' |
124
|
|
|
|
|
|
|
}, |
125
|
|
|
|
|
|
|
store => { |
126
|
|
|
|
|
|
|
class => 'Tangram', |
127
|
|
|
|
|
|
|
tangram_user_class => 'Users', |
128
|
|
|
|
|
|
|
tangram_model => 'Tangram', |
129
|
|
|
|
|
|
|
storage_method => 'storage', # $c->model('Tangram')->storage use_roles => 1, |
130
|
|
|
|
|
|
|
role_relation -> 'authority', |
131
|
|
|
|
|
|
|
role_name_field => 'name', |
132
|
|
|
|
|
|
|
}, |
133
|
|
|
|
|
|
|
}, |
134
|
|
|
|
|
|
|
}, |
135
|
|
|
|
|
|
|
}); |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Log a user in: |
138
|
|
|
|
|
|
|
sub login : Global { |
139
|
|
|
|
|
|
|
my ( $self, $c ) = @_; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
$c->authenticate({ |
142
|
|
|
|
|
|
|
email_address => $c->req->param('email_address'), |
143
|
|
|
|
|
|
|
password => $c->req->param('password'), |
144
|
|
|
|
|
|
|
}); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head1 DESCRIPTION |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
The Catalyst::Authentication::Store::Tangram class provides access to |
150
|
|
|
|
|
|
|
authentication information stored in a database via L<Tangram>. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head1 CONFIGURATION |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
The Tangram authentication store is activated by setting the store configuration |
155
|
|
|
|
|
|
|
class element to I<Tangram> as shown above. See the |
156
|
|
|
|
|
|
|
L<Catalyst::Plugin::Authentication> documentation for more details on |
157
|
|
|
|
|
|
|
configuring the store. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
The Tangram storage module has several configuration options |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
authentication => { |
162
|
|
|
|
|
|
|
default_realm => 'members', |
163
|
|
|
|
|
|
|
realms => { |
164
|
|
|
|
|
|
|
members => { |
165
|
|
|
|
|
|
|
credential => { |
166
|
|
|
|
|
|
|
# ... |
167
|
|
|
|
|
|
|
}, |
168
|
|
|
|
|
|
|
store => { |
169
|
|
|
|
|
|
|
class => 'Tangram', |
170
|
|
|
|
|
|
|
user_class => 'Users', |
171
|
|
|
|
|
|
|
tangram_model => 'Tangram', |
172
|
|
|
|
|
|
|
storage_method => 'storage', # $c->model('Tangram')->storage |
173
|
|
|
|
|
|
|
}, |
174
|
|
|
|
|
|
|
}, |
175
|
|
|
|
|
|
|
}, |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=over |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=item class |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
Class is part of the core L<Catalyst::Plugin::Authentication> module, it contains the class name of the store to be used. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=item tangram_user_class |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Contains the class name of the class persisted in your Tangram schema to use as |
187
|
|
|
|
|
|
|
the source for user information. |
188
|
|
|
|
|
|
|
This config item is B<REQUIRED>. This class name is used to get a Tangram remote |
189
|
|
|
|
|
|
|
object when constructing a search for your user when first authenticating, and |
190
|
|
|
|
|
|
|
also this is the class which the ->load method is called on to restore the user |
191
|
|
|
|
|
|
|
from a session. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=item tangram_model |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Contains the class name (as passed to $c->model()) of the Tangram model to use |
196
|
|
|
|
|
|
|
as the source for user information. |
197
|
|
|
|
|
|
|
This config item is REQUIRED. The I<storage_method> method will be invoked on |
198
|
|
|
|
|
|
|
this class to get the L<Tangram::Storage> instance to restore the user from. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=item storage_method |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
Contains the method to call on the I<tangram_model> to retrieve the instance of |
203
|
|
|
|
|
|
|
L<Tangram::Storage> which users are looked up from. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=item user_class |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Contains the class which the user object is blessed into. This class is usually |
208
|
|
|
|
|
|
|
L<Catalyst::Authentication::Store::Tangram::User>, but you can sub-class that |
209
|
|
|
|
|
|
|
class and have your subclass used instead by setting this configuration |
210
|
|
|
|
|
|
|
parameter. You will not need to use this setting unless you are doing unusual |
211
|
|
|
|
|
|
|
things with the user class. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=item use_roles |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Activates role support if set to '1' |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=item role_relation |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
The name of the method to call on your Tangram user object to retrieve an array |
220
|
|
|
|
|
|
|
of roles for this user. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
This field may be a L<Tangram::Type::Array::FromMany>, or a |
223
|
|
|
|
|
|
|
L<Tangram::Type::Array::FromOne> (in which case you will also need to use |
224
|
|
|
|
|
|
|
I<role_name_field>), or it may be your own function which returns a list of |
225
|
|
|
|
|
|
|
roles.. |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=item role_name_field |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
The name of the field to retrieve the name of the role from on the Tangram |
230
|
|
|
|
|
|
|
class representing roles. Note that if this configuration parameter isn't |
231
|
|
|
|
|
|
|
supplied, then the list returned by the method call to role_relation will be |
232
|
|
|
|
|
|
|
used directly. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=back |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=head1 METHODS |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=head2 new ( $config, $app, $realm ) |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Simple constructor, returns a blessed reference to the store object instance. |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=head2 find_user ( $authinfo, $c ) |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
I<$auth_info> is expected to be a hash with the keys being field names on your |
245
|
|
|
|
|
|
|
Tangram user object, and the values being what those fields should be matched |
246
|
|
|
|
|
|
|
against. A tangram select will be built from the supplied authentication |
247
|
|
|
|
|
|
|
information, and this select is used to retrieve the user from Tangram. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=head2 for_session ( $c, $user ) |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
This method returns the Tangram ID for the user, as that is all that is |
252
|
|
|
|
|
|
|
necessary to be persisted in the session to restore the user. |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head2 from_session ( $c, $frozenuser ) |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
This method is called whenever a user is being restored from the session. |
257
|
|
|
|
|
|
|
$frozenuser contains the Tangram ID of the user to restore. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=head2 user_supports |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Delegates to the L<Catalyst::Authentication::Store::Tangram::User->supports|Catalyst::Authentication::Store::Tangram::User#supports> method. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 user_results_filter |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
This is a Perl CODE ref that can be used to filter out multiple results |
266
|
|
|
|
|
|
|
from your Tangram query. In theory, your Tangram query should only return one |
267
|
|
|
|
|
|
|
result and find_user() will throw an exception if it encounters more than one |
268
|
|
|
|
|
|
|
result. However, if you have, for whatever reason, a legitimate reason for |
269
|
|
|
|
|
|
|
returning multiple search results from your Tangram query, use |
270
|
|
|
|
|
|
|
C<user_results_filter> to filter out the Tangram entries you do not want |
271
|
|
|
|
|
|
|
considered. Your CODE ref should expect a single argument, an instance of |
272
|
|
|
|
|
|
|
your Tangram user object, and it should return exactly one value, which is |
273
|
|
|
|
|
|
|
used as a true/false. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
Example: |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
user_results_filter => sub { |
278
|
|
|
|
|
|
|
my $obj = shift; |
279
|
|
|
|
|
|
|
$obj->permissions =~ /catalystapp/ ? 1 : 0 |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Note: The above example is B<not> a best practice method for storing roles |
283
|
|
|
|
|
|
|
against a user, you really want a L<Tangram::Type::Array::FromMany> |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=head2 lookup_roles |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Returns a list of roles that this user is authorised for. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
Calls the method specified by the role_relation configuration key, and expects |
290
|
|
|
|
|
|
|
either a list, or a reference to an array of roles to be returned. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Note that this method will call the I<role_relation> method on the |
293
|
|
|
|
|
|
|
I<user_class>, not on the I<tangram_user_class> directly. This can therefore be |
294
|
|
|
|
|
|
|
used to add a custom role lookup without changing your underlying model class |
295
|
|
|
|
|
|
|
lookup by sub-classing I<Catalyst::Authentication::Storage::Tangram::User>, and |
296
|
|
|
|
|
|
|
adding the custom lookup there (then setting I<role_relation> and I<user_class> |
297
|
|
|
|
|
|
|
appropriately. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head1 SEE ALSO |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
L<Catalyst::Authentication::Store::Tangram::User>, |
302
|
|
|
|
|
|
|
L<Catalyst::Plugin::Authentication>, |
303
|
|
|
|
|
|
|
L<Catalyst::Authentication::Store> |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=head1 AUTHOR |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
Tomas Doran, <bobtfish at bobtfish dot net> |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
With thanks to state51, my employer, for giving me the time to work on this. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Various ideas stolen from other Catalyst::Authentication modules by other |
312
|
|
|
|
|
|
|
authors. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=head1 BUGS |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
All complex software has bugs, and I'm sure that this module is no exception. |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Please report bugs through the rt.cpan.org bug tracker. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head1 COPYRIGHT |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Copyright (c) 2008, state51. Some rights reserved. |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head1 LICENSE |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
This module is free software; you can use, redistribute, and modify it |
327
|
|
|
|
|
|
|
under the same terms as Perl 5.8.x. |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=cut |
330
|
|
|
|
|
|
|
|