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  }