...

Source file src/cloud.google.com/go/auth/credentials/impersonate/integration_test.go

Documentation: cloud.google.com/go/auth/credentials/impersonate

     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 impersonate_test
    16  
    17  import (
    18  	"context"
    19  	"flag"
    20  	"fmt"
    21  	"log"
    22  	"math/rand"
    23  	"os"
    24  	"testing"
    25  	"time"
    26  
    27  	"cloud.google.com/go/auth"
    28  	"cloud.google.com/go/auth/credentials"
    29  	"cloud.google.com/go/auth/credentials/idtoken"
    30  	"cloud.google.com/go/auth/credentials/impersonate"
    31  	"cloud.google.com/go/auth/internal/credsfile"
    32  	"cloud.google.com/go/auth/internal/testutil"
    33  	"cloud.google.com/go/auth/internal/testutil/testgcs"
    34  )
    35  
    36  const (
    37  	envProjectID   = "GCLOUD_TESTS_GOLANG_PROJECT_ID"
    38  	envReaderCreds = "GCLOUD_TESTS_IMPERSONATE_READER_KEY"
    39  	envReaderEmail = "GCLOUD_TESTS_IMPERSONATE_READER_EMAIL"
    40  	envWriterEmail = "GCLOUD_TESTS_IMPERSONATE_WRITER_EMAIL"
    41  )
    42  
    43  var (
    44  	baseKeyFile   string
    45  	readerKeyFile string
    46  	readerEmail   string
    47  	writerEmail   string
    48  	projectID     string
    49  	random        *rand.Rand
    50  )
    51  
    52  func TestMain(m *testing.M) {
    53  	flag.Parse()
    54  	random = rand.New(rand.NewSource(time.Now().UnixNano()))
    55  	baseKeyFile = os.Getenv(credsfile.GoogleAppCredsEnvVar)
    56  	projectID = os.Getenv(envProjectID)
    57  	readerKeyFile = os.Getenv(envReaderCreds)
    58  	readerEmail = os.Getenv(envReaderEmail)
    59  	writerEmail = os.Getenv(envWriterEmail)
    60  
    61  	if !testing.Short() && (baseKeyFile == "" ||
    62  		readerKeyFile == "" ||
    63  		readerEmail == "" ||
    64  		writerEmail == "" ||
    65  		projectID == "") {
    66  		log.Println("required environment variable not set, skipping")
    67  		os.Exit(0)
    68  	}
    69  
    70  	os.Exit(m.Run())
    71  }
    72  
    73  func TestNewCredentialsIntegration(t *testing.T) {
    74  	testutil.IntegrationTestCheck(t)
    75  	tests := []struct {
    76  		name            string
    77  		baseKeyFile     string
    78  		delegates       []string
    79  		useDefaultCreds bool
    80  	}{
    81  		{
    82  			name:        "SA -> SA",
    83  			baseKeyFile: readerKeyFile,
    84  		},
    85  		{
    86  			name:            "SA -> SA (Default)",
    87  			baseKeyFile:     readerKeyFile,
    88  			useDefaultCreds: true,
    89  		},
    90  		{
    91  			name:        "SA -> Delegate -> SA",
    92  			baseKeyFile: baseKeyFile,
    93  			delegates:   []string{readerEmail},
    94  		},
    95  	}
    96  
    97  	for _, tt := range tests {
    98  		t.Run(tt.name, func(t *testing.T) {
    99  			ctx := context.Background()
   100  			var baseCreds *auth.Credentials
   101  			if !tt.useDefaultCreds {
   102  				var err error
   103  				baseCreds, err = credentials.DetectDefault(&credentials.DetectOptions{
   104  					Scopes:          []string{"https://www.googleapis.com/auth/cloud-platform"},
   105  					CredentialsFile: tt.baseKeyFile,
   106  				})
   107  				if err != nil {
   108  					t.Fatalf("credentials.DetectDefault() = %v", err)
   109  				}
   110  			}
   111  
   112  			opts := &impersonate.CredentialsOptions{
   113  				TargetPrincipal: writerEmail,
   114  				Scopes:          []string{"https://www.googleapis.com/auth/devstorage.full_control"},
   115  				Delegates:       tt.delegates,
   116  			}
   117  			if !tt.useDefaultCreds {
   118  				opts.Credentials = baseCreds
   119  			}
   120  			creds, err := impersonate.NewCredentials(opts)
   121  			if err != nil {
   122  				t.Fatalf("failed to create ts: %v", err)
   123  			}
   124  			client := testgcs.NewClient(creds)
   125  			bucketName := fmt.Sprintf("%s-impersonate-test-%d", projectID, random.Int63())
   126  			if err := client.CreateBucket(ctx, projectID, bucketName); err != nil {
   127  				t.Fatalf("error creating bucket: %v", err)
   128  			}
   129  			if err := client.DeleteBucket(ctx, bucketName); err != nil {
   130  				t.Fatalf("unable to cleanup bucket %q: %v", bucketName, err)
   131  			}
   132  		})
   133  	}
   134  }
   135  
   136  func TestNewIDTokenCredentialsIntegration(t *testing.T) {
   137  	testutil.IntegrationTestCheck(t)
   138  
   139  	ctx := context.Background()
   140  	tests := []struct {
   141  		name            string
   142  		baseKeyFile     string
   143  		delegates       []string
   144  		useDefaultCreds bool
   145  	}{
   146  		{
   147  			name:        "SA -> SA",
   148  			baseKeyFile: readerKeyFile,
   149  		},
   150  		{
   151  			name:            "SA -> SA (Default)",
   152  			useDefaultCreds: true,
   153  		},
   154  		{
   155  			name:        "SA -> Delegate -> SA",
   156  			baseKeyFile: baseKeyFile,
   157  			delegates:   []string{readerEmail},
   158  		},
   159  	}
   160  
   161  	for _, tt := range tests {
   162  		name := tt.name
   163  		t.Run(name, func(t *testing.T) {
   164  			var baseCreds *auth.Credentials
   165  			if !tt.useDefaultCreds {
   166  				var err error
   167  				baseCreds, err = credentials.DetectDefault(&credentials.DetectOptions{
   168  					Scopes:          []string{"https://www.googleapis.com/auth/cloud-platform"},
   169  					CredentialsFile: tt.baseKeyFile,
   170  				})
   171  				if err != nil {
   172  					t.Fatalf("credentials.DetectDefault() = %v", err)
   173  				}
   174  			}
   175  			aud := "http://example.com/"
   176  			opts := &impersonate.IDTokenOptions{
   177  				TargetPrincipal: writerEmail,
   178  				Audience:        aud,
   179  				Delegates:       tt.delegates,
   180  				IncludeEmail:    true,
   181  			}
   182  			if !tt.useDefaultCreds {
   183  				opts.Credentials = baseCreds
   184  			}
   185  			creds, err := impersonate.NewIDTokenCredentials(opts)
   186  			if err != nil {
   187  				t.Fatalf("failed to create ts: %v", err)
   188  			}
   189  			tok, err := creds.Token(ctx)
   190  			if err != nil {
   191  				t.Fatalf("unable to retrieve Token: %v", err)
   192  			}
   193  			validTok, err := idtoken.Validate(ctx, tok.Value, aud)
   194  			if err != nil {
   195  				t.Fatalf("token validation failed: %v", err)
   196  			}
   197  			if validTok.Audience != aud {
   198  				t.Fatalf("got %q, want %q", validTok.Audience, aud)
   199  			}
   200  			if validTok.Claims["email"] != writerEmail {
   201  				t.Fatalf("got %q, want %q", validTok.Claims["email"], writerEmail)
   202  			}
   203  		})
   204  	}
   205  }
   206  

View as plain text