mirror of
https://github.com/juanfont/headscale.git
synced 2025-02-08 18:18:03 +09:00
clean up handler methods, common logging (#2384)
Some checks are pending
Build / build-nix (push) Waiting to run
Build / build-cross (GOARCH=386 GOOS=linux) (push) Waiting to run
Build / build-cross (GOARCH=amd64 GOOS=darwin) (push) Waiting to run
Build / build-cross (GOARCH=amd64 GOOS=linux) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=5) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=6) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=7) (push) Waiting to run
Build / build-cross (GOARCH=arm64 GOOS=darwin) (push) Waiting to run
Build / build-cross (GOARCH=arm64 GOOS=linux) (push) Waiting to run
Tests / test (push) Waiting to run
Some checks are pending
Build / build-nix (push) Waiting to run
Build / build-cross (GOARCH=386 GOOS=linux) (push) Waiting to run
Build / build-cross (GOARCH=amd64 GOOS=darwin) (push) Waiting to run
Build / build-cross (GOARCH=amd64 GOOS=linux) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=5) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=6) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=7) (push) Waiting to run
Build / build-cross (GOARCH=arm64 GOOS=darwin) (push) Waiting to run
Build / build-cross (GOARCH=arm64 GOOS=linux) (push) Waiting to run
Tests / test (push) Waiting to run
* clean up handler methods, common logging Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * streamline http.Error calls Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> --------- Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
parent
f44b1d37c4
commit
cd3b8e68ff
4 changed files with 53 additions and 241 deletions
|
@ -32,6 +32,12 @@ const (
|
||||||
reservedResponseHeaderSize = 4
|
reservedResponseHeaderSize = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// httpError logs an error and sends an HTTP error response with the given
|
||||||
|
func httpError(w http.ResponseWriter, err error, userError string, code int) {
|
||||||
|
log.Error().Err(err).Msg(userError)
|
||||||
|
http.Error(w, userError, code)
|
||||||
|
}
|
||||||
|
|
||||||
var ErrRegisterMethodCLIDoesNotSupportExpire = errors.New(
|
var ErrRegisterMethodCLIDoesNotSupportExpire = errors.New(
|
||||||
"machines registered with CLI does not support expire",
|
"machines registered with CLI does not support expire",
|
||||||
)
|
)
|
||||||
|
@ -52,7 +58,7 @@ func parseCabailityVersion(req *http.Request) (tailcfg.CapabilityVersion, error)
|
||||||
return tailcfg.CapabilityVersion(clientCapabilityVersion), nil
|
return tailcfg.CapabilityVersion(clientCapabilityVersion), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) handleVerifyRequest(
|
func (h *Headscale) derpRequestIsAllowed(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
) (bool, error) {
|
) (bool, error) {
|
||||||
body, err := io.ReadAll(req.Body)
|
body, err := io.ReadAll(req.Body)
|
||||||
|
@ -79,21 +85,14 @@ func (h *Headscale) VerifyHandler(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
) {
|
) {
|
||||||
if req.Method != http.MethodPost {
|
if req.Method != http.MethodPost {
|
||||||
http.Error(writer, "Wrong method", http.StatusMethodNotAllowed)
|
httpError(writer, nil, "Wrong method", http.StatusMethodNotAllowed)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug().
|
|
||||||
Str("handler", "/verify").
|
|
||||||
Msg("verify client")
|
|
||||||
|
|
||||||
allow, err := h.handleVerifyRequest(req)
|
allow, err := h.derpRequestIsAllowed(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
httpError(writer, err, "Internal error", http.StatusInternalServerError)
|
||||||
Caller().
|
return
|
||||||
Err(err).
|
|
||||||
Msg("Failed to verify client")
|
|
||||||
http.Error(writer, "Internal error", http.StatusInternalServerError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := tailcfg.DERPAdmitClientResponse{
|
resp := tailcfg.DERPAdmitClientResponse{
|
||||||
|
@ -101,14 +100,7 @@ func (h *Headscale) VerifyHandler(
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "application/json")
|
writer.Header().Set("Content-Type", "application/json")
|
||||||
writer.WriteHeader(http.StatusOK)
|
json.NewEncoder(writer).Encode(resp)
|
||||||
err = json.NewEncoder(writer).Encode(resp)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyHandler provides the Headscale pub key
|
// KeyHandler provides the Headscale pub key
|
||||||
|
@ -120,35 +112,17 @@ func (h *Headscale) KeyHandler(
|
||||||
// New Tailscale clients send a 'v' parameter to indicate the CurrentCapabilityVersion
|
// New Tailscale clients send a 'v' parameter to indicate the CurrentCapabilityVersion
|
||||||
capVer, err := parseCabailityVersion(req)
|
capVer, err := parseCabailityVersion(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
httpError(writer, err, "Internal error", http.StatusInternalServerError)
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("could not get capability version")
|
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
||||||
writer.WriteHeader(http.StatusInternalServerError)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().
|
|
||||||
Str("handler", "/key").
|
|
||||||
Int("cap_ver", int(capVer)).
|
|
||||||
Msg("New noise client")
|
|
||||||
|
|
||||||
// TS2021 (Tailscale v2 protocol) requires to have a different key
|
// TS2021 (Tailscale v2 protocol) requires to have a different key
|
||||||
if capVer >= NoiseCapabilityVersion {
|
if capVer >= NoiseCapabilityVersion {
|
||||||
resp := tailcfg.OverTLSPublicKeyResponse{
|
resp := tailcfg.OverTLSPublicKeyResponse{
|
||||||
PublicKey: h.noisePrivateKey.Public(),
|
PublicKey: h.noisePrivateKey.Public(),
|
||||||
}
|
}
|
||||||
writer.Header().Set("Content-Type", "application/json")
|
writer.Header().Set("Content-Type", "application/json")
|
||||||
writer.WriteHeader(http.StatusOK)
|
json.NewEncoder(writer).Encode(resp)
|
||||||
err = json.NewEncoder(writer).Encode(resp)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -169,18 +143,10 @@ func (h *Headscale) HealthHandler(
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writer.WriteHeader(http.StatusInternalServerError)
|
writer.WriteHeader(http.StatusInternalServerError)
|
||||||
log.Error().Caller().Err(err).Msg("health check failed")
|
|
||||||
res.Status = "fail"
|
res.Status = "fail"
|
||||||
}
|
}
|
||||||
|
|
||||||
buf, err := json.Marshal(res)
|
json.NewEncoder(writer).Encode(res)
|
||||||
if err != nil {
|
|
||||||
log.Error().Caller().Err(err).Msg("marshal failed")
|
|
||||||
}
|
|
||||||
_, err = writer.Write(buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Caller().Err(err).Msg("write failed")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.db.PingDB(req.Context()); err != nil {
|
if err := h.db.PingDB(req.Context()); err != nil {
|
||||||
|
@ -233,16 +199,11 @@ func (a *AuthProviderWeb) RegisterHandler(
|
||||||
// the template and log an error.
|
// the template and log an error.
|
||||||
registrationId, err := types.RegistrationIDFromString(registrationIdStr)
|
registrationId, err := types.RegistrationIDFromString(registrationIdStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, "invalid registration ID", http.StatusBadRequest)
|
httpError(writer, err, "invalid registration ID", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
if _, err := writer.Write([]byte(templates.RegisterWeb(registrationId).Render())); err != nil {
|
writer.Write([]byte(templates.RegisterWeb(registrationId).Render()))
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,9 +80,7 @@ func (h *Headscale) NoiseUpgradeHandler(
|
||||||
noiseServer.earlyNoise,
|
noiseServer.earlyNoise,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("noise upgrade failed")
|
httpError(writer, err, "noise upgrade failed", http.StatusInternalServerError)
|
||||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,12 +158,7 @@ func isSupportedVersion(version tailcfg.CapabilityVersion) bool {
|
||||||
func rejectUnsupported(writer http.ResponseWriter, version tailcfg.CapabilityVersion) bool {
|
func rejectUnsupported(writer http.ResponseWriter, version tailcfg.CapabilityVersion) bool {
|
||||||
// Reject unsupported versions
|
// Reject unsupported versions
|
||||||
if !isSupportedVersion(version) {
|
if !isSupportedVersion(version) {
|
||||||
log.Info().
|
httpError(writer, nil, "unsupported client version", http.StatusBadRequest)
|
||||||
Caller().
|
|
||||||
Int("min_version", int(MinimumCapVersion)).
|
|
||||||
Int("client_version", int(version)).
|
|
||||||
Msg("unsupported client connected")
|
|
||||||
http.Error(writer, "unsupported client version", http.StatusBadRequest)
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -190,23 +183,10 @@ func (ns *noiseServer) NoisePollNetMapHandler(
|
||||||
|
|
||||||
var mapRequest tailcfg.MapRequest
|
var mapRequest tailcfg.MapRequest
|
||||||
if err := json.Unmarshal(body, &mapRequest); err != nil {
|
if err := json.Unmarshal(body, &mapRequest); err != nil {
|
||||||
log.Error().
|
httpError(writer, err, "Internal error", http.StatusInternalServerError)
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Cannot parse MapRequest")
|
|
||||||
http.Error(writer, "Internal error", http.StatusInternalServerError)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().
|
|
||||||
Caller().
|
|
||||||
Str("handler", "NoisePollNetMap").
|
|
||||||
Any("headers", req.Header).
|
|
||||||
Str("node", mapRequest.Hostinfo.Hostname).
|
|
||||||
Int("capver", int(mapRequest.Version)).
|
|
||||||
Msg("PollNetMapHandler called")
|
|
||||||
|
|
||||||
// Reject unsupported versions
|
// Reject unsupported versions
|
||||||
if rejectUnsupported(writer, mapRequest.Version) {
|
if rejectUnsupported(writer, mapRequest.Version) {
|
||||||
return
|
return
|
||||||
|
@ -220,11 +200,7 @@ func (ns *noiseServer) NoisePollNetMapHandler(
|
||||||
key.NodePublic{},
|
key.NodePublic{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
httpError(writer, err, "Internal error", http.StatusInternalServerError)
|
||||||
Str("handler", "NoisePollNetMap").
|
|
||||||
Msgf("Failed to fetch node from the database with node key: %s", mapRequest.NodeKey.String())
|
|
||||||
http.Error(writer, "Internal error", http.StatusInternalServerError)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,26 +218,16 @@ func (ns *noiseServer) NoiseRegistrationHandler(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
) {
|
) {
|
||||||
log.Trace().Caller().Msgf("Noise registration handler for client %s", req.RemoteAddr)
|
|
||||||
if req.Method != http.MethodPost {
|
if req.Method != http.MethodPost {
|
||||||
http.Error(writer, "Wrong method", http.StatusMethodNotAllowed)
|
httpError(writer, nil, "Wrong method", http.StatusMethodNotAllowed)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().
|
|
||||||
Any("headers", req.Header).
|
|
||||||
Caller().
|
|
||||||
Msg("Headers")
|
|
||||||
|
|
||||||
body, _ := io.ReadAll(req.Body)
|
body, _ := io.ReadAll(req.Body)
|
||||||
var registerRequest tailcfg.RegisterRequest
|
var registerRequest tailcfg.RegisterRequest
|
||||||
if err := json.Unmarshal(body, ®isterRequest); err != nil {
|
if err := json.Unmarshal(body, ®isterRequest); err != nil {
|
||||||
log.Error().
|
httpError(writer, err, "Internal error", http.StatusInternalServerError)
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Cannot parse RegisterRequest")
|
|
||||||
http.Error(writer, "Internal error", http.StatusInternalServerError)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,34 +134,28 @@ func (a *AuthProviderOIDC) RegisterHandler(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
) {
|
) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
registrationIdStr, ok := vars["registration_id"]
|
registrationIdStr, _ := vars["registration_id"]
|
||||||
|
|
||||||
// We need to make sure we dont open for XSS style injections, if the parameter that
|
// We need to make sure we dont open for XSS style injections, if the parameter that
|
||||||
// is passed as a key is not parsable/validated as a NodePublic key, then fail to render
|
// is passed as a key is not parsable/validated as a NodePublic key, then fail to render
|
||||||
// the template and log an error.
|
// the template and log an error.
|
||||||
registrationId, err := types.RegistrationIDFromString(registrationIdStr)
|
registrationId, err := types.RegistrationIDFromString(registrationIdStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, "invalid registration ID", http.StatusBadRequest)
|
httpError(writer, err, "invalid registration ID", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().
|
|
||||||
Caller().
|
|
||||||
Str("registration_id", registrationId.String()).
|
|
||||||
Bool("ok", ok).
|
|
||||||
Msg("Received oidc register call")
|
|
||||||
|
|
||||||
// Set the state and nonce cookies to protect against CSRF attacks
|
// Set the state and nonce cookies to protect against CSRF attacks
|
||||||
state, err := setCSRFCookie(writer, req, "state")
|
state, err := setCSRFCookie(writer, req, "state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
httpError(writer, err, "Internal server error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the state and nonce cookies to protect against CSRF attacks
|
// Set the state and nonce cookies to protect against CSRF attacks
|
||||||
nonce, err := setCSRFCookie(writer, req, "nonce")
|
nonce, err := setCSRFCookie(writer, req, "nonce")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, "Internal server error", http.StatusInternalServerError)
|
httpError(writer, err, "Internal server error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,35 +219,34 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
||||||
) {
|
) {
|
||||||
code, state, err := extractCodeAndStateParamFromRequest(req)
|
code, state, err := extractCodeAndStateParamFromRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, err.Error(), http.StatusBadRequest)
|
httpError(writer, err, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Interface("cookies", req.Cookies()).Msg("Received oidc callback")
|
|
||||||
cookieState, err := req.Cookie("state")
|
cookieState, err := req.Cookie("state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, "state not found", http.StatusBadRequest)
|
httpError(writer, err, "state not found", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if state != cookieState.Value {
|
if state != cookieState.Value {
|
||||||
http.Error(writer, "state did not match", http.StatusBadRequest)
|
httpError(writer, err, "state did not match", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
idToken, err := a.extractIDToken(req.Context(), code, state)
|
idToken, err := a.extractIDToken(req.Context(), code, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, err.Error(), http.StatusBadRequest)
|
httpError(writer, err, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, err := req.Cookie("nonce")
|
nonce, err := req.Cookie("nonce")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, "nonce not found", http.StatusBadRequest)
|
httpError(writer, err, "nonce not found", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if idToken.Nonce != nonce.Value {
|
if idToken.Nonce != nonce.Value {
|
||||||
http.Error(writer, "nonce did not match", http.StatusBadRequest)
|
httpError(writer, err, "nonce did not match", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,28 +254,29 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
||||||
|
|
||||||
var claims types.OIDCClaims
|
var claims types.OIDCClaims
|
||||||
if err := idToken.Claims(&claims); err != nil {
|
if err := idToken.Claims(&claims); err != nil {
|
||||||
http.Error(writer, fmt.Errorf("failed to decode ID token claims: %w", err).Error(), http.StatusInternalServerError)
|
err = fmt.Errorf("decoding ID token claims: %w", err)
|
||||||
|
httpError(writer, err, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateOIDCAllowedDomains(a.cfg.AllowedDomains, &claims); err != nil {
|
if err := validateOIDCAllowedDomains(a.cfg.AllowedDomains, &claims); err != nil {
|
||||||
http.Error(writer, err.Error(), http.StatusUnauthorized)
|
httpError(writer, err, err.Error(), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateOIDCAllowedGroups(a.cfg.AllowedGroups, &claims); err != nil {
|
if err := validateOIDCAllowedGroups(a.cfg.AllowedGroups, &claims); err != nil {
|
||||||
http.Error(writer, err.Error(), http.StatusUnauthorized)
|
httpError(writer, err, err.Error(), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateOIDCAllowedUsers(a.cfg.AllowedUsers, &claims); err != nil {
|
if err := validateOIDCAllowedUsers(a.cfg.AllowedUsers, &claims); err != nil {
|
||||||
http.Error(writer, err.Error(), http.StatusUnauthorized)
|
httpError(writer, err, err.Error(), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := a.createOrUpdateUserFromClaim(&claims)
|
user, err := a.createOrUpdateUserFromClaim(&claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
httpError(writer, err, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +291,7 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
||||||
verb := "Reauthenticated"
|
verb := "Reauthenticated"
|
||||||
newNode, err := a.handleRegistrationID(user, *registrationId, nodeExpiry)
|
newNode, err := a.handleRegistrationID(user, *registrationId, nodeExpiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
httpError(writer, err, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +302,7 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
||||||
// TODO(kradalby): replace with go-elem
|
// TODO(kradalby): replace with go-elem
|
||||||
content, err := renderOIDCCallbackTemplate(user, verb)
|
content, err := renderOIDCCallbackTemplate(user, verb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
httpError(writer, err, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +317,7 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
||||||
|
|
||||||
// Neither node nor machine key was found in the state cache meaning
|
// Neither node nor machine key was found in the state cache meaning
|
||||||
// that we could not reauth nor register the node.
|
// that we could not reauth nor register the node.
|
||||||
http.Error(writer, "login session expired, try again", http.StatusInternalServerError)
|
httpError(writer, nil, "login session expired, try again", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +417,6 @@ func validateOIDCAllowedUsers(
|
||||||
) error {
|
) error {
|
||||||
if len(allowedUsers) > 0 &&
|
if len(allowedUsers) > 0 &&
|
||||||
!slices.Contains(allowedUsers, claims.Email) {
|
!slices.Contains(allowedUsers, claims.Email) {
|
||||||
log.Trace().Msg("authenticated principal does not match any allowed user")
|
|
||||||
return errOIDCAllowedUsers
|
return errOIDCAllowedUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid/v5"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/juanfont/headscale/hscontrol/templates"
|
"github.com/juanfont/headscale/hscontrol/templates"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WindowsConfigMessage shows a simple message in the browser for how to configure the Windows Tailscale client.
|
// WindowsConfigMessage shows a simple message in the browser for how to configure the Windows Tailscale client.
|
||||||
|
@ -20,13 +19,7 @@ func (h *Headscale) WindowsConfigMessage(
|
||||||
) {
|
) {
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
writer.Write([]byte(templates.Windows(h.cfg.ServerURL).Render()))
|
||||||
if _, err := writer.Write([]byte(templates.Windows(h.cfg.ServerURL).Render())); err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppleConfigMessage shows a simple message in the browser to point the user to the iOS/MacOS profile and instructions for how to install it.
|
// AppleConfigMessage shows a simple message in the browser to point the user to the iOS/MacOS profile and instructions for how to install it.
|
||||||
|
@ -36,13 +29,7 @@ func (h *Headscale) AppleConfigMessage(
|
||||||
) {
|
) {
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
writer.Write([]byte(templates.Apple(h.cfg.ServerURL).Render()))
|
||||||
if _, err := writer.Write([]byte(templates.Apple(h.cfg.ServerURL).Render())); err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) ApplePlatformConfig(
|
func (h *Headscale) ApplePlatformConfig(
|
||||||
|
@ -52,51 +39,19 @@ func (h *Headscale) ApplePlatformConfig(
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
platform, ok := vars["platform"]
|
platform, ok := vars["platform"]
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Error().
|
httpError(writer, nil, "No platform specified", http.StatusBadRequest)
|
||||||
Str("handler", "ApplePlatformConfig").
|
|
||||||
Msg("No platform specified")
|
|
||||||
http.Error(writer, "No platform specified", http.StatusBadRequest)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := uuid.NewV4()
|
id, err := uuid.NewV4()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
httpError(writer, nil, "Failed to create UUID", http.StatusInternalServerError)
|
||||||
Str("handler", "ApplePlatformConfig").
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed not create UUID")
|
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
||||||
writer.WriteHeader(http.StatusInternalServerError)
|
|
||||||
_, err := writer.Write([]byte("Failed to create UUID"))
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
contentID, err := uuid.NewV4()
|
contentID, err := uuid.NewV4()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
httpError(writer, nil, "Failed to create UUID", http.StatusInternalServerError)
|
||||||
Str("handler", "ApplePlatformConfig").
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed not create UUID")
|
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
||||||
writer.WriteHeader(http.StatusInternalServerError)
|
|
||||||
_, err := writer.Write([]byte("Failed to create content UUID"))
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,68 +61,25 @@ func (h *Headscale) ApplePlatformConfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload bytes.Buffer
|
var payload bytes.Buffer
|
||||||
handleMacError := func(ierr error) {
|
|
||||||
log.Error().
|
|
||||||
Str("handler", "ApplePlatformConfig").
|
|
||||||
Err(ierr).
|
|
||||||
Msg("Could not render Apple macOS template")
|
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
||||||
writer.WriteHeader(http.StatusInternalServerError)
|
|
||||||
_, err := writer.Write([]byte("Could not render Apple macOS template"))
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch platform {
|
switch platform {
|
||||||
case "macos-standalone":
|
case "macos-standalone":
|
||||||
if err := macosStandaloneTemplate.Execute(&payload, platformConfig); err != nil {
|
if err := macosStandaloneTemplate.Execute(&payload, platformConfig); err != nil {
|
||||||
handleMacError(err)
|
httpError(writer, err, "Could not render Apple macOS template", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "macos-app-store":
|
case "macos-app-store":
|
||||||
if err := macosAppStoreTemplate.Execute(&payload, platformConfig); err != nil {
|
if err := macosAppStoreTemplate.Execute(&payload, platformConfig); err != nil {
|
||||||
handleMacError(err)
|
httpError(writer, err, "Could not render Apple macOS template", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "ios":
|
case "ios":
|
||||||
if err := iosTemplate.Execute(&payload, platformConfig); err != nil {
|
if err := iosTemplate.Execute(&payload, platformConfig); err != nil {
|
||||||
log.Error().
|
httpError(writer, err, "Could not render Apple iOS template", http.StatusInternalServerError)
|
||||||
Str("handler", "ApplePlatformConfig").
|
|
||||||
Err(err).
|
|
||||||
Msg("Could not render Apple iOS template")
|
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
||||||
writer.WriteHeader(http.StatusInternalServerError)
|
|
||||||
_, err := writer.Write([]byte("Could not render Apple iOS template"))
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
httpError(writer, err, "Invalid platform. Only ios, macos-app-store and macos-standalone are supported", http.StatusInternalServerError)
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, err := writer.Write(
|
|
||||||
[]byte("Invalid platform. Only ios, macos-app-store and macos-standalone are supported"),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,34 +91,14 @@ func (h *Headscale) ApplePlatformConfig(
|
||||||
|
|
||||||
var content bytes.Buffer
|
var content bytes.Buffer
|
||||||
if err := commonTemplate.Execute(&content, config); err != nil {
|
if err := commonTemplate.Execute(&content, config); err != nil {
|
||||||
log.Error().
|
httpError(writer, err, "Could not render platform iOS template", http.StatusInternalServerError)
|
||||||
Str("handler", "ApplePlatformConfig").
|
|
||||||
Err(err).
|
|
||||||
Msg("Could not render Apple platform template")
|
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
||||||
writer.WriteHeader(http.StatusInternalServerError)
|
|
||||||
_, err := writer.Write([]byte("Could not render Apple platform template"))
|
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Header().
|
writer.Header().
|
||||||
Set("Content-Type", "application/x-apple-aspen-config; charset=utf-8")
|
Set("Content-Type", "application/x-apple-aspen-config; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
_, err = writer.Write(content.Bytes())
|
writer.Write(content.Bytes())
|
||||||
if err != nil {
|
|
||||||
log.Error().
|
|
||||||
Caller().
|
|
||||||
Err(err).
|
|
||||||
Msg("Failed to write response")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppleMobileConfig struct {
|
type AppleMobileConfig struct {
|
||||||
|
|
Loading…
Reference in a new issue