mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 13:05:46 +00:00
4ce4bb6271
This completes the migration to setting up authentication state in the client first before fetching any node data or rendering the client view. Notable changes: - `authorizeRequest` is now only enforced on `/api/*` calls (with the exception of /api/auth, which is handled early because it's needed to initially setup auth, particularly for synology) - re-separate the App and WebClient components to ensure that auth is completed before moving on - refactor platform auth (synology and QNAP) to fit into this new structure. Synology no longer returns redirect for auth, but returns authResponse instructing the client to fetch a SynoToken Updates tailscale/corp#14335 Signed-off-by: Will Norris <will@tailscale.com>
62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// synology.go contains handlers and logic, such as authentication,
|
|
// that is specific to running the web client on Synology.
|
|
|
|
package web
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"tailscale.com/util/groupmember"
|
|
)
|
|
|
|
// authorizeSynology authenticates the logged-in Synology user and verifies
|
|
// that they are authorized to use the web client.
|
|
// The returned authResponse indicates if the user is authorized,
|
|
// and if additional steps are needed to authenticate the user.
|
|
// If the user is authenticated, but not authorized to use the client, an error is returned.
|
|
func authorizeSynology(r *http.Request) (resp authResponse, err error) {
|
|
if !hasSynoToken(r) {
|
|
return authResponse{OK: false, AuthNeeded: synoAuth}, nil
|
|
}
|
|
|
|
// authenticate the Synology user
|
|
cmd := exec.Command("/usr/syno/synoman/webman/modules/authenticate.cgi")
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return resp, fmt.Errorf("auth: %v: %s", err, out)
|
|
}
|
|
user := strings.TrimSpace(string(out))
|
|
|
|
// check if the user is in the administrators group
|
|
isAdmin, err := groupmember.IsMemberOfGroup("administrators", user)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
if !isAdmin {
|
|
return resp, errors.New("not a member of administrators group")
|
|
}
|
|
|
|
return authResponse{OK: true}, nil
|
|
}
|
|
|
|
// hasSynoToken returns true if the request include a SynoToken used for synology auth.
|
|
func hasSynoToken(r *http.Request) bool {
|
|
if r.Header.Get("X-Syno-Token") != "" {
|
|
return true
|
|
}
|
|
if r.URL.Query().Get("SynoToken") != "" {
|
|
return true
|
|
}
|
|
if r.Method == "POST" && r.FormValue("SynoToken") != "" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|