| // 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) |
| } |
| } |