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