Skip to content

Commit

Permalink
chore: update samples for new auth
Browse files Browse the repository at this point in the history
  • Loading branch information
codyoss committed Sep 16, 2024
1 parent fcc49d3 commit 228b4ed
Show file tree
Hide file tree
Showing 48 changed files with 330 additions and 565 deletions.
34 changes: 18 additions & 16 deletions auth/access_token_from_impersonated_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,51 +21,53 @@ import (
"io"
"time"

"golang.org/x/oauth2/google"
"google.golang.org/api/impersonate"
"google.golang.org/api/option"
"cloud.google.com/go/auth/credentials"
"cloud.google.com/go/auth/credentials/impersonate"
)

// getAccessTokenFromImpersonatedCredentials uses a service account (SA1) to impersonate
// another service account (SA2) and obtain OAuth2 token for the impersonated account.
// another service account (SA2) and obtain a token for the impersonated account.
// To obtain a token for SA2, SA1 should have the "roles/iam.serviceAccountTokenCreator" permission on SA2.
func getAccessTokenFromImpersonatedCredentials(w io.Writer, impersonatedServiceAccount, scope string) error {
// impersonatedServiceAccount := "[email protected]"
// scope := "https://www.googleapis.com/auth/cloud-platform"

ctx := context.Background()

// Construct the GoogleCredentials object which obtains the default configuration from your
// working environment.
credentials, err := google.FindDefaultCredentials(ctx, scope)
// Construct the Credentials object which obtains the default configuration
// from your working environment.
creds, err := credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{scope},
})
if err != nil {
fmt.Fprintf(w, "failed to generate default credentials: %v", err)
return fmt.Errorf("failed to generate default credentials: %w", err)
}

ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
impCreds, err := impersonate.NewCredentials(&impersonate.CredentialsOptions{
TargetPrincipal: impersonatedServiceAccount,
Scopes: []string{scope},
Lifetime: 300 * time.Second,
// delegates: The chained list of delegates required to grant the final accessToken.
// For more information, see:
// https://cloud.google.com/iam/docs/create-short-lived-credentials-direct#sa-credentials-permissions
// Delegates is NOT USED here.
Delegates: []string{},
}, option.WithCredentials(credentials))
Delegates: []string{},
Credentials: creds,
})
if err != nil {
fmt.Fprintf(w, "CredentialsTokenSource error: %v", err)
return fmt.Errorf("CredentialsTokenSource error: %w", err)
fmt.Fprintf(w, "NewCredentials error: %v", err)
return fmt.Errorf("NewCredentials error: %w", err)
}

// Get the OAuth2 token.
// Once you've obtained the OAuth2 token, you can use it to make an authenticated call.
t, err := ts.Token()
// Get the token. Once you've obtained the token, you can use it to make a
// authenticated call.
t, err := impCreds.Token(ctx)
if err != nil {
fmt.Fprintf(w, "failed to receive token: %v", err)
return fmt.Errorf("failed to receive token: %w", err)
}
fmt.Fprintf(w, "Generated OAuth2 token with length %d.\n", len(t.AccessToken))
fmt.Fprintf(w, "Generated OAuth2 token with length %d.\n", len(t.Value))

return nil
}
Expand Down
6 changes: 3 additions & 3 deletions auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import (
"strings"
"testing"

"cloud.google.com/go/auth/credentials"
"github.com/GoogleCloudPlatform/golang-samples/internal/testutil"
"golang.org/x/oauth2/google"
"google.golang.org/api/idtoken"
"google.golang.org/api/option"
)
Expand Down Expand Up @@ -87,12 +87,12 @@ func TestAuthSnippets(t *testing.T) {
buf.Reset()
want = "ID token verified."

credentials, err := google.FindDefaultCredentials(ctx)
credentials, err := credentials.DetectDefault(nil)
if err != nil {
t.Fatalf("failed to generate default credentials: %v", err)
}

ts, err := idtoken.NewTokenSource(ctx, audience, option.WithCredentials(credentials))
ts, err := idtoken.NewTokenSource(ctx, audience, option.WithAuthCredentials(credentials))
if err != nil {
t.Fatalf("failed to create NewTokenSource: %v", err)
}
Expand Down
29 changes: 17 additions & 12 deletions auth/authenticate_explicit_with_adc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import (
"fmt"
"io"

"cloud.google.com/go/auth/credentials"
"cloud.google.com/go/storage"
"golang.org/x/oauth2/google"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
)
Expand All @@ -31,28 +31,33 @@ import (
func authenticateExplicitWithAdc(w io.Writer) error {
ctx := context.Background()

// Construct the Google credentials object which obtains the default configuration from your
// Construct Credentials which obtains the default configuration from your
// working environment.
// google.FindDefaultCredentials() will give you ComputeEngineCredentials
// if you are on a GCE (or other metadata server supported environments).
credentials, err := google.FindDefaultCredentials(ctx, "https://www.googleapis.com/auth/cloud-platform")
credentials, err := credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
})
if err != nil {
return fmt.Errorf("failed to generate default credentials: %w", err)
}
// If you are authenticating to a Cloud API, you can let the library include the default scope,
// https://www.googleapis.com/auth/cloud-platform, because IAM is used to provide fine-grained
// permissions for Cloud.
// For more information on scopes to use,
// see: https://developers.google.com/identity/protocols/oauth2/scopes
// If you are authenticating to a Cloud API, you can let the library include
// the default scope, https://www.googleapis.com/auth/cloud-platform,
// because IAM is used to provide fine-grained permissions for Cloud. For
// more information on scopes to use, see:
// https://developers.google.com/identity/protocols/oauth2/scopes

// Construct the Storage client.
client, err := storage.NewClient(ctx, option.WithCredentials(credentials))
client, err := storage.NewClient(ctx, option.WithAuthCredentials(credentials))
if err != nil {
return fmt.Errorf("NewClient: %w", err)
}
defer client.Close()

it := client.Buckets(ctx, credentials.ProjectID)
projID, err := credentials.ProjectID(ctx)
if err != nil {
return fmt.Errorf("ProjectID: %w", err)
}

it := client.Buckets(ctx, projID)
for {
bucketAttrs, err := it.Next()
if err == iterator.Done {
Expand Down
34 changes: 19 additions & 15 deletions auth/downscoping/credential_initialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,35 @@ package downscopedoverview
// [START auth_downscoping_initialize_downscoped_cred]

import (
"context"
"fmt"

"golang.org/x/oauth2/google"
"golang.org/x/oauth2/google/downscope"
"cloud.google.com/go/auth/credentials"
"cloud.google.com/go/auth/credentials/downscope"
)

// initializeCredentials will generate a downscoped token using the provided Access Boundary Rules.
// initializeCredentials will generate a downscoped token using the provided
// Access Boundary Rules.
func initializeCredentials(accessBoundary []downscope.AccessBoundaryRule) error {
ctx := context.Background()

// You must provide the "https://www.googleapis.com/auth/cloud-platform" scope.
// This Source can be initialized in multiple ways; the following example uses
// Application Default Credentials.
rootSource, err := google.DefaultTokenSource(ctx, "https://www.googleapis.com/auth/cloud-platform")
// You must provide the "https://www.googleapis.com/auth/cloud-platform"
// scope. This credential can be initialized in multiple ways; the following
// example uses Application Default Credentials.
rootCreds, err := credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
})
if err != nil {
return fmt.Errorf("failed to generate rootSource: %w", err)
return fmt.Errorf("failed to generate rootCreds: %w", err)
}

// downscope.NewTokenSource constructs the token source with the configuration provided.
dts, err := downscope.NewTokenSource(ctx, downscope.DownscopingConfig{RootSource: rootSource, Rules: accessBoundary})
// downscope.NewCredentials constructs the credentials with the
// configuration provided.
downscopedCreds, err := downscope.NewCredentials(&downscope.Options{
Credentials: rootCreds,
Rules: accessBoundary,
})
if err != nil {
return fmt.Errorf("failed to generate downscoped token source: %w", err)
return fmt.Errorf("failed to generate downscoped credentials: %w", err)
}
_ = dts
_ = downscopedCreds
// You can now use dts to access Google Storage resources.
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion auth/downscoping/downscoped_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import (
"testing"
"time"

"cloud.google.com/go/auth/credentials/downscope"
"cloud.google.com/go/storage"
"github.com/GoogleCloudPlatform/golang-samples/internal/testutil"
"github.com/google/uuid"
"golang.org/x/oauth2/google/downscope"
)

func TestInitializeCredentials(t *testing.T) {
Expand Down
5 changes: 3 additions & 2 deletions auth/downscoping/initialize_CAB.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ package downscopedoverview

// [START auth_downscoping_rules]

import "golang.org/x/oauth2/google/downscope"
import "cloud.google.com/go/auth/credentials/downscope"

// constructCAB shows how to initialize a Credential Access Boundary for downscoping tokens.
// constructCAB shows how to initialize a Credential Access Boundary for
// downscoped tokens.
func constructCAB(bucketName string, prefix string) {
// bucketName := "foo"
// prefix := "profile-picture-"
Expand Down
40 changes: 23 additions & 17 deletions auth/downscoping/token_broker.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ import (
"context"
"fmt"

"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/google/downscope"
"cloud.google.com/go/auth/credentials"
"cloud.google.com/go/auth/credentials/downscope"
)

// createDownscopedToken would be run on the token broker in order to generate
// a downscoped access token that only grants access to objects whose name begins with prefix.
// The token broker would then pass the newly created token to the requesting token consumer for use.
// a downscoped access token that only grants access to objects whose name
// begins with prefix. The token broker would then pass the newly created token
// to the requesting token consumer for use.
func createDownscopedToken(bucketName string, prefix string) error {
// bucketName := "foo"
// prefix := "profile-picture-"
Expand All @@ -50,23 +50,29 @@ func createDownscopedToken(bucketName string, prefix string) error {
},
}

// This Source can be initialized in multiple ways; the following example uses
// Application Default Credentials.
var rootSource oauth2.TokenSource

// You must provide the "https://www.googleapis.com/auth/cloud-platform" scope.
rootSource, err := google.DefaultTokenSource(ctx, "https://www.googleapis.com/auth/cloud-platform")
// This credential can be initialized in multiple ways; the following example
// uses Application Default Credentials. You must provide the
// "https://www.googleapis.com/auth/cloud-platform" scope.
creds, err := credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{
"https://www.googleapis.com/auth/cloud-platform",
},
})
if err != nil {
return fmt.Errorf("failed to generate rootSource: %w", err)
return fmt.Errorf("failed to generate creds: %w", err)
}

// downscope.NewTokenSource constructs the token source with the configuration provided.
dts, err := downscope.NewTokenSource(ctx, downscope.DownscopingConfig{RootSource: rootSource, Rules: accessBoundary})
// downscope.NewCredentials constructs the credential with the configuration
// provided.
downscopedCreds, err := downscope.NewCredentials(&downscope.Options{
Credentials: creds,
Rules: accessBoundary,
})
if err != nil {
return fmt.Errorf("failed to generate downscoped token source: %w", err)
return fmt.Errorf("failed to generate downscoped credentials: %w", err)
}
// Token() uses the previously declared TokenSource to generate a downscoped token.
tok, err := dts.Token()
// Token uses the previously declared Credentials to generate a downscoped token.
tok, err := downscopedCreds.Token(ctx)
if err != nil {
return fmt.Errorf("failed to generate token: %w", err)
}
Expand Down
53 changes: 29 additions & 24 deletions auth/downscoping/token_consumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,48 @@ import (
"io"
"io/ioutil"

"golang.org/x/oauth2/google"
"golang.org/x/oauth2/google/downscope"
"cloud.google.com/go/auth"
"cloud.google.com/go/auth/credentials"
"cloud.google.com/go/auth/credentials/downscope"

"cloud.google.com/go/storage"
"golang.org/x/oauth2"
"google.golang.org/api/option"
)

// A token consumer should define their own tokenSource. In the Token() method,
// it should send a query to a token broker requesting a downscoped token.
// The token broker holds the root credential that is used to generate the
// downscoped token.
type localTokenSource struct {
ctx context.Context
// A token consumer should define their own auth.Credentials . In the `Token`
// method, it should send a query to a token broker requesting a downscoped
// token. The token broker holds the root credential that is used to generate
// the downscoped token.
type localTokenProvider struct {
bucketName string
brokerURL string
}

func (lts localTokenSource) Token() (*oauth2.Token, error) {
var remoteToken *oauth2.Token
// Usually you would now retrieve remoteToken, an oauth2.Token, from token broker.
// This snippet performs the same functionality locally.
func (lts localTokenProvider) Token(ctx context.Context) (*auth.Token, error) {
var remoteToken *auth.Token
// Usually you would now retrieve remoteToken, an auth.Token, from token
// broker. This snippet performs the same functionality locally.
accessBoundary := []downscope.AccessBoundaryRule{
{
AvailableResource: "//storage.googleapis.com/projects/_/buckets/" + lts.bucketName,
AvailablePermissions: []string{"inRole:roles/storage.objectViewer"},
},
}
rootSource, err := google.DefaultTokenSource(lts.ctx, "https://www.googleapis.com/auth/cloud-platform")
creds, err := credentials.DetectDefault(&credentials.DetectOptions{
Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
})
if err != nil {
return nil, fmt.Errorf("failed to generate rootSource: %w", err)
return nil, fmt.Errorf("failed to generate creds: %w", err)
}
dts, err := downscope.NewTokenSource(lts.ctx, downscope.DownscopingConfig{RootSource: rootSource, Rules: accessBoundary})
downscopedCreds, err := downscope.NewCredentials(&downscope.Options{
Credentials: creds,
Rules: accessBoundary,
})
if err != nil {
return nil, fmt.Errorf("failed to generate downscoped token source: %w", err)
return nil, fmt.Errorf("failed to generate downscoped credentials: %w", err)
}
// Token() uses the previously declared TokenSource to generate a downscoped token.
remoteToken, err = dts.Token()
// Token uses the previously declared Credentials to generate a downscoped token.
remoteToken, err = downscopedCreds.Token(ctx)
if err != nil {
return nil, fmt.Errorf("failed to generate token: %w", err)
}
Expand All @@ -75,16 +79,17 @@ func getObjectContents(output io.Writer, bucketName string, objectName string) e

ctx := context.Background()

thisTokenSource := localTokenSource{
ctx: ctx,
tokenProvider := localTokenProvider{
bucketName: bucketName,
brokerURL: "yourURL.com/internal/broker",
}

// Wrap the TokenSource in an oauth2.ReuseTokenSource to enable automatic refreshing.
refreshableTS := oauth2.ReuseTokenSource(nil, thisTokenSource)
// You can now use the token source to access Google Cloud Storage resources as follows.
storageClient, err := storage.NewClient(ctx, option.WithTokenSource(refreshableTS))
storageClient, err := storage.NewClient(ctx, option.WithAuthCredentials(
auth.NewCredentials(&auth.CredentialsOptions{
TokenProvider: auth.NewCachedTokenProvider(tokenProvider, nil),
}),
))
if err != nil {
return fmt.Errorf("failed to create the storage client: %w", err)
}
Expand Down
Loading

0 comments on commit 228b4ed

Please sign in to comment.