Use a custom authorization header, to avoid conflicts with proxies using basic auth (fixes #146)
This commit is contained in:
@@ -14,6 +14,7 @@ const (
|
|||||||
DefaultDbPath = "navidrome.db?cache=shared&_busy_timeout=15000&_journal_mode=WAL"
|
DefaultDbPath = "navidrome.db?cache=shared&_busy_timeout=15000&_journal_mode=WAL"
|
||||||
InitialSetupFlagKey = "InitialSetup"
|
InitialSetupFlagKey = "InitialSetup"
|
||||||
|
|
||||||
|
UIAuthorizationHeader = "X-ND-Authorization"
|
||||||
JWTSecretKey = "JWTSecret"
|
JWTSecretKey = "JWTSecret"
|
||||||
JWTIssuer = "ND"
|
JWTIssuer = "ND"
|
||||||
DefaultSessionTimeout = 30 * time.Minute
|
DefaultSessionTimeout = 30 * time.Minute
|
||||||
|
|||||||
+2
-1
@@ -38,8 +38,9 @@ func (app *Router) routes(path string) http.Handler {
|
|||||||
r.Post("/createAdmin", CreateAdmin(app.ds))
|
r.Post("/createAdmin", CreateAdmin(app.ds))
|
||||||
|
|
||||||
r.Route("/api", func(r chi.Router) {
|
r.Route("/api", func(r chi.Router) {
|
||||||
|
r.Use(mapAuthHeader())
|
||||||
r.Use(jwtauth.Verifier(auth.TokenAuth))
|
r.Use(jwtauth.Verifier(auth.TokenAuth))
|
||||||
r.Use(Authenticator(app.ds))
|
r.Use(authenticator(app.ds))
|
||||||
app.R(r, "/user", model.User{})
|
app.R(r, "/user", model.User{})
|
||||||
app.R(r, "/song", model.MediaFile{})
|
app.R(r, "/song", model.MediaFile{})
|
||||||
app.R(r, "/album", model.Album{})
|
app.R(r, "/album", model.Album{})
|
||||||
|
|||||||
+13
-2
@@ -169,7 +169,18 @@ func getToken(ds model.DataStore, ctx context.Context) (*jwt.Token, error) {
|
|||||||
return nil, errors.New("invalid authentication")
|
return nil, errors.New("invalid authentication")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Authenticator(ds model.DataStore) func(next http.Handler) http.Handler {
|
// This method maps the custom authorization header to the default 'Authorization', used by the jwtauth library
|
||||||
|
func mapAuthHeader() func(next http.Handler) http.Handler {
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
bearer := r.Header.Get(consts.UIAuthorizationHeader)
|
||||||
|
r.Header.Set("Authorization", bearer)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func authenticator(ds model.DataStore) func(next http.Handler) http.Handler {
|
||||||
auth.InitTokenAuth(ds)
|
auth.InitTokenAuth(ds)
|
||||||
|
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
@@ -194,7 +205,7 @@ func Authenticator(ds model.DataStore) func(next http.Handler) http.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Authorization", newTokenString)
|
w.Header().Set(consts.UIAuthorizationHeader, newTokenString)
|
||||||
next.ServeHTTP(w, r.WithContext(newCtx))
|
next.ServeHTTP(w, r.WithContext(newCtx))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/deluan/navidrome/consts"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Auth", func() {
|
||||||
|
Describe("mapAuthHeader", func() {
|
||||||
|
It("maps the custom header to Authorization header", func() {
|
||||||
|
r := httptest.NewRequest("GET", "/index.html", nil)
|
||||||
|
r.Header.Set(consts.UIAuthorizationHeader, "test authorization bearer")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
mapAuthHeader()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
Expect(r.Header.Get("Authorization")).To(Equal("test authorization bearer"))
|
||||||
|
w.WriteHeader(200)
|
||||||
|
})).ServeHTTP(w, r)
|
||||||
|
|
||||||
|
Expect(w.Code).To(Equal(200))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -12,7 +12,7 @@ const httpClient = (url, options = {}) => {
|
|||||||
}
|
}
|
||||||
const token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
if (token) {
|
if (token) {
|
||||||
options.headers.set('Authorization', `Bearer ${token}`)
|
options.headers.set('X-ND-Authorization', `Bearer ${token}`)
|
||||||
}
|
}
|
||||||
return fetchUtils.fetchJson(url, options).then((response) => {
|
return fetchUtils.fetchJson(url, options).then((response) => {
|
||||||
const token = response.headers.get('authorization')
|
const token = response.headers.get('authorization')
|
||||||
|
|||||||
Reference in New Issue
Block a user