// NewProtoClient returns a ProtoClient for communicating with a Google cloud service, // configured with the given ClientOptions. func NewProtoClient(ctx context.Context, opt ...cloud.ClientOption) (*ProtoClient, error) { var o opts.DialOpt for _, opt := range opt { opt.Resolve(&o) } if o.GRPCClient != nil { return nil, errors.New("unsupported GRPC base transport specified") } var client *http.Client switch { case o.HTTPClient != nil: if o.TokenSource != nil { return nil, errors.New("at most one of WithTokenSource or WithBaseHTTP may be provided") } client = o.HTTPClient case o.TokenSource != nil: client = oauth2.NewClient(ctx, o.TokenSource) default: var err error client, err = google.DefaultClient(ctx, o.Scopes...) if err != nil { return nil, err } } return &ProtoClient{ client: client, endpoint: o.Endpoint, userAgent: o.UserAgent, }, nil }
// DefaultClient returns an HTTP Client that uses the // DefaultTokenSource to obtain authentication credentials. // // This client should be used when developing services // that run on Google App Engine or Google Compute Engine // and use "Application Default Credentials." // // For more details, see: // https://developers.google.com/accounts/docs/application-default-credentials // func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) { ts, err := DefaultTokenSource(ctx, scope...) if err != nil { return nil, err } return oauth2.NewClient(ctx, ts), nil }
// TODO(djd): Delete this function when it's no longer used. func Context(scopes ...string) context.Context { ctx := oauth2.NoContext ts := TokenSource(ctx, scopes...) if ts == nil { return nil } return cloud.NewContext(ProjID(), oauth2.NewClient(ctx, ts)) }
// NewHTTPClient returns an HTTP client for use communicating with a Google cloud // service, configured with the given ClientOptions. It also returns the endpoint // for the service as specified in the options. func NewHTTPClient(ctx context.Context, opt ...cloud.ClientOption) (*http.Client, string, error) { var o opts.DialOpt for _, opt := range opt { opt.Resolve(&o) } if o.GRPCClient != nil { return nil, "", errors.New("unsupported GRPC base transport specified") } // TODO(djd): Wrap all http.Clients with appropriate internal version to add // UserAgent header and prepend correct endpoint. if o.HTTPClient != nil { return o.HTTPClient, o.Endpoint, nil } if o.TokenSource == nil { var err error o.TokenSource, err = google.DefaultTokenSource(ctx, o.Scopes...) if err != nil { return nil, "", fmt.Errorf("google.DefaultTokenSource: %v", err) } } return oauth2.NewClient(ctx, o.TokenSource), o.Endpoint, nil }
// Token reader func (gr *gitHubReader) Token(authCode string) (*oauth2.Token, error) { if authCode == "" { return nil, errors.Trace(errors.Errorf("authCode is empty!")) } conf := &oauth2.Config{ ClientID: gr.clientID, ClientSecret: gr.clientSecret, Scopes: []string{}, Endpoint: oauthGithub.Endpoint, } token, err := conf.Exchange(oauth2.NoContext, authCode) if err != nil { logger.WithField("authCode", authCode).Errorf("%s", err) return nil, errors.Trace(err) } gr.token = token logger.WithField("authCode", authCode).Debugf("Got token, will expiry at [%s]", gr.token.Expiry) ts := oauth2.StaticTokenSource(gr.token) tc := oauth2.NewClient(oauth2.NoContext, ts) client := github.NewClient(tc) gr.user, _, err = client.Users.Get("") if err != nil { logger.WithField("authCode", authCode).Errorf("%s", err) return nil, errors.Trace(err) } logger.WithField("authCode", authCode).WithField("user", gr.user.Email).Debugf("[%s]", gr.user.String()) return gr.token, nil }
func (js jwtSource) Token() (*oauth2.Token, error) { pk, err := internal.ParseKey(js.conf.PrivateKey) if err != nil { return nil, err } hc := oauth2.NewClient(js.ctx, nil) claimSet := &jws.ClaimSet{ Iss: js.conf.Email, Scope: strings.Join(js.conf.Scopes, " "), Aud: js.conf.TokenURL, } if subject := js.conf.Subject; subject != "" { claimSet.Sub = subject // prn is the old name of sub. Keep setting it // to be compatible with legacy OAuth 2.0 providers. claimSet.Prn = subject } if t := js.conf.Expires; t > 0 { claimSet.Exp = time.Now().Add(t).Unix() } payload, err := jws.Encode(defaultHeader, claimSet, pk) if err != nil { return nil, err } v := url.Values{} v.Set("grant_type", defaultGrantType) v.Set("assertion", payload) resp, err := hc.PostForm(js.conf.TokenURL, v) if err != nil { return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err) } defer resp.Body.Close() body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) if err != nil { return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err) } if c := resp.StatusCode; c < 200 || c > 299 { return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", resp.Status, body) } // tokenRes is the JSON response body. var tokenRes struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` IDToken string `json:"id_token"` ExpiresIn int64 `json:"expires_in"` // relative seconds from now } if err := json.Unmarshal(body, &tokenRes); err != nil { return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err) } token := &oauth2.Token{ AccessToken: tokenRes.AccessToken, TokenType: tokenRes.TokenType, } raw := make(map[string]interface{}) json.Unmarshal(body, &raw) // no error checks for optional fields token = token.WithExtra(raw) if secs := tokenRes.ExpiresIn; secs > 0 { token.Expiry = time.Now().Add(time.Duration(secs) * time.Second) } if v := tokenRes.IDToken; v != "" { // decode returned id token to get expiry claimSet, err := jws.Decode(v) if err != nil { return nil, fmt.Errorf("oauth2: error decoding JWT token: %v", err) } token.Expiry = time.Unix(claimSet.Exp, 0) } return token, nil }
// Client returns an HTTP client wrapping the context's // HTTP transport and adding Authorization headers with tokens // obtained from c. // // The returned client and its Transport should not be modified. func (c *Config) Client(ctx context.Context) *http.Client { return oauth2.NewClient(ctx, c.TokenSource(ctx)) }
func main() { flag.Parse() if *proj == "" { log.Fatalf("Missing --project flag") } prefix := "https://www.googleapis.com/compute/v1/projects/" + *proj machType := prefix + "/zones/" + *zone + "/machineTypes/" + *mach const tokenFileName = "token.dat" tokenFile := tokenCacheFile(tokenFileName) tokenSource := oauth2.ReuseTokenSource(nil, tokenFile) token, err := tokenSource.Token() if err != nil { if *writeObject != "" { log.Fatalf("Can't use --write_object without a valid token.dat file already cached.") } log.Printf("Error getting token from %s: %v", tokenFileName, err) log.Printf("Get auth code from %v", config.AuthCodeURL("my-state")) fmt.Print("\nEnter auth code: ") sc := bufio.NewScanner(os.Stdin) sc.Scan() authCode := strings.TrimSpace(sc.Text()) token, err = config.Exchange(oauth2.NoContext, authCode) if err != nil { log.Fatalf("Error exchanging auth code for a token: %v", err) } if err := tokenFile.WriteToken(token); err != nil { log.Fatalf("Error writing to %s: %v", tokenFileName, err) } tokenSource = oauth2.ReuseTokenSource(token, nil) } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) if *writeObject != "" { writeCloudStorageObject(oauthClient) return } computeService, _ := compute.New(oauthClient) natIP := *staticIP if natIP == "" { // Try to find it by name. aggAddrList, err := computeService.Addresses.AggregatedList(*proj).Do() if err != nil { log.Fatal(err) } // http://godoc.org/code.google.com/p/google-api-go-client/compute/v1#AddressAggregatedList IPLoop: for _, asl := range aggAddrList.Items { for _, addr := range asl.Addresses { if addr.Name == *instName+"-ip" && addr.Status == "RESERVED" { natIP = addr.Address break IPLoop } } } } cloudConfig := baseConfig if *sshPub != "" { key := strings.TrimSpace(readFile(*sshPub)) cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", key) } if os.Getenv("USER") == "bradfitz" { cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwks9dwWKlRC+73gRbvYtVg0vdCwDSuIlyt4z6xa/YU/jTDynM4R4W10hm2tPjy8iR1k8XhDv4/qdxe6m07NjG/By1tkmGpm1mGwho4Pr5kbAAy/Qg+NLCSdAYnnE00FQEcFOC15GFVMOW2AzDGKisReohwH9eIzHPzdYQNPRWXE= [email protected]") } const maxCloudConfig = 32 << 10 // per compute API docs if len(cloudConfig) > maxCloudConfig { log.Fatalf("cloud config length of %d bytes is over %d byte limit", len(cloudConfig), maxCloudConfig) } instance := &compute.Instance{ Name: *instName, Description: "Go Builder", MachineType: machType, Disks: []*compute.AttachedDisk{instanceDisk(computeService)}, Tags: &compute.Tags{ Items: []string{"http-server", "https-server"}, }, Metadata: &compute.Metadata{ Items: []*compute.MetadataItems{ { Key: "user-data", Value: &cloudConfig, }, }, }, NetworkInterfaces: []*compute.NetworkInterface{ &compute.NetworkInterface{ AccessConfigs: []*compute.AccessConfig{ &compute.AccessConfig{ Type: "ONE_TO_ONE_NAT", Name: "External NAT", NatIP: natIP, }, }, Network: prefix + "/global/networks/default", }, }, ServiceAccounts: []*compute.ServiceAccount{ { Email: "default", Scopes: []string{ compute.DevstorageFullControlScope, compute.ComputeScope, }, }, }, } log.Printf("Creating instance...") op, err := computeService.Instances.Insert(*proj, *zone, instance).Do() if err != nil { log.Fatalf("Failed to create instance: %v", err) } opName := op.Name log.Printf("Created. Waiting on operation %v", opName) OpLoop: for { time.Sleep(2 * time.Second) op, err := computeService.ZoneOperations.Get(*proj, *zone, opName).Do() if err != nil { log.Fatalf("Failed to get op %s: %v", opName, err) } switch op.Status { case "PENDING", "RUNNING": log.Printf("Waiting on operation %v", opName) continue case "DONE": if op.Error != nil { for _, operr := range op.Error.Errors { log.Printf("Error: %+v", operr) } log.Fatalf("Failed to start.") } log.Printf("Success. %+v", op) break OpLoop default: log.Fatalf("Unknown status %q: %+v", op.Status, op) } } inst, err := computeService.Instances.Get(*proj, *zone, *instName).Do() if err != nil { log.Fatalf("Error getting instance after creation: %v", err) } ij, _ := json.MarshalIndent(inst, "", " ") log.Printf("Instance: %s", ij) }