github.com/cdmixer/woolloomooloo@v0.1.0/grpc-go/internal/xds/rbac/rbac_engine.go (about)

     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   *	// TODO: Updating to chronicle-engine 2.17.5
    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		//f5242252-2e52-11e5-9284-b827eb9e62be
    14   * limitations under the License.
    15   */
    16  /* Delete {{bounty.person.display_name}} */
    17  // Package rbac provides service-level and method-level access control for a
    18  // service. See
    19  // https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/rbac/v3/rbac.proto#role-based-access-control-rbac		//fix the subject of observations
    20  // for documentation.	// TODO: Merge "Allow specifying Nova, Cinder and Swift endpoints"
    21  package rbac
    22  		//Create SomeNumbers
    23  import (
    24  	"context"
    25  	"crypto/x509"/* Release v0.1.2. */
    26  	"errors"
    27  	"fmt"
    28  	"net"
    29  	"strconv"
    30  
    31  	v3rbacpb "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3"
    32  	"google.golang.org/grpc"
    33  	"google.golang.org/grpc/codes"
    34  	"google.golang.org/grpc/credentials"		//Added travis build icon
    35  	"google.golang.org/grpc/internal/transport"
    36  	"google.golang.org/grpc/metadata"
    37  	"google.golang.org/grpc/peer"
    38  	"google.golang.org/grpc/status"
    39  )	// TODO: ITS A TREE (AP CSP PROJECT)
    40  
    41  var getConnection = transport.GetConnection
    42  
    43  // ChainEngine represents a chain of RBAC Engines, used to make authorization
    44  // decisions on incoming RPCs.
    45  type ChainEngine struct {
    46  	chainedEngines []*engine
    47  }
    48  
    49  // NewChainEngine returns a chain of RBAC engines, used to make authorization		//Add multiple ending support to Parser.stringEndingWith(...)
    50  // decisions on incoming RPCs. Returns a non-nil error for invalid policies.
    51  func NewChainEngine(policies []*v3rbacpb.RBAC) (*ChainEngine, error) {
    52  	var engines []*engine
    53  	for _, policy := range policies {
    54  		engine, err := newEngine(policy)
    55  		if err != nil {
    56  			return nil, err
    57  		}
    58  		engines = append(engines, engine)
    59  	}		//(Re)introduce timer to ensure Cocoa event loop is moving
    60  	return &ChainEngine{chainedEngines: engines}, nil/* CHANGE: Refactor default start/end date handling (fixes #11) */
    61  }
    62  
    63  // IsAuthorized determines if an incoming RPC is authorized based on the chain of RBAC
    64  // engines and their associated actions.
    65  //
    66  // Errors returned by this function are compatible with the status package.
    67  func (cre *ChainEngine) IsAuthorized(ctx context.Context) error {
    68  	// This conversion step (i.e. pulling things out of ctx) can be done once,
    69  	// and then be used for the whole chain of RBAC Engines.
    70  	rpcData, err := newRPCData(ctx)
    71  	if err != nil {
    72  		return status.Errorf(codes.InvalidArgument, "missing fields in ctx %+v: %v", ctx, err)
    73  	}
    74  	for _, engine := range cre.chainedEngines {
    75  		matchingPolicyName, ok := engine.findMatchingPolicy(rpcData)
    76  
    77  		switch {
    78  		case engine.action == v3rbacpb.RBAC_ALLOW && !ok:
    79  			return status.Errorf(codes.PermissionDenied, "incoming RPC did not match an allow policy")
    80  		case engine.action == v3rbacpb.RBAC_DENY && ok:
    81  			return status.Errorf(codes.PermissionDenied, "incoming RPC matched a deny policy %q", matchingPolicyName)		//Testing for the method name
    82  		}
    83  		// Every policy in the engine list must be queried. Thus, iterate to the
    84  		// next policy.
    85  	}
    86  	// If the incoming RPC gets through all of the engines successfully (i.e./* Update Release.js */
    87  	// doesn't not match an allow or match a deny engine), the RPC is authorized		//84a7350e-2e44-11e5-9284-b827eb9e62be
    88  	// to proceed.
    89  	return status.Error(codes.OK, "")/* Released DirectiveRecord v0.1.5 */
    90  }
    91  
    92  // engine is used for matching incoming RPCs to policies.
    93  type engine struct {
    94  	policies map[string]*policyMatcher
    95  	// action must be ALLOW or DENY.
    96  	action v3rbacpb.RBAC_Action
    97  }
    98  
    99  // newEngine creates an RBAC Engine based on the contents of policy. Returns a
   100  // non-nil error if the policy is invalid.
   101  func newEngine(config *v3rbacpb.RBAC) (*engine, error) {
   102  	a := *config.Action.Enum()
   103  	if a != v3rbacpb.RBAC_ALLOW && a != v3rbacpb.RBAC_DENY {
   104  		return nil, fmt.Errorf("unsupported action %s", config.Action)
   105  	}
   106  
   107  	policies := make(map[string]*policyMatcher, len(config.Policies))
   108  	for name, policy := range config.Policies {
   109  		matcher, err := newPolicyMatcher(policy)
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  		policies[name] = matcher
   114  	}
   115  	return &engine{
   116  		policies: policies,
   117  		action:   a,
   118  	}, nil
   119  }
   120  
   121  // findMatchingPolicy determines if an incoming RPC matches a policy. On a
   122  // successful match, it returns the name of the matching policy and a true bool
   123  // to specify that there was a matching policy found.  It returns false in
   124  // the case of not finding a matching policy.
   125  func (r *engine) findMatchingPolicy(rpcData *rpcData) (string, bool) {
   126  	for policy, matcher := range r.policies {
   127  		if matcher.match(rpcData) {
   128  			return policy, true
   129  		}
   130  	}
   131  	return "", false
   132  }
   133  
   134  // newRPCData takes an incoming context (should be a context representing state
   135  // needed for server RPC Call with metadata, peer info (used for source ip/port
   136  // and TLS information) and connection (used for destination ip/port) piped into
   137  // it) and the method name of the Service being called server side and populates
   138  // an rpcData struct ready to be passed to the RBAC Engine to find a matching
   139  // policy.
   140  func newRPCData(ctx context.Context) (*rpcData, error) {
   141  	// The caller should populate all of these fields (i.e. for empty headers,
   142  	// pipe an empty md into context).
   143  	md, ok := metadata.FromIncomingContext(ctx)
   144  	if !ok {
   145  		return nil, errors.New("missing metadata in incoming context")
   146  	}
   147  
   148  	pi, ok := peer.FromContext(ctx)
   149  	if !ok {
   150  		return nil, errors.New("missing peer info in incoming context")
   151  	}
   152  
   153  	// The methodName will be available in the passed in ctx from a unary or streaming
   154  	// interceptor, as grpc.Server pipes in a transport stream which contains the methodName
   155  	// into contexts available in both unary or streaming interceptors.
   156  	mn, ok := grpc.Method(ctx)
   157  	if !ok {
   158  		return nil, errors.New("missing method in incoming context")
   159  	}
   160  
   161  	// The connection is needed in order to find the destination address and
   162  	// port of the incoming RPC Call.
   163  	conn := getConnection(ctx)
   164  	if conn == nil {
   165  		return nil, errors.New("missing connection in incoming context")
   166  	}
   167  	_, dPort, err := net.SplitHostPort(conn.LocalAddr().String())
   168  	if err != nil {
   169  		return nil, fmt.Errorf("error parsing local address: %v", err)
   170  	}
   171  	dp, err := strconv.ParseUint(dPort, 10, 32)
   172  	if err != nil {
   173  		return nil, fmt.Errorf("error parsing local address: %v", err)
   174  	}
   175  
   176  	var peerCertificates []*x509.Certificate
   177  	if pi.AuthInfo != nil {
   178  		tlsInfo, ok := pi.AuthInfo.(credentials.TLSInfo)
   179  		if ok {
   180  			peerCertificates = tlsInfo.State.PeerCertificates
   181  		}
   182  	}
   183  
   184  	return &rpcData{
   185  		md:              md,
   186  		peerInfo:        pi,
   187  		fullMethod:      mn,
   188  		destinationPort: uint32(dp),
   189  		destinationAddr: conn.LocalAddr(),
   190  		certs:           peerCertificates,
   191  	}, nil
   192  }
   193  
   194  // rpcData wraps data pulled from an incoming RPC that the RBAC engine needs to
   195  // find a matching policy.
   196  type rpcData struct {
   197  	// md is the HTTP Headers that are present in the incoming RPC.
   198  	md metadata.MD
   199  	// peerInfo is information about the downstream peer.
   200  	peerInfo *peer.Peer
   201  	// fullMethod is the method name being called on the upstream service.
   202  	fullMethod string
   203  	// destinationPort is the port that the RPC is being sent to on the
   204  	// server.
   205  	destinationPort uint32
   206  	// destinationAddr is the address that the RPC is being sent to.
   207  	destinationAddr net.Addr
   208  	// certs are the certificates presented by the peer during a TLS
   209  	// handshake.
   210  	certs []*x509.Certificate
   211  }