X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FTutorial%2FTutorial%2FAuthorization.pod;fp=lib%2FCatalyst%2FManual%2FTutorial%2FTutorial%2FAuthorization.pod;h=9af1ce3452f8fcac54f12b992c10b4683e068b33;hp=0000000000000000000000000000000000000000;hb=d442cc9fbdf45a28fe02f13552f44e3e2f7ec22e;hpb=4be096acef2b81af64442da618294f69630029a3 diff --git a/lib/Catalyst/Manual/Tutorial/Tutorial/Authorization.pod b/lib/Catalyst/Manual/Tutorial/Tutorial/Authorization.pod new file mode 100644 index 0000000..9af1ce3 --- /dev/null +++ b/lib/Catalyst/Manual/Tutorial/Tutorial/Authorization.pod @@ -0,0 +1,413 @@ +=head1 NAME + +Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Part 5: Authorization + + +=head1 OVERVIEW + +This is B for the Catalyst tutorial. + +L + +=over 4 + +=item 1 + +L + +=item 2 + +L + +=item 3 + +L + +=item 4 + +L + +=item 5 + +B + +=item 6 + +L + +=item 7 + +L + +=item 8 + +L + +=item 9 + +L + +=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 +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 + +=head1 BASIC AUTHORIZATION + +In this section you learn how to manually configure authorization. + +=head2 Update Plugins to Include Support for Authorization + +Edit C and add C to the list: + + use Catalyst qw/ + -Debug + ConfigLoader + Static::Simple + + StackTrace + + Authentication + Authentication::Store::DBIC + Authentication::Credential::Password + Authorization::Roles + + Session + Session::Store::FastMmap + Session::State::Cookie + /; + + +=head2 Add Config Information for Authorization + +Edit C 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 + + +=head2 Add Role-Specific Logic to the "Book List" Template + +Open C in your editor and add the following +lines to the bottom of the file: + +

Hello [% Catalyst.user.username %], you have the following roles:

+ +
    + [% # Dump list of roles -%] + [% FOR role = Catalyst.user.roles %]
  • [% role %]
  • [% END %] +
+ +

+ [% # Add some simple role-specific logic to template %] + [% # Use $c->check_user_roles() to check authz -%] + [% IF Catalyst.check_user_roles('user') %] + [% # Give normal users a link for 'logout' %] + Logout + [% END %] + + [% # Can also use $c->user->check_roles() to check authz -%] + [% IF Catalyst.check_user_roles('admin') %] + [% # Give admin users a link for 'create' %] + Create + [% END %] +

+ +This code displays a different combination of links depending on the +roles assigned to the user. + +=head2 Limit C to C Users + +C statements in TT templates simply control the output that is sent +to the user's browser; it provides no real enforcement (if users know or +guess the appropriate URLs, they are still perfectly free to hit any +action within your application). We need to enhance the controller +logic to wrap restricted actions with role-validation logic. + +For example, we might want to restrict the "formless create" action to +admin-level users by editing C and +updating C to match the following code: + + =head2 url_create + + Create a book with the supplied title and rating, + with manual authorization + + =cut + + sub url_create : Local { + # In addition to self & context, get the title, rating & author_id args + # from the URL. Note that Catalyst automatically puts extra information + # after the "//check_user_roles('admin')) { + # 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({ + title => $title, + rating => $rating + }); + + # 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 + # hurt anything either. + $Data::Dumper::Useperl = 1; + + # Set the TT template to use + $c->stash->{template} = 'books/create_done.tt2'; + } else { + # Provide very simple feedback to the user + $c->response->body('Unauthorized!'); + } + } + + +To add authorization, we simply wrap the main code of this method in an +C statement that calls C. If the user does not +have the appropriate permissions, they receive an "Unauthorized!" +message. Note that we intentionally chose to display the message this +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). + +B: If you want to keep your existing C 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 and C<=end> after the closing C<}>. + +=head2 Try Out Authentication And Authorization + +Press C to kill the previous server instance (if it's still +running) and restart it: + + $ script/myapp_server.pl + +Now trying going to L and you should +be taken to the login page (you might have to C your +browser and/or click the "Logout" link on the book list page). Try +logging in with both C and C (both use a password +of C) and notice how the roles information updates at the +bottom of the "Book List" page. Also try the C link on the +book list page. + +Now the "url_create" URL will work if you are already logged in as user +C, but receive an authorization failure if you are logged in as +C. 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 in you browser directly) when you are +done. + + +=head1 ENABLE ACL-BASED AUTHORIZATION + +This section takes a brief look at how the +L +plugin can automate much of the work required to perform role-based +authorization in a Catalyst application. + +=head2 Add the C Plugin + +Open C in your editor and add the following plugin to the +C statement: + + Authorization::ACL + +Note that the remaining C plugins from earlier sections +are not shown here, but they should still be included. + +=head2 Add ACL Rules to the Application Class + +Open C in your editor and add the following B the +C<__PACKAGE__-Esetup;> statement: + + # Authorization::ACL Rules + __PACKAGE__->deny_access_unless( + "/books/form_create", + [qw/admin/], + ); + __PACKAGE__->deny_access_unless( + "/books/form_create_do", + [qw/admin/], + ); + __PACKAGE__->deny_access_unless( + "/books/delete", + [qw/user admin/], + ); + +Each of the three statements above comprises an ACL plugin "rule". The +first two rules only allow admin-level users to create new books using +the form (both the form itself and the data submission logic are +protected). The third statement allows both users and admins to delete +books. The C action will continue to be protected by +the "manually configured" authorization created earlier in this part of +the tutorial. + +The ACL plugin permits you to apply allow/deny logic in a variety of +ways. The following provides a basic overview of the capabilities: + +=over 4 + +=item * + +The ACL plugin only operates on the Catalyst "private namespace". You +are using the private namespace when you use C actions. C, +C, and C allow you to specify actions where the path and +the namespace differ -- the ACL plugin will not work in these cases. + +=item * + +Each rule is expressed in a separate +C<__PACKAGE__-Edeny_access_unless()> or +C<__PACKAGE__-Eallow_access_if()> line (there are several other +methods that can be used for more complex policies, see the C +portion of the +L +documentation for more details). + +=item * + +Each rule can contain multiple roles but only a single path. + +=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 +is specified. Rules "fall through" if there is not a "match" (where a +"match" means the user has the specified role). If a "match" is found, +then processing stops there and the appropriate allow/deny action is +taken. + +=item * + +If none of the rules match, then access is allowed. + +=item * + +The rules currently need to be specific in the application class +C B the C<__PACKAGE__-Esetup;> line. + +=back + +=head2 Add a Method to Handle Access Violations + +By default, +L +throws an exception when authorization fails. This will take the user +to the Catalyst debug screen, or a "Please come back later" message if +you are not using the C<-Debug> flag. This step uses the +C method in order to provide more appropriate feedback to +the user. + +Open C in your editor and add the +following method: + + =head2 access_denied + + Handle Catalyst::Plugin::Authorization::ACL access denied exceptions + + =cut + + sub access_denied : Private { + my ($self, $c) = @_; + + # Set the error message + $c->stash->{error_msg} = 'Unauthorized!'; + + # Display the list + $c->forward('list'); + } + +Then run the Catalyst development server script: + + $ script/myapp_server.pl + +Log in as C. Once at the book list, click the "Create" link to +try the C 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 inside an C statement that only displays +the list to admin-level users.) If you log in as C you should +be able to view the C form and add a new book. + +When you are done, use one of the 'Logout' links (or go to the +L URL directly) when you are done. + + +=head1 AUTHOR + +Kennedy Clark, C + +Please report any errors, issues or suggestions to the author. The +most recent version of the Catalyst Tutorial can be found at +L. + +Copyright 2006, Kennedy Clark, under Creative Commons License +(L). +