From d5dfed498b317e0619142289f5ad5283d8a77d03 Mon Sep 17 00:00:00 2001 From: Misha Bragin Date: Mon, 13 Feb 2023 09:07:15 -0500 Subject: [PATCH] Add account settings (#686) Add account settings with a global peer expiration flag and duration --- management/server/account.go | 56 ++++++++++++++++++++++--------- management/server/account_test.go | 3 +- management/server/file_store.go | 7 ++-- management/server/grpcserver.go | 4 +-- management/server/peer.go | 7 ++-- management/server/peer_test.go | 35 ++++++++++++------- 6 files changed, 75 insertions(+), 37 deletions(-) diff --git a/management/server/account.go b/management/server/account.go index 8521be795..89d3dd659 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -120,6 +120,23 @@ type DefaultAccountManager struct { dnsDomain string } +// Settings represents Account settings structure that can be modified via API and Dashboard +type Settings struct { + // PeerLoginExpirationEnabled globally enables or disables peer login expiration + PeerLoginExpirationEnabled bool + // PeerLoginExpiration is a setting that indicates when peer login expires. + // Applies to all peers that have Peer.LoginExpirationEnabled set to true. + PeerLoginExpiration time.Duration +} + +// Copy copies the Settings struct +func (s *Settings) Copy() *Settings { + return &Settings{ + PeerLoginExpirationEnabled: s.PeerLoginExpirationEnabled, + PeerLoginExpiration: s.PeerLoginExpiration, + } +} + // Account represents a unique account of the system type Account struct { Id string @@ -137,9 +154,8 @@ type Account struct { Routes map[string]*route.Route NameServerGroups map[string]*nbdns.NameServerGroup DNSSettings *DNSSettings - // PeerLoginExpiration is a setting that indicates when peer login expires. - // Applies to all peers that have Peer.LoginExpirationEnabled set to true. - PeerLoginExpiration time.Duration + // Settings is a dictionary of Account settings + Settings *Settings } type UserInfo struct { @@ -472,7 +488,12 @@ func (a *Account) Copy() *Account { var dnsSettings *DNSSettings if a.DNSSettings != nil { - dnsSettings = a.DNSSettings + dnsSettings = a.DNSSettings.Copy() + } + + var settings *Settings + if a.Settings != nil { + settings = a.Settings.Copy() } return &Account{ @@ -490,7 +511,7 @@ func (a *Account) Copy() *Account { Routes: routes, NameServerGroups: nsGroups, DNSSettings: dnsSettings, - PeerLoginExpiration: a.PeerLoginExpiration, + Settings: settings, } } @@ -1097,17 +1118,20 @@ func newAccountWithId(accountId, userId, domain string) *Account { log.Debugf("created new account %s with setup key %s", accountId, defaultKey.Key) acc := &Account{ - Id: accountId, - SetupKeys: setupKeys, - Network: network, - Peers: peers, - Users: users, - CreatedBy: userId, - Domain: domain, - Routes: routes, - NameServerGroups: nameServersGroups, - DNSSettings: dnsSettings, - PeerLoginExpiration: DefaultPeerLoginExpiration, + Id: accountId, + SetupKeys: setupKeys, + Network: network, + Peers: peers, + Users: users, + CreatedBy: userId, + Domain: domain, + Routes: routes, + NameServerGroups: nameServersGroups, + DNSSettings: dnsSettings, + Settings: &Settings{ + PeerLoginExpirationEnabled: true, + PeerLoginExpiration: DefaultPeerLoginExpiration, + }, } addAllGroup(acc) diff --git a/management/server/account_test.go b/management/server/account_test.go index 58ea86181..3ca4f68fd 100644 --- a/management/server/account_test.go +++ b/management/server/account_test.go @@ -1251,7 +1251,8 @@ func TestAccount_Copy(t *testing.T) { ID: "nsGroup1", }, }, - DNSSettings: &DNSSettings{}, + DNSSettings: &DNSSettings{DisabledManagementGroups: []string{}}, + Settings: &Settings{}, } err := hasNilField(account) if err != nil { diff --git a/management/server/file_store.go b/management/server/file_store.go index 602b2e7d8..73bece90a 100644 --- a/management/server/file_store.go +++ b/management/server/file_store.go @@ -82,8 +82,11 @@ func restore(file string) (*FileStore, error) { for accountID, account := range store.Accounts { - if account.PeerLoginExpiration.Seconds() == 0 { - account.PeerLoginExpiration = DefaultPeerLoginExpiration + if account.Settings == nil { + account.Settings = &Settings{ + PeerLoginExpirationEnabled: false, + PeerLoginExpiration: DefaultPeerLoginExpiration, + } } for setupKeyId := range account.SetupKeys { diff --git a/management/server/grpcserver.go b/management/server/grpcserver.go index 039a396e9..cfd5413c2 100644 --- a/management/server/grpcserver.go +++ b/management/server/grpcserver.go @@ -136,7 +136,7 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi if err != nil { return status.Error(codes.Internal, "internal server error") } - expired, left := peer.LoginExpired(account.PeerLoginExpiration) + expired, left := peer.LoginExpired(account.Settings) if peer.UserID != "" && expired { return status.Errorf(codes.PermissionDenied, "peer login has expired %v ago. Please log in once more", left) } @@ -376,7 +376,7 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p if err != nil { return nil, status.Error(codes.Internal, "internal server error") } - expired, left := peer.LoginExpired(account.PeerLoginExpiration) + expired, left := peer.LoginExpired(account.Settings) if peer.UserID != "" && expired { // it might be that peer expired but user has logged in already, check token then if loginReq.GetJwtToken() == "" { diff --git a/management/server/peer.go b/management/server/peer.go index 79bbbebac..74c30cc10 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -89,11 +89,12 @@ func (p *Peer) Copy() *Peer { // LoginExpired indicates whether peer's login has expired or not. // If Peer.LastLogin plus the expiresIn duration has happened already then login has expired. // Return true if login has expired, false otherwise and time left to expiration (negative when expired). -func (p *Peer) LoginExpired(expiresIn time.Duration) (bool, time.Duration) { - expiresAt := p.LastLogin.Add(expiresIn) +// Expiration can be disabled/enabled on the Account or Peer level. +func (p *Peer) LoginExpired(accountSettings *Settings) (bool, time.Duration) { + expiresAt := p.LastLogin.Add(accountSettings.PeerLoginExpiration) now := time.Now() left := expiresAt.Sub(now) - return p.LoginExpirationEnabled && (left <= 0), left + return accountSettings.PeerLoginExpirationEnabled && p.LoginExpirationEnabled && (left <= 0), left } // FQDN returns peers FQDN combined of the peer's DNS label and the system's DNS domain diff --git a/management/server/peer_test.go b/management/server/peer_test.go index e4998f221..eb503d218 100644 --- a/management/server/peer_test.go +++ b/management/server/peer_test.go @@ -13,42 +13,51 @@ func TestPeer_LoginExpired(t *testing.T) { tt := []struct { name string - expirationEnbaled bool + expirationEnabled bool lastLogin time.Time - expiresIn time.Duration expected bool + accountSettings *Settings }{ { name: "Peer Login Expiration Disabled. Peer Login Should Not Expire", - expirationEnbaled: false, + expirationEnabled: false, lastLogin: time.Now().Add(-25 * time.Hour), - expiresIn: time.Hour, - expected: false, + accountSettings: &Settings{ + PeerLoginExpirationEnabled: true, + PeerLoginExpiration: time.Hour, + }, + expected: false, }, { name: "Peer Login Should Expire", - expirationEnbaled: true, + expirationEnabled: true, lastLogin: time.Now().Add(-25 * time.Hour), - expiresIn: time.Hour, - expected: true, + accountSettings: &Settings{ + PeerLoginExpirationEnabled: true, + PeerLoginExpiration: time.Hour, + }, + expected: true, }, { name: "Peer Login Should Not Expire", - expirationEnbaled: true, + expirationEnabled: true, lastLogin: time.Now(), - expiresIn: time.Hour, - expected: false, + accountSettings: &Settings{ + PeerLoginExpirationEnabled: true, + PeerLoginExpiration: time.Hour, + }, + expected: false, }, } for _, c := range tt { t.Run(c.name, func(t *testing.T) { peer := &Peer{ - LoginExpirationEnabled: c.expirationEnbaled, + LoginExpirationEnabled: c.expirationEnabled, LastLogin: c.lastLogin, } - expired, _ := peer.LoginExpired(c.expiresIn) + expired, _ := peer.LoginExpired(c.accountSettings) assert.Equal(t, expired, c.expected) }) }