Google-Auth

 view release on metacpan or  search on metacpan

t/13-impersonated-credentials.t  view on Meta::CPAN

}

subtest 'Impersonated Credentials Loading and Token Exchange' => sub {
  my $mock_ua = Test::LWP::UserAgent->new();

  package MockSource;
  use Moo;
  has access_token => (is => 'ro', default => sub { 'mock-source-token' });

  package main;

  my $source_creds = MockSource->new();

  my $creds = Google::Auth::ImpersonatedServiceAccountCredentials->new(
    source_credentials => $source_creds,
    impersonation_url  =>
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/test-sa@google.com:generateAccessToken',
    scope => 'https://www.googleapis.com/auth/cloud-platform',
    ua    => $mock_ua,
  );

  ok(defined $creds, 'credentials object created');
  is(
    $creds->impersonation_url,
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/test-sa@google.com:generateAccessToken',
    'impersonation URL matches'
  );

  $mock_ua->map_response(
    sub {
      my ($request) = @_;
      return $request->url eq
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/test-sa@google.com:generateAccessToken'
        && $request->header('Authorization') eq 'Bearer mock-source-token'
        && $request->header('Content-Type') eq 'application/json';
    },
    HTTP::Response->new(
      200, 'OK',
      ['Content-Type' => 'application/json'],
      encode_json({
          accessToken => 'mock-impersonated-token',
          expireTime  => '2026-06-02T08:30:00Z'
        })));

  my $token = $creds->fetch_access_token();
  is($token, 'mock-impersonated-token', 'exchanged token matches');
  is($creds->access_token, 'mock-impersonated-token', 'cached token matches');
  is($creds->expires_at,   '2026-06-02T08:30:00Z', 'expiration time matches');
};

subtest 'Load from JSON configuration' => sub {
  my $json_config = {
    type                              => 'impersonated_service_account',
    service_account_impersonation_url =>
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/target-sa@google.com:generateAccessToken',
    scopes             => ['https://www.googleapis.com/auth/compute'],
    source_credentials => {
      type         => 'service_account',
      project_id   => 'test-project',
      client_email => 'source-sa@google.com',
      private_key  => 'some-private-key',
    }};

  require Google::Auth::DefaultCredentials;
  my $creds =
    Google::Auth::DefaultCredentials->make_creds(json_key => $json_config,);

  ok(defined $creds, 'loaded credentials successfully');
  isa_ok($creds, 'Google::Auth::ImpersonatedServiceAccountCredentials');
  is(
    $creds->impersonation_url,
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/target-sa@google.com:generateAccessToken',
    'impersonation URL parsed'
  );
  is_deeply($creds->scope, ['https://www.googleapis.com/auth/compute'],
    'scope parsed');
  ok(defined $creds->source_credentials, 'source credentials loaded');
  isa_ok($creds->source_credentials, 'Google::Auth::ServiceAccountCredentials');
  is($creds->source_credentials->client_email,
    'source-sa@google.com', 'source email matches');
};

subtest 'Validation and Configuration Errors' => sub {

  # 1. Missing base and source credentials
  eval {
    Google::Auth::ImpersonatedServiceAccountCredentials->new(
      impersonation_url =>
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/test-sa@google.com:generateAccessToken',
      scope => 'https://www.googleapis.com/auth/cloud-platform',
    );
  };
  like(
    $@,
    qr/either source_credentials or base_credentials must be provided/,
    'throws error on missing source/base credentials'
  );

  # 2. Missing impersonation_url (Moo required validation)
  eval {
    Google::Auth::ImpersonatedServiceAccountCredentials->new(
      source_credentials => MockSource->new(),
      scope              => 'https://www.googleapis.com/auth/cloud-platform',
    );
  };
  like(
    $@,
    qr/Missing required arguments: impersonation_url/,
    'throws error on missing impersonation_url'
  );

  # 3. Nested impersonation check at constructor
  my $source_creds = MockSource->new();
  my $impersonated_source =
    Google::Auth::ImpersonatedServiceAccountCredentials->new(
    source_credentials => $source_creds,
    impersonation_url  =>
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/first-sa@google.com:generateAccessToken',
    scope => 'https://www.googleapis.com/auth/cloud-platform',
    );



( run in 0.581 second using v1.01-cache-2.11-cpan-8dfa8b56332 )