Files
kopia/internal/server/api_object_get.go
Jarek Kowalski 689ed0a851 server: refactored authentication and authorization (#871)
This formalizes the concept of a 'UI user' which is a local
user that can call APIs the same way that UI does it.

The server will now allow access to:

- UI user (identified using `--server-username` with password specified
  using `--server-password' or `--random-password`)
- remote users with usersnames/passwords specified in `--htpasswd-file`
- remote users defined in the repository using `kopia users add`
  when `--allow-repository-users` is passed.

The UI user only has access to methods specifically designated as such
(normally APIs used by the UI + few special ones such as 'shutdown').

Remote users (identified via `user@host`) don't get access to UI APIs.

There are some APIs that can be accessed by any authenticated
caller (UI or remote):

- /api/v1/flush
- /api/v1/repo/status
- /api/v1/repo/sync
- /api/v1/repo/parameters

To make this easier to understand in code, refactored server handlers
to require specifing what kind of authorization is required
at registration time.
2021-03-08 22:25:22 -08:00

55 lines
1.1 KiB
Go

package server
import (
"errors"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/kopia/kopia/internal/clock"
"github.com/kopia/kopia/repo/object"
"github.com/kopia/kopia/snapshot/snapshotfs"
)
func (s *Server) handleObjectGet(w http.ResponseWriter, r *http.Request) {
oidstr := mux.Vars(r)["objectID"]
if !requireUIUser(s, r) {
http.Error(w, "access denied", http.StatusForbidden)
return
}
oid, err := object.ParseID(oidstr)
if err != nil {
http.Error(w, "invalid object id", http.StatusBadRequest)
return
}
obj, err := s.rep.OpenObject(r.Context(), oid)
if errors.Is(err, object.ErrObjectNotFound) {
http.Error(w, "object not found", http.StatusNotFound)
return
}
if snapshotfs.IsDirectoryID(oid) {
w.Header().Set("Content-Type", "application/json")
}
fname := oid.String()
if p := r.URL.Query().Get("fname"); p != "" {
fname = p
w.Header().Set("Content-Disposition", "attachment; filename=\""+p+"\"")
}
mtime := clock.Now()
if p := r.URL.Query().Get("mtime"); p != "" {
if m, err := time.Parse(time.RFC3339Nano, p); err == nil {
mtime = m
}
}
http.ServeContent(w, r, fname, mtime, obj)
}