GOOGLE-ADWORDS-PERL-CLIENT

 view release on metacpan or  search on metacpan

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

use Google::Ads::Common::Constants; our $VERSION = ${Google::Ads::Common::Constants::VERSION};

use Crypt::OpenSSL::RSA;
use HTTP::Request;
use LWP::UserAgent;
use MIME::Base64 qw(encode_base64 decode_base64);
use utf8;

use constant OAUTH2_BASE_URL => "https://accounts.google.com/o/oauth2";

# 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 %email_address_of : ATTR(:name<email_address> :default<>);
my %delegated_email_address_of : ATTR(:name<delegated_email_address> :default<>);
my %pem_file_of : ATTR(:name<pem_file> :default<>);
my %__crypt_module_of : ATTR(:name<__crypt_module> :default<>);

# Constructor
sub START {
    my ($self, $ident) = @_;

  $__crypt_module_of{$ident} ||= "Crypt::OpenSSL::RSA";
}

sub initialize :CUMULATIVE(BASE FIRST) {
  my ($self, $api_client, $properties) = @_;
  my $ident = ident $self;

  $email_address_of{$ident} = $properties->{oAuth2ServiceAccountEmailAddress} ||
      $email_address_of{$ident};
  $delegated_email_address_of{$ident} =
      $properties->{oAuth2ServiceAccountDelegateEmailAddress} ||
      $delegated_email_address_of{$ident};
  $pem_file_of{$ident} = $properties->{oAuth2ServiceAccountPEMFile} ||
      $pem_file_of{$ident};
}

sub _refresh_access_token {
  my $self = shift;

  my $iat = time;
  my $exp = $iat + 3600;
  my $iss = $self->get_email_address();
  my $delegated_email_address = $self->get_delegated_email_address();
  my $scope = $self->_scope();

  my $file = $self->__read_certificate_file() || return 0;

  my $header= '{"alg":"RS256","typ":"JWT"}';
  my $claims = "{
    \"iss\":\"${iss}\",
    \"prn\":\"${delegated_email_address}\",
    \"scope\":\"${scope}\",
    \"aud\":\"" . OAUTH2_BASE_URL . "/token\",
    \"exp\":${exp},
    \"iat\":${iat}
  }";

  my $encoded_header = __encode_base64_url($header);
  my $encoded_claims = __encode_base64_url($claims);
  my $key = $self->get___crypt_module()->new_private_key($file) || return 0;
  $key->use_pkcs1_padding();
  $key->use_sha256_hash();

  my $signature = $key->sign("${encoded_header}.${encoded_claims}");
  my $encoded_signature =  __encode_base64_url($signature);
  my $assertion = "${encoded_header}.${encoded_claims}.${encoded_signature}";
  my $body = "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" .
      "&assertion=" . $assertion;
  push my @headers, "Content-Type" => "application/x-www-form-urlencoded";
  my $request = HTTP::Request->new("POST", OAUTH2_BASE_URL . "/token",
                                   \@headers, $body);
  my $user_agent = $self->get___user_agent();
  my $res = $user_agent->request($request);

  if (!$res->is_success()) {
    warn($res->decoded_content());
    return 0;
  }

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

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

sub __read_certificate_file {
  my $self = shift;
  my $file_str;

  $self->get_pem_file() || return 0;
  open (MYFILE, $self->get_pem_file()) || return 0;
  while (<MYFILE>) {
   $file_str .= $_;
  }
  close(MYFILE);

  return $file_str;
}

sub __encode_base64_url($) {
  my ($s) = shift;
  $s = encode_base64($s);
  $s =~ tr{+/}{-_};
  $s =~ s/=*$//;
  $s =~ s/\n//g;
  return $s;
}

sub _scope {
  my $self = shift;
  die "Need to be implemented by subclass";
}

sub _throw_error {
  my ($self, $err_msg) = @_;

  $self->get_api_client()->get_die_on_faults() ? die($err_msg) : warn($err_msg);
}

1;



( run in 2.621 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )