Replace basic auth with cookie authentication (#440)

* Add logout functionality and button
* Make session age configurable
This commit is contained in:
WithoutPants
2020-04-08 12:51:12 +10:00
committed by GitHub
parent b3e8d1e8dd
commit 15e7756d33
73 changed files with 12297 additions and 49 deletions

View File

@@ -7,6 +7,7 @@ import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
@@ -37,38 +38,69 @@ var uiBox *packr.Box
//var legacyUiBox *packr.Box
var setupUIBox *packr.Box
var loginUIBox *packr.Box
func allowUnauthenticated(r *http.Request) bool {
return strings.HasPrefix(r.URL.Path, "/login") || r.URL.Path == "/css"
}
func authenticateHandler() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// only do this if credentials have been configured
if !config.HasCredentials() {
next.ServeHTTP(w, r)
ctx := r.Context()
// translate api key into current user, if present
userID := ""
var err error
// handle session
userID, err = getSessionUserID(w, r)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
authUser, authPW, ok := r.BasicAuth()
// handle redirect if no user and user is required
if userID == "" && config.HasCredentials() && !allowUnauthenticated(r) {
// always allow
if !ok || !config.ValidateCredentials(authUser, authPW) {
unauthorized(w)
// if we don't have a userID, then redirect
// if graphql was requested, we just return a forbidden error
if r.URL.Path == "/graphql" {
w.Header().Add("WWW-Authenticate", `FormBased`)
w.WriteHeader(http.StatusUnauthorized)
return
}
// otherwise redirect to the login page
u := url.URL{
Path: "/login",
}
q := u.Query()
q.Set(returnURLParam, r.URL.Path)
u.RawQuery = q.Encode()
http.Redirect(w, r, u.String(), http.StatusFound)
return
}
ctx = context.WithValue(ctx, ContextUser, userID)
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
}
func unauthorized(w http.ResponseWriter) {
w.Header().Add("WWW-Authenticate", `Basic realm=\"Stash\"`)
w.WriteHeader(http.StatusUnauthorized)
}
func Start() {
uiBox = packr.New("UI Box", "../../ui/v2.5/build")
//legacyUiBox = packr.New("UI Box", "../../ui/v1/dist/stash-frontend")
setupUIBox = packr.New("Setup UI Box", "../../ui/setup")
loginUIBox = packr.New("Login UI Box", "../../ui/login")
initSessionStore()
initialiseImages()
r := chi.NewRouter()
@@ -107,6 +139,12 @@ func Start() {
r.Handle("/graphql", gqlHandler)
r.Handle("/playground", handler.Playground("GraphQL playground", "/graphql"))
// session handlers
r.Post("/login", handleLogin)
r.Get("/logout", handleLogout)
r.Get("/login", getLoginHandler)
r.Mount("/gallery", galleryRoutes{}.Routes())
r.Mount("/performer", performerRoutes{}.Routes())
r.Mount("/scene", sceneRoutes{}.Routes())
@@ -144,6 +182,16 @@ func Start() {
http.FileServer(setupUIBox).ServeHTTP(w, r)
}
})
r.HandleFunc("/login*", func(w http.ResponseWriter, r *http.Request) {
ext := path.Ext(r.URL.Path)
if ext == ".html" || ext == "" {
data, _ := loginUIBox.Find("login.html")
_, _ = w.Write(data)
} else {
r.URL.Path = strings.Replace(r.URL.Path, "/login", "", 1)
http.FileServer(loginUIBox).ServeHTTP(w, r)
}
})
r.Post("/init", func(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {