[Catalyst] Authentication not working as expected

Hernan Lopes hernanlopes at gmail.com
Tue Jan 11 18:06:09 GMT 2011


Or try this application which implements authentication example with perl
catalyst from scratch.
You can test it, its just a couple steps.. hope it helps.
i wrote it sometime ago but i have not tested yet.

1. create a database
2. create tables:

CREATE TABLE users
(
  id serial NOT NULL,
  nome text,
  sobrenome text,
  is_deleted integer DEFAULT 0,
  endereco text,
  created date DEFAULT now(),
  username text,
  "password" text,
  telefone text,
  email character varying(255),
  CONSTRAINT users_pkey PRIMARY KEY (id)
);

CREATE TABLE roles
(
  id integer NOT NULL,
  "role" text,
  CONSTRAINT role_pkey PRIMARY KEY (id)
);


CREATE TABLE users_to_roles
(
  user_id integer NOT NULL,
  role_id integer NOT NULL,
  CONSTRAINT users_to_roles_pkey PRIMARY KEY (user_id, role_id),
  CONSTRAINT users_to_roles_role_id_fkey FOREIGN KEY (role_id)
      REFERENCES roles (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT users_to_roles_user_id_fkey FOREIGN KEY (user_id)
      REFERENCES users (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);

2.1 add some data onto db:

insert into roles (id, role) values (1, 'admin');
insert into roles (id, role) values (2, 'gerente');
insert into roles (id, role) values (3, 'banidos');
insert into roles (id, role) values (4, 'funcionario');
insert into roles (id, role) values (5, 'secretaria');

insert into users (nome, sobrenome, is_deleted, endereco, username,
password, email) values ('joe', 'silva', '0', '-', 'joe', 'silva', '
joe at silva.net');
insert into users (nome, sobrenome, is_deleted, endereco, username,
password, email) values ('maria', 'gomes', '0', '-', 'maria', 'gomes', '
mariagomes at hotmail.com');
insert into users (nome, sobrenome, is_deleted, endereco, username,
password, email) values ('admin', 'admin', '0', '-', 'admin', 'admin', '
admin at admins.com');


insert into users_to_roles ( role_id, user_id ) values (1, 3);
insert into users_to_roles ( role_id, user_id ) values (2, 1);
insert into users_to_roles ( role_id, user_id ) values (2, 2);

3. create a  default catalyst app

catalyst.pl Example::Catalyst::Auth
cd Example-Catalyst-Auth/

4. create TT view

script/example_catalyst_auth_create.pl view TT

5. open TT.pm file to edit

vim lib/Example/Catalyst/Auth/View/TT.pm

6. insert the following into your TT.pm

package Example::Catalyst::Auth::View::TT;
use warnings;
use strict;
use base 'Catalyst::View::TT';

__PACKAGE__->config(
    # Set to 1 for detailed timer stats in your HTML as comments
    TIMER   =3D> 0,
    # This is your wrapper template located in the 'root/src'
    WRAPPER =3D> 'wrapper.tt2',
    # Change default TT extension
    TEMPLATE_EXTENSION =3D> '.tt2',
    # Set the location for TT files
    INCLUDE_PATH =3D> [
            Example::Catalyst::Auth->path_to( 'root',  ),
        ],
);

__PACKAGE__->meta->make_immutable;

1;


7. now open the main ap config

vim lib/Example/Catalyst/Auth.pm

8. and insert inside your __PACKAGE__->config() :

default_view =3D> 'TT',
ENCODING =3D> 'utf-8',

8.1 and also declare these inside your use Catalyst qw//:

    Unicode

    StackTrace
    Authentication
    Authorization::Roles

8.2 and insert the Auth configuration also.. on that same file:

__PACKAGE__->config->{'Plugin::Authentication'} =3D {
        default =3D> {
            class           =3D> 'SimpleDB',
#           user_model      =3D> 'DBICSchemamodel::Users',
            user_model      =3D> 'DBICSchemamodel::User',
            password_type   =3D> 'clear',
            user_role_user_field =3D> 'user_id',
            user_role_role_field =3D> 'role_id',
        },
    };

8.3 and also insert the Store config

__PACKAGE__->config->{'Plugin::Cache'}{backend} =3D { #DEFAULT backend
  store =3D> "FastMmap",
    class =3D> "Cache::FastMmap",
      storage =3D> "/tmp/cache",
        expires =3D> 3600,
          };






8. create the wrapper:

vim root/wrapper.tt2

9. and insert this content:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd">
<html xmlns=3D"http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
[%content%]
</body>
</html>

10. now lets modify our Root controller.
We should create one index page (And test the view we setup is working)
We should create one hidden page, which will show only when logged in.

vim lib/Example/Catalyst/Auth/Controller/Root.pm

10.1 declare use HTML::FormHandler

use HTML::FormHandler;

11. delete index action and add the following:

sub auto :Private {
    my ($self, $c) =3D at _;

    if ( $c->action eq $c->controller('root')->action_for('login')
        || $c->action eq $c->controller('root')->action_for('index')
        ) {
        return 1;
    }

    # If a user doesn't exist, force login
    if (
        !$c->user_exists
        or (
            (
                    !$c->check_user_roles('admin')
                and !$c->check_user_roles('gerente')
                and !$c->check_user_roles('funcionario')
            )
        )
      )
    {
        # Redirect the user to the login page
        $c->forward('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;
    }

sub index :Path :Args(0) {
    my ( $self, $c ) =3D @_;
    $c->stash(template =3D> \'Welcome please <a href=3D"/login">login</a>')=
; #or
i could use: template =3D> 'index.tt2', and create that file inside myapp/r=
oot
}

sub hidden_page :Path('/hidden_page') :Args(0) {
    my ( $self, $c ) =3D @_;
    $c->stash( template =3D> \'CONTE=DADO ESCONDIDO' );
    }

sub login : Path('/login') : Args(0) {
    my ( $self, $c ) =3D @_;

        my $form =3D HTML::FormHandler->new({
            field_list =3D> [
              username =3D> {
                  type =3D> 'Text',
                  label =3D> 'Login',
                  required =3D> 1,
                  required_message =3D> 'Campo Requerido',
                  },
              password =3D> {
                  type =3D> 'Password',
                  label =3D> 'Password',
                  required =3D> 1,
                  required_message =3D> 'Campo Requerido',
                  },
              submit =3D> {
                  type =3D> 'Submit',
                  value =3D> 'Login',
                  },
              ],
            });
        $c->stash( template =3D> \$form->render);

    # Get the username and password from form
    my $username =3D $c->request->params->{username} || undef;
    my $password =3D $c->request->params->{password} || undef;

    # If the username and password values were found in form
    if ( defined($username) && defined($password) ) {

        # Attempt to log the user in
        if (
            $c->authenticate(
                {
                    username =3D> $username,
                    password =3D> $password
                }
            )
          )
        {

            $c->forward('hidden_page');

            return;
        }
        else {

            # Set an error message
            $c->stash->{error_msg} =3D
 "Login desconhecido. Verifique seu login e senha e tente novamente. ";
        }
    }

    # If either of above don't work out, send to the login page
    $c->detach('index') if ($c->user_exists);
}




sub logout : Path('/logout') : Args(0) {
    my ( $self, $c ) =3D @_;

    # Clear the user's state
    $c->logout;

    # Send the user to the starting point
    $c->response->redirect( $c->uri_for('/') );
}









12. now create your schema:

script/example_catalyst_auth_create.pl model DBICSchemamodel DBIC::Schema
Example::Catalyst::Auth::DBSchema create=3Dstatic dbi:Pg:dbname=3Dtest_auth
dblogin password

13. add many_to_many relationships to model User

vim lib/Example/Catalyst/Auth/DBSchema/Result/User.pm

14. insert before make_immutable or 1

__PACKAGE__->many_to_many('roles', 'users_to_roles' =3D> 'role');

15. add many_to_many relationships to model Role

vim lib/Example/Catalyst/Auth/DBSchema/Result/Role.pm

14. insert before make_immutable or 1

__PACKAGE__->many_to_many('users', 'users_to_roles' =3D> 'user');







att,
Hernan


On Tue, Jan 11, 2011 at 3:18 PM, Mike Raynham <catalyst at mikeraynham.co.uk>w=
rote:

> On 11/01/11 16:09, Ben Lavery wrote:
>
>> Dear all,
>>
>> After installing Catalyst on an OpenIndiana virtual machine, I've been
>> working through the Definitive Guide to Catalyst for the last few weeks =
and
>> have been impressed with how smoothly most of it has gone.
>>
>> I have, however, become unstuck at Chapter 6.  The book explains how to
>> create an application that uses some simple CRUD with user and role data,
>> and uses authentication to prevent users updating other user's data.
>> I have a working application that allows one to create and read user dat=
a,
>> but I can't figure out how to apply the authentication.  The book says:
>> "When using the Authentication plug-in, as we showed in Chapter 3..."
>>
>> I've gone back to Chapter 3 and followed the steps, but I'm not sure whe=
re
>> I am supposed to put the "$c->authenticate".
>> If I place it in DBAuthTest::Controller::Root in a subroutine called
>> "auto", every page on the site needs me to log in, but no matter what I =
put
>> in the username and password fields it says that the data is invalid.
>> As such I have no idea where I have gone wrong, after Googling I can't
>> find similar problems, or people who have had similar problems or
>> implemented a similar system in a similar way.
>> I have looked at the source code provided on the publisher's site, but it
>> doesn't include code for the whole chapter, and indeed seems to stop giv=
en
>> code a page or two previous to where I am now...
>>
>> I have uploaded a copy of my application to
>> http://hashbang0.com/personal/DBAuthTest.tar.bz2 (~46K) which I hope help
>> demonstrate where I am currently.
>>
>> Many thanks for your time, I appreciate any help you can give,
>>
>> Ben Lavery
>>
>
> The authentication section of the online tutorial, as suggested by Hernan
> Lopes, is definitely worth reading.  However, what follows may get you
> started.  The following approach doesn't deal with roles or permission
> levels - it just tests if a user is logged in or not.
>
> The following code is just to give you an idea of how it would work. I've
> just grabbed bits of code from various places and stuck them together, so
> please don't expect to be able to just copy and paste it into your code :=
-)
>
> In your secure controller actions, you need to check if a user is logged
> in:
>
> In DBAuthTest::Controller::AuthUsers...
>
> ###
>
> sub add : Chained('base'): PathPart('add'): Args(0) {
>    my ($self, $c) =3D @_;
>
>    # Detach to the no_user action if a user is not logged in.
>    $c->detach( '/no_user' ) unless $c->user_exists;
>
>    # Do secure stuff here...
> }
>
> ###
>
> Then in DBAuthTest::Controller::Root...
>
> ###
>
> sub no_user :Chained('/') :PathPart :Args(0) {
>    my ($self, $c) =3D @_;
>
>    # The user is not logged in.
>
>    # Remember the failed action so that we can redirect to it
>    # after login.
>    $c->session->{action_private_path} =3D $c->action->private_path;
>
>    # Put a message in the flash so that we can display it on the
>    # login page.
>    $c->flash(
>        error_msg =3D>
>            'To perform the requested action, you must be logged in.'
>    );
>
>    # Redirect to a login page.
>    $c->response->redirect(
>        $c->uri_for_action( '/login' )
>    );
> }
>
> ###
>
> You then need a suitable controller to handle authentication:
>
> ###
>
> package DBAuthTest::Controller::Login;
>
> sub login :Chained('base') :PathPart('login') :Args(0) {
>    my ( $self, $c ) =3D @_;
>
>    # Get username and password from somewhere...
>    my $username =3D $c->request->params->{username};
>    my $password =3D $c->request->params->{password};
>
>    # Do something here if username and password have
>    # not been supplied.
>
>    unless ( $c->authenticate( {
>        username =3D> $username,
>        password =3D> $password
>    } ) ) {
>
>        # Stash an error message.
>        $c->stash(
>            error_msg =3D> 'Incorrect username, password, or both',
>        );
>
>        # Handle invalid credentials.
>
>        return;
>    }
>
>    if( $c->session->{action_private_path} ) {
>
>        # Redirect to the previously unauthorised action.
>        $c->response->redirect(
>            $c->uri_for_action( $c->session->{action_private_path} )
>        );
>
>        delete $c->session->{action_private_path};
>
>    } else {
>
>        # Redirect to a default page.
>        $c->response->redirect( $c->uri_for_action('/index') );
>
>    }
> }
>
> ###
>
>
>
> _______________________________________________
> List: Catalyst at lists.scsys.co.uk
> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
> Searchable archive:
> http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
> Dev site: http://dev.catalyst.perl.org/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20110111/2be0b=
04a/attachment.htm


More information about the Catalyst mailing list