blob: 2d1770f4192bc43e9e0f811c1f721deb31bbd5ba [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// 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 credsfile
import (
"encoding/json"
"os"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestParseServiceAccount(t *testing.T) {
b, err := os.ReadFile("../testdata/sa.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseServiceAccount(b)
if err != nil {
t.Fatal(err)
}
want := &ServiceAccountFile{
Type: "service_account",
ProjectID: "fake_project",
PrivateKeyID: "abcdef1234567890",
PrivateKey: "-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALX0PQoe1igW12ikv1bN/r9lN749y2ijmbc/mFHPyS3hNTyOCjDvBbXYbDhQJzWVUikh4mvGBA07qTj79Xc3yBDfKP2IeyYQIFe0t0zkd7R9Zdn98Y2rIQC47aAbDfubtkU1U72t4zL11kHvoa0/RuFZjncvlr42X7be7lYh4p3NAgMBAAECgYASk5wDw4Az2ZkmeuN6Fk/y9H+Lcb2pskJIXjrL533vrDWGOC48LrsThMQPv8cxBky8HFSEklPpkfTF95tpD43iVwJRB/GrCtGTw65IfJ4/tI09h6zGc4yqvIo1cHX/LQ+SxKLGyir/dQM925rGt/VojxY5ryJR7GLbCzxPnJm/oQJBANwOCO6D2hy1LQYJhXh7O+RLtA/tSnT1xyMQsGT+uUCMiKS2bSKx2wxo9k7h3OegNJIu1q6nZ6AbxDK8H3+d0dUCQQDTrPSXagBxzp8PecbaCHjzNRSQE2in81qYnrAFNB4o3DpHyMMY6s5ALLeHKscEWnqP8Ur6X4PvzZecCWU9BKAZAkAutLPknAuxSCsUOvUfS1i87ex77Ot+w6POp34pEX+UWb+u5iFn2cQacDTHLV1LtE80L8jVLSbrbrlH43H0DjU5AkEAgidhycxS86dxpEljnOMCw8CKoUBd5I880IUahEiUltk7OLJYS/Ts1wbn3kPOVX3wyJs8WBDtBkFrDHW2ezth2QJADj3e1YhMVdjJW5jqwlD/VNddGjgzyunmiZg0uOXsHXbytYmsA545S8KRQFaJKFXYYFo2kOjqOiC1T2cAzMDjCQ==\n-----END PRIVATE KEY-----\n",
ClientEmail: "gopher@fake_project.iam.gserviceaccount.com",
ClientID: "gopher",
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://oauth2.googleapis.com/token",
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseImpersonatedServiceAccount(t *testing.T) {
b, err := os.ReadFile("../testdata/imp.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseImpersonatedServiceAccount(b)
if err != nil {
t.Fatal(err)
}
want := &ImpersonatedServiceAccountFile{
Type: "impersonated_service_account",
ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa3@developer.gserviceaccount.com:generateAccessToken",
Delegates: []string{
"sa1@developer.gserviceaccount.com",
"sa2@developer.gserviceaccount.com",
},
CredSource: json.RawMessage(`{
"type": "service_account",
"project_id": "fake_project",
"private_key_id": "89asd789789uo473454c47543",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALX0PQoe1igW12ikv1bN/r9lN749y2ijmbc/mFHPyS3hNTyOCjDvBbXYbDhQJzWVUikh4mvGBA07qTj79Xc3yBDfKP2IeyYQIFe0t0zkd7R9Zdn98Y2rIQC47aAbDfubtkU1U72t4zL11kHvoa0/RuFZjncvlr42X7be7lYh4p3NAgMBAAECgYASk5wDw4Az2ZkmeuN6Fk/y9H+Lcb2pskJIXjrL533vrDWGOC48LrsThMQPv8cxBky8HFSEklPpkfTF95tpD43iVwJRB/GrCtGTw65IfJ4/tI09h6zGc4yqvIo1cHX/LQ+SxKLGyir/dQM925rGt/VojxY5ryJR7GLbCzxPnJm/oQJBANwOCO6D2hy1LQYJhXh7O+RLtA/tSnT1xyMQsGT+uUCMiKS2bSKx2wxo9k7h3OegNJIu1q6nZ6AbxDK8H3+d0dUCQQDTrPSXagBxzp8PecbaCHjzNRSQE2in81qYnrAFNB4o3DpHyMMY6s5ALLeHKscEWnqP8Ur6X4PvzZecCWU9BKAZAkAutLPknAuxSCsUOvUfS1i87ex77Ot+w6POp34pEX+UWb+u5iFn2cQacDTHLV1LtE80L8jVLSbrbrlH43H0DjU5AkEAgidhycxS86dxpEljnOMCw8CKoUBd5I880IUahEiUltk7OLJYS/Ts1wbn3kPOVX3wyJs8WBDtBkFrDHW2ezth2QJADj3e1YhMVdjJW5jqwlD/VNddGjgzyunmiZg0uOXsHXbytYmsA545S8KRQFaJKFXYYFo2kOjqOiC1T2cAzMDjCQ==\n-----END PRIVATE KEY-----\n",
"client_email": "sa@fake_project.iam.gserviceaccount.com",
"client_id": "gopher",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token"
}`),
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseGDCHServiceAccount(t *testing.T) {
b, err := os.ReadFile("../testdata/gdch.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseGDCHServiceAccount(b)
if err != nil {
t.Fatal(err)
}
want := &GDCHServiceAccountFile{
Type: "gdch_service_account",
FormatVersion: "1",
Project: "fake_project",
Name: "sa_name",
PrivateKey: "-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALX0PQoe1igW12ikv1bN/r9lN749y2ijmbc/mFHPyS3hNTyOCjDvBbXYbDhQJzWVUikh4mvGBA07qTj79Xc3yBDfKP2IeyYQIFe0t0zkd7R9Zdn98Y2rIQC47aAbDfubtkU1U72t4zL11kHvoa0/RuFZjncvlr42X7be7lYh4p3NAgMBAAECgYASk5wDw4Az2ZkmeuN6Fk/y9H+Lcb2pskJIXjrL533vrDWGOC48LrsThMQPv8cxBky8HFSEklPpkfTF95tpD43iVwJRB/GrCtGTw65IfJ4/tI09h6zGc4yqvIo1cHX/LQ+SxKLGyir/dQM925rGt/VojxY5ryJR7GLbCzxPnJm/oQJBANwOCO6D2hy1LQYJhXh7O+RLtA/tSnT1xyMQsGT+uUCMiKS2bSKx2wxo9k7h3OegNJIu1q6nZ6AbxDK8H3+d0dUCQQDTrPSXagBxzp8PecbaCHjzNRSQE2in81qYnrAFNB4o3DpHyMMY6s5ALLeHKscEWnqP8Ur6X4PvzZecCWU9BKAZAkAutLPknAuxSCsUOvUfS1i87ex77Ot+w6POp34pEX+UWb+u5iFn2cQacDTHLV1LtE80L8jVLSbrbrlH43H0DjU5AkEAgidhycxS86dxpEljnOMCw8CKoUBd5I880IUahEiUltk7OLJYS/Ts1wbn3kPOVX3wyJs8WBDtBkFrDHW2ezth2QJADj3e1YhMVdjJW5jqwlD/VNddGjgzyunmiZg0uOXsHXbytYmsA545S8KRQFaJKFXYYFo2kOjqOiC1T2cAzMDjCQ==\n-----END PRIVATE KEY-----\n",
PrivateKeyID: "abcdef1234567890",
CertPath: "cert.pem",
TokenURL: "replace_me",
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseClientCredential_Web(t *testing.T) {
b, err := os.ReadFile("../testdata/clientcreds_web.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseClientCredentials(b)
if err != nil {
t.Fatal(err)
}
want := &ClientCredentialsFile{
Web: &Config3LO{
ClientID: "222-nprqovg5k43uum874cs9osjt2koe97g8.apps.googleusercontent.com",
ClientSecret: "3Oknc4jS_wA2r9i",
RedirectURIs: []string{"https://www.example.com/oauth2callback"},
AuthURI: "https://google.com/o/oauth2/auth",
TokenURI: "https://google.com/o/oauth2/token",
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseClientCredential_Installed(t *testing.T) {
b, err := os.ReadFile("../testdata/clientcreds_installed.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseClientCredentials(b)
if err != nil {
t.Fatal(err)
}
want := &ClientCredentialsFile{
Installed: &Config3LO{
ClientID: "222-installed.apps.googleusercontent.com",
ClientSecret: "shhhh",
RedirectURIs: []string{"https://www.example.com/oauth2callback"},
AuthURI: "https://accounts.google.com/o/oauth2/auth",
TokenURI: "https://accounts.google.com/o/oauth2/token",
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseUserCredentials(t *testing.T) {
b, err := os.ReadFile("../testdata/user.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseUserCredentials(b)
if err != nil {
t.Fatal(err)
}
want := &UserCredentialsFile{
Type: "authorized_user",
ClientID: "abc123.apps.googleusercontent.com",
ClientSecret: "shh",
QuotaProjectID: "fake_project2",
RefreshToken: "refreshing",
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseExternalAccount_AWS(t *testing.T) {
b, err := os.ReadFile("../testdata/exaccount_aws.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseExternalAccount(b)
if err != nil {
t.Fatal(err)
}
want := &ExternalAccountFile{
Type: "external_account",
Audience: "//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID",
SubjectTokenType: "urn:ietf:params:aws:token-type:aws4_request",
ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$EMAIL:generateAccessToken",
TokenURL: "https://sts.googleapis.com/v1/token",
CredentialSource: &CredentialSource{
URL: "http://169.254.169.254/latest/meta-data/iam/security-credentials",
EnvironmentID: "aws1",
RegionURL: "http://169.254.169.254/latest/meta-data/placement/availability-zone",
RegionalCredVerificationURL: "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
IMDSv2SessionTokenURL: "http://169.254.169.254/latest/api/token",
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseExternalAccount_URL(t *testing.T) {
b, err := os.ReadFile("../testdata/exaccount_url.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseExternalAccount(b)
if err != nil {
t.Fatal(err)
}
want := &ExternalAccountFile{
Type: "external_account",
Audience: "//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID",
SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$EMAIL:generateAccessToken",
TokenURL: "https://sts.googleapis.com/v1/token",
CredentialSource: &CredentialSource{
URL: "http://localhost:5000/token",
Format: &Format{
Type: "json",
SubjectTokenFieldName: "id_token",
},
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseExternalAccount_File(t *testing.T) {
b, err := os.ReadFile("../testdata/exaccount_file.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseExternalAccount(b)
if err != nil {
t.Fatal(err)
}
want := &ExternalAccountFile{
Type: "external_account",
Audience: "//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID",
SubjectTokenType: "urn:ietf:params:oauth:token-type:saml2",
ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$EMAIL:generateAccessToken",
TokenURL: "https://sts.googleapis.com/v1/token",
CredentialSource: &CredentialSource{
File: "/var/run/saml/assertion/token",
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseExternalAccount_Cmd(t *testing.T) {
b, err := os.ReadFile("../testdata/exaccount_cmd.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseExternalAccount(b)
if err != nil {
t.Fatal(err)
}
want := &ExternalAccountFile{
Type: "external_account",
Audience: "//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID",
SubjectTokenType: "urn:ietf:params:oauth:token-type:saml2",
ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$EMAIL@project.iam.gserviceaccount.com:generateAccessToken",
TokenURL: "https://sts.googleapis.com/v1/token",
CredentialSource: &CredentialSource{
Executable: &ExecutableConfig{
Command: "/path/to/executable --arg1=value1 --arg2=value2",
OutputFile: "/path/to/cached/credentials",
},
},
}
want.CredentialSource.Executable.TimeoutMillis = 5000
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}
func TestParseExternalAccountAuthorizedUser(t *testing.T) {
b, err := os.ReadFile("../testdata/exaccount_user.json")
if err != nil {
t.Fatal(err)
}
got, err := ParseExternalAccountAuthorizedUser(b)
if err != nil {
t.Fatal(err)
}
want := &ExternalAccountAuthorizedUserFile{
Type: "external_account_authorized_user",
Audience: "//iam.googleapis.com/locations/global/workforcePools/$POOL_ID/providers/$PROVIDER_ID",
ClientID: "abc123.apps.googleusercontent.com",
ClientSecret: "shh",
RefreshToken: "refreshing",
TokenURL: "https://sts.googleapis.com/v1/oauthtoken",
TokenInfoURL: "https://sts.googleapis.com/v1/info",
RevokeURL: "https://sts.googleapis.com/v1/revoke",
QuotaProjectID: "fake_project2",
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("(-want +got):\n%s", diff)
}
}