X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FAuthentication%2FCredential%2FOpenID.pm;h=6eb4d72820dae9648212032d6ead0a9c934b3730;hb=0638ecfb29f35dcb62c095307ad5966f299fa36e;hp=477b9e75c71047788bc4747458af034530b822dd;hpb=f29585f9540eae594f78959a0fec474ef9b18cd6;p=catagits%2FCatalyst-Authentication-Credential-OpenID.git diff --git a/lib/Catalyst/Authentication/Credential/OpenID.pm b/lib/Catalyst/Authentication/Credential/OpenID.pm index 477b9e7..6eb4d72 100644 --- a/lib/Catalyst/Authentication/Credential/OpenID.pm +++ b/lib/Catalyst/Authentication/Credential/OpenID.pm @@ -1,59 +1,63 @@ package Catalyst::Authentication::Credential::OpenID; use strict; use warnings; -no warnings "uninitialized"; -use parent "Class::Accessor::Fast"; +use base "Class::Accessor::Fast"; -BEGIN { - __PACKAGE__->mk_accessors(qw/ _config realm debug secret /); -} +__PACKAGE__->mk_accessors(qw/ + realm debug secret + openid_field + consumer_secret + ua_class + ua_args + extension_args + errors_are_fatal + extensions +/); -our $VERSION = "0.04"; +our $VERSION = "0.16"; use Net::OpenID::Consumer; -use UNIVERSAL::require; use Catalyst::Exception (); -sub new : method { +sub new { my ( $class, $config, $c, $realm ) = @_; - my $self = { _config => { %{ $config }, - %{ $realm->{config} } - } + my $self = { + %{ $config }, + %{ $realm->{config} } }; bless $self, $class; # 2.0 spec says "SHOULD" be named "openid_identifier." - $self->_config->{openid_field} ||= "openid_identifier"; - - $self->debug( $self->_config->{debug} ); + $self->{openid_field} ||= "openid_identifier"; - my $secret = $self->_config->{consumer_secret} ||= join("+", + my $secret = $self->{consumer_secret} ||= join("+", __PACKAGE__, $VERSION, sort keys %{ $c->config } ); $secret = substr($secret,0,255) if length $secret > 255; - $self->secret( $secret ); - $self->_config->{ua_class} ||= "LWPx::ParanoidAgent"; + $self->secret($secret); + # If user has no preference we prefer L::PA b/c it can prevent DoS attacks. + my $ua_class = $self->{ua_class} ||= eval "use LWPx::ParanoidAgent" ? + "LWPx::ParanoidAgent" : "LWP::UserAgent"; - eval { - $self->_config->{ua_class}->require; - } - or Catalyst::Exception->throw("Could not 'require' user agent class " . - $self->_config->{ua_class}); + my $agent_class = $self->ua_class; + eval "require $agent_class" + or Catalyst::Exception->throw("Could not 'require' user agent class " . + $self->ua_class); $c->log->debug("Setting consumer secret: " . $secret) if $self->debug; return $self; } -sub authenticate : method { +sub authenticate { my ( $self, $c, $realm, $authinfo ) = @_; $c->log->debug("authenticate() called from " . $c->request->uri) if $self->debug; - my $field = $self->{_config}->{openid_field}; + my $field = $self->openid_field; my $claimed_uri = $authinfo->{ $field }; @@ -61,18 +65,43 @@ sub authenticate : method { $claimed_uri ||= $c->req->method eq 'GET' ? $c->req->query_params->{ $field } : $c->req->body_params->{ $field }; + my $csr = Net::OpenID::Consumer->new( - ua => $self->_config->{ua_class}->new(%{$self->_config->{ua_args} || {}}), + ua => $self->ua_class->new(%{$self->ua_args || {}}), args => $c->req->params, consumer_secret => $self->secret, ); + if ( $self->extension_args and $self->debug ) + { + # FIXME - Only on startup, remove extension_args accessor + $c->log->warn("The configuration key 'extension_args' is deprecated; use 'extensions'"); + } + + my @extensions = $self->extensions ? + @{ $self->extensions } : $self->extension_args ? + @{ $self->extension_args } : (); + if ( $claimed_uri ) { my $current = $c->uri_for($c->req->uri->path); # clear query/fragment... - my $identity = $csr->claimed_identity($claimed_uri) - or Catalyst::Exception->throw($csr->err); + my $identity = $csr->claimed_identity($claimed_uri); + unless ( $identity ) + { + if ( $self->errors_are_fatal ) + { + Catalyst::Exception->throw($csr->err); + } + else + { + $c->log->error($csr->err . " -- $claimed_uri"); + $c->detach(); + } + } + + $identity->set_extension_args(@extensions) + if @extensions; my $check_url = $identity->check_url( return_to => $current . '?openid-check=1', @@ -80,7 +109,7 @@ sub authenticate : method { delayed_return => 1, ); $c->res->redirect($check_url); - return; + $c->detach(); } elsif ( $c->req->params->{'openid-check'} ) { @@ -98,6 +127,12 @@ sub authenticate : method { # This is where we ought to build an OpenID user and verify against the spec. my $user = +{ map { $_ => scalar $identity->$_ } qw( url display rss atom foaf declared_rss declared_atom declared_foaf foafmaker ) }; + # Dude, I did not design the array as hash spec. Don't curse me [apv]. + my %flat = @extensions; + for my $key ( keys %flat ) + { + $user->{extensions}->{$key} = $identity->signed_extension_fields($key); + } my $user_obj = $realm->find_user($user, $c); @@ -107,14 +142,16 @@ sub authenticate : method { } else { - $c->log->debug("Verified OpenID identity failed to load with find_user; bad user_class? Try 'Null.'") if $c->debug; + $c->log->debug("Verified OpenID identity failed to load with find_user; bad user_class? Try 'Null.'") if $self->debug; return; } } else { - Catalyst::Exception->throw("Error validating identity: " . - $csr->err); + $self->errors_are_fatal ? + Catalyst::Exception->throw("Error validating identity: " . $csr->err) + : + $c->log->error( $csr->err); } } return; @@ -126,15 +163,27 @@ __END__ =head1 NAME -Catalyst::Authentication::Credential::OpenID - OpenID credential for L framework. +Catalyst::Authentication::Credential::OpenID - OpenID credential for Catalyst::Plugin::Authentication framework. =head1 VERSION -0.04 +0.16 + +=head1 BACKWARDS COMPATIBILITY CHANGES + +=head2 EXTENSION_ARGS v EXTENSIONS + +B: The extensions were previously configured under the key C. They are now configured under C. This prevents the need for double configuration but it breaks extensions in your application if you do not change the name. The old version is supported for now but may be phased out at any time. + +As previously noted, L, I have not tested the extensions. I would be grateful for any feedback or, better, tests. + +=head2 FATALS + +The problems encountered by failed OpenID operations have always been fatals in the past. This is unexpected behavior for most users as it differs from other credentials. Authentication errors here are no longer fatal. Debug/error output is improved to offset the loss of information. If for some reason you would prefer the legacy/fatal behavior, set the configuration variable C to a true value. =head1 SYNOPSIS -In MyApp.pm. +In MyApp.pm- use Catalyst qw/ Authentication @@ -143,7 +192,7 @@ In MyApp.pm. Session::State::Cookie /; -Somewhere in myapp.conf. +Somewhere in myapp.conf- default_realm openid @@ -151,13 +200,13 @@ Somewhere in myapp.conf. class OpenID + ua_class LWP::UserAgent - ua_class LWPx::ParanoidAgent -Or in your myapp.yml if you're using L instead. +Or in your myapp.yml if you're using L instead- Plugin::Authentication: default_realm: openid @@ -165,9 +214,9 @@ Or in your myapp.yml if you're using L instead. openid: credential: class: OpenID - ua_class: LWPx::ParanoidAgent + ua_class: LWP::UserAgent -In a controller, perhaps C. +In a controller, perhaps C- sub openid : Local { my($self, $c) = @_; @@ -183,7 +232,7 @@ In a controller, perhaps C. } } -And a L