Skip Menu |

This queue is for tickets about the Flickr-Upload CPAN distribution.

Report information
The Basics
Id: 117084
Status: resolved
Priority: 0/
Queue: Flickr-Upload

People
Owner: SSEVERIN [...] cpan.org
Requestors: cpan [...] kensaku-yamaguchi.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 1.51
Fixed in: (no value)



Subject: OAuth authentication
Flickr::Upload requires the old Flickr Authentication API for user authentication, and does not, if I understand correctly, support OAuth. The attached patch allows OAuth to be used to authenticate the user. (No OAuth support is added to flickr_upload, however.)
Subject: 0001-support-OAuth-authentication.patch
From a5d3f8ab49934cbb446bde59245910c3218c23da Mon Sep 17 00:00:00 2001 From: Kensaku Yamaguchi <cpan@kensaku-yamaguchi.org> Date: Sun, 21 Aug 2016 10:23:47 +0900 Subject: [PATCH] support OAuth authentication --- lib/Flickr/Upload.pm | 78 +++++++++++++++++++++++++++++++++++++++++++++------- t/oauth.t | 21 ++++++++++++++ 2 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 t/oauth.t diff --git a/lib/Flickr/Upload.pm b/lib/Flickr/Upload.pm index 3af07fd..0d7746e 100644 --- a/lib/Flickr/Upload.pm +++ b/lib/Flickr/Upload.pm @@ -5,6 +5,8 @@ use warnings; use LWP::UserAgent; use HTTP::Request::Common; +use Net::OAuth; +use URI::Escape; use Flickr::API; use XML::Simple qw(:strict); use Digest::MD5 qw(md5_hex); @@ -45,15 +47,37 @@ Upload an image to L<flickr.com>. =head2 new +=over + +=item Using Flickr Authentication + my $ua = Flickr::Upload->new( { 'key' => '90909354', 'secret' => '37465825' }); -Instantiates a L<Flickr::Upload> instance. The C<key> argument is your -API key and the C<secret> is the API secret associated with it. To get an -API key and secret, go to L<https://www.flickr.com/services/api/key.gne>. +=item Using OAuth Authentication + + my $ua = Flickr::Upload->new( + { + 'consumer_key' => 'your_api_key', + 'consumer_secret' => 'your_app_secret', + }); + +=item Retrieve saved configuration (possibly including OAuth access token) + + my $config_file = "$ENV{HOME}/saved-flickr.st"; + my $ua = Flickr::Upload->import_storable_config($config_file); + +=back + +Instantiates a L<Flickr::Upload> instance, using either the Flickr +Authentication or the OAuth Authentication. The C<key> or +C<consumer_key> argument is your API key and the C<secret> or +C<consumer_secret> argument is the API secret associated with it. To +get an API key and secret, go to +L<https://www.flickr.com/services/api/key.gne>. The resulting L<Flickr::Upload> instance is a subclass of L<Flickr::API> and can be used for any other Flickr API calls. As such, @@ -73,9 +97,14 @@ L<Flickr::Upload> is also a subclass of L<LWP::UserAgent>. Taking a L<Flickr::Upload> instance C<$ua> as an argument, this is basically a direct interface to the Flickr Photo Upload API. Required -parameters are C<photo> and C<auth_token>. Note that the C<auth_token> -must have been issued against the API key and secret used to instantiate -the uploader. +parameters are C<photo> and, when using Flickr Authentication, +C<auth_token>. Note that the C<auth_token> must have been issued +against the API key and secret used to instantiate the uploader. + +When using OAuth, C<auth_token> is not required, and the +L<Flickr::Upload> instance must instead contain a valid L<Net::OAuth> +access token which can be added by calling the L<Flickr::API> +C<oauth_access_token> method. Returns the resulting identifier of the uploaded photo on success, C<undef> on failure. According to the API documentation, after an upload the @@ -97,7 +126,7 @@ sub upload { # these are the only things _required_ by the uploader. die "Can't read photo '$args{'photo'}'" unless $args{'photo'} and -f $args{'photo'}; - die "Missing 'auth_token'" unless defined $args{'auth_token'}; + die "Missing 'auth_token'" unless $self->is_oauth or defined $args{'auth_token'}; # create a request object and execute it my $req = $self->make_upload_request( %args ); @@ -196,7 +225,11 @@ sub make_upload_request { my %args = @_; # _required_ by the uploader. - die "Missing 'auth_token' argument" unless $args{'auth_token'}; + unless ($self->is_oauth) { + die "Missing 'auth_token' argument" unless $args{'auth_token'}; + } else { + croak "OAuth access token needed" unless defined $self->{oauth}->{token}; + } my $uri = $args{'uri'} || 'https://api.flickr.com/services/upload/'; @@ -205,13 +238,38 @@ sub make_upload_request { # Flickr::API includes this with normal requests, but we're building a custom # message. - $args{'api_key'} = $self->{'api_key'}; + $args{'api_key'} = $self->{'api_key'} unless $self->is_oauth; # photo is _not_ included in the sig my $photo = $args{photo}; delete $args{photo}; - $args{'api_sig'} = $self->_sign_args(\%args); + unless( $self->is_oauth ) { + $args{'api_sig'} = $self->_sign_args(\%args); + } else { + my %oauth = ( + 'nonce' => $self->_make_nonce(), + 'consumer_key' => $self->{oauth}->{consumer_key}, + 'consumer_secret' => $self->{oauth}->{consumer_secret}, + 'timestamp' => time, + 'signature_method' => $self->{oauth}->{signature_method}, + 'version' => $self->{oauth}->{version}, + 'token' => $self->{oauth}->{token}, + 'token_secret' => $self->{oauth}->{token_secret}, + ); + $oauth{extra_params} = \%args; + $oauth{request_method} = 'POST'; + $oauth{request_url} = $uri; + $Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A; + my $req = Net::OAuth->request( "protected resource" )->new( %oauth ); + $req->sign(); + my $tmp_body = $req->to_post_body(); + %args = (); + foreach (split '&', $tmp_body) { + my ($name, $val) = split '=', $_, 2; + $args{$name} = URI::Escape::uri_unescape( $val ); + } + } # unlikely that the caller would set up the photo as an array, # but... diff --git a/t/oauth.t b/t/oauth.t new file mode 100644 index 0000000..2d7152f --- /dev/null +++ b/t/oauth.t @@ -0,0 +1,21 @@ +use Test::More qw(no_plan); +BEGIN { use_ok('Flickr::Upload') }; + +# Load saved configuration including access token. If none, fail nicely. +my $saved_config = 't/saved_config'; +-r $saved_config or (print STDERR "No stored Flickr::API config file\n" && exit 0); +my $ua = Flickr::Upload->import_storable_config($saved_config); +ok(defined $ua); + +my $rc = $ua->upload( + 'photo' => 't/testimage.jpg', + 'tags' => "test kernel perl cat dog", + 'description' => "Flickr Upload test for $0", + 'is_public' => 0, + 'is_friend' => 0, + 'is_family' => 0, +); + +ok( defined $rc ); + +exit 0; -- 2.1.4
Thanks so much for sending this in, Kensaku. I'm reviewing your patch now, and I'll plan to get a new release out in the next couple of days. The only issue I see at a glance is that Flickr::Upload's flickr_upload tool is already using ~/.flickrrc to store authentication information and other settings. This is at odds with your patch (and Flickr::API), which use, or at least suggest, ~/saved-flickr.st. I think this filename is a bit of an odd choice, but I haven't yet thought through the pros and cons. Cheers, -Steve On Sun Aug 21 01:20:18 2016, https://me.yahoo.co.jp/a/.s1jk4sXP4Xi_0fY7OJ2.u240qM0mg--#7c583 wrote: Show quoted text
> Flickr::Upload requires the old Flickr Authentication API for user > authentication, and does not, if I understand correctly, support > OAuth. The attached patch allows OAuth to be used to authenticate the > user. (No OAuth support is added to flickr_upload, however.)
Subject: Re: [rt.cpan.org #117084] OAuth authentication
Date: Mon, 22 Aug 2016 13:07:12 +0900
To: bug-Flickr-Upload [...] rt.cpan.org
From: Kensaku Yamaguchi <cpan [...] kensaku-yamaguchi.org>
Hello Steve, and thank you for looking at the patch. Show quoted text
> [...] This is at odds with your patch (and Flickr::API), which use, or at least suggest, ~/saved-flickr.st. I think this filename is a bit of an odd choice, but I haven't yet thought through the pros and cons.
The name ~/saved-flickr.st is from the documentation for Flickr::API, in SYNOPSIS, "Authenticate an OAuth API Object starting with saved configuration." The author appears to suggest the use of export_storable_config/import_storable_config to store access token information, which is different from the way flickr_upload uses .flickrrc. The file name in the documentation is obviously an example. I haven't actually considered how flickr_upload might read OAuth access token information from .flickrrc. Maybe it can read "token" and "token_secret" as two separate strings and construct a Net::OAuth Access Token object from those strings, or maybe it can read the information from a separate file containing the return value of export_config. Best regards, Kensaku Yamaguchi
It would be ideal if flickr_upload could use the same storage as Flickr::API, but it would be a nontrivial change to switch to Storable, which would make .flickrrc no longer readily editable. Maybe I need to have flickr_upload store the OAuth data using export_storable_config in a separate file, something like ~/.flickroauth. I gather that the command-line flickr_upload tool is not something you're using, but I would like to enable OAuth through that tool at the same time I release support via the Flickr::Upload API. I do see that Flickr::API's synopsis contains template code for performing the initial OAuth setup, so I should be able to get this done quickly. Regards, -Steve
Okay, I have a working command-line process to step you through OAuth write-access authorization and save the resulting credentials in ~/.flickroauth.st. I've set it up to check for the old authentication method first, and if that fails, check for OAuth credentials. I'll need to tidy it up a bit, do some error checking, and write a bit of documentation, but I think it will be usable. Thanks again for your patch and communication regarding it. I should be able to get a release out tomorrow. Regards, -Steve
From: cpan [...] kensaku-yamaguchi.org
Yes, I used only the module and not the flickr_upload tool, so I did not have enough familiarity with the tool to suggest changes to it in the patch. Thank you for working on this. FWIW my feeling is that your solution for flickr_upload is completely reasonable. Best regards, Kensaku Yamaguchi
I've pushed the code to Github, and I'll look again at the photo-as-array issue.