[Catalyst] Extending C::Plugin::Authentication::Store::DBIC for additional constraints

Jay K jayk at ion0.com
Thu Mar 29 06:58:28 GMT 2007


Man, it never fails, I leave the computer alone for a few days and
someone immediately asks a question I needed to answer. :-)

Steve is correct, this is exactly the kind of problem that I was
trying to solve with the dev release of C::P::Authentication.

In fact, if you look at:

http://search.cpan.org/~jayk/Catalyst-Plugin-Authentication-Store-
DBIx-Class-0.02/lib/Catalyst/Plugin/Authentication/Store/DBIx/Class.pm

You will see that the additional restraint you are looking for is
doable without even specifying realms, though I suspect you will want
to restrict actions based on which user group they are in - which
would, in fact, require realms.

The simple way, is to set up the default realm using the
C::P::Authentication::Store::DBIx::Class attached to your user table
(see the C::P::A dev release documentation and the above doc for how
that is done)

Then simply set up your login routine to check your site id in
addition to username/password:

     sub login : Local {
         my ( $self, $c ) = @_;

         my $site_id = ... # however you determine the appropriate
site id

         if ($c->authenticate({
                           username => $c->req->params->{username},
                           password => $c->req->params->{password},
                           site_id => $site_id }) ) {

	    # do successful login stuff
          } else {
             # do failed login stuff
          }
     }

The additional restraint is automatically applied during lookup - so
even if you have a 'johndoe' in the database - if the site_id in the
database doesn't match the one provided to the authentication call,
it will not match the user.  In this case, for all intents and
purposes 'johndoe' doesn't exist.

If you, however, in post-authentication actions, you would like to be
able to tell which site_id the user authenticated against, then you
want to set up three realms (foo_realm, bar_realm and foobar_realm),
and then use $c->user_in_realm("foo") in place of $c->user_exists().
Your login routine would look more like this:

     sub login : Local {
         my ( $self, $c ) = @_;

	my $site_id = ... ; # however it is you retrieve this.
	if ($site_id eq 'foo') {
		$c->authenticate({
                           username => $c->req->params->{username},
                           password => $c->req->params->{password},
                           site_id => 'foo' }, 'foo_realm');
	} elsif ( $site_id eq 'bar' ) {
		$c->authenticate({
                           username => $c->req->params->{username},
                           password => $c->req->params->{password},
                           site_id => 'bar' }, 'bar_realm');
	} elsif ( $site_id eq 'foobar') {
		$c->authenticate({
                           username => $c->req->params->{username},
                           password => $c->req->params->{password},
                           site_id => 'foobar' }, 'foobar_realm');
          }
	if ($c->user_exists) {
  		# do successful login stuff
	} else {
		# do unsuccessful login stuff
	}
   }

and in your authenticated actions:

sub doFooBarStuff : Local {
	my ( $self, $c ) = @_;

	if ($c->user_in_realm('foobar_realm')) {
	       # do stuff
	} else {
		$c->stash->{'error'} = "Sorry, you are not a member of foobar, you
need to signup or login at foobar.mycatalystsite.com";
	}
}

Even if a user had authenticated successfully for foo_realm,  the
user_in_realm call would return false, since the user_in_realms check
requires the user to be a member of foobar_realm.  You can still use
$c->user_exists() if, in some actions, you only care that they are
authenticated, regardless of realm:

sub doActionForAllSites : Local {
	my ( $self, $c ) = @_;

	if ($c->user_exists) {
	       # do stuff
	} else {
		$c->stash->{'error'} = "Sorry, you are not logged in.";
	}
}

The advantage to setting it up with the realms scenario is that since
each realm is set up independantly - you could later separate the
groups of users into separate tables, or what have you, and it would
require no changes to the application code - just the realm setup.

Hope this all makes sense.  It's all perfectly clear to me... but
then, it would be since I wrote it... if it is not clear to you, I'm
happy to continue to assist.

JayK


On Mar 26, 2007, at 1:38 AM, Steve Sabljak wrote:

> On 3/26/07, Doran L. Barton <fozz at iodynamics.com> wrote:
>> I'd like some advice on how to do this. I'm developing a single
>> Cat app
>> that will handle multiple sites by looking at the 'host' header. All
>> sites will be associated with domain names under a specific
>> domain. Think
>> wildcard A records in DNS, if you will. For example, all of the
>> following
>> would be caught and handled by the app:
>>
>>    foo.mycatalystsite.com
>>    bar.mycatalystsite.com
>>    foobar.mycatalystsite.com
>>
>> I want each site to have its own pool of users for authentication.
>> The
>> users table, therefore, has a site_id associated with each user.
>>
>> Herein lies the gotcha! I need to be able to tell the
>> Authentication plugin
>> to authenticate the user using $username, $password, and a site_id
>> (as
>> opposed to the usual $username and $password). After looking
>> through the
>> Catalyst::Plugin::Authentication::Store::DBIC code, I can't
>> immediately see
>> how I could subclass it and add this functionality.
>>
>> Thoughts, anyone?
>>
>
> Seems like exactly the kind of thing the development release of
> Catalyst::Plugin::Authentication supports with realms.
> Have a look at http://search.cpan.org/~jayk/Catalyst-Plugin-
> Authentication-0.09999_01/
>
> cheers,
> Steve Sabljak
>
> _______________________________________________
> List: Catalyst at lists.rawmode.org
> Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
> Searchable archive: http://www.mail-archive.com/
> catalyst at lists.rawmode.org/
> Dev site: http://dev.catalyst.perl.org/

---
For most things, throwing yourself at the wall over and over is a
better way to improve than thinking hard about the wall and taking
pictures of it.  -- D.Litwack





More information about the Catalyst mailing list