mirror of
https://github.com/portainer/portainer.git
synced 2025-08-04 13:25:26 +02:00
feat(api): prevent non administrator users to use admin restricted API endpoints (#3227)
This commit is contained in:
parent
1fbe6a12f1
commit
f7480c4ad4
21 changed files with 118 additions and 93 deletions
|
@ -34,7 +34,7 @@ type (
|
|||
}
|
||||
|
||||
// RestrictedRequestContext is a data structure containing information
|
||||
// used in RestrictedAccess
|
||||
// used in AuthenticatedAccess
|
||||
RestrictedRequestContext struct {
|
||||
IsAdmin bool
|
||||
IsTeamLeader bool
|
||||
|
@ -64,22 +64,40 @@ func (bouncer *RequestBouncer) PublicAccess(h http.Handler) http.Handler {
|
|||
return h
|
||||
}
|
||||
|
||||
// AuthorizedAccess defines a security check for API endpoints that require an authorization check.
|
||||
// AdminAccess defines a security check for API endpoints that require an authorization check.
|
||||
// Authentication is required to access these endpoints.
|
||||
// If the RBAC extension is enabled, authorizations are required to use these endpoints.
|
||||
// If the RBAC extension is not enabled, the administrator role is required to use these endpoints.
|
||||
func (bouncer *RequestBouncer) AuthorizedAccess(h http.Handler) http.Handler {
|
||||
// The request context will be enhanced with a RestrictedRequestContext object
|
||||
// that might be used later to inside the API operation for extra authorization validation
|
||||
// and resource filtering.
|
||||
func (bouncer *RequestBouncer) AdminAccess(h http.Handler) http.Handler {
|
||||
h = bouncer.mwUpgradeToRestrictedRequest(h)
|
||||
h = bouncer.mwCheckPortainerAuthorizations(h)
|
||||
h = bouncer.mwCheckPortainerAuthorizations(h, true)
|
||||
h = bouncer.mwAuthenticatedUser(h)
|
||||
return h
|
||||
}
|
||||
|
||||
// RestrictedAccess defines a security check for restricted API endpoints.
|
||||
// Authentication is required to access these endpoints.
|
||||
// If the RBAC extension is enabled, authorizations are required to use these endpoints.
|
||||
// If the RBAC extension is not enabled, access is granted to any authenticated user.
|
||||
// The request context will be enhanced with a RestrictedRequestContext object
|
||||
// that might be used later to authorize/filter access to resources inside an endpoint.
|
||||
// that might be used later to inside the API operation for extra authorization validation
|
||||
// and resource filtering.
|
||||
func (bouncer *RequestBouncer) RestrictedAccess(h http.Handler) http.Handler {
|
||||
h = bouncer.mwUpgradeToRestrictedRequest(h)
|
||||
h = bouncer.mwCheckPortainerAuthorizations(h, false)
|
||||
h = bouncer.mwAuthenticatedUser(h)
|
||||
return h
|
||||
}
|
||||
|
||||
// AuthenticatedAccess defines a security check for restricted API endpoints.
|
||||
// Authentication is required to access these endpoints.
|
||||
// The request context will be enhanced with a RestrictedRequestContext object
|
||||
// that might be used later to inside the API operation for extra authorization validation
|
||||
// and resource filtering.
|
||||
func (bouncer *RequestBouncer) AuthenticatedAccess(h http.Handler) http.Handler {
|
||||
h = bouncer.mwUpgradeToRestrictedRequest(h)
|
||||
h = bouncer.mwAuthenticatedUser(h)
|
||||
return h
|
||||
|
@ -191,11 +209,13 @@ func (bouncer *RequestBouncer) mwAuthenticatedUser(h http.Handler) http.Handler
|
|||
// mwCheckPortainerAuthorizations will verify that the user has the required authorization to access
|
||||
// a specific API endpoint. It will leverage the RBAC extension authorization validation if the extension
|
||||
// is enabled.
|
||||
func (bouncer *RequestBouncer) mwCheckPortainerAuthorizations(next http.Handler) http.Handler {
|
||||
// If the administratorOnly flag is specified and the RBAC extension is not enabled, this will prevent non-admin
|
||||
// users from accessing the endpoint.
|
||||
func (bouncer *RequestBouncer) mwCheckPortainerAuthorizations(next http.Handler, administratorOnly bool) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
tokenData, err := RetrieveTokenData(r)
|
||||
if err != nil {
|
||||
httperror.WriteError(w, http.StatusForbidden, "Access denied", portainer.ErrResourceAccessDenied)
|
||||
httperror.WriteError(w, http.StatusForbidden, "Access denied", portainer.ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -206,6 +226,11 @@ func (bouncer *RequestBouncer) mwCheckPortainerAuthorizations(next http.Handler)
|
|||
|
||||
extension, err := bouncer.extensionService.Extension(portainer.RBACExtension)
|
||||
if err == portainer.ErrObjectNotFound {
|
||||
if administratorOnly {
|
||||
httperror.WriteError(w, http.StatusForbidden, "Access denied", portainer.ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
} else if err != nil {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue