Moving tutorial POD here
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / Tutorial / Authentication.pod
diff --git a/lib/Catalyst/Manual/Tutorial/Tutorial/Authentication.pod b/lib/Catalyst/Manual/Tutorial/Tutorial/Authentication.pod
new file mode 100644 (file)
index 0000000..46b061c
--- /dev/null
@@ -0,0 +1,875 @@
+=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/>).