Skip to content

Commit

Permalink
server: allow access to the UI with a blank query (#21)
Browse files Browse the repository at this point in the history
If a caller requests the root UI and does not send a query, skip checking the
source and serve the UI directly. A non-blank query still triggers a check.
  • Loading branch information
creachadair committed Mar 22, 2024
1 parent 4356add commit 254767d
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 9 deletions.
10 changes: 8 additions & 2 deletions server/tailsql/tailsql.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func (s *Server) serveUI(w http.ResponseWriter, r *http.Request) {
return
}

caller, isAuthorized := s.checkAuth(w, r, src)
caller, isAuthorized := s.checkAuth(w, r, src, query)
if !isAuthorized {
authErrorCount.Add(1)
return
Expand Down Expand Up @@ -570,7 +570,7 @@ func (s *Server) dbHandleForSource(src string) *dbHandle {
// given source. If the caller does not have access, checkAuth logs an error
// to w and returns false. The reported caller name will be "" if no caller
// can be identified.
func (s *Server) checkAuth(w http.ResponseWriter, r *http.Request, src string) (string, bool) {
func (s *Server) checkAuth(w http.ResponseWriter, r *http.Request, src, query string) (string, bool) {
// If there is no local client, allow everything.
if s.lc == nil {
return "", true
Expand All @@ -589,6 +589,12 @@ func (s *Server) checkAuth(w http.ResponseWriter, r *http.Request, src string) (
} else {
caller = whois.UserProfile.LoginName
}

// If the caller wants the UI and didn't send a query, allow it.
// The source does not matter when there is no query.
if r.URL.Path == "/" && query == "" {
return caller, true
}
if err := s.authorize(src, whois); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return caller, false
Expand Down
23 changes: 16 additions & 7 deletions server/tailsql/tailsql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,12 @@ func TestAuth(t *testing.T) {
cli := htest.Client()

mustCall := func(t *testing.T, url string, want int) {
rsp, err := cli.Get(url)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
t.Fatalf("New request for %q: %v", url, err)
}
req.Header.Set("Sec-Tailsql", "ok")
rsp, err := cli.Do(req)
if err != nil {
t.Fatalf("Get %q: unexpected error: %v", url, err)
}
Expand All @@ -393,6 +398,7 @@ func TestAuth(t *testing.T) {
t.Errorf("Get %q: got %d, want %d", url, got, want)
}
}
testQuery := url.Values{"q": {"select 'ok'"}}.Encode()

// Check for a user who is not logged in.
t.Run("NotLogged", func(t *testing.T) {
Expand All @@ -405,24 +411,27 @@ func TestAuth(t *testing.T) {
UserProfile: userProfile1,
}

// Check for a response for a tagged node not granted access by
// capabilities.
t.Run("TaggedNode", func(t *testing.T) {
mustCall(t, htest.URL, http.StatusForbidden)
// A tagged node cannot query a source it's not granted.
// However, anyone can get the UI with no query.
t.Run("TaggedNode/Query", func(t *testing.T) {
mustCall(t, htest.URL+"?"+testQuery, http.StatusForbidden)
})
t.Run("TaggedNode/UI", func(t *testing.T) {
mustCall(t, htest.URL, http.StatusOK)
})

fc.result.Node = untaggedNode

// Check for a valid user who is authorized.
t.Run("ValidAuth", func(t *testing.T) {
mustCall(t, htest.URL, http.StatusOK)
mustCall(t, htest.URL+"?"+testQuery, http.StatusOK)
})

fc.result.UserProfile.ID = 678910

// Check for a valid user who is not authorized.
t.Run("ValidUnauth", func(t *testing.T) {
mustCall(t, htest.URL+"?src=other", http.StatusForbidden)
mustCall(t, htest.URL+"?src=other&"+testQuery, http.StatusForbidden)
})
}

Expand Down

0 comments on commit 254767d

Please sign in to comment.