mirror of
https://github.com/netbirdio/netbird.git
synced 2025-06-02 08:06:01 +02:00
181 lines
5.1 KiB
Go
181 lines
5.1 KiB
Go
package internal
|
|
|
|
import (
|
|
"context"
|
|
"net/url"
|
|
|
|
"github.com/google/uuid"
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"github.com/netbirdio/netbird/client/ssh"
|
|
"github.com/netbirdio/netbird/client/system"
|
|
mgm "github.com/netbirdio/netbird/management/client"
|
|
mgmProto "github.com/netbirdio/netbird/management/proto"
|
|
)
|
|
|
|
// IsLoginRequired check that the server is support SSO or not
|
|
func IsLoginRequired(ctx context.Context, config *Config) (bool, error) {
|
|
mgmURL := config.ManagementURL
|
|
mgmClient, err := getMgmClient(ctx, config.PrivateKey, mgmURL)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer func() {
|
|
err = mgmClient.Close()
|
|
if err != nil {
|
|
cStatus, ok := status.FromError(err)
|
|
if !ok || ok && cStatus.Code() != codes.Canceled {
|
|
log.Warnf("failed to close the Management service client, err: %v", err)
|
|
}
|
|
}
|
|
}()
|
|
log.Debugf("connected to the Management service %s", mgmURL.String())
|
|
|
|
pubSSHKey, err := ssh.GeneratePublicKey([]byte(config.SSHKey))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
_, err = doMgmLogin(ctx, mgmClient, pubSSHKey, config)
|
|
if isLoginNeeded(err) {
|
|
return true, nil
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
// Login or register the client
|
|
func Login(ctx context.Context, config *Config, setupKey string, jwtToken string) error {
|
|
mgmClient, err := getMgmClient(ctx, config.PrivateKey, config.ManagementURL)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
err = mgmClient.Close()
|
|
if err != nil {
|
|
cStatus, ok := status.FromError(err)
|
|
if !ok || ok && cStatus.Code() != codes.Canceled {
|
|
log.Warnf("failed to close the Management service client, err: %v", err)
|
|
}
|
|
}
|
|
}()
|
|
log.Debugf("connected to the Management service %s", config.ManagementURL.String())
|
|
|
|
pubSSHKey, err := ssh.GeneratePublicKey([]byte(config.SSHKey))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
serverKey, err := doMgmLogin(ctx, mgmClient, pubSSHKey, config)
|
|
if serverKey != nil && isRegistrationNeeded(err) {
|
|
log.Debugf("peer registration required")
|
|
_, err = registerPeer(ctx, *serverKey, mgmClient, setupKey, jwtToken, pubSSHKey, config)
|
|
return err
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func getMgmClient(ctx context.Context, privateKey string, mgmURL *url.URL) (*mgm.GrpcClient, error) {
|
|
// validate our peer's Wireguard PRIVATE key
|
|
myPrivateKey, err := wgtypes.ParseKey(privateKey)
|
|
if err != nil {
|
|
log.Errorf("failed parsing Wireguard key %s: [%s]", privateKey, err.Error())
|
|
return nil, err
|
|
}
|
|
|
|
var mgmTlsEnabled bool
|
|
if mgmURL.Scheme == "https" {
|
|
mgmTlsEnabled = true
|
|
}
|
|
|
|
log.Debugf("connecting to the Management service %s", mgmURL.String())
|
|
mgmClient, err := mgm.NewClient(ctx, mgmURL.Host, myPrivateKey, mgmTlsEnabled)
|
|
if err != nil {
|
|
log.Errorf("failed connecting to the Management service %s %v", mgmURL.String(), err)
|
|
return nil, err
|
|
}
|
|
return mgmClient, err
|
|
}
|
|
|
|
func doMgmLogin(ctx context.Context, mgmClient *mgm.GrpcClient, pubSSHKey []byte, config *Config) (*wgtypes.Key, error) {
|
|
serverKey, err := mgmClient.GetServerPublicKey()
|
|
if err != nil {
|
|
log.Errorf("failed while getting Management Service public key: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
sysInfo := system.GetInfo(ctx)
|
|
sysInfo.SetFlags(
|
|
config.RosenpassEnabled,
|
|
config.RosenpassPermissive,
|
|
config.ServerSSHAllowed,
|
|
config.DisableClientRoutes,
|
|
config.DisableServerRoutes,
|
|
config.DisableDNS,
|
|
config.DisableFirewall,
|
|
)
|
|
_, err = mgmClient.Login(*serverKey, sysInfo, pubSSHKey)
|
|
return serverKey, err
|
|
}
|
|
|
|
// registerPeer checks whether setupKey was provided via cmd line and if not then it prompts user to enter a key.
|
|
// Otherwise tries to register with the provided setupKey via command line.
|
|
func registerPeer(ctx context.Context, serverPublicKey wgtypes.Key, client *mgm.GrpcClient, setupKey string, jwtToken string, pubSSHKey []byte, config *Config) (*mgmProto.LoginResponse, error) {
|
|
validSetupKey, err := uuid.Parse(setupKey)
|
|
if err != nil && jwtToken == "" {
|
|
return nil, status.Errorf(codes.InvalidArgument, "invalid setup-key or no sso information provided, err: %v", err)
|
|
}
|
|
|
|
log.Debugf("sending peer registration request to Management Service")
|
|
info := system.GetInfo(ctx)
|
|
info.SetFlags(
|
|
config.RosenpassEnabled,
|
|
config.RosenpassPermissive,
|
|
config.ServerSSHAllowed,
|
|
config.DisableClientRoutes,
|
|
config.DisableServerRoutes,
|
|
config.DisableDNS,
|
|
config.DisableFirewall,
|
|
)
|
|
loginResp, err := client.Register(serverPublicKey, validSetupKey.String(), jwtToken, info, pubSSHKey)
|
|
if err != nil {
|
|
log.Errorf("failed registering peer %v,%s", err, validSetupKey.String())
|
|
return nil, err
|
|
}
|
|
|
|
log.Infof("peer has been successfully registered on Management Service")
|
|
|
|
return loginResp, nil
|
|
}
|
|
|
|
func isLoginNeeded(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
s, ok := status.FromError(err)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isRegistrationNeeded(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
s, ok := status.FromError(err)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if s.Code() == codes.PermissionDenied {
|
|
return true
|
|
}
|
|
return false
|
|
}
|