accept cookies for authentication

This commit is contained in:
Hayden 2023-02-17 19:01:35 -09:00
parent 889686ecfa
commit 213245f82e
No known key found for this signature in database
GPG key ID: 17CF79474E257545

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"net/http" "net/http"
"net/url"
"strings" "strings"
"github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/core/services"
@ -68,6 +69,45 @@ func (a *app) mwRoles(rm RoleMode, required ...string) server.Middleware {
} }
} }
type KeyFunc func(r *http.Request) (string, error)
func getBearer(r *http.Request) (string, error) {
auth := r.Header.Get("Authorization")
if auth == "" {
return "", errors.New("authorization header is required")
}
return auth, nil
}
func getQuery(r *http.Request) (string, error) {
token := r.URL.Query().Get("access_token")
if token == "" {
return "", errors.New("access_token query is required")
}
token, err := url.QueryUnescape(token)
if err != nil {
return "", errors.New("access_token query is required")
}
return token, nil
}
func getCookie(r *http.Request) (string, error) {
cookie, err := r.Cookie("hb.auth.token")
if err != nil {
return "", errors.New("access_token cookie is required")
}
token, err := url.QueryUnescape(cookie.Value)
if err != nil {
return "", errors.New("access_token cookie is required")
}
return token, nil
}
// mwAuthToken is a middleware that will check the database for a stateful token // mwAuthToken is a middleware that will check the database for a stateful token
// and attach it's user to the request context, or return an appropriate error. // and attach it's user to the request context, or return an appropriate error.
// Authorization support is by token via Headers or Query Parameter // Authorization support is by token via Headers or Query Parameter
@ -75,26 +115,36 @@ func (a *app) mwRoles(rm RoleMode, required ...string) server.Middleware {
// Example: // Example:
// - header = "Bearer 1234567890" // - header = "Bearer 1234567890"
// - query = "?access_token=1234567890" // - query = "?access_token=1234567890"
// - cookie = hb.auth.token = 1234567890
func (a *app) mwAuthToken(next server.Handler) server.Handler { func (a *app) mwAuthToken(next server.Handler) server.Handler {
return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
requestToken := r.Header.Get("Authorization") keyFuncs := [...]KeyFunc{
if requestToken == "" { getBearer,
// check for query param getCookie,
requestToken = r.URL.Query().Get("access_token") getQuery,
if requestToken == "" { }
return validate.NewRequestError(errors.New("Authorization header or query is required"), http.StatusUnauthorized)
var requestToken string
for _, keyFunc := range keyFuncs {
token, err := keyFunc(r)
if err == nil {
requestToken = token
break
} }
} }
if requestToken == "" {
return validate.NewRequestError(errors.New("Authorization header or query is required"), http.StatusUnauthorized)
}
requestToken = strings.TrimPrefix(requestToken, "Bearer ") requestToken = strings.TrimPrefix(requestToken, "Bearer ")
r = r.WithContext(context.WithValue(r.Context(), hashedToken, requestToken)) r = r.WithContext(context.WithValue(r.Context(), hashedToken, requestToken))
usr, err := a.services.User.GetSelf(r.Context(), requestToken) usr, err := a.services.User.GetSelf(r.Context(), requestToken)
// Check the database for the token // Check the database for the token
if err != nil { if err != nil {
return validate.NewRequestError(errors.New("Authorization header is required"), http.StatusUnauthorized) return validate.NewRequestError(errors.New("valid authorization header is required"), http.StatusUnauthorized)
} }
r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken)) r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken))