mirror of
https://github.com/netbirdio/netbird.git
synced 2024-12-24 15:48:52 +01:00
add signatures and frame for peer approval
This commit is contained in:
parent
b7c0eba1e5
commit
a7e55cc5e3
2
go.mod
2
go.mod
@ -51,7 +51,7 @@ require (
|
||||
github.com/miekg/dns v1.1.43
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/nadoo/ipset v0.5.0
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818
|
||||
github.com/okta/okta-sdk-golang/v2 v2.18.0
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pion/logging v0.2.2
|
||||
|
14
go.sum
14
go.sum
@ -495,8 +495,18 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc=
|
||||
github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88 h1:zhe8qseauBuYOS910jpl5sv8Tb+36zxQPXrwYXqll0g=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944 h1:n7o2/NCZzn0+73LGdl/VMh7DOTdWZ98le2woeZ4HlB0=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a h1:6aipBr80s0GPKO9Wl+f5TUOSwebQ91uX2thk9tElyqc=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127165733-0d0650c84683 h1:jJMO8KL2u3ok5VtGgZtFpuVK0GBEXXIb84idlmqGe68=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127165733-0d0650c84683/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127170523-a11fee39970a h1:DIe9xdl6RcxeZFu5Pr3OPC8SHM6yadF212W3LJlzfhQ=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127170523-a11fee39970a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a h1:iMEPP7MC3/7DTs/BNMshsBoviG3yWSTRbIzXKdrUwHw=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818 h1:PTQ2SSijkoN8Qkctq9oLzEdzCLLv7WoD2dqScmpb15o=
|
||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
|
||||
github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g=
|
||||
github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||
github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949 h1:xbWM9BU6mwZZLHxEjxIX/V8Hv3HurQt4mReIE4mY4DM=
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
|
||||
"github.com/eko/gocache/v3/cache"
|
||||
cacheStore "github.com/eko/gocache/v3/store"
|
||||
"github.com/netbirdio/management-integrations/integrations"
|
||||
gocache "github.com/patrickmn/go-cache"
|
||||
"github.com/rs/xid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@ -159,12 +160,12 @@ type Settings struct {
|
||||
// JWTGroupsClaimName from which we extract groups name to add it to account groups
|
||||
JWTGroupsClaimName string
|
||||
|
||||
// Extra contains additional settings that are not supported in the open-source version
|
||||
// Extra is a dictionary of Account settings
|
||||
Extra *ExtraSettings
|
||||
}
|
||||
|
||||
type ExtraSettings struct {
|
||||
// PeerApprovalEnabled enables or disables the need for peers to be approved by an administrator
|
||||
// PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator
|
||||
PeerApprovalEnabled bool
|
||||
}
|
||||
|
||||
@ -352,7 +353,20 @@ func (a *Account) GetGroup(groupID string) *Group {
|
||||
|
||||
// GetPeerNetworkMap returns a group by ID if exists, nil otherwise
|
||||
func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap {
|
||||
peer := a.Peers[peerID]
|
||||
if peer == nil {
|
||||
return &NetworkMap{
|
||||
Network: a.Network.Copy(),
|
||||
}
|
||||
}
|
||||
validatedPeers := integrations.ValidatePeers([]*Peer{peer}, a)
|
||||
if len(validatedPeers) == 0 {
|
||||
return &NetworkMap{
|
||||
Network: a.Network.Copy(),
|
||||
}
|
||||
}
|
||||
aclPeers, firewallRules := a.getPeerConnectionResources(peerID)
|
||||
aclPeers = integrations.ValidatePeers(aclPeers, a)
|
||||
// exclude expired peers
|
||||
var peersToConnect []*Peer
|
||||
var expiredPeers []*Peer
|
||||
@ -879,6 +893,11 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = integrations.ValidateExtraSettings(newSettings.Extra, account, am)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, err := account.FindUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -905,6 +924,18 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string,
|
||||
am.checkAndSchedulePeerLoginExpiration(account)
|
||||
}
|
||||
|
||||
// if oldSettings.PeerApprovalEnabled != newSettings.PeerApprovalEnabled {
|
||||
// event := activity.AccountPeerApprovalEnabled
|
||||
// if !newSettings.PeerApprovalEnabled {
|
||||
// event = activity.AccountPeerApprovalDisabled
|
||||
// }
|
||||
// am.StoreEvent(userID, accountID, accountID, event, nil)
|
||||
//
|
||||
// for _, peer := range account.Peers {
|
||||
// peer.Status.RequiresApproval = false
|
||||
// }
|
||||
// }
|
||||
|
||||
updatedAccount := account.UpdateSettings(newSettings)
|
||||
|
||||
err = am.Store.SaveAccount(account)
|
||||
|
@ -120,6 +120,14 @@ const (
|
||||
IntegrationUpdated
|
||||
// IntegrationDeleted indicates that the user deleted an integration
|
||||
IntegrationDeleted
|
||||
// AccountPeerApprovalEnabled indicates that the user enabled peer approval for the account
|
||||
AccountPeerApprovalEnabled
|
||||
// AccountPeerApprovalDisabled indicates that the user disabled peer approval for the account
|
||||
AccountPeerApprovalDisabled
|
||||
// PeerApproved indicates that the peer has been approved
|
||||
PeerApproved
|
||||
// PeerApprovalRevoked indicates that the peer approval has been revoked
|
||||
PeerApprovalRevoked
|
||||
)
|
||||
|
||||
var activityMap = map[Activity]Code{
|
||||
@ -178,6 +186,10 @@ var activityMap = map[Activity]Code{
|
||||
IntegrationCreated: {"Integration created", "integration.create"},
|
||||
IntegrationUpdated: {"Integration updated", "integration.update"},
|
||||
IntegrationDeleted: {"Integration deleted", "integration.delete"},
|
||||
AccountPeerApprovalEnabled: {"Account peer approval enabled", "account.setting.peer.approval.enable"},
|
||||
AccountPeerApprovalDisabled: {"Account peer approval disabled", "account.setting.peer.approval.disable"},
|
||||
PeerApproved: {"Peer approved", "peer.approve"},
|
||||
PeerApprovalRevoked: {"Peer approval revoked", "peer.approval.revoke"},
|
||||
}
|
||||
|
||||
// StringCode returns a string code of the activity
|
||||
|
@ -77,6 +77,10 @@ func (h *AccountsHandler) UpdateAccount(w http.ResponseWriter, r *http.Request)
|
||||
PeerLoginExpiration: time.Duration(float64(time.Second.Nanoseconds()) * float64(req.Settings.PeerLoginExpiration)),
|
||||
}
|
||||
|
||||
if req.Settings.Extra != nil {
|
||||
settings.Extra = &server.ExtraSettings{PeerApprovalEnabled: *req.Settings.Extra.PeerApprovalEnabled}
|
||||
}
|
||||
|
||||
if req.Settings.JwtGroupsEnabled != nil {
|
||||
settings.JWTGroupsEnabled = *req.Settings.JwtGroupsEnabled
|
||||
}
|
||||
@ -99,14 +103,20 @@ func (h *AccountsHandler) UpdateAccount(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
func toAccountResponse(account *server.Account) *api.Account {
|
||||
settings := api.AccountSettings{
|
||||
PeerLoginExpiration: int(account.Settings.PeerLoginExpiration.Seconds()),
|
||||
PeerLoginExpirationEnabled: account.Settings.PeerLoginExpirationEnabled,
|
||||
GroupsPropagationEnabled: &account.Settings.GroupsPropagationEnabled,
|
||||
JwtGroupsEnabled: &account.Settings.JWTGroupsEnabled,
|
||||
JwtGroupsClaimName: &account.Settings.JWTGroupsClaimName,
|
||||
}
|
||||
|
||||
if account.Settings.Extra != nil {
|
||||
settings.Extra = &api.AccountExtraSettings{PeerApprovalEnabled: &account.Settings.Extra.PeerApprovalEnabled}
|
||||
}
|
||||
|
||||
return &api.Account{
|
||||
Id: account.Id,
|
||||
Settings: api.AccountSettings{
|
||||
PeerLoginExpiration: int(account.Settings.PeerLoginExpiration.Seconds()),
|
||||
PeerLoginExpirationEnabled: account.Settings.PeerLoginExpirationEnabled,
|
||||
GroupsPropagationEnabled: &account.Settings.GroupsPropagationEnabled,
|
||||
JwtGroupsEnabled: &account.Settings.JWTGroupsEnabled,
|
||||
JwtGroupsClaimName: &account.Settings.JWTGroupsClaimName,
|
||||
},
|
||||
Id: account.Id,
|
||||
Settings: settings,
|
||||
}
|
||||
}
|
||||
|
@ -66,9 +66,18 @@ components:
|
||||
description: Name of the claim from which we extract groups names to add it to account groups.
|
||||
type: string
|
||||
example: "roles"
|
||||
extra:
|
||||
$ref: '#/components/schemas/AccountExtraSettings'
|
||||
required:
|
||||
- peer_login_expiration_enabled
|
||||
- peer_login_expiration
|
||||
AccountExtraSettings:
|
||||
type: object
|
||||
properties:
|
||||
peer_approval_enabled:
|
||||
description: Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin.
|
||||
type: boolean
|
||||
example: true
|
||||
AccountRequest:
|
||||
type: object
|
||||
properties:
|
||||
@ -213,6 +222,10 @@ components:
|
||||
login_expiration_enabled:
|
||||
type: boolean
|
||||
example: false
|
||||
approval_required:
|
||||
description: (Cloud only) Indicates whether peer needs approval
|
||||
type: boolean
|
||||
example: true
|
||||
required:
|
||||
- name
|
||||
- ssh_enabled
|
||||
@ -281,6 +294,10 @@ components:
|
||||
type: string
|
||||
format: date-time
|
||||
example: 2023-05-05T09:00:35.477782Z
|
||||
approval_required:
|
||||
description: (Cloud only) Indicates whether peer needs approval
|
||||
type: boolean
|
||||
example: true
|
||||
required:
|
||||
- ip
|
||||
- connected
|
||||
|
@ -142,6 +142,12 @@ type Account struct {
|
||||
Settings AccountSettings `json:"settings"`
|
||||
}
|
||||
|
||||
// AccountExtraSettings defines model for AccountExtraSettings.
|
||||
type AccountExtraSettings struct {
|
||||
// PeerApprovalEnabled Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin.
|
||||
PeerApprovalEnabled *bool `json:"peer_approval_enabled,omitempty"`
|
||||
}
|
||||
|
||||
// AccountRequest defines model for AccountRequest.
|
||||
type AccountRequest struct {
|
||||
Settings AccountSettings `json:"settings"`
|
||||
@ -149,6 +155,8 @@ type AccountRequest struct {
|
||||
|
||||
// AccountSettings defines model for AccountSettings.
|
||||
type AccountSettings struct {
|
||||
Extra *AccountExtraSettings `json:"extra,omitempty"`
|
||||
|
||||
// GroupsPropagationEnabled Allows propagate the new user auto groups to peers that belongs to the user
|
||||
GroupsPropagationEnabled *bool `json:"groups_propagation_enabled,omitempty"`
|
||||
|
||||
@ -323,6 +331,9 @@ type Peer struct {
|
||||
// AccessiblePeers List of accessible peers
|
||||
AccessiblePeers []AccessiblePeer `json:"accessible_peers"`
|
||||
|
||||
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
||||
ApprovalRequired *bool `json:"approval_required,omitempty"`
|
||||
|
||||
// Connected Peer to Management connection status
|
||||
Connected bool `json:"connected"`
|
||||
|
||||
@ -374,6 +385,9 @@ type Peer struct {
|
||||
|
||||
// PeerBase defines model for PeerBase.
|
||||
type PeerBase struct {
|
||||
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
||||
ApprovalRequired *bool `json:"approval_required,omitempty"`
|
||||
|
||||
// Connected Peer to Management connection status
|
||||
Connected bool `json:"connected"`
|
||||
|
||||
@ -428,6 +442,9 @@ type PeerBatch struct {
|
||||
// AccessiblePeersCount Number of accessible peers
|
||||
AccessiblePeersCount int `json:"accessible_peers_count"`
|
||||
|
||||
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
||||
ApprovalRequired *bool `json:"approval_required,omitempty"`
|
||||
|
||||
// Connected Peer to Management connection status
|
||||
Connected bool `json:"connected"`
|
||||
|
||||
@ -488,6 +505,8 @@ type PeerMinimum struct {
|
||||
|
||||
// PeerRequest defines model for PeerRequest.
|
||||
type PeerRequest struct {
|
||||
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
|
||||
ApprovalRequired *bool `json:"approval_required,omitempty"`
|
||||
LoginExpirationEnabled bool `json:"login_expiration_enabled"`
|
||||
Name string `json:"name"`
|
||||
SshEnabled bool `json:"ssh_enabled"`
|
||||
|
@ -81,6 +81,11 @@ func (h *PeersHandler) updatePeer(account *server.Account, user *server.User, pe
|
||||
|
||||
update := &server.Peer{ID: peerID, SSHEnabled: req.SshEnabled, Name: req.Name,
|
||||
LoginExpirationEnabled: req.LoginExpirationEnabled}
|
||||
|
||||
if req.ApprovalRequired != nil {
|
||||
update.Status = &server.PeerStatus{RequiresApproval: *req.ApprovalRequired}
|
||||
}
|
||||
|
||||
peer, err := h.accountManager.UpdatePeer(account.Id, user.Id, update)
|
||||
if err != nil {
|
||||
util.WriteError(err, w)
|
||||
@ -248,6 +253,7 @@ func toSinglePeerResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dnsD
|
||||
LastLogin: peer.LastLogin,
|
||||
LoginExpired: peer.Status.LoginExpired,
|
||||
AccessiblePeers: accessiblePeer,
|
||||
Approved: &peer.Status.Approved,
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,6 +276,7 @@ func toPeerListItemResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dn
|
||||
LastLogin: peer.LastLogin,
|
||||
LoginExpired: peer.Status.LoginExpired,
|
||||
AccessiblePeersCount: accessiblePeersCount,
|
||||
Approved: peer.Status.Approved,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/management-integrations/integrations"
|
||||
"github.com/rs/xid"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/activity"
|
||||
@ -46,6 +47,8 @@ type PeerStatus struct {
|
||||
Connected bool
|
||||
// LoginExpired
|
||||
LoginExpired bool
|
||||
// RequiresApproval indicates whether peer requires approval or not
|
||||
RequiresApproval bool
|
||||
}
|
||||
|
||||
// PeerSync used as a data object between the gRPC API and AccountManager on Sync request.
|
||||
@ -192,9 +195,10 @@ func (p *Peer) EventMeta(dnsDomain string) map[string]any {
|
||||
// Copy PeerStatus
|
||||
func (p *PeerStatus) Copy() *PeerStatus {
|
||||
return &PeerStatus{
|
||||
LastSeen: p.LastSeen,
|
||||
Connected: p.Connected,
|
||||
LoginExpired: p.LoginExpired,
|
||||
LastSeen: p.LastSeen,
|
||||
Connected: p.Connected,
|
||||
LoginExpired: p.LoginExpired,
|
||||
RequiresApproval: p.RequiresApproval,
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,6 +308,11 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *Pe
|
||||
return nil, status.Errorf(status.NotFound, "peer %s not found", update.ID)
|
||||
}
|
||||
|
||||
update, err = integrations.ValidatePeersUpdateRequest(update, peer, am)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if peer.SSHEnabled != update.SSHEnabled {
|
||||
peer.SSHEnabled = update.SSHEnabled
|
||||
event := activity.PeerSSHEnabled
|
||||
@ -562,6 +571,10 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (*
|
||||
Ephemeral: ephemeral,
|
||||
}
|
||||
|
||||
if account.Settings.Extra.PeerApprovalEnabled {
|
||||
newPeer.Status.RequiresApproval = true
|
||||
}
|
||||
|
||||
// add peer to 'All' group
|
||||
group, err := account.GetGroupAll()
|
||||
if err != nil {
|
||||
@ -632,6 +645,11 @@ func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*Peer, *NetworkMap, er
|
||||
return nil, nil, status.Errorf(status.Unauthenticated, "peer is not registered")
|
||||
}
|
||||
|
||||
validatedPeers := integrations.ValidatePeers([]*Peer{peer}, account)
|
||||
if len(validatedPeers) == 0 {
|
||||
return nil, nil, status.Errorf(status.PermissionDenied, "peer validation failed")
|
||||
}
|
||||
|
||||
err = checkIfPeerOwnerIsBlocked(peer, account)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
Loading…
Reference in New Issue
Block a user