--- /dev/null
+=head1 NAME
+
+Catalyst::Manual::Tutorial::Authentication - Catalyst Tutorial - Part 4: Authentication
+
+
+=head1 OVERVIEW
+
+This is B<Part 4 of 9> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
+
+=item 3
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
+
+=item 4
+
+B<Authentication>
+
+=item 5
+
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
+
+=item 6
+
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+
+=item 7
+
+L<Testing|Catalyst::Manual::Tutorial::Testing>
+
+=item 8
+
+L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 9
+
+L<Appendices|Catalyst::Manual::Tutorial::Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+Now that we finally have a simple yet functional application, we can
+focus on providing authentication (with authorization coming next in
+Part 5).
+
+This part of the tutorial is divided into two main sections: 1) basic,
+cleartext authentication and 2) hash-based authentication.
+
+You can checkout the source code for this example from the catalyst
+subversion repository as per the instructions in
+L<Catalyst::Manual::Tutorial::Intro>
+
+=head1 BASIC AUTHENTICATION
+
+This section explores how to add authentication logic to a Catalyst
+application.
+
+
+=head2 Add Users and Roles to the Database
+
+First, we add both user and role information to the database (we will
+add the role information here although it will not be used until the
+authorization section, Part 5). Create a new SQL script file by opening
+C<myapp02.sql> in your editor and insert:
+
+ --
+ -- Add users and roles tables, along with a many-to-many join table
+ --
+ CREATE TABLE users (
+ id INTEGER PRIMARY KEY,
+ username TEXT,
+ password TEXT,
+ email_address TEXT,
+ first_name TEXT,
+ last_name TEXT,
+ active INTEGER
+ );
+ CREATE TABLE roles (
+ id INTEGER PRIMARY KEY,
+ role TEXT
+ );
+ CREATE TABLE user_roles (
+ user_id INTEGER,
+ role_id INTEGER,
+ PRIMARY KEY (user_id, role_id)
+ );
+ --
+ -- Load up some initial test data
+ --
+ INSERT INTO users VALUES (1, 'test01', 'mypass', 't01@na.com', 'Joe', 'Blow', 1);
+ INSERT INTO users VALUES (2, 'test02', 'mypass', 't02@na.com', 'Jane', 'Doe', 1);
+ INSERT INTO users VALUES (3, 'test03', 'mypass', 't03@na.com', 'No', 'Go', 0);
+ INSERT INTO roles VALUES (1, 'user');
+ INSERT INTO roles VALUES (2, 'admin');
+ INSERT INTO user_roles VALUES (1, 1);
+ INSERT INTO user_roles VALUES (1, 2);
+ INSERT INTO user_roles VALUES (2, 1);
+ INSERT INTO user_roles VALUES (3, 1);
+
+Then load this into the C<myapp.db> database with the following command:
+
+ $ sqlite3 myapp.db < myapp02.sql
+
+
+=head2 Add User and Role Information to DBIC Schema
+
+This step adds DBIC-based classes for the user-related database tables
+(the role information will not be used until Part 5):
+
+Edit C<lib/MyAppDB.pm> and update the contents to match (only the
+C<MyAppDB =E<gt> [qw/Book BookAuthor Author User UserRole Role/]> line
+has changed):
+
+ package MyAppDB;
+
+ =head1 NAME
+
+ MyAppDB -- DBIC Schema Class
+
+ =cut
+
+ # Our schema needs to inherit from 'DBIx::Class::Schema'
+ use base qw/DBIx::Class::Schema/;
+
+ # Need to load the DB Model classes here.
+ # You can use this syntax if you want:
+ # __PACKAGE__->load_classes(qw/Book BookAuthor Author User UserRole Role/);
+ # Also, if you simply want to load all of the classes in a directory
+ # of the same name as your schema class (as we do here) you can use:
+ # __PACKAGE__->load_classes(qw//);
+ # But the variation below is more flexible in that it can be used to
+ # load from multiple namespaces.
+ __PACKAGE__->load_classes({
+ MyAppDB => [qw/Book BookAuthor Author User UserRole Role/]
+ });
+
+ 1;
+
+
+=head2 Create New "Result Source Objects"
+
+Create the following three files with the content shown below.
+
+C<lib/MyAppDB/User.pm>:
+
+ package MyAppDB::User;
+
+ use base qw/DBIx::Class/;
+
+ # Load required DBIC stuff
+ __PACKAGE__->load_components(qw/PK::Auto Core/);
+ # Set the table name
+ __PACKAGE__->table('users');
+ # Set columns in table
+ __PACKAGE__->add_columns(qw/id username password email_address first_name last_name/);
+ # Set the primary key for the table
+ __PACKAGE__->set_primary_key('id');
+
+ #
+ # Set relationships:
+ #
+
+ # has_many():
+ # args:
+ # 1) Name of relationship, DBIC will create accessor with this name
+ # 2) Name of the model class referenced by this relationship
+ # 3) Column name in *foreign* table
+ __PACKAGE__->has_many(map_user_role => 'MyAppDB::UserRole', 'user_id');
+
+
+ =head1 NAME
+
+ MyAppDB::User - A model object representing a person with access to the system.
+
+ =head1 DESCRIPTION
+
+ This is an object that represents a row in the 'users' table of your application
+ database. It uses DBIx::Class (aka, DBIC) to do ORM.
+
+ For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
+ Offline utilities may wish to use this class directly.
+
+ =cut
+
+ 1;
+
+
+C<lib/MyAppDB/Role.pm>:
+
+ package MyAppDB::Role;
+
+ use base qw/DBIx::Class/;
+
+ # Load required DBIC stuff
+ __PACKAGE__->load_components(qw/PK::Auto Core/);
+ # Set the table name
+ __PACKAGE__->table('roles');
+ # Set columns in table
+ __PACKAGE__->add_columns(qw/id role/);
+ # Set the primary key for the table
+ __PACKAGE__->set_primary_key('id');
+
+ #
+ # Set relationships:
+ #
+
+ # has_many():
+ # args:
+ # 1) Name of relationship, DBIC will create accessor with this name
+ # 2) Name of the model class referenced by this relationship
+ # 3) Column name in *foreign* table
+ __PACKAGE__->has_many(map_user_role => 'MyAppDB::UserRole', 'role_id');
+
+
+ =head1 NAME
+
+ MyAppDB::Role - A model object representing a class of access permissions to
+ the system.
+
+ =head1 DESCRIPTION
+
+ This is an object that represents a row in the 'roles' table of your
+ application database. It uses DBIx::Class (aka, DBIC) to do ORM.
+
+ For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
+ "Offline" utilities may wish to use this class directly.
+
+ =cut
+
+ 1;
+
+
+C<lib/MyAppDB/UserRole.pm>:
+
+ package MyAppDB::UserRole;
+
+ use base qw/DBIx::Class/;
+
+ # Load required DBIC stuff
+ __PACKAGE__->load_components(qw/PK::Auto Core/);
+ # Set the table name
+ __PACKAGE__->table('user_roles');
+ # Set columns in table
+ __PACKAGE__->add_columns(qw/user_id role_id/);
+ # Set the primary key for the table
+ __PACKAGE__->set_primary_key(qw/user_id role_id/);
+
+ #
+ # Set relationships:
+ #
+
+ # belongs_to():
+ # args:
+ # 1) Name of relationship, DBIC will create accessor with this name
+ # 2) Name of the model class referenced by this relationship
+ # 3) Column name in *this* table
+ __PACKAGE__->belongs_to(user => 'MyAppDB::User', 'user_id');
+
+ # belongs_to():
+ # args:
+ # 1) Name of relationship, DBIC will create accessor with this name
+ # 2) Name of the model class referenced by this relationship
+ # 3) Column name in *this* table
+ __PACKAGE__->belongs_to(role => 'MyAppDB::Role', 'role_id');
+
+
+ =head1 NAME
+
+ MyAppDB::UserRole - A model object representing the JOIN between Users and Roles.
+
+ =head1 DESCRIPTION
+
+ This is an object that represents a row in the 'user_roles' table of your application
+ database. It uses DBIx::Class (aka, DBIC) to do ORM.
+
+ You probably won't need to use this class directly -- it will be automatically
+ used by DBIC where joins are needed.
+
+ For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
+ Offline utilities may wish to use this class directly.
+
+ =cut
+
+ 1;
+
+The code for these three result source classes is obviously very familiar to the C<Book>, C<Author>, and C<BookAuthor> classes created in Part 2.
+
+
+=head2 Sanity-Check Reload of Development Server
+
+We aren't ready to try out the authentication just yet; we only want to do a quick check to be sure our model loads correctly. Press C<Ctrl-C> to kill the previous server instance (if it's still running) and restart it:
+
+ $ script/myapp_server.pl
+
+Look for the three new model objects in the startup debug output:
+
+ ...
+ .-------------------------------------------------------------------+----------.
+ | Class | Type |
+ +-------------------------------------------------------------------+----------+
+ | MyApp::Controller::Books | instance |
+ | MyApp::Controller::Root | instance |
+ | MyApp::Model::MyAppDB | instance |
+ | MyApp::Model::MyAppDB::Author | class |
+ | MyApp::Model::MyAppDB::Book | class |
+ | MyApp::Model::MyAppDB::BookAuthor | class |
+ | MyApp::Model::MyAppDB::Role | class |
+ | MyApp::Model::MyAppDB::User | class |
+ | MyApp::Model::MyAppDB::UserRole | class |
+ | MyApp::View::TT | instance |
+ '-------------------------------------------------------------------+----------'
+ ...
+
+Again, notice that your "result source" classes have been "re-loaded" by Catalyst under C<MyApp::Model>.
+
+
+=head2 Include Authentication and Session Plugins
+
+Edit C<lib/MyApp.pm> and update it as follows (everything below C<StackTrace> is new):
+
+ use Catalyst qw/
+ -Debug
+ ConfigLoader
+ Static::Simple
+
+ StackTrace
+
+ Authentication
+ Authentication::Store::DBIC
+ Authentication::Credential::Password
+
+ Session
+ Session::Store::FastMmap
+ Session::State::Cookie
+ /;
+
+The three C<Authentication> plugins work together to support
+Authentication while the C<Session> plugins are required to maintain
+state across multiple HTTP requests. Note that there are several
+options for L<Session::Store|Catalyst::Plugin::Session::Store>
+(L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap>
+is generally a good choice if you are on Unix; try
+L<Cache::FileCache|Catalyst::Plugin::Cache::FileCache> if you are on
+Win32) -- consult L<Session::Store|Catalyst::Plugin::Session::Store> and
+its subclasses for additional information.
+
+
+=head2 Configure Authentication
+
+Although C<__PACKAGE__-E<gt>config(name =E<gt> 'value');> is still
+supported, newer Catalyst applications tend to place all configuration
+information in C<myapp.yml> and automatically load this information into
+C<MyApp-E<gt>config> using the
+L<ConfigLoader|Catalyst::Plugin::ConfigLoader> plugin. Here, we need
+to load several parameters that tell
+L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
+where to locate information in your database. To do this, edit the
+C<myapp.yml> YAML and update it to match:
+
+ ---
+ name: MyApp
+ authentication:
+ dbic:
+ # Note this first definition would be the same as setting
+ # __PACKAGE__->config->{authentication}->{dbic}->{user_class} = 'MyAppDB::User'
+ # in lib/MyApp.pm (IOW, each hash key becomes a "name:" in the YAML file).
+ #
+ # This is the model object created by Catalyst::Model::DBIC from your
+ # schema (you created 'MyAppDB::User' but as the Catalyst startup
+ # debug messages show, it was loaded as 'MyApp::Model::MyAppDB::User').
+ # NOTE: Omit 'MyApp::Model' to avoid a component lookup issue in Catalyst 5.66
+ user_class: MyAppDB::User
+ # This is the name of the field in your 'users' table that contains the user's name
+ user_field: username
+ # This is the name of the field in your 'users' table that contains the password
+ password_field: password
+ # Other options can go here for hashed passwords
+
+Inline comments in the code above explain how each field is being used.
+
+B<TIP>: Although YAML uses a very simple and easy-to-ready format, it
+does require the use of a consistent level of indenting. Be sure you
+line up everything on a given 'level' with the same number of indents.
+Also, be sure not to use C<tab> characters (YAML does not support them
+because they are handled inconsistently across editors).
+
+
+=head2 Add Login and Logout Controllers
+
+Use the Catalyst create script to create two stub controller files:
+
+ $ script/myapp_create.pl controller Login
+ $ script/myapp_create.pl controller Logout
+
+B<NOTE>: You could easily use a single controller here. For example,
+you could have a C<User> controller with both C<login> and C<logout>
+actions. Remember, Catalyst is designed to be very flexible, and leaves
+such matters up to you, the designer and programmer.
+
+Then open C<lib/MyApp/Controller/Login.pm>, locate the C<sub index :
+Private> method (this was automatically inserted by the helpers when we
+created the Login controller above), and delete this line:
+
+ $c->response->body('Matched MyApp::Controller::Login in Login.');
+
+Then update it to match:
+
+ =head2 index
+
+ Login logic
+
+ =cut
+
+ sub index : Private {
+ my ($self, $c) = @_;
+
+ # Get the username and password from form
+ my $username = $c->request->params->{username} || "";
+ my $password = $c->request->params->{password} || "";
+
+ # If the username and password values were found in form
+ if ($username && $password) {
+ # Attempt to log the user in
+ if ($c->login($username, $password)) {
+ # If successful, then let them use the application
+ $c->response->redirect($c->uri_for('/books/list'));
+ return;
+ } else {
+ # Set an error message
+ $c->stash->{error_msg} = "Bad username or password.";
+ }
+ }
+
+ # If either of above don't work out, send to the login page
+ $c->stash->{template} = 'login.tt2';
+ }
+
+This controller fetches the C<username> and C<password> values from the
+login form and attempts to perform a login. If successful, it redirects
+the user to the book list page. If the login fails, the user will stay
+at the login page but receive an error message. If the C<username> and
+C<password> values are not present in the form, the user will be taken
+to the empty login form.
+
+Note that we could have used something like C<sub default :Private>;
+however, the use of C<default> actions is discouraged because it does
+not receive path args as with other actions. The recommended practice
+is to only use C<default> in C<MyApp::Controller::Root>.
+
+Another option would be to use something like
+C<sub base :Path :Args(0) {...}> (where the C<...> refers to the login
+code shown in C<sub index : Private> above). We are using C<sub base
+:Path :Args(0) {...}> here to specifically match the URL C</login>.
+C<Path> actions (aka, "literal actions") create URI matches relative to
+the namespace of the controller where they are defined. Although
+C<Path> supports arguments that allow relative and absolute paths to be
+defined, here we use an empty C<Path> definition to match on just the
+name of the controller itself. The method name, C<base>, is arbitrary.
+We make the match even more specific with the C<:Args(0)> action
+modifier -- this forces the match on I<only> C</login>, not
+C</login/somethingelse>.
+
+Next, update the corresponding method in C<lib/MyApp/Controller/Logout.pm>
+to match:
+
+ =head2 index
+
+ Logout logic
+
+ =cut
+
+ sub index : Private {
+ my ($self, $c) = @_;
+
+ # Clear the user's state
+ $c->logout;
+
+ # Send the user to the starting point
+ $c->response->redirect($c->uri_for('/'));
+ }
+
+As with the login controller, be sure to delete the
+C<$c->response->body('Matched MyApp::Controller::Logout in Logout.');>
+line of the C<sub index>.
+
+
+=head2 Add a Login Form TT Template Page
+
+Create a login form by opening C<root/src/login.tt2> and inserting:
+
+ [% META title = 'Login' %]
+
+ <!-- Login form -->
+ <form method="post" action=" [% Catalyst.uri_for('/login') %] ">
+ <table>
+ <tr>
+ <td>Username:</td>
+ <td><input type="text" name="username" size="40" /></td>
+ </tr>
+ <tr>
+ <td>Password:</td>
+ <td><input type="password" name="password" size="40" /></td>
+ </tr>
+ <tr>
+ <td colspan="2"><input type="submit" name="submit" value="Submit" /></td>
+ </tr>
+ </table>
+ </form>
+
+
+=head2 Add Valid User Check
+
+We need something that provides enforcement for the authentication
+mechanism -- a I<global> mechanism that prevents users who have not
+passed authentication from reaching any pages except the login page.
+This is generally done via an C<auto> action/method (prior to Catalyst
+v5.66, this sort of thing would go in C<MyApp.pm>, but starting in
+v5.66, the preferred location is C<lib/MyApp/Controller/Root.pm>).
+
+Edit the existing C<lib/MyApp/Controller/Root.pm> class file and insert
+the following method:
+
+ =head2 auto
+
+ Check if there is a user and, if not, forward to login page
+
+ =cut
+
+ # Note that 'auto' runs after 'begin' but before your actions and that
+ # 'auto' "chain" (all from application path to most specific class are run)
+ # See the 'Actions' section of 'Catalyst::Manual::Intro' for more info.
+ sub auto : Private {
+ my ($self, $c) = @_;
+
+ # Allow unauthenticated users to reach the login page. This
+ # allows anauthenticated users to reach any action in the Login
+ # controller. To lock it down to a single action, we could use:
+ # if ($c->action eq $c->controller('Login')->action_for('index'))
+ # to only allow unauthenticated access to the C<index> action we
+ # added above.
+ if ($c->controller eq $c->controller('Login')) {
+ return 1;
+ }
+
+ # If a user doesn't exist, force login
+ if (!$c->user_exists) {
+ # Dump a log message to the development server debug output
+ $c->log->debug('***Root::auto User not found, forwarding to /login');
+ # Redirect the user to the login page
+ $c->response->redirect($c->uri_for('/login'));
+ # Return 0 to cancel 'post-auto' processing and prevent use of application
+ return 0;
+ }
+
+ # User found, so return 1 to continue with processing after this 'auto'
+ return 1;
+ }
+
+B<Note:> Catalyst provides a number of different types of actions, such
+as C<Local>, C<Regex>, and C<Private>. You should refer to
+L<Catalyst::Manual::Intro> for a more detailed explanation, but the
+following bullet points provide a quick introduction:
+
+=over 4
+
+=item *
+
+The majority of application use C<Local> actions for items that respond
+to user requests and C<Private> actions for those that do not directly
+respond to user input.
+
+=item *
+
+There are five types of C<Private> actions: C<begin>, C<end>,
+C<default>, C<index>, and C<auto>.
+
+=item *
+
+With C<begin>, C<end>, C<default>, C<index> private actions, only the
+most specific action of each type will be called. For example, if you
+define a C<begin> action in your controller it will I<override> a
+C<begin> action in your application/root controller -- I<only> the
+action in your controller will be called.
+
+=item *
+
+Unlike the other actions where only a single method is called for each
+request, I<every> auto action along the chain of namespaces will be
+called. Each C<auto> action will be called I<from the application/root
+controller down through the most specific class>.
+
+=back
+
+By placing the authentication enforcement code inside the C<auto> method
+of C<lib/MyApp/Controller/Root.pm> (or C<lib/MyApp.pm>), it will be
+called for I<every> request that is received by the entire application.
+
+
+=head2 Displaying Content Only to Authenticated Users
+
+Let's say you want to provide some information on the login page that
+changes depending on whether the user has authenticated yet. To do
+this, open C<root/src/login.tt2> in your editor and add the following
+lines to the bottom of the file:
+
+ <p>
+ [%
+ # This code illustrates how certain parts of the TT
+ # template will only be shown to users who have logged in
+ %]
+ [% IF Catalyst.user_exists %]
+ Please Note: You are already logged in as '[% Catalyst.user.username %]'.
+ You can <a href="[% Catalyst.uri_for('/logout') %]">logout</a> here.
+ [% ELSE %]
+ You need to log in to use this application.
+ [% END %]
+ [%#
+ Note that this whole block is a comment because the "#" appears
+ immediate after the "[%" (with no spaces in between). Although it
+ can be a handy way to temporarily "comment out" a whole block of
+ TT code, it's probably a little too subtle for use in "normal"
+ comments.
+ %]
+
+Although most of the code is comments, the middle few lines provide a
+"you are already logged in" reminder if the user returns to the login
+page after they have already authenticated. For users who have not yet
+authenticated, a "You need to log in..." message is displayed (note the
+use of an IF-THEN-ELSE construct in TT).
+
+
+=head2 Try Out Authentication
+
+Press C<Ctrl-C> to kill the previous server instance (if it's still
+running) and restart it:
+
+ $ script/myapp_server.pl
+
+B<IMPORTANT NOTE>: If you happen to be using Internet Explorer, you may
+need to use the command C<script/myapp_server.pl -k> to enable the
+keepalive feature in the development server. Otherwise, the HTTP
+redirect on successful login may not work correctly with IE (it seems to
+work without -k if you are running the web browser and development
+server on the same machine). If you are using browser a browser other
+than IE, it should work either way. If you want to make keepalive the
+default, you can edit C<script/myapp_server.pl> and change the
+initialization value for C<$keepalive> to C<1>. (You will need to do
+this every time you create a new Catalyst application or rebuild the
+C<myapp_server.pl> script.)
+
+Now trying going to L<http://localhost:3000/books/list> and you should
+be redirected to the login page, hitting Shift+Reload if necessary (the
+"You are already logged in" message should I<not> appear -- if it does,
+click the C<logout> button and try again). Note the C<***Root::auto User
+not found...> debug message in the development server output. Enter
+username C<test01> and password C<mypass>, and you should be taken to
+the Book List page.
+
+Open C<root/src/books/list.tt2> and add the following lines to the
+bottom:
+
+ <p>
+ <a href="[% Catalyst.uri_for('/login') %]">Login</a>
+ <a href="[% Catalyst.uri_for('form_create') %]">Create</a>
+ </p>
+
+Reload your browser and you should now see a "Login" and "Create" links
+at the bottom of the page (as mentioned earlier, you can update template
+files without reloading the development server). Click the first link
+to return to the login page. This time you I<should> see the "You are
+already logged in" message.
+
+Finally, click the C<You can logout here> link on the C</login> page.
+You should stay at the login page, but the message should change to "You
+need to log in to use this application."
+
+
+=head1 USING PASSWORD HASHES
+
+In this section we increase the security of our system by converting
+from cleartext passwords to SHA-1 password hashes.
+
+B<Note:> This section is optional. You can skip it and the rest of the
+tutorial will function normally.
+
+Note that even with the techniques shown in this section, the browser
+still transmits the passwords in cleartext to your application. We are
+just avoiding the I<storage> of cleartext passwords in the database by
+using a SHA-1 hash. If you are concerned about cleartext passwords
+between the browser and your application, consider using SSL/TLS, made
+easy with the Catalyst plugin Catalyst::Plugin:RequireSSL.
+
+
+=head2 Get a SHA-1 Hash for the Password
+
+Catalyst uses the C<Digest> module to support a variety of hashing
+algorithms. Here we will use SHA-1 (SHA = Secure Hash Algorithm).
+First, we should compute the SHA-1 hash for the "mypass" password we are
+using. The following command-line Perl script provides a "quick and
+dirty" way to do this:
+
+ $ perl -MDigest::SHA -e 'print Digest::SHA::sha1_hex("mypass"), "\n"'
+ e727d1464ae12436e899a726da5b2f11d8381b26
+ $
+
+B<Note:> You should probably modify this code for production use to
+not read the password from the command line. By having the script
+prompt for the cleartext password, it avoids having the password linger
+in forms such as your C<.bash_history> files (assuming you are using
+BASH as your shell). An example of such a script can be found in
+Appendix 3.
+
+
+=head2 Switch to SHA-1 Password Hashes in the Database
+
+Next, we need to change the C<password> column of our C<users> table to
+store this hash value vs. the existing cleartext password. Open
+C<myapp03.sql> in your editor and enter:
+
+ --
+ -- Convert passwords to SHA-1 hashes
+ --
+ UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 1;
+ UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 2;
+ UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 3;
+
+Then use the following command to update the SQLite database:
+
+ $ sqlite3 myapp.db < myapp03.sql
+
+B<Note:> We are using SHA-1 hashes here, but many other hashing
+algorithms are supported. See C<Digest> for more information.
+
+
+=head2 Enable SHA-1 Hash Passwords in
+C<Catalyst::Plugin::Authentication::Store::DBIC>
+
+Edit C<myapp.yml> and update it to match (the C<password_type> and
+C<password_hash_type> are new, everything else is the same):
+
+ ---
+ name: MyApp
+ authentication:
+ dbic:
+ # Note this first definition would be the same as setting
+ # __PACKAGE__->config->{authentication}->{dbic}->{user_class} = 'MyAppDB::User'
+ # in lib/MyApp.pm (IOW, each hash key becomes a "name:" in the YAML file).
+ #
+ # This is the model object created by Catalyst::Model::DBIC from your
+ # schema (you created 'MyAppDB::User' but as the Catalyst startup
+ # debug messages show, it was loaded as 'MyApp::Model::MyAppDB::User').
+ # NOTE: Omit 'MyApp::Model' here just as you would when using
+ # '$c->model("MyAppDB::User)'
+ user_class: MyAppDB::User
+ # This is the name of the field in your 'users' table that contains the user's name
+ user_field: username
+ # This is the name of the field in your 'users' table that contains the password
+ password_field: password
+ # Other options can go here for hashed passwords
+ # Enabled hashed passwords
+ password_type: hashed
+ # Use the SHA-1 hashing algorithm
+ password_hash_type: SHA-1
+
+
+=head2 Try Out the Hashed Passwords
+
+Press C<Ctrl-C> to kill the previous server instance (if it's still
+running) and restart it:
+
+ $ script/myapp_server.pl
+
+You should now be able to go to L<http://localhost:3000/books/list> and
+login as before. When done, click the "Logout" link on the login page
+(or point your browser at L<http://localhost:3000/logout>).
+
+B<Note:> If you receive the debug screen in your browser with a
+C<Can't call method "stash" on an undefined value...> error message,
+make sure that you are using v0.07 of
+L<Catalyst::Plugin::Authorization::ACL|Catalyst::Plugin::Authorization::ACL>.
+The following command can be a useful way to quickly dump the version number
+of this module on your system:
+
+ perl -MCatalyst::Plugin::Authorization::ACL -e 'print $Catalyst::Plugin::Authorization::ACL::VERSION, "\n";'
+
+
+=head1 USING THE SESSION FOR FLASH
+
+As discussed in Part 3 of the tutorial, C<flash> allows you to set
+variables in a way that is very similar to C<stash>, but it will
+remain set across multiple requests. Once the value is read, it
+is cleared (unless reset). Although C<flash> has nothing to do with
+authentication, it does leverage the same session plugins. Now that
+those plugins are enabled, let's go back and improve the "delete
+and redirect with query parameters" code seen at the end of the
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD> part of the
+tutorial.
+
+First, open C<lib/MyApp/Controller/Books.pm> and modify C<sub delete>
+to match the following:
+
+ =head2 delete
+
+ Delete a book
+
+ =cut
+
+ sub delete : Local {
+ # $id = primary key of book to delete
+ my ($self, $c, $id) = @_;
+
+ # Search for the book and then delete it
+ $c->model('MyAppDB::Book')->search({id => $id})->delete_all;
+
+ # Use 'flash' to save information across requests until it's read
+ $c->flash->{status_msg} = "Book deleted";
+
+ # Redirect the user back to the list page with status msg as an arg
+ $c->response->redirect($c->uri_for('/books/list'));
+ }
+
+Next, open C<root/lib/site/layout> and update the TT code to pull from
+flash vs. the C<status_msg> query parameter:
+
+ <div id="header">[% PROCESS site/header %]</div>
+
+ <div id="content">
+ <span class="message">[% status_msg || Catalyst.flash.status_msg %]</span>
+ <span class="error">[% error_msg %]</span>
+ [% content %]
+ </div>
+
+ <div id="footer">[% PROCESS site/footer %]</div>
+
+
+=head2 Try Out Flash
+
+Restart the development server and point your browser to
+L<http://localhost:3000/books/url_create/Test/1/4> to create an extra
+book. Click the "Return to list" link and delete the "Test" book you
+just added. The C<flash> mechanism should retain our "Book deleted"
+status message across the redirect.
+
+B<NOTE:> While C<flash> will save information across multiple requests,
+I<it does get cleared the first time it is read>. In general, this is
+exactly what you want -- the C<flash> message will get displayed on
+the next screen where it's appropriate, but it won't "keep showing up"
+after that first time (unless you reset it). Please refer to
+L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> for additional
+information.
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark@gmail.com>
+
+Please report any errors, issues or suggestions to the author. The
+most recent version of the Catalyst Tutorial can be found at
+L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Runtime/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).