mirror of
https://github.com/jc21/nginx-proxy-manager.git
synced 2024-08-30 18:22:48 +00:00
9faa36315f
also fixes a limit bug on listquery
95 lines
2.9 KiB
Go
95 lines
2.9 KiB
Go
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
c "npm/internal/api/context"
|
|
h "npm/internal/api/http"
|
|
"npm/internal/config"
|
|
"npm/internal/entity/user"
|
|
njwt "npm/internal/jwt"
|
|
"npm/internal/logger"
|
|
"npm/internal/util"
|
|
|
|
"github.com/go-chi/jwtauth/v5"
|
|
)
|
|
|
|
// DecodeAuth decodes an auth header
|
|
func DecodeAuth() func(http.Handler) http.Handler {
|
|
privateKey, privateKeyParseErr := njwt.GetPrivateKey()
|
|
if privateKeyParseErr != nil && privateKey == nil {
|
|
logger.Error("PrivateKeyParseError", privateKeyParseErr)
|
|
}
|
|
|
|
publicKey, publicKeyParseErr := njwt.GetPublicKey()
|
|
if publicKeyParseErr != nil && publicKey == nil {
|
|
logger.Error("PublicKeyParseError", publicKeyParseErr)
|
|
}
|
|
|
|
tokenAuth := jwtauth.New("RS256", privateKey, publicKey)
|
|
return jwtauth.Verify(tokenAuth, jwtauth.TokenFromHeader, jwtauth.TokenFromQuery)
|
|
}
|
|
|
|
// Enforce is a authentication middleware to enforce access from the
|
|
// jwtauth.Verifier middleware request context values. The Authenticator sends a 401 Unauthorised
|
|
// response for any unverified tokens and passes the good ones through.
|
|
func Enforce(permission string) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
if config.IsSetup {
|
|
token, claims, err := jwtauth.FromContext(ctx)
|
|
|
|
if err != nil {
|
|
h.ResultErrorJSON(w, r, http.StatusUnauthorized, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
userID := uint(claims["uid"].(float64))
|
|
_, enabled, _ := user.IsEnabled(userID)
|
|
if token == nil || !enabled {
|
|
h.ResultErrorJSON(w, r, http.StatusUnauthorized, "Unauthorised", nil)
|
|
return
|
|
}
|
|
|
|
// Check if permissions exist for this user
|
|
if permission != "" {
|
|
// Since the permission that we require is not on the token, we have to get it from the DB
|
|
// So we don't go crazy with hits, we will use a memory cache
|
|
cacheKey := fmt.Sprintf("userCapabilties.%v", userID)
|
|
cacheItem, found := AuthCache.Get(cacheKey)
|
|
|
|
var userCapabilities []string
|
|
if found {
|
|
userCapabilities = cacheItem.([]string)
|
|
} else {
|
|
// Get from db and store it
|
|
userCapabilities, err = user.GetCapabilities(userID)
|
|
if err != nil {
|
|
AuthCacheSet(cacheKey, userCapabilities)
|
|
}
|
|
}
|
|
|
|
// Now check that they have the permission in their admin capabilities
|
|
// full-admin can do anything
|
|
if !util.SliceContainsItem(userCapabilities, user.CapabilityFullAdmin) && !util.SliceContainsItem(userCapabilities, permission) {
|
|
// Access denied
|
|
logger.Debug("User has: %+v but needs %s", userCapabilities, permission)
|
|
h.ResultErrorJSON(w, r, http.StatusForbidden, "Forbidden", nil)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Add claims to context
|
|
ctx = context.WithValue(ctx, c.UserIDCtxKey, userID)
|
|
}
|
|
|
|
// Token is authenticated, continue as normal
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
}
|