1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-23 07:19:41 +02:00

feat(api): prevent non administrator users to use admin restricted API endpoints (#3227)

This commit is contained in:
Anthony Lapenna 2019-10-07 16:10:51 +13:00 committed by GitHub
parent 1fbe6a12f1
commit f7480c4ad4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 118 additions and 93 deletions

View file

@ -25,9 +25,9 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/dockerhub", h.Handle("/dockerhub",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.dockerhubInspect))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.dockerhubInspect))).Methods(http.MethodGet)
h.Handle("/dockerhub", h.Handle("/dockerhub",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.dockerhubUpdate))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.dockerhubUpdate))).Methods(http.MethodPut)
return h return h
} }

View file

@ -23,18 +23,18 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/endpoint_groups", h.Handle("/endpoint_groups",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointGroupCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointGroupCreate))).Methods(http.MethodPost)
h.Handle("/endpoint_groups", h.Handle("/endpoint_groups",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointGroupList))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointGroupList))).Methods(http.MethodGet)
h.Handle("/endpoint_groups/{id}", h.Handle("/endpoint_groups/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointGroupInspect))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointGroupInspect))).Methods(http.MethodGet)
h.Handle("/endpoint_groups/{id}", h.Handle("/endpoint_groups/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointGroupUpdate))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointGroupUpdate))).Methods(http.MethodPut)
h.Handle("/endpoint_groups/{id}", h.Handle("/endpoint_groups/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointGroupDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointGroupDelete))).Methods(http.MethodDelete)
h.Handle("/endpoint_groups/{id}/endpoints/{endpointId}", h.Handle("/endpoint_groups/{id}/endpoints/{endpointId}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointGroupAddEndpoint))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointGroupAddEndpoint))).Methods(http.MethodPut)
h.Handle("/endpoint_groups/{id}/endpoints/{endpointId}", h.Handle("/endpoint_groups/{id}/endpoints/{endpointId}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointGroupDeleteEndpoint))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointGroupDeleteEndpoint))).Methods(http.MethodDelete)
return h return h
} }

View file

@ -25,10 +25,10 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
requestBouncer: bouncer, requestBouncer: bouncer,
} }
h.PathPrefix("/{id}/azure").Handler( h.PathPrefix("/{id}/azure").Handler(
bouncer.RestrictedAccess(httperror.LoggerHandler(h.proxyRequestsToAzureAPI))) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.proxyRequestsToAzureAPI)))
h.PathPrefix("/{id}/docker").Handler( h.PathPrefix("/{id}/docker").Handler(
bouncer.RestrictedAccess(httperror.LoggerHandler(h.proxyRequestsToDockerAPI))) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.proxyRequestsToDockerAPI)))
h.PathPrefix("/{id}/storidge").Handler( h.PathPrefix("/{id}/storidge").Handler(
bouncer.RestrictedAccess(httperror.LoggerHandler(h.proxyRequestsToStoridgeAPI))) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.proxyRequestsToStoridgeAPI)))
return h return h
} }

View file

@ -49,25 +49,25 @@ func NewHandler(bouncer *security.RequestBouncer, authorizeEndpointManagement bo
} }
h.Handle("/endpoints", h.Handle("/endpoints",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointCreate))).Methods(http.MethodPost)
h.Handle("/endpoints/snapshot", h.Handle("/endpoints/snapshot",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointSnapshots))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointSnapshots))).Methods(http.MethodPost)
h.Handle("/endpoints", h.Handle("/endpoints",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointList))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointList))).Methods(http.MethodGet)
h.Handle("/endpoints/{id}", h.Handle("/endpoints/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointInspect))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointInspect))).Methods(http.MethodGet)
h.Handle("/endpoints/{id}", h.Handle("/endpoints/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointUpdate))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointUpdate))).Methods(http.MethodPut)
h.Handle("/endpoints/{id}", h.Handle("/endpoints/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointDelete))).Methods(http.MethodDelete)
h.Handle("/endpoints/{id}/extensions", h.Handle("/endpoints/{id}/extensions",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointExtensionAdd))).Methods(http.MethodPost) bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointExtensionAdd))).Methods(http.MethodPost)
h.Handle("/endpoints/{id}/extensions/{extensionType}", h.Handle("/endpoints/{id}/extensions/{extensionType}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointExtensionRemove))).Methods(http.MethodDelete) bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointExtensionRemove))).Methods(http.MethodDelete)
h.Handle("/endpoints/{id}/job", h.Handle("/endpoints/{id}/job",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointJob))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointJob))).Methods(http.MethodPost)
h.Handle("/endpoints/{id}/snapshot", h.Handle("/endpoints/{id}/snapshot",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.endpointSnapshot))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.endpointSnapshot))).Methods(http.MethodPost)
h.Handle("/endpoints/{id}/status", h.Handle("/endpoints/{id}/status",
bouncer.PublicAccess(httperror.LoggerHandler(h.endpointStatusInspect))).Methods(http.MethodGet) bouncer.PublicAccess(httperror.LoggerHandler(h.endpointStatusInspect))).Methods(http.MethodGet)

View file

@ -27,15 +27,15 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
} }
h.Handle("/extensions", h.Handle("/extensions",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.extensionList))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.extensionList))).Methods(http.MethodGet)
h.Handle("/extensions", h.Handle("/extensions",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.extensionCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.extensionCreate))).Methods(http.MethodPost)
h.Handle("/extensions/{id}", h.Handle("/extensions/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.extensionInspect))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.extensionInspect))).Methods(http.MethodGet)
h.Handle("/extensions/{id}", h.Handle("/extensions/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.extensionDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.extensionDelete))).Methods(http.MethodDelete)
h.Handle("/extensions/{id}/update", h.Handle("/extensions/{id}/update",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.extensionUpdate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.extensionUpdate))).Methods(http.MethodPost)
return h return h
} }

View file

@ -18,7 +18,7 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/motd", h.Handle("/motd",
bouncer.AuthorizedAccess(http.HandlerFunc(h.motd))).Methods(http.MethodGet) bouncer.RestrictedAccess(http.HandlerFunc(h.motd))).Methods(http.MethodGet)
return h return h
} }

View file

@ -33,19 +33,19 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
} }
h.Handle("/registries", h.Handle("/registries",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.registryCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.registryCreate))).Methods(http.MethodPost)
h.Handle("/registries", h.Handle("/registries",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.registryList))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.registryList))).Methods(http.MethodGet)
h.Handle("/registries/{id}", h.Handle("/registries/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.registryInspect))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.registryInspect))).Methods(http.MethodGet)
h.Handle("/registries/{id}", h.Handle("/registries/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.registryUpdate))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.registryUpdate))).Methods(http.MethodPut)
h.Handle("/registries/{id}/configure", h.Handle("/registries/{id}/configure",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.registryConfigure))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.registryConfigure))).Methods(http.MethodPost)
h.Handle("/registries/{id}", h.Handle("/registries/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.registryDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.registryDelete))).Methods(http.MethodDelete)
h.PathPrefix("/registries/{id}/v2").Handler( h.PathPrefix("/registries/{id}/v2").Handler(
bouncer.RestrictedAccess(httperror.LoggerHandler(h.proxyRequestsToRegistryAPI))) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.proxyRequestsToRegistryAPI)))
return h return h
} }

View file

@ -21,11 +21,11 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/resource_controls", h.Handle("/resource_controls",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.resourceControlCreate))).Methods(http.MethodPost) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.resourceControlCreate))).Methods(http.MethodPost)
h.Handle("/resource_controls/{id}", h.Handle("/resource_controls/{id}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.resourceControlUpdate))).Methods(http.MethodPut) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.resourceControlUpdate))).Methods(http.MethodPut)
h.Handle("/resource_controls/{id}", h.Handle("/resource_controls/{id}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.resourceControlDelete))).Methods(http.MethodDelete) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.resourceControlDelete))).Methods(http.MethodDelete)
return h return h
} }

View file

@ -21,7 +21,7 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/roles", h.Handle("/roles",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.roleList))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.roleList))).Methods(http.MethodGet)
return h return h
} }

View file

@ -28,18 +28,18 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
} }
h.Handle("/schedules", h.Handle("/schedules",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.scheduleList))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.scheduleList))).Methods(http.MethodGet)
h.Handle("/schedules", h.Handle("/schedules",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.scheduleCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.scheduleCreate))).Methods(http.MethodPost)
h.Handle("/schedules/{id}", h.Handle("/schedules/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.scheduleInspect))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.scheduleInspect))).Methods(http.MethodGet)
h.Handle("/schedules/{id}", h.Handle("/schedules/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.scheduleUpdate))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.scheduleUpdate))).Methods(http.MethodPut)
h.Handle("/schedules/{id}", h.Handle("/schedules/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.scheduleDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.scheduleDelete))).Methods(http.MethodDelete)
h.Handle("/schedules/{id}/file", h.Handle("/schedules/{id}/file",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.scheduleFile))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.scheduleFile))).Methods(http.MethodGet)
h.Handle("/schedules/{id}/tasks", h.Handle("/schedules/{id}/tasks",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.scheduleTasks))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.scheduleTasks))).Methods(http.MethodGet)
return h return h
} }

View file

@ -30,13 +30,13 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/settings", h.Handle("/settings",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.settingsInspect))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.settingsInspect))).Methods(http.MethodGet)
h.Handle("/settings", h.Handle("/settings",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.settingsUpdate))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.settingsUpdate))).Methods(http.MethodPut)
h.Handle("/settings/public", h.Handle("/settings/public",
bouncer.PublicAccess(httperror.LoggerHandler(h.settingsPublic))).Methods(http.MethodGet) bouncer.PublicAccess(httperror.LoggerHandler(h.settingsPublic))).Methods(http.MethodGet)
h.Handle("/settings/authentication/checkLDAP", h.Handle("/settings/authentication/checkLDAP",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.settingsLDAPCheck))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.settingsLDAPCheck))).Methods(http.MethodPut)
return h return h
} }

View file

@ -36,18 +36,18 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
requestBouncer: bouncer, requestBouncer: bouncer,
} }
h.Handle("/stacks", h.Handle("/stacks",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.stackCreate))).Methods(http.MethodPost) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackCreate))).Methods(http.MethodPost)
h.Handle("/stacks", h.Handle("/stacks",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.stackList))).Methods(http.MethodGet) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackList))).Methods(http.MethodGet)
h.Handle("/stacks/{id}", h.Handle("/stacks/{id}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.stackInspect))).Methods(http.MethodGet) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackInspect))).Methods(http.MethodGet)
h.Handle("/stacks/{id}", h.Handle("/stacks/{id}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.stackDelete))).Methods(http.MethodDelete) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackDelete))).Methods(http.MethodDelete)
h.Handle("/stacks/{id}", h.Handle("/stacks/{id}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.stackUpdate))).Methods(http.MethodPut) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackUpdate))).Methods(http.MethodPut)
h.Handle("/stacks/{id}/file", h.Handle("/stacks/{id}/file",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.stackFile))).Methods(http.MethodGet) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackFile))).Methods(http.MethodGet)
h.Handle("/stacks/{id}/migrate", h.Handle("/stacks/{id}/migrate",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.stackMigrate))).Methods(http.MethodPost) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.stackMigrate))).Methods(http.MethodPost)
return h return h
} }

View file

@ -21,11 +21,11 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/tags", h.Handle("/tags",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.tagCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.tagCreate))).Methods(http.MethodPost)
h.Handle("/tags", h.Handle("/tags",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.tagList))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.tagList))).Methods(http.MethodGet)
h.Handle("/tags/{id}", h.Handle("/tags/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.tagDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.tagDelete))).Methods(http.MethodDelete)
return h return h
} }

View file

@ -23,13 +23,13 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/team_memberships", h.Handle("/team_memberships",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamMembershipCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.teamMembershipCreate))).Methods(http.MethodPost)
h.Handle("/team_memberships", h.Handle("/team_memberships",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamMembershipList))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.teamMembershipList))).Methods(http.MethodGet)
h.Handle("/team_memberships/{id}", h.Handle("/team_memberships/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamMembershipUpdate))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.teamMembershipUpdate))).Methods(http.MethodPut)
h.Handle("/team_memberships/{id}", h.Handle("/team_memberships/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamMembershipDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.teamMembershipDelete))).Methods(http.MethodDelete)
return h return h
} }

View file

@ -23,17 +23,17 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/teams", h.Handle("/teams",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.teamCreate))).Methods(http.MethodPost)
h.Handle("/teams", h.Handle("/teams",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamList))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.teamList))).Methods(http.MethodGet)
h.Handle("/teams/{id}", h.Handle("/teams/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamInspect))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.teamInspect))).Methods(http.MethodGet)
h.Handle("/teams/{id}", h.Handle("/teams/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamUpdate))).Methods(http.MethodPut) bouncer.AdminAccess(httperror.LoggerHandler(h.teamUpdate))).Methods(http.MethodPut)
h.Handle("/teams/{id}", h.Handle("/teams/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.teamDelete))).Methods(http.MethodDelete)
h.Handle("/teams/{id}/memberships", h.Handle("/teams/{id}/memberships",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.teamMemberships))).Methods(http.MethodGet) bouncer.AdminAccess(httperror.LoggerHandler(h.teamMemberships))).Methods(http.MethodGet)
return h return h
} }

View file

@ -27,15 +27,15 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
} }
h.Handle("/templates", h.Handle("/templates",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.templateList))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.templateList))).Methods(http.MethodGet)
h.Handle("/templates", h.Handle("/templates",
bouncer.AuthorizedAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateCreate)))).Methods(http.MethodPost) bouncer.AdminAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateCreate)))).Methods(http.MethodPost)
h.Handle("/templates/{id}", h.Handle("/templates/{id}",
bouncer.AuthorizedAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateInspect)))).Methods(http.MethodGet) bouncer.RestrictedAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateInspect)))).Methods(http.MethodGet)
h.Handle("/templates/{id}", h.Handle("/templates/{id}",
bouncer.AuthorizedAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateUpdate)))).Methods(http.MethodPut) bouncer.AdminAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateUpdate)))).Methods(http.MethodPut)
h.Handle("/templates/{id}", h.Handle("/templates/{id}",
bouncer.AuthorizedAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateDelete)))).Methods(http.MethodDelete) bouncer.AdminAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateDelete)))).Methods(http.MethodDelete)
return h return h
} }

View file

@ -22,6 +22,6 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/upload/tls/{certificate:(?:ca|cert|key)}", h.Handle("/upload/tls/{certificate:(?:ca|cert|key)}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.uploadTLS))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.uploadTLS))).Methods(http.MethodPost)
return h return h
} }

View file

@ -32,19 +32,19 @@ func NewHandler(bouncer *security.RequestBouncer, rateLimiter *security.RateLimi
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/users", h.Handle("/users",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.userCreate))).Methods(http.MethodPost) bouncer.AdminAccess(httperror.LoggerHandler(h.userCreate))).Methods(http.MethodPost)
h.Handle("/users", h.Handle("/users",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.userList))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.userList))).Methods(http.MethodGet)
h.Handle("/users/{id}", h.Handle("/users/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.userInspect))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.userInspect))).Methods(http.MethodGet)
h.Handle("/users/{id}", h.Handle("/users/{id}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.userUpdate))).Methods(http.MethodPut) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.userUpdate))).Methods(http.MethodPut)
h.Handle("/users/{id}", h.Handle("/users/{id}",
bouncer.AuthorizedAccess(httperror.LoggerHandler(h.userDelete))).Methods(http.MethodDelete) bouncer.AdminAccess(httperror.LoggerHandler(h.userDelete))).Methods(http.MethodDelete)
h.Handle("/users/{id}/memberships", h.Handle("/users/{id}/memberships",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.userMemberships))).Methods(http.MethodGet) bouncer.RestrictedAccess(httperror.LoggerHandler(h.userMemberships))).Methods(http.MethodGet)
h.Handle("/users/{id}/passwd", h.Handle("/users/{id}/passwd",
rateLimiter.LimitAccess(bouncer.RestrictedAccess(httperror.LoggerHandler(h.userUpdatePassword)))).Methods(http.MethodPut) rateLimiter.LimitAccess(bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.userUpdatePassword)))).Methods(http.MethodPut)
h.Handle("/users/admin/check", h.Handle("/users/admin/check",
bouncer.PublicAccess(httperror.LoggerHandler(h.adminCheck))).Methods(http.MethodGet) bouncer.PublicAccess(httperror.LoggerHandler(h.adminCheck))).Methods(http.MethodGet)
h.Handle("/users/admin/init", h.Handle("/users/admin/init",

View file

@ -24,11 +24,11 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
Router: mux.NewRouter(), Router: mux.NewRouter(),
} }
h.Handle("/webhooks", h.Handle("/webhooks",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.webhookCreate))).Methods(http.MethodPost) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.webhookCreate))).Methods(http.MethodPost)
h.Handle("/webhooks", h.Handle("/webhooks",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.webhookList))).Methods(http.MethodGet) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.webhookList))).Methods(http.MethodGet)
h.Handle("/webhooks/{id}", h.Handle("/webhooks/{id}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.webhookDelete))).Methods(http.MethodDelete) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.webhookDelete))).Methods(http.MethodDelete)
h.Handle("/webhooks/{token}", h.Handle("/webhooks/{token}",
bouncer.PublicAccess(httperror.LoggerHandler(h.webhookExecute))).Methods(http.MethodPost) bouncer.PublicAccess(httperror.LoggerHandler(h.webhookExecute))).Methods(http.MethodPost)
return h return h

View file

@ -26,8 +26,8 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
requestBouncer: bouncer, requestBouncer: bouncer,
} }
h.PathPrefix("/websocket/exec").Handler( h.PathPrefix("/websocket/exec").Handler(
bouncer.RestrictedAccess(httperror.LoggerHandler(h.websocketExec))) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.websocketExec)))
h.PathPrefix("/websocket/attach").Handler( h.PathPrefix("/websocket/attach").Handler(
bouncer.RestrictedAccess(httperror.LoggerHandler(h.websocketAttach))) bouncer.AuthenticatedAccess(httperror.LoggerHandler(h.websocketAttach)))
return h return h
} }

View file

@ -34,7 +34,7 @@ type (
} }
// RestrictedRequestContext is a data structure containing information // RestrictedRequestContext is a data structure containing information
// used in RestrictedAccess // used in AuthenticatedAccess
RestrictedRequestContext struct { RestrictedRequestContext struct {
IsAdmin bool IsAdmin bool
IsTeamLeader bool IsTeamLeader bool
@ -64,22 +64,40 @@ func (bouncer *RequestBouncer) PublicAccess(h http.Handler) http.Handler {
return h 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. // 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 enabled, authorizations are required to use these endpoints.
// If the RBAC extension is not enabled, the administrator role is 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.mwUpgradeToRestrictedRequest(h)
h = bouncer.mwCheckPortainerAuthorizations(h) h = bouncer.mwCheckPortainerAuthorizations(h, true)
h = bouncer.mwAuthenticatedUser(h) h = bouncer.mwAuthenticatedUser(h)
return h return h
} }
// RestrictedAccess defines a security check for restricted API endpoints. // RestrictedAccess defines a security check for restricted API endpoints.
// Authentication is required to access these 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 // 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 { 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.mwUpgradeToRestrictedRequest(h)
h = bouncer.mwAuthenticatedUser(h) h = bouncer.mwAuthenticatedUser(h)
return 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 // 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 // a specific API endpoint. It will leverage the RBAC extension authorization validation if the extension
// is enabled. // 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) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tokenData, err := RetrieveTokenData(r) tokenData, err := RetrieveTokenData(r)
if err != nil { if err != nil {
httperror.WriteError(w, http.StatusForbidden, "Access denied", portainer.ErrResourceAccessDenied) httperror.WriteError(w, http.StatusForbidden, "Access denied", portainer.ErrUnauthorized)
return return
} }
@ -206,6 +226,11 @@ func (bouncer *RequestBouncer) mwCheckPortainerAuthorizations(next http.Handler)
extension, err := bouncer.extensionService.Extension(portainer.RBACExtension) extension, err := bouncer.extensionService.Extension(portainer.RBACExtension)
if err == portainer.ErrObjectNotFound { if err == portainer.ErrObjectNotFound {
if administratorOnly {
httperror.WriteError(w, http.StatusForbidden, "Access denied", portainer.ErrUnauthorized)
return
}
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
return return
} else if err != nil { } else if err != nil {