client/web: add logging of device management type for web client (#10492)

Add logging of device management type for the web client auth flow. Namely,
this differentiates between viewing a node you do not own, viewing a local
tagged node, viewing a remote tagged node, managing a local node, and
managing a remote node.

Updates https://github.com/tailscale/tailscale/issues/10261

Signed-off-by: Mario Minardi <mario@tailscale.com>
This commit is contained in:
Mario Minardi
2023-12-08 13:15:57 -07:00
committed by GitHub
parent 7bdea283bd
commit 21958d2934
3 changed files with 223 additions and 30 deletions

View File

@@ -14,6 +14,7 @@ import (
"time"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/ipn/ipnstate"
"tailscale.com/tailcfg"
)
@@ -102,48 +103,48 @@ var (
//
// The WhoIsResponse is always populated, with a non-nil Node and UserProfile,
// unless getTailscaleBrowserSession reports errNotUsingTailscale.
func (s *Server) getSession(r *http.Request) (*browserSession, *apitype.WhoIsResponse, error) {
func (s *Server) getSession(r *http.Request) (*browserSession, *apitype.WhoIsResponse, *ipnstate.Status, error) {
whoIs, whoIsErr := s.lc.WhoIs(r.Context(), r.RemoteAddr)
status, statusErr := s.lc.StatusWithoutPeers(r.Context())
switch {
case whoIsErr != nil:
return nil, nil, errNotUsingTailscale
return nil, nil, status, errNotUsingTailscale
case statusErr != nil:
return nil, whoIs, statusErr
return nil, whoIs, nil, statusErr
case status.Self == nil:
return nil, whoIs, errors.New("missing self node in tailscale status")
return nil, whoIs, status, errors.New("missing self node in tailscale status")
case whoIs.Node.IsTagged() && whoIs.Node.StableID == status.Self.ID:
return nil, whoIs, errTaggedLocalSource
return nil, whoIs, status, errTaggedLocalSource
case whoIs.Node.IsTagged():
return nil, whoIs, errTaggedRemoteSource
return nil, whoIs, status, errTaggedRemoteSource
case !status.Self.IsTagged() && status.Self.UserID != whoIs.UserProfile.ID:
return nil, whoIs, errNotOwner
return nil, whoIs, status, errNotOwner
}
srcNode := whoIs.Node.ID
srcUser := whoIs.UserProfile.ID
cookie, err := r.Cookie(sessionCookieName)
if errors.Is(err, http.ErrNoCookie) {
return nil, whoIs, errNoSession
return nil, whoIs, status, errNoSession
} else if err != nil {
return nil, whoIs, err
return nil, whoIs, status, err
}
v, ok := s.browserSessions.Load(cookie.Value)
if !ok {
return nil, whoIs, errNoSession
return nil, whoIs, status, errNoSession
}
session := v.(*browserSession)
if session.SrcNode != srcNode || session.SrcUser != srcUser {
// In this case the browser cookie is associated with another tailscale node.
// Maybe the source browser's machine was logged out and then back in as a different node.
// Return errNoSession because there is no session for this user.
return nil, whoIs, errNoSession
return nil, whoIs, status, errNoSession
} else if session.isExpired(s.timeNow()) {
// Session expired, remove from session map and return errNoSession.
s.browserSessions.Delete(session.ID)
return nil, whoIs, errNoSession
return nil, whoIs, status, errNoSession
}
return session, whoIs, nil
return session, whoIs, status, nil
}
// newSession creates a new session associated with the given source user/node,