X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Manual.git;a=blobdiff_plain;f=lib%2FCatalyst%2FManual%2FTutorial%2FAuthorization.pod;h=7eb2a4e9911b59203d045b1dad7508a17a56ad7c;hp=66ada75dbe465324f7312486098022815988c6fc;hb=a46b474eb241c3eac09ac0cd8af400a864de3ee5;hpb=1390ef0ecd30a0dcfe59f212353ed81094fdf64a diff --git a/lib/Catalyst/Manual/Tutorial/Authorization.pod b/lib/Catalyst/Manual/Tutorial/Authorization.pod index 66ada75..7eb2a4e 100644 --- a/lib/Catalyst/Manual/Tutorial/Authorization.pod +++ b/lib/Catalyst/Manual/Tutorial/Authorization.pod @@ -1,11 +1,11 @@ =head1 NAME -Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Part 6: Authorization +Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Chapter 6: Authorization =head1 OVERVIEW -This is B for the Catalyst tutorial. +This is B for the Catalyst tutorial. L @@ -56,11 +56,12 @@ L =head1 DESCRIPTION -This part of the tutorial adds role-based authorization to the existing -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. +This chapter of the tutorial adds role-based authorization to the +existing authentication implemented in Chapter 5. It provides simple +examples of how to use roles in both TT templates and controller +actions. The first half looks at basic authorization concepts. The +second half looks at how moving your authorization code to your model +can simplify your code and make things easier to maintain. You can checkout the source code for this example from the catalyst subversion repository as per the instructions in @@ -69,76 +70,33 @@ L. =head1 BASIC AUTHORIZATION -In this section you learn how to manually configure authorization. +In this section you learn the basics of how authorization works under +Catalyst. =head2 Update Plugins to Include Support for Authorization Edit C and add C to the list: - __PACKAGE__->setup(qw/ - -Debug - ConfigLoader - Static::Simple - - StackTrace - - Authentication - Authorization::Roles - - Session - Session::Store::FastMmap - Session::State::Cookie - /; - - -=head2 Add Config Information for Authorization - -Edit C and update it to match the following (the -C and C 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 - - default_realm dbic - - - - # 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 - - - # 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 - - - - + # Load plugins + use Catalyst qw/-Debug + ConfigLoader + Static::Simple + + StackTrace + + Authentication + Authorization::Roles + + Session + Session::Store::FastMmap + Session::State::Cookie + /; + +B As discussed in MoreCatalystBasics, different versions of +C have used a variety of methods to load the plugins. +You can put the plugins in the C statement if you +prefer. =head2 Add Role-Specific Logic to the "Book List" Template @@ -146,6 +104,7 @@ C and C definitions are new): Open C in your editor and add the following lines to the bottom of the file: + ...

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

    @@ -158,13 +117,13 @@ lines to the bottom of the file: [% # Use $c->check_user_roles() to check authz -%] [% IF c.check_user_roles('user') %] [% # Give normal users a link for 'logout' %] - Logout + User Logout [% END %] [% # Can also use $c->user->check_roles() to check authz -%] [% IF c.check_user_roles('admin') %] [% # Give admin users a link for 'create' %] - Create + Admin Create [% END %]

    @@ -172,7 +131,7 @@ This code displays a different combination of links depending on the roles assigned to the user. -=head2 Limit C to C Users +=head2 Limit Books::add to 'admin' 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 @@ -191,7 +150,7 @@ updating C to match the following code: =cut - sub url_create : Local { + sub url_create :Chained('base') :PathPart('url_create') :Args(3) { # In addition to self & context, get the title, rating & author_id args # from the URL. Note that Catalyst automatically puts extra information # after the "// to match the following code: # 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 + # Provide very simple feedback to the user. $c->response->body('Unauthorized!'); } } @@ -240,12 +191,12 @@ 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 3). +Chapter 3 or C to an action that shows an "unauthorized" page). 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<}>. +Pod comment. For example, put something like C<=begin> before +C and C<=end> after the closing C<}>. =head2 Try Out Authentication And Authorization @@ -257,10 +208,10 @@ running) and restart it: Now trying going to L and you should be taken to the login page (you might have to C or -C your browser and/or click the "Logout" link on the book +C your browser and/or click the "User 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 +updates at the bottom of the "Book List" page. Also try the "User Logout" link on the book list page. Now the "url_create" URL will work if you are already logged in as user @@ -269,146 +220,124 @@ 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 +while logged in as each user. Use one of the "logout" links (or go to L in your 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<__PACKAGE__-Esetup> 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 * +=head1 ENABLE MODEL-BASED AUTHORIZATION -If none of the rules match, then access is allowed. +Hopefully it's fairly obvious that adding detailed permission checking +logic to our controllers and view templates isn't a very clean or +scalable way to build role-based permissions into out application. As +with many other aspects of MVC web development, the goal is to have +your controllers and views be an "thin" as possible, with all of the +"fancy business logic" built into your model. -=item * - -The rules currently need to be specified in the application class -C B the C<__PACKAGE__-Esetup;> line. - -=back +For example, let's add a method to our C Result Class to +check if a user is allowed to delete a book. Open +C and add the following method +(be sure to add it below the "C" line): + =head2 delete_allowed_by + + Can the specified user delete the current book? + + =cut + + sub delete_allowed_by { + my ($self, $user) = @_; + + # Only allow delete if user has 'admin' role + return $user->has_role('admin'); + } -=head2 Add a Method to Handle Access Violations +Here we call a C method on our user object, so we should add +this method to our Result Class. Open +C and add the following method below +the "C" line: -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. + =head 2 has_role + + Check if a user has the specified role + + =cut + + use Perl6::Junction qw/any/; + sub has_role { + my ($self, $role) = @_; + + # Does this user posses the required role? + return any(map { $_->role } $self->roles) eq $role; + } -Open C in your editor and add the -following method: +Now we need to add some enforcement inside our controller. Open +C and update the C method to +match the following code: - =head2 access_denied + =head2 delete - Handle Catalyst::Plugin::Authorization::ACL access denied exceptions + Delete a book =cut - sub access_denied : Private { + sub delete :Chained('object') :PathPart('delete') :Args(0) { my ($self, $c) = @_; - # Set the error message - $c->stash->{error_msg} = 'Unauthorized!'; + # Check permissions + $c->detach('/error_noperms') + unless $c->stash->{object}->delete_allowed_by($c->user->get_object); - # Display the list - $c->forward('list'); + # Use the book object saved by 'object' and delete it along + # with related 'book_authors' entries + $c->stash->{object}->delete; + + # 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 + $c->response->redirect($c->uri_for($self->action_for('list'))); + } + +Here, we C to an error page if the user is lacking the +appropriate permissions. For this to work, we need to make +arrangements for the '/error_noperms' action to work. Open +C and add this method: + + =head2 error_noperms + + Permissions error screen + + =cut + + sub error_noperms :Chained('/') :PathPath('error_noperms') :Args(0) { + my ($self, $c) = @_; + + $c->stash->{template} = 'error_noperms.tt2'; } +And also add the template file by putting the following text into +C: + + Permission Denied + 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 -the example code the "Create" link code in C -is 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. +Log in as C and create several new books using the C +feature: + + http://localhost:3000/books/url_create/Test/1/4 + +Then, while still logged in as C, click the "Delete" link next +to one of these books. The book should be removed and you should see +the usual green "Book deleted" message. Next, click the "User Logout" +link and log back in as C. Now try deleting one of the books. +You should be taken to the red "Permission Denied" message on our +error page. -When you are done, use one of the 'Logout' links (or go to the +Use one of the 'Logout' links (or go to the L URL directly) when you are done. @@ -418,7 +347,7 @@ 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. +L. Copyright 2006-2008, Kennedy Clark, under Creative Commons License (L).