mirror of
https://github.com/portainer/portainer.git
synced 2025-07-22 23:09:41 +02:00
feat(uac): add multi user management and UAC (#647)
This commit is contained in:
parent
f28f223624
commit
80d50378c5
91 changed files with 3973 additions and 866 deletions
|
@ -1,33 +1,61 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/portainer/portainer"
|
||||
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Service represents a service to manage HTTP middlewares
|
||||
type middleWareService struct {
|
||||
jwtService portainer.JWTService
|
||||
authDisabled bool
|
||||
}
|
||||
|
||||
func addMiddleware(h http.Handler, middleware ...func(http.Handler) http.Handler) http.Handler {
|
||||
for _, mw := range middleware {
|
||||
h = mw(h)
|
||||
type (
|
||||
// middleWareService represents a service to manage HTTP middlewares
|
||||
middleWareService struct {
|
||||
jwtService portainer.JWTService
|
||||
authDisabled bool
|
||||
}
|
||||
contextKey int
|
||||
)
|
||||
|
||||
const (
|
||||
contextAuthenticationKey contextKey = iota
|
||||
)
|
||||
|
||||
func extractTokenDataFromRequestContext(request *http.Request) (*portainer.TokenData, error) {
|
||||
contextData := request.Context().Value(contextAuthenticationKey)
|
||||
if contextData == nil {
|
||||
return nil, portainer.ErrMissingContextData
|
||||
}
|
||||
|
||||
tokenData := contextData.(*portainer.TokenData)
|
||||
return tokenData, nil
|
||||
}
|
||||
|
||||
// public defines a chain of middleware for public endpoints (no authentication required)
|
||||
func (service *middleWareService) public(h http.Handler) http.Handler {
|
||||
h = mwSecureHeaders(h)
|
||||
return h
|
||||
}
|
||||
|
||||
func (service *middleWareService) addMiddleWares(h http.Handler) http.Handler {
|
||||
h = service.middleWareSecureHeaders(h)
|
||||
h = service.middleWareAuthenticate(h)
|
||||
// authenticated defines a chain of middleware for private endpoints (authentication required)
|
||||
func (service *middleWareService) authenticated(h http.Handler) http.Handler {
|
||||
h = service.mwCheckAuthentication(h)
|
||||
h = mwSecureHeaders(h)
|
||||
return h
|
||||
}
|
||||
|
||||
// middleWareAuthenticate provides secure headers middleware for handlers
|
||||
func (*middleWareService) middleWareSecureHeaders(next http.Handler) http.Handler {
|
||||
// administrator defines a chain of middleware for private administrator restricted endpoints
|
||||
// (authentication and role admin required)
|
||||
func (service *middleWareService) administrator(h http.Handler) http.Handler {
|
||||
h = mwCheckAdministratorRole(h)
|
||||
h = service.mwCheckAuthentication(h)
|
||||
h = mwSecureHeaders(h)
|
||||
return h
|
||||
}
|
||||
|
||||
// mwSecureHeaders provides secure headers middleware for handlers
|
||||
func mwSecureHeaders(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Add("X-Frame-Options", "DENY")
|
||||
|
@ -35,9 +63,28 @@ func (*middleWareService) middleWareSecureHeaders(next http.Handler) http.Handle
|
|||
})
|
||||
}
|
||||
|
||||
// middleWareAuthenticate provides Authentication middleware for handlers
|
||||
func (service *middleWareService) middleWareAuthenticate(next http.Handler) http.Handler {
|
||||
// mwCheckAdministratorRole check the role of the user associated to the request
|
||||
func mwCheckAdministratorRole(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
tokenData, err := extractTokenDataFromRequestContext(r)
|
||||
if err != nil {
|
||||
Error(w, portainer.ErrResourceAccessDenied, http.StatusForbidden, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if tokenData.Role != portainer.AdministratorRole {
|
||||
Error(w, portainer.ErrResourceAccessDenied, http.StatusForbidden, nil)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// mwCheckAuthentication provides Authentication middleware for handlers
|
||||
func (service *middleWareService) mwCheckAuthentication(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var tokenData *portainer.TokenData
|
||||
if !service.authDisabled {
|
||||
var token string
|
||||
|
||||
|
@ -53,14 +100,20 @@ func (service *middleWareService) middleWareAuthenticate(next http.Handler) http
|
|||
return
|
||||
}
|
||||
|
||||
err := service.jwtService.VerifyToken(token)
|
||||
var err error
|
||||
tokenData, err = service.jwtService.ParseAndVerifyToken(token)
|
||||
if err != nil {
|
||||
Error(w, err, http.StatusUnauthorized, nil)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
tokenData = &portainer.TokenData{
|
||||
Role: portainer.AdministratorRole,
|
||||
}
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
ctx := context.WithValue(r.Context(), contextAuthenticationKey, tokenData)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
return
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue