Misc updates with thanks to JC Wren
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / Authorization.pod
index 2a16efa..d0ca866 100644 (file)
@@ -1,11 +1,11 @@
 =head1 NAME
 
-Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Part 5: Authorization
+Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Part 6: Authorization
 
 
 =head1 OVERVIEW
 
-This is B<Part 5 of 9> for the Catalyst tutorial.
+This is B<Part 6 of 10> for the Catalyst tutorial.
 
 L<Tutorial Overview|Catalyst::Manual::Tutorial>
 
@@ -21,117 +21,128 @@ L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
 
 =item 3
 
-L<Basic CRUD|Catalyst::Manual::Tutorial_BasicCRUD>
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
 
 =item 4
 
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
 =item 5
 
-B<Authorization>
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
 =item 6
 
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
+B<Authorization>
 
 =item 7
 
-L<Testing|Catalyst::Manual::Tutorial::Testing>
+L<Debugging|Catalyst::Manual::Tutorial::Debugging>
 
 =item 8
 
-L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+L<Testing|Catalyst::Manual::Tutorial::Testing>
 
 =item 9
 
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
+
+=item 10
+
 L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
 =back
 
 
-
 =head1 DESCRIPTION
 
 This part of the tutorial adds role-based authorization to the existing
-authentication implemented in Part 4.  It provides simple examples of
+authentication implemented in Part 5.  It provides simple examples of
 how to use roles in both TT templates and controller actions.  The first
 half looks at manually configured authorization.  The second half looks
 at how the ACL authorization plugin can simplify your code.
 
 You can checkout the source code for this example from the catalyst
 subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::Intro>
+L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
+
 
 =head1 BASIC AUTHORIZATION
 
 In this section you learn how to manually configure authorization.
 
+
 =head2 Update Plugins to Include Support for Authorization
 
 Edit C<lib/MyApp.pm> and add C<Authorization::Roles> to the list:
 
-    use Catalyst qw/
+    __PACKAGE__->setup(qw/
             -Debug
             ConfigLoader
             Static::Simple
-            
+    
             StackTrace
-            
+    
             Authentication
-            Authentication::Store::DBIC
-            Authentication::Credential::Password
             Authorization::Roles
-            
+    
             Session
             Session::Store::FastMmap
             Session::State::Cookie
-            /;
+        /;
+
+B<Note:> As discussed in MoreCatalystBasics, different versions of 
+C<Catalyst::Devel> have used a variety of methods to load the plugins. 
+You put the plugins in the C<use Catalyst> statement if you prefer.
 
 
 =head2 Add Config Information for Authorization
 
-Edit C<myapp.yml> and update it to match (everything from the
-"authorization:" line down is new):
-
-    ---
-    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
-    authorization:
-        dbic:
-            # This is the model object created by Catalyst::Model::DBIC from your
-            # schema (you created 'MyAppDB::Role' but as the Catalyst startup
-            # debug messages show, it was loaded as 'MyApp::Model::MyAppDB::Role').
-            # NOTE: Omit 'MyApp::Model' here just as you would when using 
-            # '$c->model("MyAppDB::User)'
-            role_class: MyAppDB::Role
-            # The name of the field in the 'roles' table that contains the role name
-            role_field: role
-            # The name of the accessor used to map a role to the users who have this role
-            # See the has_many() in MyAppDB/Role.pm
-            role_rel: map_user_role
-            # The name of the field in the user_role table that references the user
-            user_role_user_field: user_id
+Edit C<myapp.conf> and update it to match the following (the
+C<role_relation> and C<role_field> definitions are new):
+
+    # rename this file to MyApp.yml and put a : in front of "name" if
+    # you want to use yaml like in old versions of Catalyst
+    name MyApp
+    <authentication>
+        default_realm dbic
+        <realms>
+            <dbic>
+                <credential>
+                    # Note this first definition would be the same as setting
+                    # __PACKAGE__->config->{authentication}->{realms}->{dbic}
+                    #     ->{credential} = 'Password' in lib/MyApp.pm
+                    #
+                    # Specify that we are going to do password-based auth
+                    class Password
+                    # This is the name of the field in the users table with the
+                    # password stored in it
+                    password_field password
+                    # Switch to more secure hashed passwords
+                    password_type  hashed
+                    # Use the SHA-1 hashing algorithm
+                    password_hash_type SHA-1
+                </credential>
+                <store>
+                    # Use DBIC to retrieve username, password & role information
+                    class DBIx::Class
+                    # This is the model object created by Catalyst::Model::DBIC
+                    # from your schema (you created 'MyApp::Schema::User' but as
+                    # the Catalyst startup debug messages show, it was loaded as
+                    # 'MyApp::Model::DB::Users').
+                    # NOTE: Omit 'MyApp::Model' here just as you would when using
+                    # '$c->model("DB::Users)'
+                    user_class DB::Users
+                    # This is the name of a many_to_many relation in the users
+                    # object that points to the roles for that user
+                    role_relation  roles
+                    # This is the name of field in the roles table that contains
+                    # the role information
+                    role_field role
+                </store>
+            </dbic>
+        </realms>
+    </authentication>
 
 
 =head2 Add Role-Specific Logic to the "Book List" Template
@@ -139,31 +150,32 @@ Edit C<myapp.yml> and update it to match (everything from the
 Open C<root/src/books/list.tt2> in your editor and add the following
 lines to the bottom of the file:
 
-    <p>Hello [% Catalyst.user.username %], you have the following roles:</p>
+    <p>Hello [% c.user.username %], you have the following roles:</p>
     
     <ul>
       [% # Dump list of roles -%]
-      [% FOR role = Catalyst.user.roles %]<li>[% role %]</li>[% END %]
+      [% FOR role = c.user.roles %]<li>[% role %]</li>[% END %]
     </ul>
     
     <p>
     [% # Add some simple role-specific logic to template %]
     [% # Use $c->check_user_roles() to check authz -%]
-    [% IF Catalyst.check_user_roles('user') %]
+    [% IF c.check_user_roles('user') %]
       [% # Give normal users a link for 'logout' %]
-      <a href="[% Catalyst.uri_for('/logout') %]">Logout</a>
+      <a href="[% c.uri_for('/logout') %]">Logout</a>
     [% END %]
     
     [% # Can also use $c->user->check_roles() to check authz -%]
-    [% IF Catalyst.check_user_roles('admin') %]
+    [% IF c.check_user_roles('admin') %]
       [% # Give admin users a link for 'create' %]
-      <a href="[% Catalyst.uri_for('form_create') %]">Create</a>
+      <a href="[% c.uri_for('form_create') %]">Create</a>
     [% END %]
     </p>
 
 This code displays a different combination of links depending on the
 roles assigned to the user.
 
+
 =head2 Limit C<Books::add> to C<admin> Users
 
 C<IF> statements in TT templates simply control the output that is sent
@@ -177,7 +189,7 @@ admin-level users by editing C<lib/MyApp/Controller/Books.pm> and
 updating C<url_create> to match the following code:
 
     =head2 url_create
-
+    
     Create a book with the supplied title and rating,
     with manual authorization
     
@@ -191,30 +203,30 @@ updating C<url_create> to match the following code:
     
         # Check the user's roles
         if ($c->check_user_roles('admin')) {
-            # Call create() on the book model object. Pass the table 
+            # Call create() on the book model object. Pass the table
             # columns/field values we want to set as hash values
-            my $book = $c->model('MyAppDB::Book')->create({
+            my $book = $c->model('DB::Books')->create({
                     title   => $title,
                     rating  => $rating
                 });
-            
-            # Add a record to the join table for this book, mapping to 
+    
+            # Add a record to the join table for this book, mapping to
             # appropriate author
             $book->add_to_book_authors({author_id => $author_id});
             # Note: Above is a shortcut for this:
             # $book->create_related('book_authors', {author_id => $author_id});
-            
+    
             # Assign the Book object to the stash for display in the view
             $c->stash->{book} = $book;
-        
+    
             # This is a hack to disable XSUB processing in Data::Dumper
             # (it's used in the view).  This is a work-around for a bug in
             # the interaction of some versions or Perl, Data::Dumper & DBIC.
             # You won't need this if you aren't using Data::Dumper (or if
-            # you are running DBIC 0.06001 or greater), but adding it doesn't 
+            # you are running DBIC 0.06001 or greater), but adding it doesn't
             # hurt anything either.
             $Data::Dumper::Useperl = 1;
-        
+    
             # Set the TT template to use
             $c->stash->{template} = 'books/create_done.tt2';
         } else {
@@ -232,13 +244,14 @@ way to demonstrate that TT templates will not be used if the response
 body has already been set.  In reality you would probably want to use a
 technique that maintains the visual continuity of your template layout
 (for example, using the "status" or "error" message feature added in
-Part 2).
+Part 3).
 
 B<TIP>: If you want to keep your existing C<url_create> method, you can
 create a new copy and comment out the original by making it look like a
 Pod comment.  For example, put something like C<=begin> before C<sub add
 : Local {> and C<=end> after the closing C<}>.
 
+
 =head2 Try Out Authentication And Authorization
 
 Press C<Ctrl-C> to kill the previous server instance (if it's still
@@ -246,13 +259,13 @@ running) and restart it:
 
     $ script/myapp_server.pl
 
-Now trying going to L<http://localhost:3000/books/list> and you should
-be taken to the login page (you might have to C<Shift+Reload> your
-browser and/or click the "Logout" link on the book list page).  Try 
-logging in with both C<test01> and C<test02> (both use a password 
-of C<mypass>) and notice how the roles information updates at the 
-bottom of the "Book List" page. Also try the C<Logout> link on the
-book list page.
+Now trying going to L<http://localhost:3000/books/list> and you should 
+be taken to the login page (you might have to C<Shift+Reload> or 
+C<Ctrl+Reload> your browser and/or click the "Logout" link on the book 
+list page).  Try logging in with both C<test01> and C<test02> (both 
+use a password of C<mypass>) and notice how the roles information 
+updates at the bottom of the "Book List" page. Also try the C<Logout> 
+link on the book list page.
 
 Now the "url_create" URL will work if you are already logged in as user
 C<test01>, but receive an authorization failure if you are logged in as
@@ -260,8 +273,8 @@ C<test02>.  Try:
 
     http://localhost:3000/books/url_create/test/1/6
 
-while logged in as each user.  Use one of the 'Logout' links (or go to
-L<http://localhost:3000/logout> in you browser directly) when you are
+while logged in as each user.  Use one of the 'Logout' links (or go to 
+L<http://localhost:3000/logout> in your browser directly) when you are 
 done.
 
 
@@ -269,23 +282,25 @@ done.
 
 This section takes a brief look at how the
 L<Catalyst::Plugin::Authorization::ACL|Catalyst::Plugin::Authorization::ACL>
-plugin can automate much of the work required to perform role-based 
+plugin can automate much of the work required to perform role-based
 authorization in a Catalyst application.
 
+
 =head2 Add the C<Catalyst::Plugin::Authorization::ACL> Plugin
 
 Open C<lib/MyApp.pm> in your editor and add the following plugin to the
-C<use Catalyst> statement:
+C<__PACKAGE__-E<gt>setup> statement:
 
     Authorization::ACL
 
 Note that the remaining C<use Catalyst> plugins from earlier sections
 are not shown here, but they should still be included.
 
+
 =head2 Add ACL Rules to the Application Class
 
 Open C<lib/MyApp.pm> in your editor and add the following B<BELOW> the
-C<__PACKAGE__-E<gt>setup;> statement:
+C<__PACKAGE__-E<gt>setup> statement:
 
     # Authorization::ACL Rules
     __PACKAGE__->deny_access_unless(
@@ -314,14 +329,14 @@ ways.  The following provides a basic overview of the capabilities:
 
 =over 4
 
-=item * 
+=item *
 
 The ACL plugin only operates on the Catalyst "private namespace".  You
 are using the private namespace when you use C<Local> actions.  C<Path>,
 C<Regex>, and C<Global> allow you to specify actions where the path and
 the namespace differ -- the ACL plugin will not work in these cases.
 
-=item * 
+=item *
 
 Each rule is expressed in a separate
 C<__PACKAGE__-E<gt>deny_access_unless()> or
@@ -331,11 +346,11 @@ portion of the
 L<Catalyst::Plugin::Authorization::ACL|Catalyst::Plugin::Authorization::ACL>
 documentation for more details).
 
-=item * 
+=item *
 
 Each rule can contain multiple roles but only a single path.
 
-=item * 
+=item *
 
 The rules are tried in order (with the "most specific" rules tested
 first), and processing stops at the first "match" where an allow or deny
@@ -344,17 +359,18 @@ is specified.  Rules "fall through" if there is not a "match" (where a
 then processing stops there and the appropriate allow/deny action is
 taken.
 
-=item * 
+=item *
 
 If none of the rules match, then access is allowed.
 
-=item * 
+=item *
 
-The rules currently need to be specific in the application class
+The rules currently need to be specified in the application class
 C<lib\MyApp.pm> B<after> the C<__PACKAGE__-E<gt>setup;> line.
 
 =back
 
+
 =head2 Add a Method to Handle Access Violations
 
 By default,
@@ -384,17 +400,17 @@ following method:
         $c->forward('list');
     }
 
-Then run the Catalyst development server script:    
+Then run the Catalyst development server script:
 
     $ script/myapp_server.pl
 
-Log in as C<test02>.  Once at the book list, click the "Create" link to
-try the C<form_create> action.  You should receive a red "Unauthorized!"
-error message at the top of the list.  (Note that in reality you would
-probably want to place the "Create" link code in
-C<root/src/books/list.tt2> inside an C<IF> statement that only displays
-the list to admin-level users.)  If you log in as C<test01> you should
-be able to view the C<form_create> form and add a new book.
+Log in as C<test02>.  Once at the book list, click the "Create" link
+to try the C<form_create> action.  You should receive a red
+"Unauthorized!"  error message at the top of the list.  (Note that in
+the example code the "Create" link code in C<root/src/books/list.tt2>
+is inside an C<IF> statement that only displays the list to
+admin-level users.)  If you log in as C<test01> you should be able to
+view the C<form_create> form and add a new book.
 
 When you are done, use one of the 'Logout' links (or go to the
 L<http://localhost:3000/logout> URL directly) when you are done.
@@ -406,8 +422,8 @@ 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-Manual/lib/Catalyst/Manual/Tutorial/>.
+L<http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
 
-Copyright 2006, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).