github.com/koko1123/flow-go-1@v0.29.6/network/validator/authorized_sender_validator.go (about) 1 package validator 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/libp2p/go-libp2p/core/peer" 8 "github.com/rs/zerolog" 9 10 "github.com/koko1123/flow-go-1/model/flow" 11 "github.com/koko1123/flow-go-1/network/channels" 12 "github.com/koko1123/flow-go-1/network/message" 13 "github.com/koko1123/flow-go-1/network/p2p" 14 "github.com/koko1123/flow-go-1/network/slashing" 15 ) 16 17 var ( 18 ErrSenderEjected = errors.New("validation failed: sender is an ejected node") 19 ErrIdentityUnverified = errors.New("validation failed: could not verify identity of sender") 20 ) 21 22 type GetIdentityFunc func(peer.ID) (*flow.Identity, bool) 23 24 // AuthorizedSenderValidator performs message authorization validation. 25 type AuthorizedSenderValidator struct { 26 log zerolog.Logger 27 slashingViolationsConsumer slashing.ViolationsConsumer 28 getIdentity GetIdentityFunc 29 } 30 31 // NewAuthorizedSenderValidator returns a new AuthorizedSenderValidator 32 func NewAuthorizedSenderValidator(log zerolog.Logger, slashingViolationsConsumer slashing.ViolationsConsumer, getIdentity GetIdentityFunc) *AuthorizedSenderValidator { 33 return &AuthorizedSenderValidator{ 34 log: log.With().Str("component", "authorized_sender_validator").Logger(), 35 slashingViolationsConsumer: slashingViolationsConsumer, 36 getIdentity: getIdentity, 37 } 38 } 39 40 // PubSubMessageValidator wraps Validate and returns PubSubMessageValidator callback that returns pubsub.ValidationReject if validation fails and pubsub.ValidationAccept if validation passes. 41 func (av *AuthorizedSenderValidator) PubSubMessageValidator(channel channels.Channel) PubSubMessageValidator { 42 return func(from peer.ID, msg interface{}) p2p.ValidationResult { 43 _, err := av.Validate(from, msg, channel, message.ProtocolPublish) 44 if err != nil { 45 return p2p.ValidationReject 46 } 47 48 return p2p.ValidationAccept 49 } 50 } 51 52 // Validate will check if the sender of a message is authorized to send the message. 53 // Using the getIdentity to get the flow identity for the sender, asserting that the sender is a staked node and not ejected. 54 // Otherwise, the message is rejected. The message is also authorized by checking that the sender is allowed to send the message on the channel. 55 // If validation fails the message is rejected, and if the validation error is an expected error, slashing data is also collected. 56 // Authorization config is defined in message.MsgAuthConfig. 57 func (av *AuthorizedSenderValidator) Validate(from peer.ID, msg interface{}, channel channels.Channel, protocol message.Protocol) (string, error) { 58 // NOTE: Gossipsub messages from unstaked nodes should be rejected by the libP2P node topic validator 59 // before they reach message validators. If a message from a unstaked peer gets to this point 60 // something terrible went wrong. 61 identity, ok := av.getIdentity(from) 62 if !ok { 63 violation := &slashing.Violation{Identity: identity, PeerID: from.String(), Channel: channel, Protocol: protocol, Err: ErrIdentityUnverified} 64 av.slashingViolationsConsumer.OnUnAuthorizedSenderError(violation) 65 return "", ErrIdentityUnverified 66 } 67 68 msgType, err := av.isAuthorizedSender(identity, channel, msg, protocol) 69 70 switch { 71 case err == nil: 72 return msgType, nil 73 case message.IsUnknownMsgTypeErr(err): 74 violation := &slashing.Violation{Identity: identity, PeerID: from.String(), MsgType: msgType, Channel: channel, Protocol: protocol, Err: err} 75 av.slashingViolationsConsumer.OnUnknownMsgTypeError(violation) 76 return msgType, err 77 case errors.Is(err, message.ErrUnauthorizedMessageOnChannel) || errors.Is(err, message.ErrUnauthorizedRole): 78 violation := &slashing.Violation{Identity: identity, PeerID: from.String(), MsgType: msgType, Channel: channel, Protocol: protocol, Err: err} 79 av.slashingViolationsConsumer.OnUnAuthorizedSenderError(violation) 80 return msgType, err 81 case errors.Is(err, ErrSenderEjected): 82 violation := &slashing.Violation{Identity: identity, PeerID: from.String(), MsgType: msgType, Channel: channel, Protocol: protocol, Err: err} 83 av.slashingViolationsConsumer.OnSenderEjectedError(violation) 84 return msgType, err 85 case errors.Is(err, message.ErrUnauthorizedUnicastOnChannel): 86 violation := &slashing.Violation{Identity: identity, PeerID: from.String(), MsgType: msgType, Channel: channel, Protocol: protocol, Err: err} 87 av.slashingViolationsConsumer.OnUnauthorizedUnicastOnChannel(violation) 88 return msgType, err 89 default: 90 // this condition should never happen and indicates there's a bug 91 // don't crash as a result of external inputs since that creates a DoS vector 92 // collect slashing data because this could potentially lead to slashing 93 err = fmt.Errorf("unexpected error during message validation: %w", err) 94 violation := &slashing.Violation{Identity: identity, PeerID: from.String(), MsgType: msgType, Channel: channel, Protocol: protocol, Err: err} 95 av.slashingViolationsConsumer.OnUnexpectedError(violation) 96 return msgType, err 97 } 98 } 99 100 // isAuthorizedSender performs network authorization validation. This func will assert the following; 101 // 1. The node is not ejected. 102 // 2. Using the message auth config 103 // A. The message is authorized to be sent on channel. 104 // B. The sender role is authorized to send message on channel. 105 // 106 // Expected error returns during normal operations: 107 // - ErrSenderEjected: if identity of sender is ejected from the network 108 // - message.ErrUnknownMsgType if message auth config us not found for the msg 109 // - message.ErrUnauthorizedMessageOnChannel if msg is not authorized to be sent on channel 110 // - message.ErrUnauthorizedRole if sender role is not authorized to send msg 111 func (av *AuthorizedSenderValidator) isAuthorizedSender(identity *flow.Identity, channel channels.Channel, msg interface{}, protocol message.Protocol) (string, error) { 112 if identity.Ejected { 113 return "", ErrSenderEjected 114 } 115 116 // get message auth config 117 conf, err := message.GetMessageAuthConfig(msg) 118 if err != nil { 119 return "", err 120 } 121 122 // handle special case for cluster prefixed channels 123 if prefix, ok := channels.ClusterChannelPrefix(channel); ok { 124 channel = channels.Channel(prefix) 125 } 126 127 if err := conf.EnsureAuthorized(identity.Role, channel, protocol); err != nil { 128 return conf.Name, err 129 } 130 131 return conf.Name, nil 132 }