[Catalyst-commits] r8574 - in
trunk/Catalyst-Authentication-Store-DBIx-Class:
lib/Catalyst/Authentication lib/Catalyst/Authentication/Realm t
jayk at dev.catalyst.perl.org
jayk at dev.catalyst.perl.org
Sun Oct 26 23:30:37 GMT 2008
Author: jayk
Date: 2008-10-26 23:30:37 +0000 (Sun, 26 Oct 2008)
New Revision: 8574
Added:
trunk/Catalyst-Authentication-Store-DBIx-Class/lib/Catalyst/Authentication/Realm/
trunk/Catalyst-Authentication-Store-DBIx-Class/lib/Catalyst/Authentication/Realm/SimpleDB.pm
trunk/Catalyst-Authentication-Store-DBIx-Class/t/08-simpledb-auth-roles-relationship.t
trunk/Catalyst-Authentication-Store-DBIx-Class/t/09-simpledb-auth-roles-column.t
Log:
Woot. Forgot the svk add. I rule
Added: trunk/Catalyst-Authentication-Store-DBIx-Class/lib/Catalyst/Authentication/Realm/SimpleDB.pm
===================================================================
--- trunk/Catalyst-Authentication-Store-DBIx-Class/lib/Catalyst/Authentication/Realm/SimpleDB.pm (rev 0)
+++ trunk/Catalyst-Authentication-Store-DBIx-Class/lib/Catalyst/Authentication/Realm/SimpleDB.pm 2008-10-26 23:30:37 UTC (rev 8574)
@@ -0,0 +1,270 @@
+package Catalyst::Authentication::Realm::SimpleDB;
+
+use strict;
+use warnings;
+use Catalyst::Exception;
+use base qw/Catalyst::Authentication::Realm/;
+
+sub new {
+ my ($class, $realmname, $config, $app) = @_;
+
+ my $newconfig = {
+ credential => {
+ class => 'Password',
+ password_type => 'clear'
+ },
+ store => {
+ class => 'DBIx::Class',
+ role_relation => 'roles',
+ role_field => 'role',
+ use_userdata_from_session => '1'
+ }
+ };
+
+ if (!defined($config->{'user_model'})) {
+ Catalyst::Exception->throw("Unable to initialize authentication, no user_model specified in SimpleDB config.");
+ }
+
+
+ ## load any overrides for the credential
+ foreach my $key (qw/ password_type password_field password_hash_type/) {
+ if (exists($config->{$key})) {
+ $newconfig->{credential}{$key} = $config->{$key};
+ }
+ }
+
+ ## load any overrides for the store
+ foreach my $key (qw/ user_model role_relation role_field role_column use_userdata_from_session/) {
+ if (exists($config->{$key})) {
+ $newconfig->{store}{$key} = $config->{$key};
+ }
+ }
+ if (exists($newconfig->{'store'}{'role_column'})) {
+ delete $newconfig->{'store'}{'role_relation'};
+ delete $newconfig->{'store'}{'role_field'};
+ }
+
+ return $class->SUPER::new($realmname, $newconfig, $app);
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Catalyst::Authentication::Realm::SimpleDB - A simplified Catalyst authentication configurator.
+
+=head1 SYNOPSIS
+
+ use Catalyst qw/
+ Authentication
+ /;
+
+ __PACKAGE__->config->{'Plugin::Authentication'} =
+ {
+ default => {
+ class => 'SimpleDB',
+ user_class => 'MyApp::User'
+ }
+ }
+
+ # later on ...
+ $c->authenticate({ username => 'myusername',
+ password => 'mypassword' });
+
+ my $age = $c->user->get('age');
+
+ $c->logout;
+
+
+=head1 DESCRIPTION
+
+The Catalyst::Authentication::Realm::SimpleDB provides a simple way to configure Catalyst Authentication
+when using the most common configuration of a password protected user retrieved from an SQL database.
+
+=head1 CONFIGURATION
+
+The SimpleDB Realm class configures the Catalyst authentication system based on the following:
+
+=over
+
+=item *
+Your user data is stored in a table that is accessible via $c->model('User');
+
+=item *
+Your passwords are stored in the 'password' field in your users table and are not encrypted.
+
+=item *
+Your roles for users are stored in a separate table and are directly
+accessible via a DBIx::Class relationship called 'roles' and the text of the
+role is stored in a field called 'role' within the role table.
+
+=item *
+Your user information is stored in the session once the user is authenticated.
+
+=back
+
+For the above usage, only one configuration option is necessary, 'user_class'.
+B<user_class> should contain the class name of your user class. See the
+L</PREPARATION> section for info on how to set up your database for use with
+this module.
+
+If your system differs from the above, some minor configuration may be
+necessary. The options available are detailed below. These options match the
+configuration options used by the underlying credential and store modules.
+More information on these options can be found in
+L<Catalyst::Authentication::Credential::Password> and
+L<Catalyst::Authentication::Store::DBIx::Class>.
+
+=over
+
+=item user_class
+
+Contains the class name (as passed to $c->model() ) of the DBIx::Class schema
+to use as the source for user information. This config item is B<REQUIRED>.
+
+=item password_field
+
+If your password field is not 'password' set this option to the name of your password field. Note that if you change this
+to, say 'users_password' you will need to use that in the authenticate call:
+
+ $c->authenticate({ username => 'bob', users_password => 'foo' });
+
+=item password_type
+
+If the password is not stored in plaintext you will need to define what format the password is in. The common options are
+B<crypted> and B<hashed>. Crypted uses the standard unix crypt to encrypt the password. Hashed uses the L<Digest> modules to
+perform password hashing.
+
+=item password_hash_type
+
+If you use a hashed password type - this defines the type of hashing. See L<Catalyst::Authentication::Credential::Password>
+for more details on this setting.
+
+=item role_column
+
+If your users roles are stored directly in your user table, set this to the column name that contains your roles. For
+example, if your user table contains a field called 'permissions', the value of role_column would be 'permissions'.
+B<NOTE>: If multiple values are stored in the role column, they should be space or pipe delimited.
+
+=item role_relation and role_field
+
+These define an alternate role relationship name and the column that holds the role's name in plain text. See
+L<Catalyst::Authentication::Store::DBIx::Class/CONFIGURATION> for more details on these settings.
+
+=item use_userdata_from_session
+
+This is a simple 1 / 0 setting which determines how a user's data is saved / restored from the session. If
+it is set to 1, the user's complete information (at the time of authentication) is cached between requests.
+If it is set to 0, the users information is loaded from the database on each request.
+
+=back
+
+
+=head1 PREPARATION
+
+This module makes several assumptions about the structure of your database.
+Below is an example of a table structure which will function with this module
+in it's default configuration. You can use this table structure as-is or add
+additional fields as necessary. B<NOTE> that this is the default SimpleDB
+configuration only. Your table structure can differ significantly from this
+when using the L<DBIx::Class
+Store|Catalyst::Authentication::Store::DBIx::Class/> directly.
+
+
+ --
+ -- note that you can add any additional columns you require to the users table.
+ --
+ CREATE TABLE users (
+ id INTEGER PRIMARY KEY,
+ username TEXT,
+ password TEXT,
+ );
+
+ 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)
+ );
+
+Also, after you have loaded this table structure into your DBIx::Class schema,
+please be sure that you have a many_to_many DBIx::Class relationship defined
+for the users to roles relation. Your schema files should contain something
+along these lines:
+
+C<lib/MyApp/Schema/Users.pm>:
+
+ __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::UserRoles', 'user_id');
+ __PACKAGE__->many_to_many(roles => 'map_user_role', 'role');
+
+C<lib/MyApp/Schema/UserRoles.pm>:
+
+ __PACKAGE__->belongs_to(role => 'MyApp::Schema::Roles', 'role_id');
+
+=head1 MIGRATION
+
+If and when your application becomes complex enough that you need more features
+than SimpleDB gives you access to, you can migrate to a standard Catalyst
+Authentication configuration fairly easily. SimpleDB simply creates a standard
+Auth config based on the inputs you give it. The config SimpleDB creates by default
+looks like this:
+
+ MyApp->config('Plugin::Authentication') = {
+ default => {
+ credential => {
+ class => 'Password',
+ password_type => 'clear'
+ },
+ store => {
+ class => 'DBIx::Class',
+ role_relation => 'roles',
+ role_field => 'role',
+ use_userdata_from_session => '1',
+ user_model => $user_model_from_simpledb_config
+ }
+ }
+ };
+
+
+=head1 SEE ALSO
+
+This module relies on a number of other modules to do it's job. For more information
+you can refer to the following:
+
+=over
+
+=item *
+L<Catalyst::Manual::Tutorial::Authentication>
+
+=item *
+L<Catalyst::Plugin::Authentication>
+
+=item *
+L<Catalyst::Authentication::Credential::Password>
+
+=item *
+L<Catalyst::Authentication::Store::DBIx::Class>
+
+=item *
+L<Catalyst::Plugin::Authorization::Roles>
+
+=back
+
+=head1 WARNINGS
+
+...
+
+=head1 NOTES
+
+...
+
+=head1 BUGS
+
+What?
+
+=cut
+
Added: trunk/Catalyst-Authentication-Store-DBIx-Class/t/08-simpledb-auth-roles-relationship.t
===================================================================
--- trunk/Catalyst-Authentication-Store-DBIx-Class/t/08-simpledb-auth-roles-relationship.t (rev 0)
+++ trunk/Catalyst-Authentication-Store-DBIx-Class/t/08-simpledb-auth-roles-relationship.t 2008-10-26 23:30:37 UTC (rev 8574)
@@ -0,0 +1,75 @@
+#!perl
+
+use strict;
+use warnings;
+use DBI;
+use File::Path;
+use FindBin;
+use Test::More;
+use lib "$FindBin::Bin/lib";
+
+BEGIN {
+ eval { require DBD::SQLite }
+ or plan skip_all =>
+ "DBD::SQLite is required for this test";
+
+ eval { require DBIx::Class }
+ or plan skip_all =>
+ "DBIx::Class is required for this test";
+
+ eval { require Catalyst::Plugin::Authorization::Roles }
+ or plan skip_all =>
+ "Catalyst::Plugin::Authorization::Roles is required for this test";
+
+ plan tests => 8;
+
+ $ENV{TESTAPP_DB_FILE} = "$FindBin::Bin/auth.db" unless exists($ENV{TESTAPP_DB_FILE});
+
+
+ $ENV{TESTAPP_CONFIG} = {
+ name => 'TestApp',
+ 'Plugin::Authentication' => {
+ default => {
+ class => 'SimpleDB',
+ user_model => 'TestApp::User',
+ }
+ }
+ };
+
+ $ENV{TESTAPP_PLUGINS} = [
+ qw/Authentication
+ Authorization::Roles
+ /
+ ];
+}
+
+use SetupDB;
+
+use Catalyst::Test 'TestApp';
+
+# test user's admin access
+{
+ ok( my $res = request('http://localhost/user_login?username=jayk&password=letmein&detach=is_admin'), 'request ok' );
+ is( $res->content, 'ok', 'user is an admin' );
+}
+
+# test unauthorized user's admin access
+{
+ ok( my $res = request('http://localhost/user_login?username=nuffin&password=much&detach=is_admin'), 'request ok' );
+ is( $res->content, 'failed', 'user is not an admin' );
+}
+
+# test multiple auth roles
+{
+ ok( my $res = request('http://localhost/user_login?username=jayk&password=letmein&detach=is_admin_user'), 'request ok' );
+ is( $res->content, 'ok', 'user is an admin and a user' );
+}
+
+# test multiple unauth roles
+{
+ ok( my $res = request('http://localhost/user_login?username=nuffin&password=much&detach=is_admin_user'), 'request ok' );
+ is( $res->content, 'failed', 'user is not an admin and a user' );
+}
+
+# clean up
+unlink $ENV{TESTAPP_DB_FILE};
Added: trunk/Catalyst-Authentication-Store-DBIx-Class/t/09-simpledb-auth-roles-column.t
===================================================================
--- trunk/Catalyst-Authentication-Store-DBIx-Class/t/09-simpledb-auth-roles-column.t (rev 0)
+++ trunk/Catalyst-Authentication-Store-DBIx-Class/t/09-simpledb-auth-roles-column.t 2008-10-26 23:30:37 UTC (rev 8574)
@@ -0,0 +1,77 @@
+#!perl
+
+use strict;
+use warnings;
+use DBI;
+use File::Path;
+use FindBin;
+use Test::More;
+use lib "$FindBin::Bin/lib";
+
+BEGIN {
+ eval { require DBD::SQLite }
+ or plan skip_all =>
+ "DBD::SQLite is required for this test";
+
+ eval { require DBIx::Class }
+ or plan skip_all =>
+ "DBIx::Class is required for this test";
+
+ eval { require Catalyst::Plugin::Authorization::Roles }
+ or plan skip_all =>
+ "Catalyst::Plugin::Authorization::Roles is required for this test";
+
+ plan tests => 8;
+
+ $ENV{TESTAPP_DB_FILE} = "$FindBin::Bin/auth.db" unless exists($ENV{TESTAPP_DB_FILE});
+
+
+ $ENV{TESTAPP_CONFIG} = {
+ name => 'TestApp',
+ 'Plugin::Authentication' => {
+ default => {
+ class => 'SimpleDB',
+ user_model => 'TestApp::User',
+ role_column => 'role_text'
+ }
+ }
+
+ };
+
+ $ENV{TESTAPP_PLUGINS} = [
+ qw/Authentication
+ Authorization::Roles
+ /
+ ];
+}
+
+use SetupDB;
+
+use Catalyst::Test 'TestApp';
+
+# test user's admin access
+{
+ ok( my $res = request('http://localhost/user_login?username=joeuser&password=hackme&detach=is_admin'), 'request ok' );
+ is( $res->content, 'ok', 'user is an admin' );
+}
+
+# test unauthorized user's admin access
+{
+ ok( my $res = request('http://localhost/user_login?username=jayk&password=letmein&detach=is_admin'), 'request ok' );
+ is( $res->content, 'failed', 'user is not an admin' );
+}
+
+# test multiple auth roles
+{
+ ok( my $res = request('http://localhost/user_login?username=nuffin&password=much&detach=is_admin_user'), 'request ok' );
+ is( $res->content, 'ok', 'user is an admin and a user' );
+}
+
+# test multiple unauth roles
+{
+ ok( my $res = request('http://localhost/user_login?username=joeuser&password=hackme&detach=is_admin_user'), 'request ok' );
+ is( $res->content, 'failed', 'user is not an admin and a user' );
+}
+
+# clean up
+unlink $ENV{TESTAPP_DB_FILE};
More information about the Catalyst-commits
mailing list