...

Source file src/google.golang.org/api/integration-tests/downscope/downscope_test.go

Documentation: google.golang.org/api/integration-tests/downscope

     1  // Copyright 2021 Google LLC.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package downscope
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"log"
    13  	"os"
    14  	"testing"
    15  	"time"
    16  
    17  	"google.golang.org/api/option"
    18  
    19  	"golang.org/x/oauth2"
    20  	"golang.org/x/oauth2/google"
    21  	"golang.org/x/oauth2/google/downscope"
    22  	storage "google.golang.org/api/storage/v1"
    23  	"google.golang.org/api/transport"
    24  )
    25  
    26  const (
    27  	rootTokenScope        = "https://www.googleapis.com/auth/cloud-platform"
    28  	envServiceAccountFile = "GCLOUD_TESTS_GOLANG_KEY"
    29  	object1               = "cab-first-c45wknuy.txt"
    30  	object2               = "cab-second-c45wknuy.txt"
    31  	bucket                = "dulcet-port-762"
    32  )
    33  
    34  var (
    35  	rootCredential *google.Credentials
    36  )
    37  
    38  // TestMain contains all of the setup code that needs to be run once before any of the tests are run
    39  func TestMain(m *testing.M) {
    40  	flag.Parse()
    41  	if testing.Short() {
    42  		// This line runs all of our individual tests
    43  		os.Exit(m.Run())
    44  	}
    45  	ctx := context.Background()
    46  	credentialFileName := os.Getenv(envServiceAccountFile)
    47  
    48  	var err error
    49  	rootCredential, err = transport.Creds(ctx, option.WithCredentialsFile(credentialFileName), option.WithScopes(rootTokenScope))
    50  
    51  	if err != nil {
    52  		log.Fatalf("failed to construct root credential: %v", err)
    53  	}
    54  
    55  	// This line runs all of our individual tests
    56  	os.Exit(m.Run())
    57  
    58  }
    59  
    60  // downscopeTest holds the parameters necessary for running a test of the token downscoping capabilities implemented in `oauth2/google/downscope`
    61  type downscopeTest struct {
    62  	name                 string
    63  	availableResource    string
    64  	availablePermissions []string
    65  	condition            downscope.AvailabilityCondition
    66  	objectName           string
    67  	rootSource           oauth2.TokenSource
    68  	expectError          bool
    69  }
    70  
    71  func TestDownscopedToken(t *testing.T) {
    72  	if testing.Short() {
    73  		t.Skip("skipping integration test")
    74  	}
    75  
    76  	var downscopeTests = []downscopeTest{
    77  		{
    78  			name:                 "successfulDownscopedRead",
    79  			availableResource:    "//storage.googleapis.com/projects/_/buckets/" + bucket,
    80  			availablePermissions: []string{"inRole:roles/storage.objectViewer"},
    81  			condition: downscope.AvailabilityCondition{
    82  				Expression: "resource.name.startsWith('projects/_/buckets/" + bucket + "/objects/" + object1 + "')",
    83  			},
    84  			rootSource:  rootCredential.TokenSource,
    85  			objectName:  object1,
    86  			expectError: false,
    87  		},
    88  		{
    89  			name:                 "readWithoutPermission",
    90  			availableResource:    "//storage.googleapis.com/projects/_/buckets/" + bucket,
    91  			availablePermissions: []string{"inRole:roles/storage.objectViewer"},
    92  			condition: downscope.AvailabilityCondition{
    93  				Expression: "resource.name.startsWith('projects/_/buckets/" + bucket + "/objects/" + object1 + "')",
    94  			},
    95  			rootSource:  rootCredential.TokenSource,
    96  			objectName:  object2,
    97  			expectError: true,
    98  		},
    99  	}
   100  
   101  	for _, tt := range downscopeTests {
   102  		t.Run(tt.name, func(t *testing.T) {
   103  			err := downscopeQuery(t, tt)
   104  			// If a test isn't supposed to fail, it shouldn't fail.
   105  			if !tt.expectError && err != nil {
   106  				t.Errorf("test case %v should have succeeded, but instead returned %v", tt.name, err)
   107  			} else if tt.expectError && err == nil { // If a test is supposed to fail, it should return a non-nil error.
   108  				t.Errorf(" test case %v should have returned an error, but instead returned nil", tt.name)
   109  			}
   110  		})
   111  	}
   112  }
   113  
   114  // I'm not sure what I should name this according to convention.
   115  func downscopeQuery(t *testing.T, tt downscopeTest) error {
   116  	t.Helper()
   117  	ctx := context.Background()
   118  
   119  	// Initializes an accessBoundary
   120  	var AccessBoundaryRules []downscope.AccessBoundaryRule
   121  	AccessBoundaryRules = append(AccessBoundaryRules, downscope.AccessBoundaryRule{AvailableResource: tt.availableResource, AvailablePermissions: tt.availablePermissions, Condition: &tt.condition})
   122  
   123  	downscopedTokenSource, err := downscope.NewTokenSource(context.Background(), downscope.DownscopingConfig{RootSource: tt.rootSource, Rules: AccessBoundaryRules})
   124  	if err != nil {
   125  		return fmt.Errorf("failed to create the initial token source: %v", err)
   126  	}
   127  	downscopedTokenSource = oauth2.ReuseTokenSource(nil, downscopedTokenSource)
   128  
   129  	ctx, cancel := context.WithTimeout(ctx, time.Second*30)
   130  	defer cancel()
   131  	storageService, err := storage.NewService(ctx, option.WithTokenSource(downscopedTokenSource))
   132  	if err != nil {
   133  		return fmt.Errorf("failed to create the storage service: %v", err)
   134  	}
   135  	resp, err := storageService.Objects.Get(bucket, tt.objectName).Download()
   136  	if err != nil {
   137  		return fmt.Errorf("failed to retrieve object from GCP project with error: %v", err)
   138  	}
   139  	defer resp.Body.Close()
   140  	_, err = io.ReadAll(resp.Body)
   141  	if err != nil {
   142  		return fmt.Errorf("io.ReadAll: %v", err)
   143  	}
   144  	return nil
   145  }
   146  

View as plain text