123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- /*
- *
- * Copyright 2018 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- package alts
- import (
- "context"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "os"
- "os/exec"
- "regexp"
- "runtime"
- "strings"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/peer"
- "google.golang.org/grpc/status"
- )
- const (
- linuxProductNameFile = "/sys/class/dmi/id/product_name"
- windowsCheckCommand = "powershell.exe"
- windowsCheckCommandArgs = "Get-WmiObject -Class Win32_BIOS"
- powershellOutputFilter = "Manufacturer"
- windowsManufacturerRegex = ":(.*)"
- )
- type platformError string
- func (k platformError) Error() string {
- return fmt.Sprintf("%s is not supported", string(k))
- }
- var (
- // The following two variables will be reassigned in tests.
- runningOS = runtime.GOOS
- manufacturerReader = func() (io.Reader, error) {
- switch runningOS {
- case "linux":
- return os.Open(linuxProductNameFile)
- case "windows":
- cmd := exec.Command(windowsCheckCommand, windowsCheckCommandArgs)
- out, err := cmd.Output()
- if err != nil {
- return nil, err
- }
- for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
- if strings.HasPrefix(line, powershellOutputFilter) {
- re := regexp.MustCompile(windowsManufacturerRegex)
- name := re.FindString(line)
- name = strings.TrimLeft(name, ":")
- return strings.NewReader(name), nil
- }
- }
- return nil, errors.New("cannot determine the machine's manufacturer")
- default:
- return nil, platformError(runningOS)
- }
- }
- vmOnGCP bool
- )
- // isRunningOnGCP checks whether the local system, without doing a network request is
- // running on GCP.
- func isRunningOnGCP() bool {
- manufacturer, err := readManufacturer()
- if os.IsNotExist(err) {
- return false
- }
- if err != nil {
- log.Fatalf("failure to read manufacturer information: %v", err)
- }
- name := string(manufacturer)
- switch runningOS {
- case "linux":
- name = strings.TrimSpace(name)
- return name == "Google" || name == "Google Compute Engine"
- case "windows":
- name = strings.Replace(name, " ", "", -1)
- name = strings.Replace(name, "\n", "", -1)
- name = strings.Replace(name, "\r", "", -1)
- return name == "Google"
- default:
- log.Fatal(platformError(runningOS))
- }
- return false
- }
- func readManufacturer() ([]byte, error) {
- reader, err := manufacturerReader()
- if err != nil {
- return nil, err
- }
- if reader == nil {
- return nil, errors.New("got nil reader")
- }
- manufacturer, err := ioutil.ReadAll(reader)
- if err != nil {
- return nil, fmt.Errorf("failed reading %v: %v", linuxProductNameFile, err)
- }
- return manufacturer, nil
- }
- // AuthInfoFromContext extracts the alts.AuthInfo object from the given context,
- // if it exists. This API should be used by gRPC server RPC handlers to get
- // information about the communicating peer. For client-side, use grpc.Peer()
- // CallOption.
- func AuthInfoFromContext(ctx context.Context) (AuthInfo, error) {
- p, ok := peer.FromContext(ctx)
- if !ok {
- return nil, errors.New("no Peer found in Context")
- }
- return AuthInfoFromPeer(p)
- }
- // AuthInfoFromPeer extracts the alts.AuthInfo object from the given peer, if it
- // exists. This API should be used by gRPC clients after obtaining a peer object
- // using the grpc.Peer() CallOption.
- func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error) {
- altsAuthInfo, ok := p.AuthInfo.(AuthInfo)
- if !ok {
- return nil, errors.New("no alts.AuthInfo found in Peer")
- }
- return altsAuthInfo, nil
- }
- // ClientAuthorizationCheck checks whether the client is authorized to access
- // the requested resources based on the given expected client service accounts.
- // This API should be used by gRPC server RPC handlers. This API should not be
- // used by clients.
- func ClientAuthorizationCheck(ctx context.Context, expectedServiceAccounts []string) error {
- authInfo, err := AuthInfoFromContext(ctx)
- if err != nil {
- return status.Newf(codes.PermissionDenied, "The context is not an ALTS-compatible context: %v", err).Err()
- }
- for _, sa := range expectedServiceAccounts {
- if authInfo.PeerServiceAccount() == sa {
- return nil
- }
- }
- return status.Newf(codes.PermissionDenied, "Client %v is not authorized", authInfo.PeerServiceAccount()).Err()
- }
|