Google-Ads-GoogleAds-Client

 view release on metacpan or  search on metacpan

lib/Google/Ads/GoogleAds/OAuth2ServiceAccountsHandler.pm  view on Meta::CPAN

# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

package Google::Ads::GoogleAds::OAuth2ServiceAccountsHandler;

use strict;
use warnings;
use version;
use base qw(Google::Ads::GoogleAds::Common::OAuth2BaseHandler);

# The following needs to be on one line because CPAN uses a particularly hacky
# eval() to determine module versions.
use Google::Ads::GoogleAds::Constants; our $VERSION = ${Google::Ads::GoogleAds::Constants::VERSION};

use Class::Std::Fast;
use JSON::XS;
use JSON::WebToken;

# Class::Std-style attributes. Need to be kept in the same line.
# These need to go in the same line for older Perl interpreters to understand.
my %json_key_file_path_of : ATTR(:name<json_key_file_path> :default<>);
my %impersonated_email_of : ATTR(:name<impersonated_email> :default<>);
my %additional_scopes_of : ATTR(:name<additional_scopes> :default<>);

# Methods from Google::Ads::GoogleAds::Common::AuthHandlerInterface.
sub initialize : CUMULATIVE(BASE FIRST) {
  my ($self, $api_client, $properties) = @_;
  my $ident = ident $self;

  $json_key_file_path_of{$ident} = $properties->{jsonKeyFilePath}
    || $json_key_file_path_of{$ident};
  $impersonated_email_of{$ident} = $properties->{impersonatedEmail}
    || $impersonated_email_of{$ident};

  # Below attributes are not in the googleads.properties configuration.
  $additional_scopes_of{$ident} = $properties->{additionalScopes}
    || $additional_scopes_of{$ident};
}

# Methods from Google::Ads::GoogleAds::Common::OAuth2BaseHandler.
sub _refresh_access_token {
  my $self = shift;

  if (!$self->get_json_key_file_path()) {
    return 0;
  }

  my $json_key = $self->__read_json_key_file() || return 0;
  my $time     = time;

  my $jwt = JSON::WebToken->encode({
      iss   => $json_key->{client_email},
      scope => $self->__formatted_scopes(),
      aud   => Google::Ads::GoogleAds::Constants::OAUTH2_BASE_URL . "/token",
      exp   => $time + 3600,
      iat   => $time,
      sub   => $self->get_impersonated_email()
    },
    $json_key->{private_key},
    "RS256"
  );

  my $response = $self->get___lwp_agent()->post(
    Google::Ads::GoogleAds::Constants::OAUTH2_BASE_URL . "/token",
    {
      grant_type => "urn:ietf:params:oauth:grant-type:jwt-bearer",
      assertion  => $jwt
    });

  if (!$response->is_success()) {
    my $err_msg = $response->decoded_content();
    $self->get_api_client()->get_die_on_faults()
      ? die($err_msg)
      : warn($err_msg);
    return 0;
  }

  my $content_hash = $self->__parse_auth_response($response->decoded_content());

  $self->set_access_token($content_hash->{access_token});
  $self->set_access_token_expires(time + $content_hash->{expires_in});

  return 1;
}

sub _scope {
  my $self              = shift;
  my @parsed_scopes     = ();
  my $additional_scopes = $self->get_additional_scopes();
  if ($additional_scopes) {
    @parsed_scopes = split(/\s*,\s*/, $additional_scopes);
  }
  push @parsed_scopes, Google::Ads::GoogleAds::Constants::DEFAULT_OAUTH2_SCOPE;
  return @parsed_scopes;
}

# Retrieves the OAuth2 scopes defined in _scope as a list separated by commas.
# This is the format expected when sending the OAuth request.
sub __formatted_scopes {
  my $self          = shift;
  my @parsed_scopes = $self->_scope();
  return join(',', @parsed_scopes);
}

# Reads the values from the specified JSON key file path as a JSON object.
sub __read_json_key_file {
  my $self = shift;

  my $json_text;
  open(KEY_FILE, $self->get_json_key_file_path()) || return 0;
  while (<KEY_FILE>) {
    $json_text .= $_;
  }
  close(KEY_FILE);

  return decode_json($json_text);
}

1;



( run in 0.563 second using v1.01-cache-2.11-cpan-13bb782fe5a )