1/*
2 * Copyright 2021 gRPC authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package authz
18
19import (
20	"context"
21
22	"google.golang.org/grpc"
23	"google.golang.org/grpc/codes"
24	"google.golang.org/grpc/internal/xds/rbac"
25	"google.golang.org/grpc/status"
26)
27
28// StaticInterceptor contains engines used to make authorization decisions. It
29// either contains two engines deny engine followed by an allow engine or only
30// one allow engine.
31type StaticInterceptor struct {
32	engines rbac.ChainEngine
33}
34
35// NewStatic returns a new StaticInterceptor from a static authorization policy
36// JSON string.
37func NewStatic(authzPolicy string) (*StaticInterceptor, error) {
38	rbacs, err := translatePolicy(authzPolicy)
39	if err != nil {
40		return nil, err
41	}
42	chainEngine, err := rbac.NewChainEngine(rbacs)
43	if err != nil {
44		return nil, err
45	}
46	return &StaticInterceptor{*chainEngine}, nil
47}
48
49// UnaryInterceptor intercepts incoming Unary RPC requests.
50// Only authorized requests are allowed to pass. Otherwise, an unauthorized
51// error is returned to the client.
52func (i *StaticInterceptor) UnaryInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
53	err := i.engines.IsAuthorized(ctx)
54	if err != nil {
55		if status.Code(err) == codes.PermissionDenied {
56			return nil, status.Errorf(codes.PermissionDenied, "unauthorized RPC request rejected")
57		}
58		return nil, err
59	}
60	return handler(ctx, req)
61}
62
63// StreamInterceptor intercepts incoming Stream RPC requests.
64// Only authorized requests are allowed to pass. Otherwise, an unauthorized
65// error is returned to the client.
66func (i *StaticInterceptor) StreamInterceptor(srv interface{}, ss grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
67	err := i.engines.IsAuthorized(ss.Context())
68	if err != nil {
69		if status.Code(err) == codes.PermissionDenied {
70			return status.Errorf(codes.PermissionDenied, "unauthorized RPC request rejected")
71		}
72		return err
73	}
74	return handler(srv, ss)
75}
76