Update peer status when login expires (#688)

Extend PeerStatus with an extra field LoginExpired, that can be stored in the database.
This commit is contained in:
Misha Bragin 2023-02-15 11:27:22 +01:00 committed by GitHub
parent 756ce96da9
commit d31219ba89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 7 deletions

View File

@ -56,6 +56,7 @@ type AccountManager interface {
GetPeerByKey(peerKey string) (*Peer, error)
GetPeers(accountID, userID string) ([]*Peer, error)
MarkPeerConnected(peerKey string, connected bool) error
MarkPeerLoginExpired(peerPubKey string, loginExpired bool) error
DeletePeer(accountID, peerID, userID string) (*Peer, error)
GetPeerByIP(accountId string, peerIP string) (*Peer, error)
UpdatePeer(accountID, userID string, peer *Peer) (*Peer, error)

View File

@ -137,7 +137,11 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi
return status.Error(codes.Internal, "internal server error")
}
expired, left := peer.LoginExpired(account.Settings)
if peer.UserID != "" && expired {
if peer.UserID != "" && (expired || peer.Status.LoginExpired) {
err = s.accountManager.MarkPeerLoginExpired(peerKey.String(), true)
if err != nil {
log.Warnf("failed marking peer login expired %s %v", peerKey, err)
}
return status.Errorf(codes.PermissionDenied, "peer login has expired %v ago. Please log in once more", left)
}
@ -377,9 +381,13 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p
return nil, status.Error(codes.Internal, "internal server error")
}
expired, left := peer.LoginExpired(account.Settings)
if peer.UserID != "" && expired {
if peer.UserID != "" && (expired || peer.Status.LoginExpired) {
// it might be that peer expired but user has logged in already, check token then
if loginReq.GetJwtToken() == "" {
err = s.accountManager.MarkPeerLoginExpired(peerKey.String(), true)
if err != nil {
log.Warnf("failed marking peer login expired %s %v", peerKey, err)
}
return nil, status.Errorf(codes.PermissionDenied,
"peer login has expired %v ago. Please log in once more", left)
}

View File

@ -152,8 +152,6 @@ func toPeerResponse(peer *server.Peer, account *server.Account, dnsDomain string
fqdn = peer.DNSLabel
}
expired, _ := peer.LoginExpired(account.Settings)
return &api.Peer{
Id: peer.ID,
Name: peer.Name,
@ -170,6 +168,6 @@ func toPeerResponse(peer *server.Peer, account *server.Account, dnsDomain string
DnsLabel: fqdn,
LoginExpirationEnabled: peer.LoginExpirationEnabled,
LastLogin: peer.LastLogin,
LoginExpired: expired,
LoginExpired: peer.Status.LoginExpired,
}
}

View File

@ -23,6 +23,7 @@ type MockAccountManager struct {
GetPeerByKeyFunc func(peerKey string) (*server.Peer, error)
GetPeersFunc func(accountID, userID string) ([]*server.Peer, error)
MarkPeerConnectedFunc func(peerKey string, connected bool) error
MarkPeerLoginExpiredFunc func(peerPubKey string, loginExpired bool) error
DeletePeerFunc func(accountID, peerKey, userID string) (*server.Peer, error)
GetPeerByIPFunc func(accountId string, peerIP string) (*server.Peer, error)
GetNetworkMapFunc func(peerKey string) (*server.NetworkMap, error)
@ -161,6 +162,14 @@ func (am *MockAccountManager) MarkPeerConnected(peerKey string, connected bool)
return status.Errorf(codes.Unimplemented, "method MarkPeerConnected is not implemented")
}
// MarkPeerLoginExpired mock implementation of MarkPeerLoginExpired from server.AccountManager interface
func (am *MockAccountManager) MarkPeerLoginExpired(peerPubKey string, loginExpired bool) error {
if am.MarkPeerLoginExpiredFunc != nil {
return am.MarkPeerLoginExpiredFunc(peerPubKey, loginExpired)
}
return status.Errorf(codes.Unimplemented, "method MarkPeerLoginExpired is not implemented")
}
// GetPeerByIP mock implementation of GetPeerByIP from server.AccountManager interface
func (am *MockAccountManager) GetPeerByIP(accountId string, peerIP string) (*server.Peer, error) {
if am.GetPeerByIPFunc != nil {

View File

@ -32,6 +32,8 @@ type PeerStatus struct {
LastSeen time.Time
// Connected indicates whether peer is connected to the management service or not
Connected bool
// LoginExpired
LoginExpired bool
}
// Peer represents a machine connected to the network.
@ -115,8 +117,9 @@ func (p *Peer) EventMeta(dnsDomain string) map[string]any {
// Copy PeerStatus
func (p *PeerStatus) Copy() *PeerStatus {
return &PeerStatus{
LastSeen: p.LastSeen,
Connected: p.Connected,
LastSeen: p.LastSeen,
Connected: p.Connected,
LoginExpired: p.LoginExpired,
}
}
@ -173,6 +176,40 @@ func (am *DefaultAccountManager) GetPeers(accountID, userID string) ([]*Peer, er
return peers, nil
}
// MarkPeerLoginExpired when peer login has expired
func (am *DefaultAccountManager) MarkPeerLoginExpired(peerPubKey string, loginExpired bool) error {
account, err := am.Store.GetAccountByPeerPubKey(peerPubKey)
if err != nil {
return err
}
unlock := am.Store.AcquireAccountLock(account.Id)
defer unlock()
// ensure that we consider modification happened meanwhile (because we were outside the account lock when we fetched the account)
account, err = am.Store.GetAccount(account.Id)
if err != nil {
return err
}
peer, err := account.FindPeerByPubKey(peerPubKey)
if err != nil {
return err
}
newStatus := peer.Status.Copy()
newStatus.LastSeen = time.Now()
newStatus.LoginExpired = loginExpired
peer.Status = newStatus
account.UpdatePeer(peer)
err = am.Store.SavePeerStatus(account.Id, peer.ID, *newStatus)
if err != nil {
return err
}
return nil
}
// MarkPeerConnected marks peer as connected (true) or disconnected (false)
func (am *DefaultAccountManager) MarkPeerConnected(peerPubKey string, connected bool) error {
@ -198,6 +235,10 @@ func (am *DefaultAccountManager) MarkPeerConnected(peerPubKey string, connected
newStatus := peer.Status.Copy()
newStatus.LastSeen = time.Now()
newStatus.Connected = connected
// whenever peer got connected that means that it logged in successfully
if newStatus.Connected {
newStatus.LoginExpired = false
}
peer.Status = newStatus
account.UpdatePeer(peer)
@ -545,6 +586,10 @@ func (am *DefaultAccountManager) UpdatePeerLastLogin(peerID string) error {
}
peer.LastLogin = time.Now()
newStatus := peer.Status.Copy()
newStatus.LoginExpired = false
peer.Status = newStatus
account.UpdatePeer(peer)
err = am.Store.SaveAccount(account)