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 }