Cleanup moose, sanitise params and api
Budrica Petre Cosmin [Fri, 24 Jul 2009 09:58:33 +0000 (09:58 +0000)]
lib/Catalyst/Authentication/Credential/OAuth.pm

index 834abef..b5c15b1 100644 (file)
@@ -1,88 +1,82 @@
 package Catalyst::Authentication::Credential::OAuth;
-use strict;
-use warnings;
-
 use Moose;
-
-has _config => ( is => 'rw' );
-has realm => ( is => 'ro' );
-has debug => ( is => 'rw' );
-has defaults => ( is => 'rw' );
-has provider => ( is => 'rw' );
-
-our $VERSION = "0.01";
-
+use MooseX::Types::Moose qw/ Bool HashRef /;
+use MooseX::Types::Common::String qw/ NonEmptySimpleStr /;
 use Net::OAuth;
 #$Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A;
-use HTTP::Request::Common;
 use LWP::UserAgent;
+use HTTP::Request::Common;
 use String::Random qw/ random_string /;
-
 use Catalyst::Exception ();
+use namespace::autoclean;
 
-sub new {
-       my ($class, $config, $c, $realm) = @_;
-
-       my $self = { _config => { 
-               %{ $config },
-               %{ $realm->{config} }
-       } };
-
-       bless $self, $class;
+has debug => ( is => 'ro', isa => Bool );
+has providers => ( is => 'ro', isa => HashRef, required => 1 );
+has ua => ( is => 'ro', lazy_build => 1, init_arg => undef, isa => 'LWP::UserAgent' );
 
-       $self->debug( $self->_config->{debug} );
+sub BUILDARGS {
+    my ($self, $config, $c, $realm) = @_;
 
-       $self->defaults( {
-               request_method => 'GET',
-               signature_method => 'HMAC-SHA1',
-               nonce => random_string( 'ccccccccccccccccccc' ),
-       } );
+    return $config;
+}
 
-       return $self;
+sub BUILD {
+    my ($self) = @_;
+    $self->ua; # Ensure lazy value is built.
 }
 
+sub _build_ua {
+    my $self = shift;
+    
+    LWP::UserAgent->new;    
+}
 
 sub authenticate {
        my ($self, $c, $realm, $auth_info) = @_;
-       
-       Catalyst::Exception->throw( "Provider is not defined." ) 
-               unless defined $self->_config->{ $auth_info->{oauth_provider} };
 
-       $self->provider( $self->_config->{ $auth_info->{oauth_provider} } );
+    Catalyst::Exception->throw( "Provider is not defined." )
+        unless defined $auth_info->{provider} || defined $self->providers->{ $auth_info->{provider} };
 
-       $self->defaults( {
-               %{ $self->defaults },
-               timestamp => time,
-               consumer_key => $self->provider->{key},
-               consumer_secret => $self->provider->{secret},
-               callback => $c->uri_for( $c->action )->as_string,
-       } );
+    my $provider = $self->providers->{ $auth_info->{provider} };
+
+    for ( qw/ consumer_key consumer_secret request_token_endpoint access_token_endpoint user_auth_endpoint / ) {
+        Catalyst::Exception->throw( $_ . " is not defined for provider ". $auth_info->{provider} )
+            unless $provider->{$_};
+    }
+
+    my %defaults = (
+       consumer_key => $provider->{consumer_key},
+       consumer_secret => $provider->{consumer_secret},
+        timestamp => time,
+        nonce => random_string( 'ccccccccccccccccccc' ),
+        request_method => 'GET',
+        signature_method => 'HMAC-SHA1',
+       oauth_version => '1.0a',
+        callback => $c->uri_for( $c->action, $c->req->captures, @{ $c->req->args } )->as_string
+    );
 
        $c->log_debug( "authenticate() called from " . $c->request->uri ) if $self->debug;
 
-       my $ua = LWP::UserAgent->new;
-       
-       if( $c->req->params->{oauth_token} ) {
+    my $oauth_token = $c->req->method eq 'GET'
+        ? $c->req->query_params->{oauth_token}
+        : $c->req->body_params->{oauth_token};
 
-               my $response = Net::OAuth->response( 'user auth' )->from_hash( $c->req->params );
+       if( $oauth_token ) {
 
-               Catalyst::Exception->throw( "access_token_endpoint not defined" )
-                       unless $self->provider->{access_token_endpoint};
+               my $response = Net::OAuth->response( 'user auth' )->from_hash( $c->req->params );
 
                my $request = Net::OAuth->request( 'access token' )->new(
-                       %{ $self->defaults },
+                       %defaults,
                        token => $response->token,
                        token_secret => '',
-                       request_url => $self->provider->{access_token_endpoint},
+                       request_url => $provider->{access_token_endpoint},
                );
-
                $request->sign;
 
-               my $ua_response = $ua->request( GET $request->to_url );
-
+               my $ua_response = $self->ua->request( GET $request->to_url );
                Catalyst::Exception->throw( $ua_response->status_line.' '.$ua_response->content )
                        unless $ua_response->is_success;
-               
+
                $response = Net::OAuth->response( 'access token' )->from_post_body( $ua_response->content );
 
                my $user = +{ 
@@ -100,33 +94,25 @@ sub authenticate {
                return;
        }
        else {
-
-               Catalyst::Exception->throw( "request_token_endpoint not defined" )
-                       unless $self->provider->{request_token_endpoint};
-               
                my $request = Net::OAuth->request( 'request token' )->new(
-                       %{ $self->defaults },
-                       request_url => $self->provider->{request_token_endpoint}
+                       %defaults,
+                       request_url => $provider->{request_token_endpoint}
                );
-
                $request->sign;
 
-               my $ua_response = $ua->request( GET $request->to_url );
-                               
+               my $ua_response = $self->ua->request( GET $request->to_url );
+
                Catalyst::Exception->throw( $ua_response->status_line.' '.$ua_response->content )
                        unless $ua_response->is_success;
 
                my $response = Net::OAuth->response( 'request token' )->from_post_body( $ua_response->content );
 
-               Catalyst::Exception->throw( "user_auth_endpoint not defined" )
-                       unless $self->provider->{user_auth_endpoint};
-
                $request = Net::OAuth->request( 'user auth' )->new(
-                       %{ $self->defaults },
+                       %defaults,
                        token => $response->token,
                );
 
-               $c->res->redirect( $request->to_url( $self->provider->{user_auth_endpoint} ) );
+               $c->res->redirect( $request->to_url( $provider->{user_auth_endpoint} ) );
        }
 
 }
@@ -150,44 +136,46 @@ Catalyst::Authentication::Credential::OAuth - OAuth credential for Catalyst::Plu
 
 In MyApp.pm
 
- use Catalyst qw/
-      Authentication
-      Session
-      Session::Store::FastMmap
-      Session::State::Cookie
- /;
+    use Catalyst qw/
+        Authentication
+        Session
+        Session::Store::FastMmap
+        Session::State::Cookie
+    /;
 
 
 In myapp.conf
 
- <Plugin::Authentication>
-      default_realm    oauth
-      <realms>
-           <oauth>
+    <Plugin::Authentication>
+        default_realm  oauth
+        <realms>
+            <oauth>
                 <credential>
-                     class     OAuth
-               </credential>
-               <example_provider>
-                       key my_app_key
-                       secret my_app_secret
-                       request_token_endpoint http://example.com/oauth/request_token
-                        access_token_endpoint http://example.com/oauth/access_token
-                        user_auth_endpoint http://example.com/oauth/authorize
-               </example_provider>
-           </oauth>
-      </realms>
-</Plugin::Authentication>
+                    class      OAuth
+                    <providers>
+                        <example.com>
+                            consumer_key             my_app_key
+                            consumer_secret          my_app_secret
+                            request_token_endpoint   http://example.com/oauth/request_token
+                            access_token_endpoint    http://example.com/oauth/access_token
+                            user_auth_endpoint       http://example.com/oauth/authorize
+                        </example.com>
+                    </providers>
+                </credential>
+            </oauth>
+        </realms>
+    </Plugin::Authentication>
 
 
 In controller code,
 
-  sub oauth : Local {
-       my ($self, $c) = @_;
+    sub oauth : Local {
+        my ($self, $c) = @_;
 
-       if( $c->authenticate( { oauth_provider => 'example_provider' } ) ) {
-             #do something with $c->user
-       }
-  }
+        if( $c->authenticate( { provider => 'example.com' } ) ) {
+            #do something with $c->user
+        }
+    }
 
 
 
@@ -199,7 +187,7 @@ In controller code,
 
 =item $c->user->token_secret
 
-=item $c->user->extra_params - whatever other parameters the provider sends back
+=item $c->user->extra_params - whatever other params the provider sends back
 
 =back