feat(api): introduces swagger.yml (#1112)
parent
d3e87b2435
commit
92391254bc
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// errorResponse is a generic response for sending a error.
|
||||
|
@ -21,10 +20,3 @@ func WriteErrorResponse(w http.ResponseWriter, err error, code int, logger *log.
|
|||
w.WriteHeader(code)
|
||||
json.NewEncoder(w).Encode(&errorResponse{Err: err.Error()})
|
||||
}
|
||||
|
||||
// WriteMethodNotAllowedResponse writes an error message to the response and sets the Allow header.
|
||||
func WriteMethodNotAllowedResponse(w http.ResponseWriter, allowedMethods []string) {
|
||||
w.Header().Set("Allow", strings.Join(allowedMethods, ", "))
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
json.NewEncoder(w).Encode(&errorResponse{Err: http.StatusText(http.StatusMethodNotAllowed)})
|
||||
}
|
||||
|
|
|
@ -44,17 +44,23 @@ func NewAuthHandler(bouncer *security.RequestBouncer, authDisabled bool) *AuthHa
|
|||
authDisabled: authDisabled,
|
||||
}
|
||||
h.Handle("/auth",
|
||||
bouncer.PublicAccess(http.HandlerFunc(h.handlePostAuth)))
|
||||
bouncer.PublicAccess(http.HandlerFunc(h.handlePostAuth))).Methods(http.MethodPost)
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (handler *AuthHandler) handlePostAuth(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
httperror.WriteMethodNotAllowedResponse(w, []string{http.MethodPost})
|
||||
return
|
||||
type (
|
||||
postAuthRequest struct {
|
||||
Username string `valid:"required"`
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
|
||||
postAuthResponse struct {
|
||||
JWT string `json:"jwt"`
|
||||
}
|
||||
)
|
||||
|
||||
func (handler *AuthHandler) handlePostAuth(w http.ResponseWriter, r *http.Request) {
|
||||
if handler.authDisabled {
|
||||
httperror.WriteErrorResponse(w, ErrAuthDisabled, http.StatusServiceUnavailable, handler.Logger)
|
||||
return
|
||||
|
@ -118,12 +124,3 @@ func (handler *AuthHandler) handlePostAuth(w http.ResponseWriter, r *http.Reques
|
|||
|
||||
encodeJSON(w, &postAuthResponse{JWT: token}, handler.Logger)
|
||||
}
|
||||
|
||||
type postAuthRequest struct {
|
||||
Username string `valid:"required"`
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
|
||||
type postAuthResponse struct {
|
||||
JWT string `json:"jwt"`
|
||||
}
|
||||
|
|
|
@ -22,20 +22,28 @@ type DockerHubHandler struct {
|
|||
DockerHubService portainer.DockerHubService
|
||||
}
|
||||
|
||||
// NewDockerHubHandler returns a new instance of OldDockerHubHandler.
|
||||
// NewDockerHubHandler returns a new instance of NewDockerHubHandler.
|
||||
func NewDockerHubHandler(bouncer *security.RequestBouncer) *DockerHubHandler {
|
||||
h := &DockerHubHandler{
|
||||
Router: mux.NewRouter(),
|
||||
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
||||
}
|
||||
h.Handle("/dockerhub",
|
||||
bouncer.PublicAccess(http.HandlerFunc(h.handleGetDockerHub))).Methods(http.MethodGet)
|
||||
bouncer.AuthenticatedAccess(http.HandlerFunc(h.handleGetDockerHub))).Methods(http.MethodGet)
|
||||
h.Handle("/dockerhub",
|
||||
bouncer.AdministratorAccess(http.HandlerFunc(h.handlePutDockerHub))).Methods(http.MethodPut)
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
type (
|
||||
putDockerHubRequest struct {
|
||||
Authentication bool `valid:""`
|
||||
Username string `valid:""`
|
||||
Password string `valid:""`
|
||||
}
|
||||
)
|
||||
|
||||
// handleGetDockerHub handles GET requests on /dockerhub
|
||||
func (handler *DockerHubHandler) handleGetDockerHub(w http.ResponseWriter, r *http.Request) {
|
||||
dockerhub, err := handler.DockerHubService.DockerHub()
|
||||
|
@ -79,9 +87,3 @@ func (handler *DockerHubHandler) handlePutDockerHub(w http.ResponseWriter, r *ht
|
|||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
}
|
||||
}
|
||||
|
||||
type putDockerHubRequest struct {
|
||||
Authentication bool `valid:""`
|
||||
Username string `valid:""`
|
||||
Password string `valid:""`
|
||||
}
|
||||
|
|
|
@ -55,6 +55,31 @@ func NewEndpointHandler(bouncer *security.RequestBouncer, authorizeEndpointManag
|
|||
return h
|
||||
}
|
||||
|
||||
type (
|
||||
postEndpointsRequest struct {
|
||||
Name string `valid:"required"`
|
||||
URL string `valid:"required"`
|
||||
PublicURL string `valid:"-"`
|
||||
TLS bool
|
||||
}
|
||||
|
||||
postEndpointsResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
putEndpointAccessRequest struct {
|
||||
AuthorizedUsers []int `valid:"-"`
|
||||
AuthorizedTeams []int `valid:"-"`
|
||||
}
|
||||
|
||||
putEndpointsRequest struct {
|
||||
Name string `valid:"-"`
|
||||
URL string `valid:"-"`
|
||||
PublicURL string `valid:"-"`
|
||||
TLS bool `valid:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
// handleGetEndpoints handles GET requests on /endpoints
|
||||
func (handler *EndpointHandler) handleGetEndpoints(w http.ResponseWriter, r *http.Request) {
|
||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||
|
@ -130,17 +155,6 @@ func (handler *EndpointHandler) handlePostEndpoints(w http.ResponseWriter, r *ht
|
|||
encodeJSON(w, &postEndpointsResponse{ID: int(endpoint.ID)}, handler.Logger)
|
||||
}
|
||||
|
||||
type postEndpointsRequest struct {
|
||||
Name string `valid:"required"`
|
||||
URL string `valid:"required"`
|
||||
PublicURL string `valid:"-"`
|
||||
TLS bool
|
||||
}
|
||||
|
||||
type postEndpointsResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
// handleGetEndpoint handles GET requests on /endpoints/:id
|
||||
func (handler *EndpointHandler) handleGetEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
@ -219,11 +233,6 @@ func (handler *EndpointHandler) handlePutEndpointAccess(w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
type putEndpointAccessRequest struct {
|
||||
AuthorizedUsers []int `valid:"-"`
|
||||
AuthorizedTeams []int `valid:"-"`
|
||||
}
|
||||
|
||||
// handlePutEndpoint handles PUT requests on /endpoints/:id
|
||||
func (handler *EndpointHandler) handlePutEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
if !handler.authorizeEndpointManagement {
|
||||
|
@ -307,13 +316,6 @@ func (handler *EndpointHandler) handlePutEndpoint(w http.ResponseWriter, r *http
|
|||
}
|
||||
}
|
||||
|
||||
type putEndpointsRequest struct {
|
||||
Name string `valid:"-"`
|
||||
URL string `valid:"-"`
|
||||
PublicURL string `valid:"-"`
|
||||
TLS bool `valid:"-"`
|
||||
}
|
||||
|
||||
// handleDeleteEndpoint handles DELETE requests on /endpoints/:id
|
||||
func (handler *EndpointHandler) handleDeleteEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
if !handler.authorizeEndpointManagement {
|
||||
|
|
|
@ -36,48 +36,48 @@ const (
|
|||
ErrInvalidRequestFormat = portainer.Error("Invalid request data format")
|
||||
// ErrInvalidQueryFormat defines an error raised when the data sent in the query or the URL is invalid
|
||||
ErrInvalidQueryFormat = portainer.Error("Invalid query format")
|
||||
// ErrEmptyResponseBody defines an error raised when portainer excepts to parse the body of a HTTP response and there is nothing to parse
|
||||
// ErrEmptyResponseBody = portainer.Error("Empty response body")
|
||||
)
|
||||
|
||||
// ServeHTTP delegates a request to the appropriate subhandler.
|
||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.HasPrefix(r.URL.Path, "/api/auth") {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/auth"):
|
||||
http.StripPrefix("/api", h.AuthHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/users") {
|
||||
http.StripPrefix("/api", h.UserHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/teams") {
|
||||
http.StripPrefix("/api", h.TeamHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/team_memberships") {
|
||||
http.StripPrefix("/api", h.TeamMembershipHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/endpoints") {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/dockerhub"):
|
||||
http.StripPrefix("/api", h.DockerHubHandler).ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api/endpoints"):
|
||||
if strings.Contains(r.URL.Path, "/docker") {
|
||||
http.StripPrefix("/api/endpoints", h.DockerHandler).ServeHTTP(w, r)
|
||||
} else {
|
||||
http.StripPrefix("/api", h.EndpointHandler).ServeHTTP(w, r)
|
||||
}
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/registries") {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/registries"):
|
||||
http.StripPrefix("/api", h.RegistryHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/dockerhub") {
|
||||
http.StripPrefix("/api", h.DockerHubHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/resource_controls") {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/resource_controls"):
|
||||
http.StripPrefix("/api", h.ResourceHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/settings") {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/settings"):
|
||||
http.StripPrefix("/api", h.SettingsHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/status") {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/status"):
|
||||
http.StripPrefix("/api", h.StatusHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/templates") {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/templates"):
|
||||
http.StripPrefix("/api", h.TemplatesHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/upload") {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/upload"):
|
||||
http.StripPrefix("/api", h.UploadHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/api/websocket") {
|
||||
case strings.HasPrefix(r.URL.Path, "/api/users"):
|
||||
http.StripPrefix("/api", h.UserHandler).ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api/teams"):
|
||||
http.StripPrefix("/api", h.TeamHandler).ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api/team_memberships"):
|
||||
http.StripPrefix("/api", h.TeamMembershipHandler).ServeHTTP(w, r)
|
||||
case strings.HasPrefix(r.URL.Path, "/api/websocket"):
|
||||
http.StripPrefix("/api", h.WebSocketHandler).ServeHTTP(w, r)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/") {
|
||||
case strings.HasPrefix(r.URL.Path, "/"):
|
||||
h.FileHandler.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// encodeJSON encodes v to w in JSON format. Error() is called if encoding fails.
|
||||
// encodeJSON encodes v to w in JSON format. WriteErrorResponse() is called if encoding fails.
|
||||
func encodeJSON(w http.ResponseWriter, v interface{}, logger *log.Logger) {
|
||||
if err := json.NewEncoder(w).Encode(v); err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, logger)
|
||||
|
|
|
@ -44,6 +44,33 @@ func NewRegistryHandler(bouncer *security.RequestBouncer) *RegistryHandler {
|
|||
return h
|
||||
}
|
||||
|
||||
type (
|
||||
postRegistriesRequest struct {
|
||||
Name string `valid:"required"`
|
||||
URL string `valid:"required"`
|
||||
Authentication bool `valid:""`
|
||||
Username string `valid:""`
|
||||
Password string `valid:""`
|
||||
}
|
||||
|
||||
postRegistriesResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
putRegistryAccessRequest struct {
|
||||
AuthorizedUsers []int `valid:"-"`
|
||||
AuthorizedTeams []int `valid:"-"`
|
||||
}
|
||||
|
||||
putRegistriesRequest struct {
|
||||
Name string `valid:"required"`
|
||||
URL string `valid:"required"`
|
||||
Authentication bool `valid:""`
|
||||
Username string `valid:""`
|
||||
Password string `valid:""`
|
||||
}
|
||||
)
|
||||
|
||||
// handleGetRegistries handles GET requests on /registries
|
||||
func (handler *RegistryHandler) handleGetRegistries(w http.ResponseWriter, r *http.Request) {
|
||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||
|
@ -112,18 +139,6 @@ func (handler *RegistryHandler) handlePostRegistries(w http.ResponseWriter, r *h
|
|||
encodeJSON(w, &postRegistriesResponse{ID: int(registry.ID)}, handler.Logger)
|
||||
}
|
||||
|
||||
type postRegistriesRequest struct {
|
||||
Name string `valid:"required"`
|
||||
URL string `valid:"required"`
|
||||
Authentication bool `valid:""`
|
||||
Username string `valid:""`
|
||||
Password string `valid:""`
|
||||
}
|
||||
|
||||
type postRegistriesResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
// handleGetRegistry handles GET requests on /registries/:id
|
||||
func (handler *RegistryHandler) handleGetRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
@ -202,11 +217,6 @@ func (handler *RegistryHandler) handlePutRegistryAccess(w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
type putRegistryAccessRequest struct {
|
||||
AuthorizedUsers []int `valid:"-"`
|
||||
AuthorizedTeams []int `valid:"-"`
|
||||
}
|
||||
|
||||
// handlePutRegistry handles PUT requests on /registries/:id
|
||||
func (handler *RegistryHandler) handlePutRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
@ -276,14 +286,6 @@ func (handler *RegistryHandler) handlePutRegistry(w http.ResponseWriter, r *http
|
|||
}
|
||||
}
|
||||
|
||||
type putRegistriesRequest struct {
|
||||
Name string `valid:"required"`
|
||||
URL string `valid:"required"`
|
||||
Authentication bool `valid:""`
|
||||
Username string `valid:""`
|
||||
Password string `valid:""`
|
||||
}
|
||||
|
||||
// handleDeleteRegistry handles DELETE requests on /registries/:id
|
||||
func (handler *RegistryHandler) handleDeleteRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
|
|
@ -39,6 +39,23 @@ func NewResourceHandler(bouncer *security.RequestBouncer) *ResourceHandler {
|
|||
return h
|
||||
}
|
||||
|
||||
type (
|
||||
postResourcesRequest struct {
|
||||
ResourceID string `valid:"required"`
|
||||
Type string `valid:"required"`
|
||||
AdministratorsOnly bool `valid:"-"`
|
||||
Users []int `valid:"-"`
|
||||
Teams []int `valid:"-"`
|
||||
SubResourceIDs []string `valid:"-"`
|
||||
}
|
||||
|
||||
putResourcesRequest struct {
|
||||
AdministratorsOnly bool `valid:"-"`
|
||||
Users []int `valid:"-"`
|
||||
Teams []int `valid:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
// handlePostResources handles POST requests on /resources
|
||||
func (handler *ResourceHandler) handlePostResources(w http.ResponseWriter, r *http.Request) {
|
||||
var req postResourcesRequest
|
||||
|
@ -121,22 +138,13 @@ func (handler *ResourceHandler) handlePostResources(w http.ResponseWriter, r *ht
|
|||
|
||||
err = handler.ResourceControlService.CreateResourceControl(&resourceControl)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type postResourcesRequest struct {
|
||||
ResourceID string `valid:"required"`
|
||||
Type string `valid:"required"`
|
||||
AdministratorsOnly bool `valid:"-"`
|
||||
Users []int `valid:"-"`
|
||||
Teams []int `valid:"-"`
|
||||
SubResourceIDs []string `valid:"-"`
|
||||
}
|
||||
|
||||
// handlePutResources handles PUT requests on /resources/:id
|
||||
func (handler *ResourceHandler) handlePutResources(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
@ -210,12 +218,6 @@ func (handler *ResourceHandler) handlePutResources(w http.ResponseWriter, r *htt
|
|||
}
|
||||
}
|
||||
|
||||
type putResourcesRequest struct {
|
||||
AdministratorsOnly bool `valid:"-"`
|
||||
Users []int `valid:"-"`
|
||||
Teams []int `valid:"-"`
|
||||
}
|
||||
|
||||
// handleDeleteResources handles DELETE requests on /resources/:id
|
||||
func (handler *ResourceHandler) handleDeleteResources(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
|
|
@ -43,6 +43,27 @@ func NewSettingsHandler(bouncer *security.RequestBouncer) *SettingsHandler {
|
|||
return h
|
||||
}
|
||||
|
||||
type (
|
||||
publicSettingsResponse struct {
|
||||
LogoURL string `json:"LogoURL"`
|
||||
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
||||
AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"`
|
||||
}
|
||||
|
||||
putSettingsRequest struct {
|
||||
TemplatesURL string `valid:"required"`
|
||||
LogoURL string `valid:""`
|
||||
BlackListedLabels []portainer.Pair `valid:""`
|
||||
DisplayExternalContributors bool `valid:""`
|
||||
AuthenticationMethod int `valid:"required"`
|
||||
LDAPSettings portainer.LDAPSettings `valid:""`
|
||||
}
|
||||
|
||||
putSettingsLDAPCheckRequest struct {
|
||||
LDAPSettings portainer.LDAPSettings `valid:""`
|
||||
}
|
||||
)
|
||||
|
||||
// handleGetSettings handles GET requests on /settings
|
||||
func (handler *SettingsHandler) handleGetSettings(w http.ResponseWriter, r *http.Request) {
|
||||
settings, err := handler.SettingsService.Settings()
|
||||
|
@ -73,12 +94,6 @@ func (handler *SettingsHandler) handleGetPublicSettings(w http.ResponseWriter, r
|
|||
return
|
||||
}
|
||||
|
||||
type publicSettingsResponse struct {
|
||||
LogoURL string `json:"LogoURL"`
|
||||
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
||||
AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"`
|
||||
}
|
||||
|
||||
// handlePutSettings handles PUT requests on /settings
|
||||
func (handler *SettingsHandler) handlePutSettings(w http.ResponseWriter, r *http.Request) {
|
||||
var req putSettingsRequest
|
||||
|
@ -127,15 +142,6 @@ func (handler *SettingsHandler) handlePutSettings(w http.ResponseWriter, r *http
|
|||
}
|
||||
}
|
||||
|
||||
type putSettingsRequest struct {
|
||||
TemplatesURL string `valid:"required"`
|
||||
LogoURL string `valid:""`
|
||||
BlackListedLabels []portainer.Pair `valid:""`
|
||||
DisplayExternalContributors bool `valid:""`
|
||||
AuthenticationMethod int `valid:"required"`
|
||||
LDAPSettings portainer.LDAPSettings `valid:""`
|
||||
}
|
||||
|
||||
// handlePutSettingsLDAPCheck handles PUT requests on /settings/ldap/check
|
||||
func (handler *SettingsHandler) handlePutSettingsLDAPCheck(w http.ResponseWriter, r *http.Request) {
|
||||
var req putSettingsLDAPCheckRequest
|
||||
|
@ -161,7 +167,3 @@ func (handler *SettingsHandler) handlePutSettingsLDAPCheck(w http.ResponseWriter
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
type putSettingsLDAPCheckRequest struct {
|
||||
LDAPSettings portainer.LDAPSettings `valid:""`
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func NewTeamHandler(bouncer *security.RequestBouncer) *TeamHandler {
|
|||
h.Handle("/teams",
|
||||
bouncer.AdministratorAccess(http.HandlerFunc(h.handlePostTeams))).Methods(http.MethodPost)
|
||||
h.Handle("/teams",
|
||||
bouncer.AuthenticatedAccess(http.HandlerFunc(h.handleGetTeams))).Methods(http.MethodGet)
|
||||
bouncer.RestrictedAccess(http.HandlerFunc(h.handleGetTeams))).Methods(http.MethodGet)
|
||||
h.Handle("/teams/{id}",
|
||||
bouncer.RestrictedAccess(http.HandlerFunc(h.handleGetTeam))).Methods(http.MethodGet)
|
||||
h.Handle("/teams/{id}",
|
||||
|
@ -47,6 +47,20 @@ func NewTeamHandler(bouncer *security.RequestBouncer) *TeamHandler {
|
|||
return h
|
||||
}
|
||||
|
||||
type (
|
||||
postTeamsRequest struct {
|
||||
Name string `valid:"required"`
|
||||
}
|
||||
|
||||
postTeamsResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
putTeamRequest struct {
|
||||
Name string `valid:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
// handlePostTeams handles POST requests on /teams
|
||||
func (handler *TeamHandler) handlePostTeams(w http.ResponseWriter, r *http.Request) {
|
||||
var req postTeamsRequest
|
||||
|
@ -84,23 +98,23 @@ func (handler *TeamHandler) handlePostTeams(w http.ResponseWriter, r *http.Reque
|
|||
encodeJSON(w, &postTeamsResponse{ID: int(team.ID)}, handler.Logger)
|
||||
}
|
||||
|
||||
type postTeamsResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
type postTeamsRequest struct {
|
||||
Name string `valid:"required"`
|
||||
}
|
||||
|
||||
// handleGetTeams handles GET requests on /teams
|
||||
func (handler *TeamHandler) handleGetTeams(w http.ResponseWriter, r *http.Request) {
|
||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
teams, err := handler.TeamService.Teams()
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
encodeJSON(w, teams, handler.Logger)
|
||||
filteredTeams := security.FilterUserTeams(teams, securityContext)
|
||||
|
||||
encodeJSON(w, filteredTeams, handler.Logger)
|
||||
}
|
||||
|
||||
// handleGetTeam handles GET requests on /teams/:id
|
||||
|
@ -181,10 +195,6 @@ func (handler *TeamHandler) handlePutTeam(w http.ResponseWriter, r *http.Request
|
|||
}
|
||||
}
|
||||
|
||||
type putTeamRequest struct {
|
||||
Name string `valid:"-"`
|
||||
}
|
||||
|
||||
// handleDeleteTeam handles DELETE requests on /teams/:id
|
||||
func (handler *TeamHandler) handleDeleteTeam(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
|
|
@ -42,6 +42,24 @@ func NewTeamMembershipHandler(bouncer *security.RequestBouncer) *TeamMembershipH
|
|||
return h
|
||||
}
|
||||
|
||||
type (
|
||||
postTeamMembershipsRequest struct {
|
||||
UserID int `valid:"required"`
|
||||
TeamID int `valid:"required"`
|
||||
Role int `valid:"required"`
|
||||
}
|
||||
|
||||
postTeamMembershipsResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
putTeamMembershipRequest struct {
|
||||
UserID int `valid:"required"`
|
||||
TeamID int `valid:"required"`
|
||||
Role int `valid:"required"`
|
||||
}
|
||||
)
|
||||
|
||||
// handlePostTeamMemberships handles POST requests on /team_memberships
|
||||
func (handler *TeamMembershipHandler) handlePostTeamMemberships(w http.ResponseWriter, r *http.Request) {
|
||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||
|
@ -100,16 +118,6 @@ func (handler *TeamMembershipHandler) handlePostTeamMemberships(w http.ResponseW
|
|||
encodeJSON(w, &postTeamMembershipsResponse{ID: int(membership.ID)}, handler.Logger)
|
||||
}
|
||||
|
||||
type postTeamMembershipsResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
type postTeamMembershipsRequest struct {
|
||||
UserID int `valid:"required"`
|
||||
TeamID int `valid:"required"`
|
||||
Role int `valid:"required"`
|
||||
}
|
||||
|
||||
// handleGetTeamsMemberships handles GET requests on /team_memberships
|
||||
func (handler *TeamMembershipHandler) handleGetTeamsMemberships(w http.ResponseWriter, r *http.Request) {
|
||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||
|
@ -195,12 +203,6 @@ func (handler *TeamMembershipHandler) handlePutTeamMembership(w http.ResponseWri
|
|||
}
|
||||
}
|
||||
|
||||
type putTeamMembershipRequest struct {
|
||||
UserID int `valid:"required"`
|
||||
TeamID int `valid:"required"`
|
||||
Role int `valid:"required"`
|
||||
}
|
||||
|
||||
// handleDeleteTeamMembership handles DELETE requests on /team_memberships/:id
|
||||
func (handler *TeamMembershipHandler) handleDeleteTeamMembership(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
|
|
@ -30,17 +30,12 @@ func NewTemplatesHandler(bouncer *security.RequestBouncer) *TemplatesHandler {
|
|||
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
||||
}
|
||||
h.Handle("/templates",
|
||||
bouncer.AuthenticatedAccess(http.HandlerFunc(h.handleGetTemplates)))
|
||||
bouncer.AuthenticatedAccess(http.HandlerFunc(h.handleGetTemplates))).Methods(http.MethodGet)
|
||||
return h
|
||||
}
|
||||
|
||||
// handleGetTemplates handles GET requests on /templates?key=<key>
|
||||
func (handler *TemplatesHandler) handleGetTemplates(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
httperror.WriteMethodNotAllowedResponse(w, []string{http.MethodGet})
|
||||
return
|
||||
}
|
||||
|
||||
key := r.FormValue("key")
|
||||
if key == "" {
|
||||
httperror.WriteErrorResponse(w, ErrInvalidQueryFormat, http.StatusBadRequest, handler.Logger)
|
||||
|
|
|
@ -26,17 +26,12 @@ func NewUploadHandler(bouncer *security.RequestBouncer) *UploadHandler {
|
|||
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
||||
}
|
||||
h.Handle("/upload/tls/{certificate:(?:ca|cert|key)}",
|
||||
bouncer.AuthenticatedAccess(http.HandlerFunc(h.handlePostUploadTLS)))
|
||||
bouncer.AdministratorAccess(http.HandlerFunc(h.handlePostUploadTLS))).Methods(http.MethodPost)
|
||||
return h
|
||||
}
|
||||
|
||||
// handlePostUploadTLS handles POST requests on /upload/tls/{certificate:(?:ca|cert|key)}?folder=folder
|
||||
func (handler *UploadHandler) handlePostUploadTLS(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
httperror.WriteMethodNotAllowedResponse(w, []string{http.MethodPost})
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
certificate := vars["certificate"]
|
||||
|
||||
|
|
|
@ -47,18 +47,45 @@ func NewUserHandler(bouncer *security.RequestBouncer) *UserHandler {
|
|||
bouncer.AdministratorAccess(http.HandlerFunc(h.handleDeleteUser))).Methods(http.MethodDelete)
|
||||
h.Handle("/users/{id}/memberships",
|
||||
bouncer.AuthenticatedAccess(http.HandlerFunc(h.handleGetMemberships))).Methods(http.MethodGet)
|
||||
h.Handle("/users/{id}/teams",
|
||||
bouncer.RestrictedAccess(http.HandlerFunc(h.handleGetTeams))).Methods(http.MethodGet)
|
||||
h.Handle("/users/{id}/passwd",
|
||||
bouncer.AuthenticatedAccess(http.HandlerFunc(h.handlePostUserPasswd)))
|
||||
bouncer.AuthenticatedAccess(http.HandlerFunc(h.handlePostUserPasswd))).Methods(http.MethodPost)
|
||||
h.Handle("/users/admin/check",
|
||||
bouncer.PublicAccess(http.HandlerFunc(h.handleGetAdminCheck)))
|
||||
bouncer.PublicAccess(http.HandlerFunc(h.handleGetAdminCheck))).Methods(http.MethodGet)
|
||||
h.Handle("/users/admin/init",
|
||||
bouncer.PublicAccess(http.HandlerFunc(h.handlePostAdminInit)))
|
||||
bouncer.PublicAccess(http.HandlerFunc(h.handlePostAdminInit))).Methods(http.MethodPost)
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
type (
|
||||
postUsersRequest struct {
|
||||
Username string `valid:"required"`
|
||||
Password string `valid:""`
|
||||
Role int `valid:"required"`
|
||||
}
|
||||
|
||||
postUsersResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
postUserPasswdRequest struct {
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
|
||||
postUserPasswdResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
putUserRequest struct {
|
||||
Password string `valid:"-"`
|
||||
Role int `valid:"-"`
|
||||
}
|
||||
|
||||
postAdminInitRequest struct {
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
)
|
||||
|
||||
// handlePostUsers handles POST requests on /users
|
||||
func (handler *UserHandler) handlePostUsers(w http.ResponseWriter, r *http.Request) {
|
||||
var req postUsersRequest
|
||||
|
@ -139,16 +166,6 @@ func (handler *UserHandler) handlePostUsers(w http.ResponseWriter, r *http.Reque
|
|||
encodeJSON(w, &postUsersResponse{ID: int(user.ID)}, handler.Logger)
|
||||
}
|
||||
|
||||
type postUsersResponse struct {
|
||||
ID int `json:"Id"`
|
||||
}
|
||||
|
||||
type postUsersRequest struct {
|
||||
Username string `valid:"required"`
|
||||
Password string `valid:""`
|
||||
Role int `valid:"required"`
|
||||
}
|
||||
|
||||
// handleGetUsers handles GET requests on /users
|
||||
func (handler *UserHandler) handleGetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||
|
@ -174,11 +191,6 @@ func (handler *UserHandler) handleGetUsers(w http.ResponseWriter, r *http.Reques
|
|||
|
||||
// handlePostUserPasswd handles POST requests on /users/:id/passwd
|
||||
func (handler *UserHandler) handlePostUserPasswd(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
httperror.WriteMethodNotAllowedResponse(w, []string{http.MethodPost})
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
|
||||
|
@ -220,14 +232,6 @@ func (handler *UserHandler) handlePostUserPasswd(w http.ResponseWriter, r *http.
|
|||
encodeJSON(w, &postUserPasswdResponse{Valid: valid}, handler.Logger)
|
||||
}
|
||||
|
||||
type postUserPasswdRequest struct {
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
|
||||
type postUserPasswdResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
// handleGetUser handles GET requests on /users/:id
|
||||
func (handler *UserHandler) handleGetUser(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
@ -327,18 +331,8 @@ func (handler *UserHandler) handlePutUser(w http.ResponseWriter, r *http.Request
|
|||
}
|
||||
}
|
||||
|
||||
type putUserRequest struct {
|
||||
Password string `valid:"-"`
|
||||
Role int `valid:"-"`
|
||||
}
|
||||
|
||||
// handlePostAdminInit handles GET requests on /users/admin/check
|
||||
// handleGetAdminCheck handles GET requests on /users/admin/check
|
||||
func (handler *UserHandler) handleGetAdminCheck(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
httperror.WriteMethodNotAllowedResponse(w, []string{http.MethodGet})
|
||||
return
|
||||
}
|
||||
|
||||
users, err := handler.UserService.UsersByRole(portainer.AdministratorRole)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
|
@ -352,11 +346,6 @@ func (handler *UserHandler) handleGetAdminCheck(w http.ResponseWriter, r *http.R
|
|||
|
||||
// handlePostAdminInit handles POST requests on /users/admin/init
|
||||
func (handler *UserHandler) handlePostAdminInit(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
httperror.WriteMethodNotAllowedResponse(w, []string{http.MethodPost})
|
||||
return
|
||||
}
|
||||
|
||||
var req postAdminInitRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
httperror.WriteErrorResponse(w, ErrInvalidJSON, http.StatusBadRequest, handler.Logger)
|
||||
|
@ -391,15 +380,11 @@ func (handler *UserHandler) handlePostAdminInit(w http.ResponseWriter, r *http.R
|
|||
return
|
||||
}
|
||||
if user != nil {
|
||||
httperror.WriteErrorResponse(w, portainer.ErrAdminAlreadyInitialized, http.StatusForbidden, handler.Logger)
|
||||
httperror.WriteErrorResponse(w, portainer.ErrAdminAlreadyInitialized, http.StatusConflict, handler.Logger)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type postAdminInitRequest struct {
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
|
||||
// handleDeleteUser handles DELETE requests on /users/:id
|
||||
func (handler *UserHandler) handleDeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
@ -464,37 +449,3 @@ func (handler *UserHandler) handleGetMemberships(w http.ResponseWriter, r *http.
|
|||
|
||||
encodeJSON(w, memberships, handler.Logger)
|
||||
}
|
||||
|
||||
// handleGetTeams handles GET requests on /users/:id/teams
|
||||
func (handler *UserHandler) handleGetTeams(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
|
||||
uid, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
userID := portainer.UserID(uid)
|
||||
|
||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
if !security.AuthorizedUserManagement(userID, securityContext) {
|
||||
httperror.WriteErrorResponse(w, portainer.ErrResourceAccessDenied, http.StatusForbidden, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
teams, err := handler.TeamService.Teams()
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
filteredTeams := security.FilterUserTeams(teams, securityContext)
|
||||
|
||||
encodeJSON(w, filteredTeams, handler.Logger)
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func (bouncer *RequestBouncer) AuthenticatedAccess(h http.Handler) http.Handler
|
|||
return h
|
||||
}
|
||||
|
||||
// RestrictedAccess defines defines a security check for restricted endpoints.
|
||||
// RestrictedAccess defines a security check for restricted endpoints.
|
||||
// Authentication is required to access these endpoints.
|
||||
// The request context will be enhanced with a RestrictedRequestContext object
|
||||
// that might be used later to authorize/filter access to resources.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
angular.module('portainer')
|
||||
.controller('porAccessControlFormController', ['$q', 'UserService', 'Notifications', 'Authentication', 'ResourceControlService',
|
||||
function ($q, UserService, Notifications, Authentication, ResourceControlService) {
|
||||
.controller('porAccessControlFormController', ['$q', 'UserService', 'TeamService', 'Notifications', 'Authentication', 'ResourceControlService',
|
||||
function ($q, UserService, TeamService, Notifications, Authentication, ResourceControlService) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.availableTeams = [];
|
||||
|
@ -42,7 +42,7 @@ function ($q, UserService, Notifications, Authentication, ResourceControlService
|
|||
}
|
||||
|
||||
$q.all({
|
||||
availableTeams: UserService.userTeams(userDetails.ID),
|
||||
availableTeams: TeamService.teams(),
|
||||
availableUsers: isAdmin ? UserService.users(false) : []
|
||||
})
|
||||
.then(function success(data) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
angular.module('portainer')
|
||||
.controller('porAccessControlPanelController', ['$q', '$state', 'UserService', 'ResourceControlService', 'Notifications', 'Authentication', 'ModalService', 'FormValidator',
|
||||
function ($q, $state, UserService, ResourceControlService, Notifications, Authentication, ModalService, FormValidator) {
|
||||
.controller('porAccessControlPanelController', ['$q', '$state', 'UserService', 'TeamService', 'ResourceControlService', 'Notifications', 'Authentication', 'ModalService', 'FormValidator',
|
||||
function ($q, $state, UserService, TeamService, ResourceControlService, Notifications, Authentication, ModalService, FormValidator) {
|
||||
|
||||
var ctrl = this;
|
||||
|
||||
|
@ -121,7 +121,7 @@ function ($q, $state, UserService, ResourceControlService, Notifications, Authen
|
|||
|
||||
return $q.all({
|
||||
availableUsers: isAdmin ? UserService.users(false) : [],
|
||||
availableTeams: isAdmin || data.isPartOfRestrictedUsers ? UserService.userTeams(userId) : []
|
||||
availableTeams: isAdmin || data.isPartOfRestrictedUsers ? TeamService.teams() : []
|
||||
});
|
||||
})
|
||||
.then(function success(data) {
|
||||
|
|
|
@ -8,7 +8,6 @@ angular.module('portainer.rest')
|
|||
update: { method: 'PUT', params: { id: '@id' } },
|
||||
remove: { method: 'DELETE', params: { id: '@id'} },
|
||||
queryMemberships: { method: 'GET', isArray: true, params: { id: '@id', entity: 'memberships' } },
|
||||
queryTeams: { method: 'GET', isArray: true, params: { id: '@id', entity: 'teams' } },
|
||||
// RPCs should be moved to a specific endpoint
|
||||
checkPassword: { method: 'POST', params: { id: '@id', entity: 'passwd' } },
|
||||
checkAdminUser: { method: 'GET', params: { id: 'admin', entity: 'check' }, isArray: true },
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
angular.module('portainer.services')
|
||||
.factory('UserService', ['$q', 'Users', 'UserHelper', 'TeamMembershipService', function UserServiceFactory($q, Users, UserHelper, TeamMembershipService) {
|
||||
.factory('UserService', ['$q', 'Users', 'UserHelper', 'TeamService', 'TeamMembershipService', function UserServiceFactory($q, Users, UserHelper, TeamService, TeamMembershipService) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
|
||||
|
@ -110,28 +110,11 @@ angular.module('portainer.services')
|
|||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.userTeams = function(id) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
Users.queryTeams({id: id}).$promise
|
||||
.then(function success(data) {
|
||||
var teams = data.map(function (item) {
|
||||
return new TeamViewModel(item);
|
||||
});
|
||||
deferred.resolve(teams);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject({ msg: 'Unable to retrieve user teams', err: err });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.userLeadingTeams = function(id) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
$q.all({
|
||||
teams: service.userTeams(id),
|
||||
teams: TeamService.teams(),
|
||||
memberships: service.userMemberships(id)
|
||||
})
|
||||
.then(function success(data) {
|
||||
|
|
Loading…
Reference in New Issue