fff4bea97236d59fe73d901c57ce47b13600b27f
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / 05_Authentication.pod
1 =head1 NAME
2
3 Catalyst::Manual::Tutorial::05_Authentication - Catalyst Tutorial - Chapter 5: Authentication
4
5
6 =head1 OVERVIEW
7
8 This is B<Chapter 5 of 10> for the Catalyst tutorial.
9
10 L<Tutorial Overview|Catalyst::Manual::Tutorial>
11
12 =over 4
13
14 =item 1
15
16 L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
17
18 =item 2
19
20 L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
21
22 =item 3
23
24 L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
25
26 =item 4
27
28 L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
29
30 =item 5
31
32 B<05_Authentication>
33
34 =item 6
35
36 L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
37
38 =item 7
39
40 L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
41
42 =item 8
43
44 L<Testing|Catalyst::Manual::Tutorial::08_Testing>
45
46 =item 9
47
48 L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
49
50 =item 10
51
52 L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
53
54 =back
55
56
57 =head1 DESCRIPTION
58
59 Now that we finally have a simple yet functional application, we can
60 focus on providing authentication (with authorization coming next in
61 Chapter 6).
62
63 This chapter of the tutorial is divided into two main sections: 1) basic,
64 cleartext authentication and 2) hash-based authentication.
65
66 You can checkout the source code for this example from the catalyst
67 subversion repository as per the instructions in
68 L<Catalyst::Manual::Tutorial::01_Intro|Catalyst::Manual::Tutorial::01_Intro>.
69
70
71 =head1 BASIC AUTHENTICATION
72
73 This section explores how to add authentication logic to a Catalyst
74 application.
75
76
77 =head2 Add Users and Roles to the Database
78
79 First, we add both user and role information to the database (we will
80 add the role information here although it will not be used until the
81 authorization section, Chapter 6).  Create a new SQL script file by opening
82 C<myapp02.sql> in your editor and insert:
83
84     PRAGMA foreign_keys = ON;
85     --
86     -- Add user and role tables, along with a many-to-many join table
87     --
88     CREATE TABLE user (
89             id            INTEGER PRIMARY KEY,
90             username      TEXT,
91             password      TEXT,
92             email_address TEXT,
93             first_name    TEXT,
94             last_name     TEXT,
95             active        INTEGER
96     );
97     CREATE TABLE role (
98             id   INTEGER PRIMARY KEY,
99             role TEXT
100     );
101     CREATE TABLE user_role (
102             user_id INTEGER REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE,
103             role_id INTEGER REFERENCES role(id) ON DELETE CASCADE ON UPDATE CASCADE,
104             PRIMARY KEY (user_id, role_id)
105     );
106     --
107     -- Load up some initial test data
108     --
109     INSERT INTO user VALUES (1, 'test01', 'mypass', 't01@na.com', 'Joe',  'Blow', 1);
110     INSERT INTO user VALUES (2, 'test02', 'mypass', 't02@na.com', 'Jane', 'Doe',  1);
111     INSERT INTO user VALUES (3, 'test03', 'mypass', 't03@na.com', 'No',   'Go',   0);
112     INSERT INTO role VALUES (1, 'user');
113     INSERT INTO role VALUES (2, 'admin');
114     INSERT INTO user_role VALUES (1, 1);
115     INSERT INTO user_role VALUES (1, 2);
116     INSERT INTO user_role VALUES (2, 1);
117     INSERT INTO user_role VALUES (3, 1);
118
119 Then load this into the C<myapp.db> database with the following command:
120
121     $ sqlite3 myapp.db < myapp02.sql
122
123
124 =head2 Add User and Role Information to DBIC Schema
125
126 Although we could manually edit the DBIC schema information to include
127 the new tables added in the previous step, let's use the C<create=static>
128 option on the DBIC model helper to do most of the work for us:
129
130     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
131         create=static components=TimeStamp dbi:SQLite:myapp.db \
132         on_connect_do="PRAGMA foreign_keys = ON"
133      exists "/root/dev/MyApp/script/../lib/MyApp/Model"
134      exists "/root/dev/MyApp/script/../t"
135     Dumping manual schema for MyApp::Schema to directory /root/dev/MyApp/script/../lib ...
136     Schema dump completed.
137      exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
138     $
139     $ ls lib/MyApp/Schema/Result
140     Author.pm  BookAuthor.pm  Book.pm  Role.pm  User.pm  UserRole.pm
141
142 Notice how the helper has added three new table-specific result source
143 files to the C<lib/MyApp/Schema/Result> directory.  And, more
144 importantly, even if there were changes to the existing result source
145 files, those changes would have only been written above the C<# DO NOT
146 MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-edited
147 enhancements would have been preserved.
148
149 Speaking of "hand-editted enhancements," we should now add
150 relationship information to the three new result source files.  Edit
151 each of these files and add the following information between the C<#
152 DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>:
153
154 C<lib/MyApp/Schema/Result/User.pm>:
155
156    
157     # many_to_many():
158     #   args:
159     #     1) Name of relationship, DBIC will create accessor with this name
160     #     2) Name of has_many() relationship this many_to_many() is shortcut for
161     #     3) Name of belongs_to() relationship in model class of has_many() above
162     #   You must already have the has_many() defined to use a many_to_many().
163     __PACKAGE__->many_to_many(roles => 'user_roles', 'role');
164
165
166 The code for this update is obviously very similar to the edits we made to the
167 C<Book> and C<Author> classes created in Chapter 3.
168
169 Note that we do not need to make any change to the
170 C<lib/MyApp/Schema.pm> schema file.  It simply tells DBIC to load all
171 of the Result Class and ResultSet Class files it finds in below the
172 C<lib/MyApp/Schema> directory, so it will automatically pick up our
173 new table information.
174
175
176 =head2 Sanity-Check Reload of Development Server
177
178 We aren't ready to try out the authentication just yet; we only want
179 to do a quick check to be sure our model loads correctly.  Press
180 C<Ctrl-C> to kill the previous server instance (if it's still running)
181 and restart it:
182
183     $ script/myapp_server.pl
184
185 Look for the three new model objects in the startup debug output:
186
187     ...
188      .-------------------------------------------------------------------+----------.
189     | Class                                                             | Type     |
190     +-------------------------------------------------------------------+----------+
191     | MyApp::Controller::Books                                          | instance |
192     | MyApp::Controller::Root                                           | instance |
193     | MyApp::Model::DB                                                  | instance |
194     | MyApp::Model::DB::Author                                          | class    |
195     | MyApp::Model::DB::Book                                            | class    |
196     | MyApp::Model::DB::BookAuthor                                      | class    |
197     | MyApp::Model::DB::Role                                            | class    |
198     | MyApp::Model::DB::User                                            | class    |
199     | MyApp::Model::DB::UserRole                                        | class    |
200     | MyApp::View::TT                                                   | instance |
201     '-------------------------------------------------------------------+----------'
202     ...
203
204 Again, notice that your "Result Class" classes have been "re-loaded"
205 by Catalyst under C<MyApp::Model>.
206
207
208 =head2 Include Authentication and Session Plugins
209
210 Edit C<lib/MyApp.pm> and update it as follows (everything below
211 C<StackTrace> is new):
212
213     # Load plugins
214     use Catalyst qw/
215                     -Debug
216                     ConfigLoader
217                     Static::Simple
218     
219                     StackTrace
220     
221                     Authentication
222     
223                     Session
224                     Session::Store::FastMmap
225                     Session::State::Cookie
226                     /;
227
228 B<Note:> As discussed in MoreCatalystBasics, different versions of
229 C<Catalyst::Devel> have used a variety of methods to load the plugins,
230 but we are going to use the current Catalyst 5.8X practice of putting
231 them on the C<use Catalyst> line.
232
233 The C<Authentication> plugin supports Authentication while the
234 C<Session> plugins are required to maintain state across multiple HTTP
235 requests.
236
237 Note that the only required Authentication class is the main one. This
238 is a change that occurred in version 0.09999_01 of the
239 C<Authentication> plugin. You B<do not need> to specify a particular
240 Authentication::Store or Authentication::Credential plugin. Instead,
241 indicate the Store and Credential you want to use in your application
242 configuration (see below).
243
244 Make sure you include the additional plugins as new dependencies in
245 the Makefile.PL file something like this:
246
247     requires 'Catalyst::Plugin::Authentication';
248     requires 'Catalyst::Plugin::Session';
249     requires 'Catalyst::Plugin::Session::Store::FastMmap';
250     requires 'Catalyst::Plugin::Session::State::Cookie';
251
252 Note that there are several options for
253 L<Session::Store|Catalyst::Plugin::Session::Store>
254
255 (L<Session::Store::Memcached|Catalyst::Plugin::Session::Store::Memcached> or
256 L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap> is
257 generally a good choice if you are on Unix; try
258 L<Session::Store::File|Catalyst::Plugin::Session::Store::File> if you
259 are on Win32) -- consult
260 L<Session::Store|Catalyst::Plugin::Session::Store> and its subclasses
261 for additional information and options (for example to use a database-
262 backed session store).
263
264
265 =head2 Configure Authentication
266
267 There are a variety of ways to provide configuration information to
268 L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>.
269 Here we will use 
270 L<Catalyst::Authentication::Realm::SimpleDB|Catalyst::Authentication::Realm::SimpleDB>
271 because it automatically sets a reasonable set of defaults for us. Open 
272 C<lib/MyApp.pm> and place the following text above the call to
273 C<__PACKAGE__-E<gt>setup();>:
274
275     # Configure SimpleDB Authentication
276     __PACKAGE__->config->{'Plugin::Authentication'} = {
277             default => {
278                 class           => 'SimpleDB',
279                 user_model      => 'DB::User',
280                 password_type   => 'clear',
281             },
282         };
283
284 We could have placed this configuration in C<myapp.conf>, but placing 
285 it in C<lib/MyApp.pm> is probably a better place since it's not likely 
286 something that users of your application will want to change during 
287 deployment (or you could use a mixture: leave C<class> and 
288 C<user_model> defined in C<lib/MyApp.pm> as we show above, but place 
289 C<password_type> in C<myapp.conf> to allow the type of password to be 
290 easily modified during deployment).  We will stick with putting 
291 all of the authentication-related configuration in C<lib/MyApp.pm> 
292 for the tutorial, but if you wish to use C<myapp.conf>, just convert
293 to the following code:
294
295     <Plugin::Authentication>
296         <default>
297             password_type clear
298             user_model    DB::User
299             class         SimpleDB
300         </default>
301     </Plugin::Authentication>
302
303 B<TIP:> Here is a short script that will dump the contents of 
304 C<MyApp->config> to L<Config::General|Config::General> format in
305 C<myapp.conf>:
306
307     $ perl -Ilib -e 'use MyApp; use Config::General; 
308         Config::General->new->save_file("myapp.conf", MyApp->config);'
309
310 B<NOTE:> Because we are using SimpleDB along with a database layout 
311 that complies with its default assumptions, we don't need to specify
312 the names of the columns where our username and password information
313 is stored (hence, the "Simple" part of "SimpleDB").  That being said,
314 SimpleDB lets you specify that type of information if you need to.
315 Take a look at 
316 C<Catalyst::Authentication::Realm::SimpleDB|Catalyst::Authentication::Realm::SimpleDB>
317 for details.
318
319
320 =head2 Add Login and Logout Controllers
321
322 Use the Catalyst create script to create two stub controller files:
323
324     $ script/myapp_create.pl controller Login
325     $ script/myapp_create.pl controller Logout
326
327 You could easily use a single controller here.  For example, you could
328 have a C<User> controller with both C<login> and C<logout> actions.
329 Remember, Catalyst is designed to be very flexible, and leaves such
330 matters up to you, the designer and programmer.
331
332 Then open C<lib/MyApp/Controller/Login.pm>, locate the
333 C<sub index :Path :Args(0)> method (or C<sub index : Private> if you
334 are using an older version of Catalyst) that was automatically
335 inserted by the helpers when we created the Login controller above,
336 and update the definition of C<sub index> to match:
337
338     =head2 index
339     
340     Login logic
341     
342     =cut
343     
344     sub index :Path :Args(0) {
345         my ($self, $c) = @_;
346     
347         # Get the username and password from form
348         my $username = $c->request->params->{username};
349         my $password = $c->request->params->{password};
350     
351         # If the username and password values were found in form
352         if ($username && $password) {
353             # Attempt to log the user in
354             if ($c->authenticate({ username => $username,
355                                    password => $password  } )) {
356                 # If successful, then let them use the application
357                 $c->response->redirect($c->uri_for(
358                     $c->controller('Books')->action_for('list')));
359                 return;
360             } else {
361                 # Set an error message
362                 $c->stash->{error_msg} = "Bad username or password.";
363             }
364         } else {
365             # Set an error message
366             $c->stash->{error_msg} = "Empty username or password.";
367         }
368     
369         # If either of above don't work out, send to the login page
370         $c->stash->{template} = 'login.tt2';
371     }
372
373 Be sure to remove the C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Login in Login.');>
374 line of the C<sub index>.
375
376 This controller fetches the C<username> and C<password> values from the
377 login form and attempts to authenticate the user.  If successful, it
378 redirects the user to the book list page.  If the login fails, the user
379 will stay at the login page and receive an error message.  If the
380 C<username> and C<password> values are not present in the form, the
381 user will be taken to the empty login form.
382
383 Note that we could have used something like "C<sub default :Path>",
384 however, it is generally recommended (partly for historical reasons,
385 and partly for code clarity) only to use C<default> in
386 C<MyApp::Controller::Root>, and then mainly to generate the 404 not
387 found page for the application.
388
389 Instead, we are using "C<sub somename :Path :Args(0) {...}>" here to
390 specifically match the URL C</login>. C<Path> actions (aka, "literal
391 actions") create URI matches relative to the namespace of the
392 controller where they are defined.  Although C<Path> supports
393 arguments that allow relative and absolute paths to be defined, here
394 we use an empty C<Path> definition to match on just the name of the
395 controller itself.  The method name, C<index>, is arbitrary. We make
396 the match even more specific with the C<:Args(0)> action modifier --
397 this forces the match on I<only> C</login>, not
398 C</login/somethingelse>.
399
400 Next, update the corresponding method in
401 C<lib/MyApp/Controller/Logout.pm> to match:
402
403     =head2 index
404     
405     Logout logic
406     
407     =cut
408     
409     sub index :Path :Args(0) {
410         my ($self, $c) = @_;
411     
412         # Clear the user's state
413         $c->logout;
414     
415         # Send the user to the starting point
416         $c->response->redirect($c->uri_for('/'));
417     }
418
419 As with the login controller, be sure to delete the
420 C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Logout in Logout.');>
421 line of the C<sub index>.
422
423
424 =head2 Add a Login Form TT Template Page
425
426 Create a login form by opening C<root/src/login.tt2> and inserting:
427
428     [% META title = 'Login' %]
429     
430     <!-- Login form -->
431     <form method="post" action="[% c.uri_for('/login') %]">
432       <table>
433         <tr>
434           <td>Username:</td>
435           <td><input type="text" name="username" size="40" /></td>
436         </tr>
437         <tr>
438           <td>Password:</td>
439           <td><input type="password" name="password" size="40" /></td>
440         </tr>
441         <tr>
442           <td colspan="2"><input type="submit" name="submit" value="Submit" /></td>
443         </tr>
444       </table>
445     </form>
446
447
448 =head2 Add Valid User Check
449
450 We need something that provides enforcement for the authentication
451 mechanism -- a I<global> mechanism that prevents users who have not
452 passed authentication from reaching any pages except the login page.
453 This is generally done via an C<auto> action/method in 
454 C<lib/MyApp/Controller/Root.pm>.
455
456 Edit the existing C<lib/MyApp/Controller/Root.pm> class file and insert
457 the following method:
458
459     =head2 auto
460     
461     Check if there is a user and, if not, forward to login page
462     
463     =cut
464     
465     # Note that 'auto' runs after 'begin' but before your actions and that
466     # 'auto's "chain" (all from application path to most specific class are run)
467     # See the 'Actions' section of 'Catalyst::Manual::Intro' for more info.
468     sub auto : Private {
469         my ($self, $c) = @_;
470     
471         # Allow unauthenticated users to reach the login page.  This
472         # allows unauthenticated users to reach any action in the Login
473         # controller.  To lock it down to a single action, we could use:
474         #   if ($c->action eq $c->controller('Login')->action_for('index'))
475         # to only allow unauthenticated access to the 'index' action we
476         # added above.
477         if ($c->controller eq $c->controller('Login')) {
478             return 1;
479         }
480     
481         # If a user doesn't exist, force login
482         if (!$c->user_exists) {
483             # Dump a log message to the development server debug output
484             $c->log->debug('***Root::auto User not found, forwarding to /login');
485             # Redirect the user to the login page
486             $c->response->redirect($c->uri_for('/login'));
487             # Return 0 to cancel 'post-auto' processing and prevent use of application
488             return 0;
489         }
490     
491         # User found, so return 1 to continue with processing after this 'auto'
492         return 1;
493     }
494
495 As discussed in
496 L<Catalyst::Manual::Tutorial::03_MoreCatalystBasics/CREATE A CATALYST CONTROLLER>,
497 every C<auto> method from the application/root controller down to the
498 most specific controller will be called.  By placing the
499 authentication enforcement code inside the C<auto> method of
500 C<lib/MyApp/Controller/Root.pm> (or C<lib/MyApp.pm>), it will be
501 called for I<every> request that is received by the entire
502 application.
503
504
505 =head2 Displaying Content Only to Authenticated Users
506
507 Let's say you want to provide some information on the login page that
508 changes depending on whether the user has authenticated yet.  To do
509 this, open C<root/src/login.tt2> in your editor and add the following
510 lines to the bottom of the file:
511
512     ...
513     <p>
514     [%
515        # This code illustrates how certain parts of the TT
516        # template will only be shown to users who have logged in
517     %]
518     [% IF c.user_exists %]
519         Please Note: You are already logged in as '[% c.user.username %]'.
520         You can <a href="[% c.uri_for('/logout') %]">logout</a> here.
521     [% ELSE %]
522         You need to log in to use this application.
523     [% END %]
524     [%#
525        Note that this whole block is a comment because the "#" appears
526        immediate after the "[%" (with no spaces in between).  Although it
527        can be a handy way to temporarily "comment out" a whole block of
528        TT code, it's probably a little too subtle for use in "normal"
529        comments.
530     %]
531     </p>
532
533 Although most of the code is comments, the middle few lines provide a
534 "you are already logged in" reminder if the user returns to the login
535 page after they have already authenticated.  For users who have not yet
536 authenticated, a "You need to log in..." message is displayed (note the
537 use of an IF-THEN-ELSE construct in TT).
538
539
540 =head2 Try Out Authentication
541
542 Press C<Ctrl-C> to kill the previous server instance (if it's still
543 running) and restart it:
544
545     $ script/myapp_server.pl
546
547 B<IMPORTANT NOTE:> If you are having issues with authentication on
548 Internet Explorer, be sure to check the system clocks on both your
549 server and client machines.  Internet Explorer is very picky about
550 timestamps for cookies.  You can quickly sync a Debian system by
551 installing the "ntpdate" package:
552
553     sudo aptitude -y install ntpdate
554
555 And then run the following command:
556
557     sudo ntpdate-debian
558
559 Or, depending on your firewall configuration:
560
561     sudo ntpdate-debian -u
562
563 Note: NTP can be a little more finicky about firewalls because it uses
564 UDP vs. the more common TCP that you see with most Internet protocols.
565 Worse case, you might have to manually set the time on your development
566 box instead of using NTP.
567
568 Now trying going to L<http://localhost:3000/books/list> and you should
569 be redirected to the login page, hitting Shift+Reload or Ctrl+Reload
570 if necessary (the "You are already logged in" message should I<not>
571 appear -- if it does, click the C<logout> button and try again). Note
572 the C<***Root::auto User not found...> debug message in the
573 development server output.  Enter username C<test01> and password
574 C<mypass>, and you should be taken to the Book List page.
575
576 Open C<root/src/books/list.tt2> and add the following lines to the
577 bottom (below the closing </table> tag):
578
579     <p>
580       <a href="[% c.uri_for('/login') %]">Login</a>
581       <a href="[% c.uri_for(c.controller.action_for('form_create')) %]">Create</a>
582     </p>
583
584 Reload your browser and you should now see a "Login" and "Create" links
585 at the bottom of the page (as mentioned earlier, you can update template
586 files without reloading the development server).  Click the first link
587 to return to the login page.  This time you I<should> see the "You are
588 already logged in" message.
589
590 Finally, click the C<You can logout here> link on the C</login> page.
591 You should stay at the login page, but the message should change to "You
592 need to log in to use this application."
593
594
595 =head1 USING PASSWORD HASHES
596
597 In this section we increase the security of our system by converting 
598 from cleartext passwords to SHA-1 password hashes that include a 
599 random "salt" value to make them extremely difficult to crack with
600 dictionary and "rainbow table" attacks.
601
602 B<Note:> This section is optional.  You can skip it and the rest of the
603 tutorial will function normally.
604
605 Be aware that even with the techniques shown in this section, the browser
606 still transmits the passwords in cleartext to your application.  We are
607 just avoiding the I<storage> of cleartext passwords in the database by
608 using a salted SHA-1 hash. If you are concerned about cleartext passwords
609 between the browser and your application, consider using SSL/TLS, made
610 easy with the Catalyst plugin Catalyst::Plugin:RequireSSL.
611
612
613 =head2 Re-Run the DBIC::Schema Model Helper to Include DBIx::Class::EncodedColumn
614
615 Next, we can re-run the model helper to have it include 
616 L<DBIx::Class::EncodedColumn|DBIx::Class::EncodedColumn> in all of the 
617 Result Classes it generates for us.  Simply use the same command we 
618 saw in Chapters 3 and 4, but add C<,EncodedColumn> to the C<components>
619 argument:
620
621     $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
622         create=static components=TimeStamp,EncodedColumn dbi:SQLite:myapp.db \
623         on_connect_do="PRAGMA foreign_keys = ON"
624
625 If you then open one of the Result Classes, you will see that it 
626 includes EncodedColumn in the C<load_components> line.  Take a look at 
627 C<lib/MyApp/Schema/Result/User.pm> since that's the main class where we
628 want to use hashed and salted passwords:
629
630     __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp", "EncodedColumn");
631
632
633 =head2 Modify the "password" Column to Use EncodedColumn
634
635 Open the file C<lib/MyApp/Schema/Result/User.pm> and enter the following
636 text below the "# DO NOT MODIFY THIS OR ANYTHING ABOVE!" line but above
637 the closing "1;":
638
639     # Have the 'password' column use a SHA-1 hash and 10-character salt
640     # with hex encoding; Generate the 'check_password" method
641     __PACKAGE__->add_columns(
642         'password' => {
643             data_type           => "TEXT",
644             size                => undef,
645             encode_column       => 1,
646             encode_class        => 'Digest',
647             encode_args         => {salt_length => 10},
648             encode_check_method => 'check_password',
649         },
650     );
651
652 This redefines the automatically generated definition for the password 
653 fields at the top of the Result Class file to now use EncodedColumn 
654 logic (C<encoded_column> is set to 1).  C<encode_class> can be set to 
655 either C<Digest> to use 
656 L<DBIx::Class::EncodedColumn::Digest|DBIx::Class::EncodedColumn::Digest>, 
657 or C<Crypt::Eksblowfish::Bcrypt> for 
658 L<DBIx::Class::EncodedColumn::Crypt::Eksblowfish::Bcrypt|DBIx::Class::EncodedColumn::Crypt::Eksblowfish::Bcrypt>.
659 C<encode_args> is then used to customize the type of Digest you 
660 selected. Here we only specified the size of the salt to use, but
661 we could have also modified the hashing algorithm ('SHA-256' is 
662 the default) and the format to use ('base64' is the default, but
663 'hex' and 'binary' are other options).  To use these, you could 
664 change the C<encode_args> to something like:
665
666             encode_args         => {algorithm => 'SHA-1', 
667                                     format => 'hex', 
668                                     salt_length => 10},
669
670
671 =head2 Load Hashed Passwords in the Database
672
673 Next, let's create a quick script to load some hashed and salted passwords
674 into the C<password> column of our C<users> table.  Open the file
675 C<set_hashed_passwords.pl> in your editor and enter the following text:
676
677     #!/usr/bin/perl
678     
679     use strict;
680     use warnings;
681     
682     use MyApp::Schema;
683     
684     my $schema = MyApp::Schema->connect('dbi:SQLite:myapp.db');
685     
686     my @users = $schema->resultset('User')->all;
687     
688     foreach my $user (@users) {
689         $user->password('mypass');
690         $user->update;
691     }
692
693 EncodedColumn lets us simple call C<$user->check_password($password)> 
694 to see if the user has supplied the correct password, or, as we show 
695 above, call C<$user->update($new_password)> to update the hashed 
696 password stored for this user.
697
698 Then run the following command:
699
700     $ DBIC_TRACE=1 perl -Ilib set_hashed_passwords.pl
701
702 We had to use the C<-Ilib> argument to tell perl to look under the 
703 C<lib> directory for our C<MyApp::Schema> model.
704
705 The DBIC_TRACE output should show that the update worked:
706
707     $ DBIC_TRACE=1 perl -Ilib set_hashed_passwords.pl
708     SELECT me.id, me.username, me.password, me.email_address, 
709     me.first_name, me.last_name, me.active FROM user me: 
710     UPDATE user SET password = ? WHERE ( id = ? ): 
711     'oXiyAcGOjowz7ISUhpIm1IrS8AxSZ9r4jNjpX9VnVeQmN6GRtRKTz', '1'
712     UPDATE user SET password = ? WHERE ( id = ? ): 
713     'PmyEPrkB8EGwvaF/DvJm7LIfxoZARjv8ygFIR7pc1gEA1OfwHGNzs', '2'
714     UPDATE user SET password = ? WHERE ( id = ? ): 
715     'h7CS1Fm9UCs4hjcbu2im0HumaHCJUq4Uriac+SQgdUMUfFSoOrz3c', '3'
716
717 But we can further confirm our actions by dumping the users table:
718
719     $ sqlite3 myapp.db "select * from user"
720     1|test01|38d3974fa9e9263099f7bc2574284b2f55473a9bM=fwpX2NR8|t01@na.com|Joe|Blow|1
721     2|test02|6ed8586587e53e0d7509b1cfed5df08feadc68cbMJlnPyPt0I|t02@na.com|Jane|Doe|1
722     3|test03|af929a151340c6aed4d54d7e2651795d1ad2e2f7UW8dHoGv9z|t03@na.com|No|Go|0
723
724 As you can see, the passwords are much harder to steal from the 
725 database (not only are the hashes stored, but every hash is different 
726 even though the passwords are the same because of the added "salt" 
727 value).  Also note that this demonstrates how to use a DBIx::Class 
728 model outside of your web application -- a very useful feature in many 
729 situations.
730
731
732 =head2 Enable Hashed and Salted Passwords
733
734 Edit C<lib/MyApp.pm> and update it to match the following text (the 
735 only change is to the C<password_type> field):
736
737     # Configure SimpleDB Authentication
738     __PACKAGE__->config->{'Plugin::Authentication'} = {
739             default => {
740                 class           => 'SimpleDB',
741                 user_model      => 'DB::User',
742                 password_type   => 'self_check',
743             },
744         };
745
746 The use of C<self_check> will cause 
747 Catalyst::Plugin::Authentication::Store::DBIC to call the 
748 C<check_password> method we enabled on our C<password> columns.
749
750
751 =head2 Try Out the Hashed Passwords
752
753 Press C<Ctrl-C> to kill the previous server instance (if it's still
754 running) and restart it:
755
756     $ script/myapp_server.pl
757
758 You should now be able to go to L<http://localhost:3000/books/list> and
759 login as before.  When done, click the "logout" link on the login page
760 (or point your browser at L<http://localhost:3000/logout>).
761
762
763 =head1 USING THE SESSION FOR FLASH
764
765 As discussed in the previous chapter of the tutorial, C<flash> allows 
766 you to set variables in a way that is very similar to C<stash>, but it 
767 will remain set across multiple requests.  Once the value is read, it 
768 is cleared (unless reset).  Although C<flash> has nothing to do with 
769 authentication, it does leverage the same session plugins.  Now that 
770 those plugins are enabled, let's go back and update the "delete and 
771 redirect with query parameters" code seen at the end of the L<Basic 
772 CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD> chapter of the tutorial to 
773 take advantage of C<flash>.
774
775 First, open C<lib/MyApp/Controller/Books.pm> and modify C<sub delete>
776 to match the following (everything after the model search line of code
777 has changed):
778
779     =head2 delete
780     
781     Delete a book
782     
783     =cut
784     
785     sub delete :Chained('object') :PathPart('delete') :Args(0) {
786         my ($self, $c) = @_;
787     
788         # Use the book object saved by 'object' and delete it along
789         # with related 'book_authors' entries
790         $c->stash->{object}->delete;
791     
792         # Use 'flash' to save information across requests until it's read
793         $c->flash->{status_msg} = "Book deleted";
794     
795         # Redirect the user back to the list page
796         $c->response->redirect($c->uri_for($self->action_for('list')));
797     }
798
799 Next, open C<root/src/wrapper.tt2> and update the TT code to pull from
800 flash vs. the C<status_msg> query parameter:
801
802     ...
803     <div id="content">
804         [%# Status and error messages %]
805         <span class="message">[% status_msg || c.flash.status_msg %]</span>
806         <span class="error">[% error_msg %]</span>
807         [%# This is where TT will stick all of your template's contents. -%]
808         [% content %]
809     </div><!-- end content -->
810     ...
811
812 Although the sample above only shows the C<content> div, leave the
813 rest of the file intact -- the only change we made to replace 
814 "|| c.request.params.status_msg" with "c.flash.status_msg" in the 
815 C<< <span class="message"> >> line.
816
817
818 =head2 Try Out Flash
819
820 Restart the development server, log in, and then point your browser to
821 L<http://localhost:3000/books/url_create/Test/1/4> to create an extra
822 several books.  Click the "Return to list" link and delete one of the
823 "Test" books you just added.  The C<flash> mechanism should retain our
824 "Book deleted" status message across the redirect.
825
826 B<NOTE:> While C<flash> will save information across multiple requests,
827 I<it does get cleared the first time it is read>.  In general, this is
828 exactly what you want -- the C<flash> message will get displayed on
829 the next screen where it's appropriate, but it won't "keep showing up"
830 after that first time (unless you reset it).  Please refer to
831 L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> for additional
832 information.
833
834
835 =head2 Switch To Flash-To-Stash
836
837 Although the a use of flash above works well, the
838 C<status_msg || c.flash.status_msg> statement is a little ugly. A nice
839 alternative is to use the C<flash_to_stash> feature that automatically
840 copies the content of flash to stash.  This makes your controller
841 and template code work regardless of where it was directly access, a
842 forward, or a redirect.  To enable C<flash_to_stash>, you can either
843 set the value in C<lib/MyApp.pm> by changing the default
844 C<__PACKAGE__-E<gt>config> setting to something like:
845
846     __PACKAGE__->config(
847             name    => 'MyApp',
848             session => {flash_to_stash => 1},
849         );
850
851 B<or> add the following to C<myapp.conf>:
852
853     <session>
854         flash_to_stash   1
855     </session>
856
857 The C<__PACKAGE__-E<gt>config> option is probably preferable here
858 since it's not something you will want to change at runtime without it
859 possibly breaking some of your code.
860
861 Then edit C<root/src/wrapper.tt2> and change the C<status_msg> line
862 to match the following:
863
864     <span class="message">[% status_msg %]</span>
865
866 Restart the development server and go to
867 L<http://localhost:3000/books/list> in your browser.  Delete another
868 of the "Test" books you added in the previous step.  Flash should still
869 maintain the status message across the redirect even though you are no
870 longer explicitly accessing C<c.flash>.
871
872
873 =head1 AUTHOR
874
875 Kennedy Clark, C<hkclark@gmail.com>
876
877 Please report any errors, issues or suggestions to the author.  The
878 most recent version of the Catalyst Tutorial can be found at
879 L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/>.
880
881 Copyright 2006-2008, Kennedy Clark, under Creative Commons License
882 (L<http://creativecommons.org/licenses/by-sa/3.0/us/>).