newRPCData takes an incoming context (should be a context representing state needed for server RPC Call with metadata, peer info (used for source ip/port and TLS information) and connection (used for destination ip/port) piped into it) and the method name of the Service being called server side and
(ctx context.Context)
| 195 | // an rpcData struct ready to be passed to the RBAC Engine to find a matching |
| 196 | // policy. |
| 197 | func newRPCData(ctx context.Context) (*rpcData, error) { |
| 198 | // The caller should populate all of these fields (i.e. for empty headers, |
| 199 | // pipe an empty md into context). |
| 200 | md, ok := metadata.FromIncomingContext(ctx) |
| 201 | if !ok { |
| 202 | return nil, errors.New("missing metadata in incoming context") |
| 203 | } |
| 204 | // ":method can be hard-coded to POST if unavailable" - A41 |
| 205 | md[":method"] = []string{"POST"} |
| 206 | // "If the transport exposes TE in Metadata, then RBAC must special-case the |
| 207 | // header to treat it as not present." - A41 |
| 208 | delete(md, "TE") |
| 209 | |
| 210 | pi, ok := peer.FromContext(ctx) |
| 211 | if !ok { |
| 212 | return nil, errors.New("missing peer info in incoming context") |
| 213 | } |
| 214 | |
| 215 | // The methodName will be available in the passed in ctx from a unary or streaming |
| 216 | // interceptor, as grpc.Server pipes in a transport stream which contains the methodName |
| 217 | // into contexts available in both unary or streaming interceptors. |
| 218 | mn, ok := grpc.Method(ctx) |
| 219 | if !ok { |
| 220 | return nil, errors.New("missing method in incoming context") |
| 221 | } |
| 222 | // gRPC-Go strips :path from the headers given to the application, but RBAC should be |
| 223 | // able to match against it. |
| 224 | md[":path"] = []string{mn} |
| 225 | |
| 226 | // The connection is needed in order to find the destination address and |
| 227 | // port of the incoming RPC Call. |
| 228 | conn := getConnection(ctx) |
| 229 | if conn == nil { |
| 230 | return nil, errors.New("missing connection in incoming context") |
| 231 | } |
| 232 | _, dPort, err := net.SplitHostPort(conn.LocalAddr().String()) |
| 233 | if err != nil { |
| 234 | return nil, fmt.Errorf("error parsing local address: %v", err) |
| 235 | } |
| 236 | dp, err := strconv.ParseUint(dPort, 10, 32) |
| 237 | if err != nil { |
| 238 | return nil, fmt.Errorf("error parsing local address: %v", err) |
| 239 | } |
| 240 | |
| 241 | var authType string |
| 242 | var peerCertificates []*x509.Certificate |
| 243 | if tlsInfo, ok := pi.AuthInfo.(credentials.TLSInfo); ok { |
| 244 | authType = pi.AuthInfo.AuthType() |
| 245 | peerCertificates = tlsInfo.State.PeerCertificates |
| 246 | } |
| 247 | |
| 248 | return &rpcData{ |
| 249 | md: md, |
| 250 | peerInfo: pi, |
| 251 | fullMethod: mn, |
| 252 | destinationPort: uint32(dp), |
| 253 | localAddr: conn.LocalAddr(), |
| 254 | authType: authType, |
no test coverage detected