1/*
2 *
3 * Copyright 2018 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19package alts
20
21import (
22	"context"
23	"errors"
24	"strings"
25
26	"google.golang.org/grpc/codes"
27	"google.golang.org/grpc/peer"
28	"google.golang.org/grpc/status"
29)
30
31// AuthInfoFromContext extracts the alts.AuthInfo object from the given context,
32// if it exists. This API should be used by gRPC server RPC handlers to get
33// information about the communicating peer. For client-side, use grpc.Peer()
34// CallOption.
35func AuthInfoFromContext(ctx context.Context) (AuthInfo, error) {
36	p, ok := peer.FromContext(ctx)
37	if !ok {
38		return nil, errors.New("no Peer found in Context")
39	}
40	return AuthInfoFromPeer(p)
41}
42
43// AuthInfoFromPeer extracts the alts.AuthInfo object from the given peer, if it
44// exists. This API should be used by gRPC clients after obtaining a peer object
45// using the grpc.Peer() CallOption.
46func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error) {
47	altsAuthInfo, ok := p.AuthInfo.(AuthInfo)
48	if !ok {
49		return nil, errors.New("no alts.AuthInfo found in Peer")
50	}
51	return altsAuthInfo, nil
52}
53
54// ClientAuthorizationCheck checks whether the client is authorized to access
55// the requested resources based on the given expected client service accounts.
56// This API should be used by gRPC server RPC handlers. This API should not be
57// used by clients.
58func ClientAuthorizationCheck(ctx context.Context, expectedServiceAccounts []string) error {
59	authInfo, err := AuthInfoFromContext(ctx)
60	if err != nil {
61		return status.Errorf(codes.PermissionDenied, "The context is not an ALTS-compatible context: %v", err)
62	}
63	peer := authInfo.PeerServiceAccount()
64	for _, sa := range expectedServiceAccounts {
65		if strings.EqualFold(peer, sa) {
66			return nil
67		}
68	}
69	return status.Errorf(codes.PermissionDenied, "Client %v is not authorized", peer)
70}
71