...

Source file src/cloud.google.com/go/auth/internal/credsfile/parse_test.go

Documentation: cloud.google.com/go/auth/internal/credsfile

     1  // Copyright 2023 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package credsfile
    16  
    17  import (
    18  	"encoding/json"
    19  	"os"
    20  	"testing"
    21  
    22  	"github.com/google/go-cmp/cmp"
    23  )
    24  
    25  func TestParseServiceAccount(t *testing.T) {
    26  	b, err := os.ReadFile("../testdata/sa.json")
    27  	if err != nil {
    28  		t.Fatal(err)
    29  	}
    30  	got, err := ParseServiceAccount(b)
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	want := &ServiceAccountFile{
    35  		Type:         "service_account",
    36  		ProjectID:    "fake_project",
    37  		PrivateKeyID: "abcdef1234567890",
    38  		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",
    39  		ClientEmail:  "gopher@fake_project.iam.gserviceaccount.com",
    40  		ClientID:     "gopher",
    41  		AuthURL:      "https://accounts.google.com/o/oauth2/auth",
    42  		TokenURL:     "https://oauth2.googleapis.com/token",
    43  	}
    44  	if diff := cmp.Diff(want, got); diff != "" {
    45  		t.Errorf("(-want +got):\n%s", diff)
    46  	}
    47  
    48  }
    49  
    50  func TestParseImpersonatedServiceAccount(t *testing.T) {
    51  	b, err := os.ReadFile("../testdata/imp.json")
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	got, err := ParseImpersonatedServiceAccount(b)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  	want := &ImpersonatedServiceAccountFile{
    60  		Type:                           "impersonated_service_account",
    61  		ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa3@developer.gserviceaccount.com:generateAccessToken",
    62  		Delegates: []string{
    63  			"sa1@developer.gserviceaccount.com",
    64  			"sa2@developer.gserviceaccount.com",
    65  		},
    66  		CredSource: json.RawMessage(`{
    67          "type": "service_account",
    68          "project_id": "fake_project",
    69          "private_key_id": "89asd789789uo473454c47543",
    70          "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",
    71          "client_email": "sa@fake_project.iam.gserviceaccount.com",
    72          "client_id": "gopher",
    73          "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    74          "token_uri": "https://oauth2.googleapis.com/token"
    75      }`),
    76  	}
    77  	if diff := cmp.Diff(want, got); diff != "" {
    78  		t.Errorf("(-want +got):\n%s", diff)
    79  	}
    80  
    81  }
    82  
    83  func TestParseGDCHServiceAccount(t *testing.T) {
    84  	b, err := os.ReadFile("../testdata/gdch.json")
    85  	if err != nil {
    86  		t.Fatal(err)
    87  	}
    88  	got, err := ParseGDCHServiceAccount(b)
    89  	if err != nil {
    90  		t.Fatal(err)
    91  	}
    92  	want := &GDCHServiceAccountFile{
    93  		Type:          "gdch_service_account",
    94  		FormatVersion: "1",
    95  		Project:       "fake_project",
    96  		Name:          "sa_name",
    97  		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",
    98  		PrivateKeyID:  "abcdef1234567890",
    99  		CertPath:      "cert.pem",
   100  		TokenURL:      "replace_me",
   101  	}
   102  	if diff := cmp.Diff(want, got); diff != "" {
   103  		t.Errorf("(-want +got):\n%s", diff)
   104  	}
   105  }
   106  
   107  func TestParseClientCredential_Web(t *testing.T) {
   108  	b, err := os.ReadFile("../testdata/clientcreds_web.json")
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  	got, err := ParseClientCredentials(b)
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  	want := &ClientCredentialsFile{
   117  		Web: &Config3LO{
   118  			ClientID:     "222-nprqovg5k43uum874cs9osjt2koe97g8.apps.googleusercontent.com",
   119  			ClientSecret: "3Oknc4jS_wA2r9i",
   120  			RedirectURIs: []string{"https://www.example.com/oauth2callback"},
   121  			AuthURI:      "https://google.com/o/oauth2/auth",
   122  			TokenURI:     "https://google.com/o/oauth2/token",
   123  		},
   124  	}
   125  	if diff := cmp.Diff(want, got); diff != "" {
   126  		t.Errorf("(-want +got):\n%s", diff)
   127  	}
   128  }
   129  
   130  func TestParseClientCredential_Installed(t *testing.T) {
   131  	b, err := os.ReadFile("../testdata/clientcreds_installed.json")
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  	got, err := ParseClientCredentials(b)
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  	want := &ClientCredentialsFile{
   140  		Installed: &Config3LO{
   141  			ClientID:     "222-installed.apps.googleusercontent.com",
   142  			ClientSecret: "shhhh",
   143  			RedirectURIs: []string{"https://www.example.com/oauth2callback"},
   144  			AuthURI:      "https://accounts.google.com/o/oauth2/auth",
   145  			TokenURI:     "https://accounts.google.com/o/oauth2/token",
   146  		},
   147  	}
   148  	if diff := cmp.Diff(want, got); diff != "" {
   149  		t.Errorf("(-want +got):\n%s", diff)
   150  	}
   151  }
   152  
   153  func TestParseUserCredentials(t *testing.T) {
   154  	b, err := os.ReadFile("../testdata/user.json")
   155  	if err != nil {
   156  		t.Fatal(err)
   157  	}
   158  	got, err := ParseUserCredentials(b)
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	want := &UserCredentialsFile{
   163  		Type:           "authorized_user",
   164  		ClientID:       "abc123.apps.googleusercontent.com",
   165  		ClientSecret:   "shh",
   166  		QuotaProjectID: "fake_project2",
   167  		RefreshToken:   "refreshing",
   168  	}
   169  	if diff := cmp.Diff(want, got); diff != "" {
   170  		t.Errorf("(-want +got):\n%s", diff)
   171  	}
   172  }
   173  
   174  func TestParseExternalAccount_AWS(t *testing.T) {
   175  	b, err := os.ReadFile("../testdata/exaccount_aws.json")
   176  	if err != nil {
   177  		t.Fatal(err)
   178  	}
   179  	got, err := ParseExternalAccount(b)
   180  	if err != nil {
   181  		t.Fatal(err)
   182  	}
   183  	want := &ExternalAccountFile{
   184  		Type:                           "external_account",
   185  		Audience:                       "//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID",
   186  		SubjectTokenType:               "urn:ietf:params:aws:token-type:aws4_request",
   187  		ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$EMAIL:generateAccessToken",
   188  		TokenURL:                       "https://sts.googleapis.com/v1/token",
   189  		CredentialSource: &CredentialSource{
   190  			URL:                         "http://169.254.169.254/latest/meta-data/iam/security-credentials",
   191  			EnvironmentID:               "aws1",
   192  			RegionURL:                   "http://169.254.169.254/latest/meta-data/placement/availability-zone",
   193  			RegionalCredVerificationURL: "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
   194  			IMDSv2SessionTokenURL:       "http://169.254.169.254/latest/api/token",
   195  		},
   196  	}
   197  	if diff := cmp.Diff(want, got); diff != "" {
   198  		t.Errorf("(-want +got):\n%s", diff)
   199  	}
   200  }
   201  
   202  func TestParseExternalAccount_URL(t *testing.T) {
   203  	b, err := os.ReadFile("../testdata/exaccount_url.json")
   204  	if err != nil {
   205  		t.Fatal(err)
   206  	}
   207  	got, err := ParseExternalAccount(b)
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  	want := &ExternalAccountFile{
   212  		Type:                           "external_account",
   213  		Audience:                       "//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID",
   214  		SubjectTokenType:               "urn:ietf:params:oauth:token-type:jwt",
   215  		ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$EMAIL:generateAccessToken",
   216  		TokenURL:                       "https://sts.googleapis.com/v1/token",
   217  		CredentialSource: &CredentialSource{
   218  			URL: "http://localhost:5000/token",
   219  			Format: &Format{
   220  				Type:                  "json",
   221  				SubjectTokenFieldName: "id_token",
   222  			},
   223  		},
   224  	}
   225  	if diff := cmp.Diff(want, got); diff != "" {
   226  		t.Errorf("(-want +got):\n%s", diff)
   227  	}
   228  }
   229  
   230  func TestParseExternalAccount_File(t *testing.T) {
   231  	b, err := os.ReadFile("../testdata/exaccount_file.json")
   232  	if err != nil {
   233  		t.Fatal(err)
   234  	}
   235  	got, err := ParseExternalAccount(b)
   236  	if err != nil {
   237  		t.Fatal(err)
   238  	}
   239  	want := &ExternalAccountFile{
   240  		Type:                           "external_account",
   241  		Audience:                       "//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID",
   242  		SubjectTokenType:               "urn:ietf:params:oauth:token-type:saml2",
   243  		ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$EMAIL:generateAccessToken",
   244  		TokenURL:                       "https://sts.googleapis.com/v1/token",
   245  		CredentialSource: &CredentialSource{
   246  			File: "/var/run/saml/assertion/token",
   247  		},
   248  	}
   249  	if diff := cmp.Diff(want, got); diff != "" {
   250  		t.Errorf("(-want +got):\n%s", diff)
   251  	}
   252  }
   253  
   254  func TestParseExternalAccount_Cmd(t *testing.T) {
   255  	b, err := os.ReadFile("../testdata/exaccount_cmd.json")
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	got, err := ParseExternalAccount(b)
   260  	if err != nil {
   261  		t.Fatal(err)
   262  	}
   263  	want := &ExternalAccountFile{
   264  		Type:                           "external_account",
   265  		Audience:                       "//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID",
   266  		SubjectTokenType:               "urn:ietf:params:oauth:token-type:saml2",
   267  		ServiceAccountImpersonationURL: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$EMAIL@project.iam.gserviceaccount.com:generateAccessToken",
   268  		TokenURL:                       "https://sts.googleapis.com/v1/token",
   269  		CredentialSource: &CredentialSource{
   270  			Executable: &ExecutableConfig{
   271  				Command:    "/path/to/executable --arg1=value1 --arg2=value2",
   272  				OutputFile: "/path/to/cached/credentials",
   273  			},
   274  		},
   275  	}
   276  	want.CredentialSource.Executable.TimeoutMillis = 5000
   277  	if diff := cmp.Diff(want, got); diff != "" {
   278  		t.Errorf("(-want +got):\n%s", diff)
   279  	}
   280  }
   281  
   282  func TestParseExternalAccountAuthorizedUser(t *testing.T) {
   283  	b, err := os.ReadFile("../testdata/exaccount_user.json")
   284  	if err != nil {
   285  		t.Fatal(err)
   286  	}
   287  	got, err := ParseExternalAccountAuthorizedUser(b)
   288  	if err != nil {
   289  		t.Fatal(err)
   290  	}
   291  	want := &ExternalAccountAuthorizedUserFile{
   292  		Type:           "external_account_authorized_user",
   293  		Audience:       "//iam.googleapis.com/locations/global/workforcePools/$POOL_ID/providers/$PROVIDER_ID",
   294  		ClientID:       "abc123.apps.googleusercontent.com",
   295  		ClientSecret:   "shh",
   296  		RefreshToken:   "refreshing",
   297  		TokenURL:       "https://sts.googleapis.com/v1/oauthtoken",
   298  		TokenInfoURL:   "https://sts.googleapis.com/v1/info",
   299  		RevokeURL:      "https://sts.googleapis.com/v1/revoke",
   300  		QuotaProjectID: "fake_project2",
   301  	}
   302  	if diff := cmp.Diff(want, got); diff != "" {
   303  		t.Errorf("(-want +got):\n%s", diff)
   304  	}
   305  }
   306  

View as plain text