[Catalyst-commits] r8928 - in
trunk/examples/CatalystAdvent/root/2008: . pen
zarquon at dev.catalyst.perl.org
zarquon at dev.catalyst.perl.org
Sat Dec 20 12:54:48 GMT 2008
Author: zarquon
Date: 2008-12-20 12:54:47 +0000 (Sat, 20 Dec 2008)
New Revision: 8928
Added:
trunk/examples/CatalystAdvent/root/2008/19.pod
Removed:
trunk/examples/CatalystAdvent/root/2008/pen/progressive_auth.pod
Log:
day 19
Copied: trunk/examples/CatalystAdvent/root/2008/19.pod (from rev 8926, trunk/examples/CatalystAdvent/root/2008/pen/progressive_auth.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2008/19.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2008/19.pod 2008-12-20 12:54:47 UTC (rev 8928)
@@ -0,0 +1,238 @@
+c=head1 Progressive Authentication with Catalyst (Using OpenID)
+
+I<Note: > This article has an accompanying example application that can be
+downloaded and run. Please see the L</"Try it and see"> section for more
+information.
+
+=head2 A brief overview of authentication
+
+Often times, as applications (especially any application with social aspects)
+grow and evolve, there becomes a necessity for "other" forms of authentication.
+Most typically, this is in the form of a temporary password that is emailed
+to a user. Many applications actually change the user's password to some
+generated password, making the previous password invalid. Other
+applications just email the forgotten password in plain text.
+
+Both of these solutions are wrong. (Now I'm just going to leave it at that.)
+
+This situation directly inspired the development of the Progressive Realm
+(L<http://search.cpan.org/~jayk/Catalyst-Plugin-Authentication-0.100091/lib/Catalyst/Authentication/Realm/Progressive.pm>).
+We won't cover proper handling of temporary passwords, since that is a
+more involved topic and much larger article (to be discussed at a later date,
+but I provide a brief note at the bottom of this article).
+
+Instead, I will cover how to query multiple realms to do authentications in a
+very simple setting.
+
+=head2 OpenID and Local Authentication
+
+The simple example is centered around handling OpenID. OpenID, by itself, is
+very simple. However there are some nits that eventually result in ugly and
+unmaintainable code, unless you have the foresight to handle it. This
+foresight usually comes from writing the above mentioned ugly code. The
+subsequent solution that isn't ugly tends to look very similar to the
+Progressive realm, hence its creation.
+
+First off, to handle OpenID and local authentication is an almost
+trivial matter. To get it running, it requires nothing more than the
+Authentication plugin, the OpenID credential, and a session plugin. The
+main issue to overcome with OpenID is that while you can associate the
+authenticating URL to an account, sometimes users also have a password
+on the site. It can be difficult to handle the authentication for both,
+and often times the login controller becomes ugly. There is far too
+much logic there, and it doesn't really do much other than determine
+which realm the user is in. The Progressive realm is the ready-made
+solution!
+
+(As an aside, a very cool usage for this is to have an application that
+progressively reveals features to users based on their authenticating realm.)
+
+To configure the realms, you first have to load the authentication plugin.
+Also, you need a session store, because what good is authenticating users if
+their authentication only lasts for one request? To do this, we just add the
+following plugins to MyApp.pm:
+
+ use Catalyst qw/
+ ConfigLoader Static::Simple
+ Authentication Session Session::Store::FastMmap Session::State::Cookie
+ /;
+
+=head2 The Simple Case: Local Authentication
+
+Now, the Authentication and Session plugins are loaded and it is time to
+configure Authentication. Most Authentication configurations just use the
+Password credential, and the configuration looks something like this:
+
+ __PACKAGE__->config(
+ name => 'MyApp',
+ 'Plugin::Authentication' => {
+ default_realm => 'local',
+ realms => {
+ 'local' => {
+ credential => {
+ class => 'Password',
+ password_field => 'password',
+ password_type => 'clear'
+ },
+ # A more typical store is the DBIC store
+ store => {
+ class => 'Minimal',
+ users => { ... }
+ }
+ },
+ }
+ }
+ );
+
+Now, a simple call to authenticate in your controller will check the password
+against the store and either succeed or fail. The code here is very
+simple:
+
+ if ( $c->authenticate({ username => $username, password => $password }) ) {
+ $c->log->info("We did it!");
+ } else {
+ $c->log->info("User failed it!");
+ }
+
+We don't specify a realm, because the default realm is C<local> and that's it.
+
+=head2 Adding OpenID
+
+Up next is adding in OpenID. It's a simple adjustment to the configuration to
+add the credential in:
+
+ __PACKAGE__->config(
+ name => 'MyApp',
+ 'Plugin::Authentication' => {
+ default_realm => 'local',
+ realms => {
+ 'openid' => {
+ credential => {
+ class => 'OpenID'
+ },
+ store => {
+ class => 'Null',
+ }
+ },
+ 'local' => {
+ credential => {
+ class => 'Password',
+ password_field => 'password',
+ password_type => 'clear'
+ },
+ store => {
+ class => 'Minimal',
+ users => { ... }
+ }
+ },
+ }
+ }
+ );
+
+Now, we can change the authentication method a bit. Before the progressive
+realm, the code starts to look like this:
+
+ my $data = {};
+ my $realm;
+
+ if ( $c->req->params->{openid_identifier} ) {
+ $data->{openid_identifier} = $c->req->params->{openid_identifier};
+ } else {
+ $data->{username} = $c->req->params->{username};
+ $data->{password} = $c->req->params->{password};
+ }
+ if ( $c->authenticate( $data, $realm ) ) {
+ $c->log->info("We did it!");
+ } else {
+ $c->log->info("User failed it!");
+ }
+
+That's not bad code, but it's a lot more than just using a single realm. The
+problem is when you continue to add realms and other mechanisms for users to
+authenticate (web services, temporary passwords) it grows and becomes more
+unmaintainable. Eventually, it ends up on The Daily WTF and people refer to
+it with hand waves and resignations.
+
+=head2 Now, with Progressive Realms
+
+The first step is to simply configure a default realm that uses the
+Progressive realm class, and then list what realms are legitimate to try.
+
+ __PACKAGE__->config(
+ name => 'MyApp',
+ 'Plugin::Authentication' => {
+ default_realm => 'progressive',
+ realms => {
+ progressive => {
+ class => 'Progressive',
+ realms => [ 'openid', 'local' ],
+ },
+ 'openid' => {
+ credential => {
+ class => 'OpenID'
+ },
+ store => {
+ class => 'Null',
+ }
+ },
+ 'local' => {
+ credential => {
+ class => 'Password',
+ password_field => 'password',
+ password_type => 'clear'
+ },
+ store => {
+ class => 'Minimal',
+ users => { ... }
+ }
+ },
+ }
+ }
+ );
+
+With the configuration finished, it's time to modify the authenticate call to
+remove the specific realm (or, if C<progressive> isn't your default realm, to
+set that explicitly).
+
+Also, it is a good idea to filter exactly what you are putting into the
+authenticate call. Then it is a simple "whitelist" check and you pass in the
+entire stash. The code for authenticating now looks like this:
+
+ my %data = map { $_ => $c->req->params->{$_} }
+ # Filter out parameters not defined
+ grep { defined $c->req->params->{$_} }
+ # List of parameters potentially used:
+ qw/openid_identifier username password/;
+ if ( $c->authenticate({ %data }) ) {
+ $c->log->info("We did it!");
+ } else {
+ $c->log->info("User failed it!");
+ }
+
+When new realms are added, simply add the parameter keys to the list of
+parameters and things should work transparently. The order of C<realms> in
+the Progressive configuration determines the order the subordinate realms are
+called, and whichever one matches first returns.
+
+=head2 Try it and see
+
+This Advent entry is accompanied by a fully working example application that
+demonstrates the principles. It is available as a standalone tarball at
+L<http://www.coldhardcode.com/examples/catalyst/ProgressiveAuth-0.01.tar.gz>
+or if you prefer an svn checkout:
+
+ svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/ProgressiveAuth/
+
+=head1 Author
+
+Jay Shirley, the IT Director at L<http://www.nasaproracing.com> and Co-Founder
+of L<http://www.coldhardcode.com>. He is a die-hard Catalyst user, evangelist
+and Perl hacker.
+
+=head2 Appendix A: A note on temporary passwords
+
+As a follow-up, the proper solution for temporary passwords is to have
+multiple realms for authentication: one for temporary passwords and one for
+legitimate passwords. If the user authenticates in the temporary realm then
+you force a password change. If the user authenticates via the normal realm,
+nothing changes.
Deleted: trunk/examples/CatalystAdvent/root/2008/pen/progressive_auth.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2008/pen/progressive_auth.pod 2008-12-19 12:54:48 UTC (rev 8927)
+++ trunk/examples/CatalystAdvent/root/2008/pen/progressive_auth.pod 2008-12-20 12:54:47 UTC (rev 8928)
@@ -1,238 +0,0 @@
-c=head1 Progressive Authentication with Catalyst (Using OpenID)
-
-I<Note: > This article has an accompanying example application that can be
-downloaded and run. Please see the L</"Try it and see"> section for more
-information.
-
-=head2 A brief overview of authentication
-
-Often times, as applications (especially any application with social aspects)
-grow and evolve, there becomes a necessity for "other" forms of authentication.
-Most typically, this is in the form of a temporary password that is emailed
-to a user. Many applications actually change the user's password to some
-generated password, making the previous password invalid. Other
-applications just email the forgotten password in plain text.
-
-Both of these solutions are wrong. (Now I'm just going to leave it at that.)
-
-This situation directly inspired the development of the Progressive Realm
-(L<http://search.cpan.org/~jayk/Catalyst-Plugin-Authentication-0.100091/lib/Catalyst/Authentication/Realm/Progressive.pm>).
-We won't cover proper handling of temporary passwords, since that is a
-more involved topic and much larger article (to be discussed at a later date,
-but I provide a brief note at the bottom of this article).
-
-Instead, I will cover how to query multiple realms to do authentications in a
-very simple setting.
-
-=head2 OpenID and Local Authentication
-
-The simple example is centered around handling OpenID. OpenID, by itself, is
-very simple. However there are some nits that eventually result in ugly and
-unmaintainable code, unless you have the foresight to handle it. This
-foresight usually comes from writing the above mentioned ugly code. The
-subsequent solution that isn't ugly tends to look very similar to the
-Progressive realm, hence its creation.
-
-First off, to handle OpenID and local authentication is an almost
-trivial matter. To get it running, it requires nothing more than the
-Authentication plugin, the OpenID credential, and a session plugin. The
-main issue to overcome with OpenID is that while you can associate the
-authenticating URL to an account, sometimes users also have a password
-on the site. It can be difficult to handle the authentication for both,
-and often times the login controller becomes ugly. There is far too
-much logic there, and it doesn't really do much other than determine
-which realm the user is in. The Progressive realm is the ready-made
-solution!
-
-(As an aside, a very cool usage for this is to have an application that
-progressively reveals features to users based on their authenticating realm.)
-
-To configure the realms, you first have to load the authentication plugin.
-Also, you need a session store, because what good is authenticating users if
-their authentication only lasts for one request? To do this, we just add the
-following plugins to MyApp.pm:
-
- use Catalyst qw/
- ConfigLoader Static::Simple
- Authentication Session Session::Store::FastMmap Session::State::Cookie
- /;
-
-=head2 The Simple Case: Local Authentication
-
-Now, the Authentication and Session plugins are loaded and it is time to
-configure Authentication. Most Authentication configurations just use the
-Password credential, and the configuration looks something like this:
-
- __PACKAGE__->config(
- name => 'MyApp',
- 'Plugin::Authentication' => {
- default_realm => 'local',
- realms => {
- 'local' => {
- credential => {
- class => 'Password',
- password_field => 'password',
- password_type => 'clear'
- },
- # A more typical store is the DBIC store
- store => {
- class => 'Minimal',
- users => { ... }
- }
- },
- }
- }
- );
-
-Now, a simple call to authenticate in your controller will check the password
-against the store and either succeed or fail. The code here is very
-simple:
-
- if ( $c->authenticate({ username => $username, password => $password }) ) {
- $c->log->info("We did it!");
- } else {
- $c->log->info("User failed it!");
- }
-
-We don't specify a realm, because the default realm is C<local> and that's it.
-
-=head2 Adding OpenID
-
-Up next is adding in OpenID. It's a simple adjustment to the configuration to
-add the credential in:
-
- __PACKAGE__->config(
- name => 'MyApp',
- 'Plugin::Authentication' => {
- default_realm => 'local',
- realms => {
- 'openid' => {
- credential => {
- class => 'OpenID'
- },
- store => {
- class => 'Null',
- }
- },
- 'local' => {
- credential => {
- class => 'Password',
- password_field => 'password',
- password_type => 'clear'
- },
- store => {
- class => 'Minimal',
- users => { ... }
- }
- },
- }
- }
- );
-
-Now, we can change the authentication method a bit. Before the progressive
-realm, the code starts to look like this:
-
- my $data = {};
- my $realm;
-
- if ( $c->req->params->{openid_identifier} ) {
- $data->{openid_identifier} = $c->req->params->{openid_identifier};
- } else {
- $data->{username} = $c->req->params->{username};
- $data->{password} = $c->req->params->{password};
- }
- if ( $c->authenticate( $data, $realm ) ) {
- $c->log->info("We did it!");
- } else {
- $c->log->info("User failed it!");
- }
-
-That's not bad code, but it's a lot more than just using a single realm. The
-problem is when you continue to add realms and other mechanisms for users to
-authenticate (web services, temporary passwords) it grows and becomes more
-unmaintainable. Eventually, it ends up on The Daily WTF and people refer to
-it with hand waves and resignations.
-
-=head2 Now, with Progressive Realms
-
-The first step is to simply configure a default realm that uses the
-Progressive realm class, and then list what realms are legitimate to try.
-
- __PACKAGE__->config(
- name => 'MyApp',
- 'Plugin::Authentication' => {
- default_realm => 'progressive',
- realms => {
- progressive => {
- class => 'Progressive',
- realms => [ 'openid', 'local' ],
- },
- 'openid' => {
- credential => {
- class => 'OpenID'
- },
- store => {
- class => 'Null',
- }
- },
- 'local' => {
- credential => {
- class => 'Password',
- password_field => 'password',
- password_type => 'clear'
- },
- store => {
- class => 'Minimal',
- users => { ... }
- }
- },
- }
- }
- );
-
-With the configuration finished, it's time to modify the authenticate call to
-remove the specific realm (or, if C<progressive> isn't your default realm, to
-set that explicitly).
-
-Also, it is a good idea to filter exactly what you are putting into the
-authenticate call. Then it is a simple "whitelist" check and you pass in the
-entire stash. The code for authenticating now looks like this:
-
- my %data = map { $_ => $c->req->params->{$_} }
- # Filter out parameters not defined
- grep { defined $c->req->params->{$_} }
- # List of parameters potentially used:
- qw/openid_identifier username password/;
- if ( $c->authenticate({ %data }) ) {
- $c->log->info("We did it!");
- } else {
- $c->log->info("User failed it!");
- }
-
-When new realms are added, simply add the parameter keys to the list of
-parameters and things should work transparently. The order of C<realms> in
-the Progressive configuration determines the order the subordinate realms are
-called, and whichever one matches first returns.
-
-=head2 Try it and see
-
-This Advent entry is accompanied by a fully working example application that
-demonstrates the principles. It is available as a standalone tarball at
-L<http://www.coldhardcode.com/examples/catalyst/ProgressiveAuth-0.01.tar.gz>
-or if you prefer an svn checkout:
-
- svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/ProgressiveAuth/
-
-=head1 Author
-
-Jay Shirley, the IT Director at L<http://www.nasaproracing.com> and Co-Founder
-of L<http://www.coldhardcode.com>. He is a die-hard Catalyst user, evangelist
-and Perl hacker.
-
-=head2 Appendix A: A note on temporary passwords
-
-As a follow-up, the proper solution for temporary passwords is to have
-multiple realms for authentication: one for temporary passwords and one for
-legitimate passwords. If the user authenticates in the temporary realm then
-you force a password change. If the user authenticates via the normal realm,
-nothing changes.
More information about the Catalyst-commits
mailing list