Refactor AddPeer to ensure consistency (#557)

This commit is contained in:
Misha Bragin 2022-11-08 16:14:36 +01:00 committed by GitHub
parent 157137e4ad
commit e19d5dca7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 88 deletions

View File

@ -15,6 +15,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"math/rand"
"net"
"net/netip"
"reflect"
"regexp"
@ -62,7 +63,7 @@ type AccountManager interface {
UpdatePeer(accountID string, peer *Peer) (*Peer, error)
GetNetworkMap(peerKey string) (*NetworkMap, error)
GetPeerNetwork(peerKey string) (*Network, error)
AddPeer(setupKey string, userId string, peer *Peer) (*Peer, error)
AddPeer(setupKey, userID string, peer *Peer) (*Peer, error)
UpdatePeerMeta(peerKey string, meta PeerSystemMeta) error
UpdatePeerSSHKey(peerKey string, sshKey string) error
GetUsersFromAccount(accountID, userID string) ([]*UserInfo, error)
@ -277,7 +278,41 @@ func (a *Account) FindUser(userID string) (*User, error) {
return user, nil
}
// getPeerDNSLabels return the account's peers' dns labels
// FindSetupKey looks for a given SetupKey in the Account or returns error if it wasn't found.
func (a *Account) FindSetupKey(setupKey string) (*SetupKey, error) {
key := a.SetupKeys[setupKey]
if key == nil {
return nil, Errorf(SetupKeyNotFound, "setup key not found")
}
return key, nil
}
func (a *Account) getUserGroups(userID string) ([]string, error) {
user, err := a.FindUser(userID)
if err != nil {
return nil, err
}
return user.AutoGroups, nil
}
func (a *Account) getSetupKeyGroups(setupKey string) ([]string, error) {
key, err := a.FindSetupKey(setupKey)
if err != nil {
return nil, err
}
return key.AutoGroups, nil
}
func (a *Account) getTakenIPs() []net.IP {
var takenIps []net.IP
for _, existingPeer := range a.Peers {
takenIps = append(takenIps, existingPeer.IP)
}
return takenIps
}
func (a *Account) getPeerDNSLabels() lookupMap {
existingLabels := make(lookupMap)
for _, peer := range a.Peers {
@ -925,15 +960,6 @@ func newAccountWithId(accountId, userId, domain string) *Account {
return acc
}
func getAccountSetupKeyByKey(acc *Account, key string) *SetupKey {
for _, k := range acc.SetupKeys {
if key == k.Key {
return k
}
}
return nil
}
func removeFromList(inputList []string, toRemove []string) []string {
toRemoveMap := make(map[string]struct{})
for _, item := range toRemove {

View File

@ -130,7 +130,7 @@ func getPeerHostLabel(name string, peerLabels lookupMap) (string, error) {
uniqueLabel := getUniqueHostLabel(label, peerLabels)
if uniqueLabel == "" {
return "", fmt.Errorf("couldn't find a unique valid lavel for %s, parsed label %s", name, label)
return "", fmt.Errorf("couldn't find a unique valid label for %s, parsed label %s", name, label)
}
return uniqueLabel, nil
}

View File

@ -6,17 +6,20 @@ import (
const (
// UserAlreadyExists indicates that user already exists
UserAlreadyExists ErrorType = 1
UserAlreadyExists ErrorType = iota
// AccountNotFound indicates that specified account hasn't been found
AccountNotFound ErrorType = iota
AccountNotFound
// PreconditionFailed indicates that some pre-condition for the operation hasn't been fulfilled
PreconditionFailed ErrorType = iota
PreconditionFailed
// UserNotFound indicates that user wasn't found in the system (or under a given Account)
UserNotFound ErrorType = iota
UserNotFound
// PermissionDenied indicates that user has no permissions to view data
PermissionDenied ErrorType = iota
PermissionDenied
// SetupKeyNotFound indicates that the setup key wasn't found in the system (or under a given Account)
SetupKeyNotFound
)
// ErrorType is a type of the Error

View File

@ -185,7 +185,7 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi
func (s *GRPCServer) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Peer, error) {
var (
reqSetupKey string
userId string
userID string
)
if req.GetJwtToken() != "" {
@ -204,12 +204,11 @@ func (s *GRPCServer) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest)
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to fetch account with claims, err: %v", err)
}
userId = claims.UserId
userID = claims.UserId
} else {
log.Debugln("using setup key to register peer")
reqSetupKey = req.GetSetupKey()
userId = ""
userID = ""
}
meta := req.GetMeta()
@ -222,7 +221,7 @@ func (s *GRPCServer) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest)
sshKey = req.GetPeerKeys().GetSshPubKey()
}
peer, err := s.accountManager.AddPeer(reqSetupKey, userId, &Peer{
peer, err := s.accountManager.AddPeer(reqSetupKey, userID, &Peer{
Key: peerKey.String(),
Name: meta.GetHostname(),
SSHKey: string(sshKey),
@ -238,13 +237,18 @@ func (s *GRPCServer) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest)
},
})
if err != nil {
s, ok := status.FromError(err)
if ok {
if s.Code() == codes.FailedPrecondition || s.Code() == codes.OutOfRange {
return nil, err
if e, ok := FromError(err); ok {
switch e.Type() {
case PreconditionFailed:
return nil, status.Errorf(codes.FailedPrecondition, e.message)
case AccountNotFound:
case SetupKeyNotFound:
case UserNotFound:
return nil, status.Errorf(codes.NotFound, e.message)
default:
}
}
return nil, status.Errorf(codes.NotFound, "provided setup key doesn't exists")
return nil, status.Errorf(codes.Internal, "failed registering new peer")
}
// todo move to DefaultAccountManager the code below

View File

@ -5,8 +5,6 @@ import (
nbdns "github.com/netbirdio/netbird/dns"
"github.com/netbirdio/netbird/route"
"github.com/rs/xid"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"math/rand"
"net"
"sync"
@ -95,7 +93,7 @@ func AllocatePeerIP(ipNet net.IPNet, takenIps []net.IP) (net.IP, error) {
ips, _ := generateIPs(&ipNet, takenIPMap)
if len(ips) == 0 {
return nil, status.Errorf(codes.OutOfRange, "failed allocating new IP for the ipNet %s - network is out of IPs", ipNet.String())
return nil, Errorf(PreconditionFailed, "failed allocating new IP for the ipNet %s - network is out of IPs", ipNet.String())
}
// pick a random IP

View File

@ -319,59 +319,20 @@ func (am *DefaultAccountManager) GetPeerNetwork(peerPubKey string) (*Network, er
// to it. We also add the User ID to the peer metadata to identify registrant.
// Each new Peer will be assigned a new next net.IP from the Account.Network and Account.Network.LastIP will be updated (IP's are not reused).
// The peer property is just a placeholder for the Peer properties to pass further
func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *Peer) (*Peer, error) {
func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (*Peer, error) {
upperKey := strings.ToUpper(setupKey)
var account *Account
var err error
var sk *SetupKey
// auto-assign groups that are coming with a SetupKey or a User
var groupsToAdd []string
if len(upperKey) != 0 {
account, err = am.Store.GetAccountBySetupKey(upperKey)
if err != nil {
return nil, status.Errorf(
codes.NotFound,
"unable to register peer, unable to find account with setupKey %s",
upperKey,
)
}
sk = getAccountSetupKeyByKey(account, upperKey)
if sk == nil {
// shouldn't happen actually
return nil, status.Errorf(
codes.NotFound,
"unable to register peer, unknown setupKey %s",
upperKey,
)
}
if !sk.IsValid() {
return nil, status.Errorf(
codes.FailedPrecondition,
"unable to register peer, its setup key is invalid (expired, overused or revoked)",
)
}
groupsToAdd = sk.AutoGroups
} else if len(userID) != 0 {
addedByUser := false
if len(userID) > 0 {
addedByUser = true
account, err = am.Store.GetAccountByUser(userID)
if err != nil {
return nil, status.Errorf(codes.NotFound, "unable to register peer, unknown user with ID: %s", userID)
}
user, ok := account.Users[userID]
if !ok {
return nil, status.Errorf(codes.NotFound, "unable to register peer, unknown user with ID: %s", userID)
}
groupsToAdd = user.AutoGroups
} else {
// Empty setup key and jwt fail
return nil, status.Errorf(codes.InvalidArgument, "no setup key or user id provided")
account, err = am.Store.GetAccountBySetupKey(setupKey)
}
if err != nil {
return nil, Errorf(AccountNotFound, "failed adding new peer: account not found")
}
unlock := am.Store.AcquireAccountLock(account.Id)
@ -383,22 +344,29 @@ func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *P
return nil, err
}
var takenIps []net.IP
existingLabels := make(lookupMap)
for _, existingPeer := range account.Peers {
takenIps = append(takenIps, existingPeer.IP)
if existingPeer.DNSLabel != "" {
existingLabels[existingPeer.DNSLabel] = struct{}{}
if !addedByUser {
// validate the setup key if adding with a key
sk, err := account.FindSetupKey(upperKey)
if err != nil {
return nil, err
}
if !sk.IsValid() {
return nil, Errorf(PreconditionFailed, "couldn't add peer: setup key is invalid")
}
account.SetupKeys[sk.Key] = sk.IncrementUsage()
}
takenIps := account.getTakenIPs()
existingLabels := account.getPeerDNSLabels()
newLabel, err := getPeerHostLabel(peer.Name, existingLabels)
if err != nil {
return nil, err
}
peer.DNSLabel = newLabel
network := account.Network
nextIp, err := AllocatePeerIP(network.Net, takenIps)
if err != nil {
@ -425,6 +393,19 @@ func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *P
}
group.Peers = append(group.Peers, newPeer.Key)
var groupsToAdd []string
if addedByUser {
groupsToAdd, err = account.getUserGroups(userID)
if err != nil {
return nil, err
}
} else {
groupsToAdd, err = account.getSetupKeyGroups(upperKey)
if err != nil {
return nil, err
}
}
if len(groupsToAdd) > 0 {
for _, s := range groupsToAdd {
if g, ok := account.Groups[s]; ok && g.Name != "All" {
@ -434,11 +415,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *P
}
account.Peers[newPeer.Key] = newPeer
if len(upperKey) != 0 {
account.SetupKeys[sk.Key] = sk.IncrementUsage()
}
account.Network.IncSerial()
err = am.Store.SaveAccount(account)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed adding peer")