Add account settings (#686)

Add account settings with a global peer expiration flag and duration
This commit is contained in:
Misha Bragin 2023-02-13 09:07:15 -05:00 committed by GitHub
parent 3fc89749c1
commit d5dfed498b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 37 deletions

View File

@ -120,6 +120,23 @@ type DefaultAccountManager struct {
dnsDomain string 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 // Account represents a unique account of the system
type Account struct { type Account struct {
Id string Id string
@ -137,9 +154,8 @@ type Account struct {
Routes map[string]*route.Route Routes map[string]*route.Route
NameServerGroups map[string]*nbdns.NameServerGroup NameServerGroups map[string]*nbdns.NameServerGroup
DNSSettings *DNSSettings DNSSettings *DNSSettings
// PeerLoginExpiration is a setting that indicates when peer login expires. // Settings is a dictionary of Account settings
// Applies to all peers that have Peer.LoginExpirationEnabled set to true. Settings *Settings
PeerLoginExpiration time.Duration
} }
type UserInfo struct { type UserInfo struct {
@ -472,7 +488,12 @@ func (a *Account) Copy() *Account {
var dnsSettings *DNSSettings var dnsSettings *DNSSettings
if a.DNSSettings != nil { if a.DNSSettings != nil {
dnsSettings = a.DNSSettings dnsSettings = a.DNSSettings.Copy()
}
var settings *Settings
if a.Settings != nil {
settings = a.Settings.Copy()
} }
return &Account{ return &Account{
@ -490,7 +511,7 @@ func (a *Account) Copy() *Account {
Routes: routes, Routes: routes,
NameServerGroups: nsGroups, NameServerGroups: nsGroups,
DNSSettings: dnsSettings, 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) log.Debugf("created new account %s with setup key %s", accountId, defaultKey.Key)
acc := &Account{ acc := &Account{
Id: accountId, Id: accountId,
SetupKeys: setupKeys, SetupKeys: setupKeys,
Network: network, Network: network,
Peers: peers, Peers: peers,
Users: users, Users: users,
CreatedBy: userId, CreatedBy: userId,
Domain: domain, Domain: domain,
Routes: routes, Routes: routes,
NameServerGroups: nameServersGroups, NameServerGroups: nameServersGroups,
DNSSettings: dnsSettings, DNSSettings: dnsSettings,
PeerLoginExpiration: DefaultPeerLoginExpiration, Settings: &Settings{
PeerLoginExpirationEnabled: true,
PeerLoginExpiration: DefaultPeerLoginExpiration,
},
} }
addAllGroup(acc) addAllGroup(acc)

View File

@ -1251,7 +1251,8 @@ func TestAccount_Copy(t *testing.T) {
ID: "nsGroup1", ID: "nsGroup1",
}, },
}, },
DNSSettings: &DNSSettings{}, DNSSettings: &DNSSettings{DisabledManagementGroups: []string{}},
Settings: &Settings{},
} }
err := hasNilField(account) err := hasNilField(account)
if err != nil { if err != nil {

View File

@ -82,8 +82,11 @@ func restore(file string) (*FileStore, error) {
for accountID, account := range store.Accounts { for accountID, account := range store.Accounts {
if account.PeerLoginExpiration.Seconds() == 0 { if account.Settings == nil {
account.PeerLoginExpiration = DefaultPeerLoginExpiration account.Settings = &Settings{
PeerLoginExpirationEnabled: false,
PeerLoginExpiration: DefaultPeerLoginExpiration,
}
} }
for setupKeyId := range account.SetupKeys { for setupKeyId := range account.SetupKeys {

View File

@ -136,7 +136,7 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi
if err != nil { if err != nil {
return status.Error(codes.Internal, "internal server error") return status.Error(codes.Internal, "internal server error")
} }
expired, left := peer.LoginExpired(account.PeerLoginExpiration) expired, left := peer.LoginExpired(account.Settings)
if peer.UserID != "" && expired { if peer.UserID != "" && expired {
return status.Errorf(codes.PermissionDenied, "peer login has expired %v ago. Please log in once more", left) 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 { if err != nil {
return nil, status.Error(codes.Internal, "internal server error") 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 { if peer.UserID != "" && expired {
// it might be that peer expired but user has logged in already, check token then // it might be that peer expired but user has logged in already, check token then
if loginReq.GetJwtToken() == "" { if loginReq.GetJwtToken() == "" {

View File

@ -89,11 +89,12 @@ func (p *Peer) Copy() *Peer {
// LoginExpired indicates whether peer's login has expired or not. // LoginExpired indicates whether peer's login has expired or not.
// If Peer.LastLogin plus the expiresIn duration has happened already then login has expired. // 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). // 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) { // Expiration can be disabled/enabled on the Account or Peer level.
expiresAt := p.LastLogin.Add(expiresIn) func (p *Peer) LoginExpired(accountSettings *Settings) (bool, time.Duration) {
expiresAt := p.LastLogin.Add(accountSettings.PeerLoginExpiration)
now := time.Now() now := time.Now()
left := expiresAt.Sub(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 // FQDN returns peers FQDN combined of the peer's DNS label and the system's DNS domain

View File

@ -13,42 +13,51 @@ func TestPeer_LoginExpired(t *testing.T) {
tt := []struct { tt := []struct {
name string name string
expirationEnbaled bool expirationEnabled bool
lastLogin time.Time lastLogin time.Time
expiresIn time.Duration
expected bool expected bool
accountSettings *Settings
}{ }{
{ {
name: "Peer Login Expiration Disabled. Peer Login Should Not Expire", name: "Peer Login Expiration Disabled. Peer Login Should Not Expire",
expirationEnbaled: false, expirationEnabled: false,
lastLogin: time.Now().Add(-25 * time.Hour), lastLogin: time.Now().Add(-25 * time.Hour),
expiresIn: time.Hour, accountSettings: &Settings{
expected: false, PeerLoginExpirationEnabled: true,
PeerLoginExpiration: time.Hour,
},
expected: false,
}, },
{ {
name: "Peer Login Should Expire", name: "Peer Login Should Expire",
expirationEnbaled: true, expirationEnabled: true,
lastLogin: time.Now().Add(-25 * time.Hour), lastLogin: time.Now().Add(-25 * time.Hour),
expiresIn: time.Hour, accountSettings: &Settings{
expected: true, PeerLoginExpirationEnabled: true,
PeerLoginExpiration: time.Hour,
},
expected: true,
}, },
{ {
name: "Peer Login Should Not Expire", name: "Peer Login Should Not Expire",
expirationEnbaled: true, expirationEnabled: true,
lastLogin: time.Now(), lastLogin: time.Now(),
expiresIn: time.Hour, accountSettings: &Settings{
expected: false, PeerLoginExpirationEnabled: true,
PeerLoginExpiration: time.Hour,
},
expected: false,
}, },
} }
for _, c := range tt { for _, c := range tt {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
peer := &Peer{ peer := &Peer{
LoginExpirationEnabled: c.expirationEnbaled, LoginExpirationEnabled: c.expirationEnabled,
LastLogin: c.lastLogin, LastLogin: c.lastLogin,
} }
expired, _ := peer.LoginExpired(c.expiresIn) expired, _ := peer.LoginExpired(c.accountSettings)
assert.Equal(t, expired, c.expected) assert.Equal(t, expired, c.expected)
}) })
} }