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
}
// 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)

View File

@ -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 {

View File

@ -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 {

View File

@ -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() == "" {

View File

@ -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

View File

@ -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)
})
}