mirror of
https://github.com/datarhei/core.git
synced 2025-09-26 20:11:29 +08:00
Fix process and iam enforcing credentials
This commit is contained in:
@@ -122,6 +122,7 @@ func (r *ProcessReport) Marshal() app.Report {
|
||||
|
||||
type ProcessReportSearchResult struct {
|
||||
ProcessID string `json:"id"`
|
||||
Domain string `json:"domain"`
|
||||
Reference string `json:"reference"`
|
||||
ExitState string `json:"exit_state"`
|
||||
CreatedAt int64 `json:"created_at" format:"int64"`
|
||||
|
@@ -22,7 +22,6 @@ import (
|
||||
// @Tags v16.?.?
|
||||
// @ID cluster-3-get-all-processes
|
||||
// @Produce json
|
||||
// @Param domain query string false "Domain to act on"
|
||||
// @Param filter query string false "Comma separated list of fields (config, state, report, metadata) that will be part of the output. If empty, all fields will be part of the output."
|
||||
// @Param reference query string false "Return only these process that have this reference value. If empty, the reference will be ignored."
|
||||
// @Param id query string false "Comma separated list of process ids to list. Overrides the reference. If empty all IDs will be returned."
|
||||
@@ -40,16 +39,15 @@ func (h *ClusterHandler) ProcessList(c echo.Context) error {
|
||||
wantids := strings.FieldsFunc(util.DefaultQuery(c, "id", ""), func(r rune) bool {
|
||||
return r == rune(',')
|
||||
})
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
idpattern := util.DefaultQuery(c, "idpattern", "")
|
||||
refpattern := util.DefaultQuery(c, "refpattern", "")
|
||||
ownerpattern := util.DefaultQuery(c, "ownerpattern", "")
|
||||
domainpattern := util.DefaultQuery(c, "domainpattern", "")
|
||||
|
||||
procs := h.proxy.ProcessList(node.ProcessListOptions{
|
||||
ID: wantids,
|
||||
Filter: filter.Slice(),
|
||||
Domain: domain,
|
||||
ID: wantids,
|
||||
Filter: filter.Slice(),
|
||||
//Domain: domain,
|
||||
Reference: reference,
|
||||
IDPattern: idpattern,
|
||||
RefPattern: refpattern,
|
||||
@@ -60,7 +58,7 @@ func (h *ClusterHandler) ProcessList(c echo.Context) error {
|
||||
pmap := map[app.ProcessID]api.Process{}
|
||||
|
||||
for _, p := range procs {
|
||||
if !h.iam.Enforce(ctxuser, domain, "process", p.ID, "read") {
|
||||
if !h.iam.Enforce(ctxuser, p.Domain, "process", p.ID, "read") {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -72,10 +70,10 @@ func (h *ClusterHandler) ProcessList(c echo.Context) error {
|
||||
// Here we have to add those processes that are in the cluster DB and couldn't be deployed
|
||||
{
|
||||
processes := h.cluster.Store().ProcessList()
|
||||
filtered := h.getFilteredStoreProcesses(processes, wantids, domain, reference, idpattern, refpattern, ownerpattern, domainpattern)
|
||||
filtered := h.getFilteredStoreProcesses(processes, wantids, reference, idpattern, refpattern, ownerpattern, domainpattern)
|
||||
|
||||
for _, p := range filtered {
|
||||
if !h.iam.Enforce(ctxuser, domain, "process", p.Config.ID, "read") {
|
||||
if !h.iam.Enforce(ctxuser, p.Config.Domain, "process", p.Config.ID, "read") {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -105,7 +103,7 @@ func (h *ClusterHandler) ProcessList(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, processes)
|
||||
}
|
||||
|
||||
func (h *ClusterHandler) getFilteredStoreProcesses(processes []store.Process, wantids []string, _, reference, idpattern, refpattern, ownerpattern, domainpattern string) []store.Process {
|
||||
func (h *ClusterHandler) getFilteredStoreProcesses(processes []store.Process, wantids []string, reference, idpattern, refpattern, ownerpattern, domainpattern string) []store.Process {
|
||||
filtered := []store.Process{}
|
||||
|
||||
count := 0
|
||||
@@ -252,7 +250,6 @@ func (h *ClusterHandler) ProcessGet(c echo.Context) error {
|
||||
// @Router /api/v3/cluster/process [post]
|
||||
func (h *ClusterHandler) ProcessAdd(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
superuser := util.DefaultContext(c, "superuser", false)
|
||||
|
||||
process := api.ProcessConfig{
|
||||
ID: shortuuid.New(),
|
||||
@@ -269,12 +266,6 @@ func (h *ClusterHandler) ProcessAdd(c echo.Context) error {
|
||||
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write this process in domain %s", ctxuser, process.Domain)
|
||||
}
|
||||
|
||||
if !superuser {
|
||||
if !h.iam.Enforce(process.Owner, process.Domain, "process", process.ID, "write") {
|
||||
return api.Err(http.StatusForbidden, "", "user %s is not allowed to write this process in domain %s", process.Owner, process.Domain)
|
||||
}
|
||||
}
|
||||
|
||||
if process.Type != "ffmpeg" {
|
||||
return api.Err(http.StatusBadRequest, "", "unsupported process type: supported process types are: ffmpeg")
|
||||
}
|
||||
@@ -314,7 +305,6 @@ func (h *ClusterHandler) ProcessAdd(c echo.Context) error {
|
||||
// @Router /api/v3/cluster/process/{id} [put]
|
||||
func (h *ClusterHandler) ProcessUpdate(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
superuser := util.DefaultContext(c, "superuser", false)
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
id := util.PathParam(c, "id")
|
||||
|
||||
@@ -348,12 +338,6 @@ func (h *ClusterHandler) ProcessUpdate(c echo.Context) error {
|
||||
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write this process", ctxuser)
|
||||
}
|
||||
|
||||
if !superuser {
|
||||
if !h.iam.Enforce(process.Owner, process.Domain, "process", process.ID, "write") {
|
||||
return api.Err(http.StatusForbidden, "", "user %s is not allowed to write this process", process.Owner)
|
||||
}
|
||||
}
|
||||
|
||||
config, metadata := process.Marshal()
|
||||
|
||||
if err := h.cluster.ProcessUpdate("", pid, config); err != nil {
|
||||
|
@@ -292,13 +292,13 @@ func (h *IAMHandler) UpdateIdentityPolicies(c echo.Context) error {
|
||||
// @Router /api/v3/iam/user [get]
|
||||
func (h *IAMHandler) ListIdentities(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
domain := util.DefaultQuery(c, "domain", "$none")
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
|
||||
identities := h.iam.ListIdentities()
|
||||
|
||||
users := make([]api.IAMUser, len(identities)+1)
|
||||
users := []api.IAMUser{}
|
||||
|
||||
for i, iamuser := range identities {
|
||||
for _, iamuser := range identities {
|
||||
if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "read") {
|
||||
continue
|
||||
}
|
||||
@@ -311,7 +311,9 @@ func (h *IAMHandler) ListIdentities(c echo.Context) error {
|
||||
|
||||
policies := h.iam.ListPolicies(iamuser.Name, "", nil, "", nil)
|
||||
|
||||
users[i].Marshal(iamuser, policies)
|
||||
user := api.IAMUser{}
|
||||
user.Marshal(iamuser, policies)
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
anon := identity.User{
|
||||
@@ -320,7 +322,9 @@ func (h *IAMHandler) ListIdentities(c echo.Context) error {
|
||||
|
||||
policies := h.iam.ListPolicies("$anon", "", nil, "", nil)
|
||||
|
||||
users[len(users)-1].Marshal(anon, policies)
|
||||
user := api.IAMUser{}
|
||||
user.Marshal(anon, policies)
|
||||
users = append(users, user)
|
||||
|
||||
return c.JSON(http.StatusOK, users)
|
||||
}
|
||||
|
@@ -50,7 +50,6 @@ func NewProcess(restream restream.Restreamer, iam iam.IAM) *ProcessHandler {
|
||||
// @Router /api/v3/process [post]
|
||||
func (h *ProcessHandler) Add(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
superuser := util.DefaultContext(c, "superuser", false)
|
||||
|
||||
process := api.ProcessConfig{
|
||||
ID: shortuuid.New(),
|
||||
@@ -67,12 +66,6 @@ func (h *ProcessHandler) Add(c echo.Context) error {
|
||||
return api.Err(http.StatusForbidden, "", "You are not allowed to write this process, check the domain and process ID")
|
||||
}
|
||||
|
||||
if !superuser {
|
||||
if !h.iam.Enforce(process.Owner, process.Domain, "process", process.ID, "write") {
|
||||
return api.Err(http.StatusForbidden, "", "The owner '%s' is not allowed to write this process", process.Owner)
|
||||
}
|
||||
}
|
||||
|
||||
if process.Type != "ffmpeg" {
|
||||
return api.Err(http.StatusBadRequest, "", "unsupported process type, supported process types are: ffmpeg")
|
||||
}
|
||||
@@ -107,7 +100,6 @@ func (h *ProcessHandler) Add(c echo.Context) error {
|
||||
// @Tags v16.7.2
|
||||
// @ID process-3-get-all
|
||||
// @Produce json
|
||||
// @Param domain query string false "Domain to act on"
|
||||
// @Param filter query string false "Comma separated list of fields (config, state, report, metadata) that will be part of the output. If empty, all fields will be part of the output."
|
||||
// @Param reference query string false "Return only these process that have this reference value. If empty, the reference will be ignored."
|
||||
// @Param id query string false "Comma separated list of process ids to list. Overrides the reference. If empty all IDs will be returned."
|
||||
@@ -125,7 +117,6 @@ func (h *ProcessHandler) GetAll(c echo.Context) error {
|
||||
wantids := strings.FieldsFunc(util.DefaultQuery(c, "id", ""), func(r rune) bool {
|
||||
return r == rune(',')
|
||||
})
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
idpattern := util.DefaultQuery(c, "idpattern", "")
|
||||
refpattern := util.DefaultQuery(c, "refpattern", "")
|
||||
ownerpattern := util.DefaultQuery(c, "ownerpattern", "")
|
||||
@@ -157,19 +148,19 @@ func (h *ProcessHandler) GetAll(c echo.Context) error {
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
for i := 0; i < 8; /*runtime.NumCPU()*/ i++ {
|
||||
for range 8 {
|
||||
wg.Add(1)
|
||||
|
||||
go func(idChan <-chan app.ProcessID) {
|
||||
defer wg.Done()
|
||||
|
||||
for id := range idChan {
|
||||
if !h.iam.Enforce(ctxuser, domain, "process", id.ID, "read") {
|
||||
process, err := h.getProcess(id, filter)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
process, err := h.getProcess(id, filter)
|
||||
if err != nil {
|
||||
if !h.iam.Enforce(ctxuser, process.Domain, "process", id.ID, "read") {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -218,7 +209,7 @@ func (h *ProcessHandler) Get(c echo.Context) error {
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
|
||||
if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
|
||||
return api.Err(http.StatusForbidden, "Forbidden")
|
||||
return api.Err(http.StatusForbidden, "")
|
||||
}
|
||||
|
||||
tid := app.ProcessID{
|
||||
@@ -251,7 +242,6 @@ func (h *ProcessHandler) Get(c echo.Context) error {
|
||||
// @Router /api/v3/process/{id} [delete]
|
||||
func (h *ProcessHandler) Delete(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
superuser := util.DefaultContext(c, "superuser", false)
|
||||
id := util.PathParam(c, "id")
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
|
||||
@@ -260,10 +250,8 @@ func (h *ProcessHandler) Delete(c echo.Context) error {
|
||||
Domain: domain,
|
||||
}
|
||||
|
||||
if !superuser {
|
||||
if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
|
||||
return api.Err(http.StatusForbidden, "")
|
||||
}
|
||||
if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
|
||||
return api.Err(http.StatusForbidden, "")
|
||||
}
|
||||
|
||||
if err := h.restream.StopProcess(tid); err != nil {
|
||||
@@ -296,7 +284,6 @@ func (h *ProcessHandler) Delete(c echo.Context) error {
|
||||
// @Router /api/v3/process/{id} [put]
|
||||
func (h *ProcessHandler) Update(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
superuser := util.DefaultContext(c, "superuser", false)
|
||||
domain := util.DefaultQuery(c, "domain", "")
|
||||
id := util.PathParam(c, "id")
|
||||
|
||||
@@ -333,12 +320,6 @@ func (h *ProcessHandler) Update(c echo.Context) error {
|
||||
return api.Err(http.StatusForbidden, "", "You are not allowed to write this process: %s", process.ID)
|
||||
}
|
||||
|
||||
if !superuser {
|
||||
if !h.iam.Enforce(process.Owner, process.Domain, "process", process.ID, "write") {
|
||||
return api.Err(http.StatusForbidden, "", "The owner '%s' is not allowed to write this process: %s", process.Owner, process.ID)
|
||||
}
|
||||
}
|
||||
|
||||
config, metadata := process.Marshal()
|
||||
|
||||
if err := h.restream.UpdateProcess(tid, config); err != nil {
|
||||
@@ -397,15 +378,16 @@ func (h *ProcessHandler) Command(c echo.Context) error {
|
||||
}
|
||||
|
||||
var err error
|
||||
if command.Command == "start" {
|
||||
switch command.Command {
|
||||
case "start":
|
||||
err = h.restream.StartProcess(tid)
|
||||
} else if command.Command == "stop" {
|
||||
case "stop":
|
||||
err = h.restream.StopProcess(tid)
|
||||
} else if command.Command == "restart" {
|
||||
case "restart":
|
||||
err = h.restream.RestartProcess(tid)
|
||||
} else if command.Command == "reload" {
|
||||
case "reload":
|
||||
err = h.restream.ReloadProcess(tid)
|
||||
} else {
|
||||
default:
|
||||
return api.Err(http.StatusBadRequest, "", "unknown command provided: known commands are: start, stop, reload, restart")
|
||||
}
|
||||
|
||||
@@ -673,6 +655,7 @@ func (h *ProcessHandler) SetReport(c echo.Context) error {
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/v3/report/process [get]
|
||||
func (h *ProcessHandler) SearchReportHistory(c echo.Context) error {
|
||||
ctxuser := util.DefaultContext(c, "user", "")
|
||||
idpattern := util.DefaultQuery(c, "idpattern", "")
|
||||
refpattern := util.DefaultQuery(c, "refpattern", "")
|
||||
state := util.DefaultQuery(c, "state", "")
|
||||
@@ -701,13 +684,20 @@ func (h *ProcessHandler) SearchReportHistory(c echo.Context) error {
|
||||
|
||||
result := h.restream.SearchProcessLogHistory(idpattern, refpattern, state, from, to)
|
||||
|
||||
response := make([]api.ProcessReportSearchResult, len(result))
|
||||
for i, b := range result {
|
||||
response[i].ProcessID = b.ProcessID
|
||||
response[i].Reference = b.Reference
|
||||
response[i].ExitState = b.ExitState
|
||||
response[i].CreatedAt = b.CreatedAt.Unix()
|
||||
response[i].ExitedAt = b.ExitedAt.Unix()
|
||||
response := []api.ProcessReportSearchResult{}
|
||||
for _, b := range result {
|
||||
if !h.iam.Enforce(ctxuser, b.Domain, "process", b.ProcessID, "read") {
|
||||
continue
|
||||
}
|
||||
|
||||
response = append(response, api.ProcessReportSearchResult{
|
||||
ProcessID: b.ProcessID,
|
||||
Domain: b.Domain,
|
||||
Reference: b.Reference,
|
||||
ExitState: b.ExitState,
|
||||
CreatedAt: b.CreatedAt.Unix(),
|
||||
ExitedAt: b.ExitedAt.Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, response)
|
||||
@@ -843,43 +833,6 @@ func (h *ProcessHandler) ValidateConfig(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, process)
|
||||
}
|
||||
|
||||
// Skills returns the detected FFmpeg capabilities
|
||||
// @Summary FFmpeg capabilities
|
||||
// @Description List all detected FFmpeg capabilities.
|
||||
// @Tags v16.7.2
|
||||
// @ID skills-3
|
||||
// @Produce json
|
||||
// @Success 200 {object} api.Skills
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/v3/skills [get]
|
||||
func (h *ProcessHandler) Skills(c echo.Context) error {
|
||||
skills := h.restream.Skills()
|
||||
|
||||
apiskills := api.Skills{}
|
||||
apiskills.Unmarshal(skills)
|
||||
|
||||
return c.JSON(http.StatusOK, apiskills)
|
||||
}
|
||||
|
||||
// ReloadSkills will refresh the FFmpeg capabilities
|
||||
// @Summary Refresh FFmpeg capabilities
|
||||
// @Description Refresh the available FFmpeg capabilities.
|
||||
// @Tags v16.7.2
|
||||
// @ID skills-3-reload
|
||||
// @Produce json
|
||||
// @Success 200 {object} api.Skills
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/v3/skills/reload [get]
|
||||
func (h *ProcessHandler) ReloadSkills(c echo.Context) error {
|
||||
h.restream.ReloadSkills()
|
||||
skills := h.restream.Skills()
|
||||
|
||||
apiskills := api.Skills{}
|
||||
apiskills.Unmarshal(skills)
|
||||
|
||||
return c.JSON(http.StatusOK, apiskills)
|
||||
}
|
||||
|
||||
// GetProcessMetadata returns the metadata stored with a process
|
||||
// @Summary Retrieve JSON metadata stored with a process under a key
|
||||
// @Description Retrieve the previously stored JSON metadata under the given key. If the key is empty, all metadata will be returned.
|
||||
@@ -1028,6 +981,43 @@ func (h *ProcessHandler) SetMetadata(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, data)
|
||||
}
|
||||
|
||||
// Skills returns the detected FFmpeg capabilities
|
||||
// @Summary FFmpeg capabilities
|
||||
// @Description List all detected FFmpeg capabilities.
|
||||
// @Tags v16.7.2
|
||||
// @ID skills-3
|
||||
// @Produce json
|
||||
// @Success 200 {object} api.Skills
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/v3/skills [get]
|
||||
func (h *ProcessHandler) Skills(c echo.Context) error {
|
||||
skills := h.restream.Skills()
|
||||
|
||||
apiskills := api.Skills{}
|
||||
apiskills.Unmarshal(skills)
|
||||
|
||||
return c.JSON(http.StatusOK, apiskills)
|
||||
}
|
||||
|
||||
// ReloadSkills will refresh the FFmpeg capabilities
|
||||
// @Summary Refresh FFmpeg capabilities
|
||||
// @Description Refresh the available FFmpeg capabilities.
|
||||
// @Tags v16.7.2
|
||||
// @ID skills-3-reload
|
||||
// @Produce json
|
||||
// @Success 200 {object} api.Skills
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/v3/skills/reload [get]
|
||||
func (h *ProcessHandler) ReloadSkills(c echo.Context) error {
|
||||
h.restream.ReloadSkills()
|
||||
skills := h.restream.Skills()
|
||||
|
||||
apiskills := api.Skills{}
|
||||
apiskills.Unmarshal(skills)
|
||||
|
||||
return c.JSON(http.StatusOK, apiskills)
|
||||
}
|
||||
|
||||
type filter struct {
|
||||
config bool
|
||||
state bool
|
||||
|
Reference in New Issue
Block a user