Separate resource type and resource for IAM policies

This commit is contained in:
Ingo Oppermann
2023-09-18 17:11:09 +02:00
parent 8349f4ebe3
commit ad2a50df6f
30 changed files with 283 additions and 186 deletions

View File

@@ -696,19 +696,22 @@ func (a *api) start(ctx context.Context) error {
{ {
Name: "$anon", Name: "$anon",
Domain: "$none", Domain: "$none",
Resource: "fs:/**", Types: []string{"fs"},
Resource: "/**",
Actions: []string{"GET", "HEAD", "OPTIONS"}, Actions: []string{"GET", "HEAD", "OPTIONS"},
}, },
{ {
Name: "$anon", Name: "$anon",
Domain: "$none", Domain: "$none",
Resource: "api:/api", Types: []string{"api"},
Resource: "/api",
Actions: []string{"GET", "HEAD", "OPTIONS"}, Actions: []string{"GET", "HEAD", "OPTIONS"},
}, },
{ {
Name: "$anon", Name: "$anon",
Domain: "$none", Domain: "$none",
Resource: "api:/api/v3/widget/process/**", Types: []string{"api"},
Resource: "/api/v3/widget/process/**",
Actions: []string{"GET", "HEAD", "OPTIONS"}, Actions: []string{"GET", "HEAD", "OPTIONS"},
}, },
} }
@@ -728,7 +731,8 @@ func (a *api) start(ctx context.Context) error {
policies = append(policies, iamaccess.Policy{ policies = append(policies, iamaccess.Policy{
Name: cfg.Storage.Memory.Auth.Username, Name: cfg.Storage.Memory.Auth.Username,
Domain: "$none", Domain: "$none",
Resource: "fs:/memfs/**", Types: []string{"fs"},
Resource: "/memfs/**",
Actions: []string{"ANY"}, Actions: []string{"ANY"},
}) })
} }
@@ -753,7 +757,8 @@ func (a *api) start(ctx context.Context) error {
policies = append(policies, iamaccess.Policy{ policies = append(policies, iamaccess.Policy{
Name: s.Auth.Username, Name: s.Auth.Username,
Domain: "$none", Domain: "$none",
Resource: "fs:" + s.Mountpoint + "/**", Types: []string{"fs"},
Resource: s.Mountpoint + "/**",
Actions: []string{"ANY"}, Actions: []string{"ANY"},
}) })
} }
@@ -763,7 +768,8 @@ func (a *api) start(ctx context.Context) error {
policies = append(policies, iamaccess.Policy{ policies = append(policies, iamaccess.Policy{
Name: "$anon", Name: "$anon",
Domain: "$none", Domain: "$none",
Resource: "rtmp:/**", Types: []string{"rtmp"},
Resource: "/**",
Actions: []string{"ANY"}, Actions: []string{"ANY"},
}) })
} }
@@ -772,7 +778,8 @@ func (a *api) start(ctx context.Context) error {
policies = append(policies, iamaccess.Policy{ policies = append(policies, iamaccess.Policy{
Name: "$anon", Name: "$anon",
Domain: "$none", Domain: "$none",
Resource: "srt:**", Types: []string{"srt"},
Resource: "**",
Actions: []string{"ANY"}, Actions: []string{"ANY"},
}) })
} }
@@ -789,7 +796,7 @@ func (a *api) start(ctx context.Context) error {
} }
for _, policy := range policies { for _, policy := range policies {
manager.AddPolicy(policy.Name, policy.Domain, policy.Resource, policy.Actions) manager.AddPolicy(policy.Name, policy.Domain, policy.Types, policy.Resource, policy.Actions)
} }
} }
} }

View File

@@ -1142,6 +1142,12 @@ const docTemplateClusterAPI = `{
}, },
"resource": { "resource": {
"type": "string" "type": "string"
},
"types": {
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },

View File

@@ -1134,6 +1134,12 @@
}, },
"resource": { "resource": {
"type": "string" "type": "string"
},
"types": {
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },

View File

@@ -12,6 +12,10 @@ definitions:
type: string type: string
resource: resource:
type: string type: string
types:
items:
type: string
type: array
type: object type: object
app.Config: app.Config:
properties: properties:

View File

@@ -60,8 +60,8 @@ func (m *manager) apply(op store.Operation) {
} }
} }
func (m *manager) Enforce(name, domain, resource, action string) bool { func (m *manager) Enforce(name, domain, rtype, resource, action string) bool {
return m.iam.Enforce(name, domain, resource, action) return m.iam.Enforce(name, domain, rtype, resource, action)
} }
func (m *manager) HasDomain(domain string) bool { func (m *manager) HasDomain(domain string) bool {
@@ -72,20 +72,20 @@ func (m *manager) ListDomains() []string {
return m.iam.ListDomains() return m.iam.ListDomains()
} }
func (m *manager) HasPolicy(name, domain, resource string, actions []string) bool { func (m *manager) HasPolicy(name, domain string, types []string, resource string, actions []string) bool {
return m.iam.HasPolicy(name, domain, resource, actions) return m.iam.HasPolicy(name, domain, types, resource, actions)
} }
func (m *manager) AddPolicy(name, domain, resource string, actions []string) error { func (m *manager) AddPolicy(name, domain string, types []string, resource string, actions []string) error {
return ErrClusterMode return ErrClusterMode
} }
func (m *manager) RemovePolicy(name, domain, resource string, actions []string) error { func (m *manager) RemovePolicy(name, domain string, types []string, resource string, actions []string) error {
return ErrClusterMode return ErrClusterMode
} }
func (m *manager) ListPolicies(name, domain, resource string, actions []string) []access.Policy { func (m *manager) ListPolicies(name, domain string, types []string, resource string, actions []string) []access.Policy {
return m.iam.ListPolicies(name, domain, resource, actions) return m.iam.ListPolicies(name, domain, types, resource, actions)
} }
func (m *manager) ReloadPolicies() error { func (m *manager) ReloadPolicies() error {

View File

@@ -5689,6 +5689,12 @@ const docTemplate = `{
}, },
"resource": { "resource": {
"type": "string" "type": "string"
},
"types": {
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },

View File

@@ -5681,6 +5681,12 @@
}, },
"resource": { "resource": {
"type": "string" "type": "string"
},
"types": {
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },

View File

@@ -770,6 +770,10 @@ definitions:
type: string type: string
resource: resource:
type: string type: string
types:
items:
type: string
type: array
type: object type: object
api.IAMUser: api.IAMUser:
properties: properties:

View File

@@ -45,6 +45,7 @@ func (u *IAMUser) Marshal(user identity.User, policies []access.Policy) {
for _, p := range policies { for _, p := range policies {
u.Policies = append(u.Policies, IAMPolicy{ u.Policies = append(u.Policies, IAMPolicy{
Domain: p.Domain, Domain: p.Domain,
Types: p.Types,
Resource: p.Resource, Resource: p.Resource,
Actions: p.Actions, Actions: p.Actions,
}) })
@@ -84,6 +85,7 @@ func (u *IAMUser) Unmarshal() (identity.User, []access.Policy) {
iampolicies = append(iampolicies, access.Policy{ iampolicies = append(iampolicies, access.Policy{
Name: u.Name, Name: u.Name,
Domain: p.Domain, Domain: p.Domain,
Types: p.Types,
Resource: p.Resource, Resource: p.Resource,
Actions: p.Actions, Actions: p.Actions,
}) })
@@ -122,6 +124,7 @@ type IAMAuth0Tenant struct {
type IAMPolicy struct { type IAMPolicy struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Domain string `json:"domain"` Domain string `json:"domain"`
Types []string `json:"types"`
Resource string `json:"resource"` Resource string `json:"resource"`
Actions []string `json:"actions"` Actions []string `json:"actions"`
} }

View File

@@ -19,7 +19,7 @@ import (
func (r *queryResolver) PlayoutStatus(ctx context.Context, id string, domain string, input string) (*models.RawAVstream, error) { func (r *queryResolver) PlayoutStatus(ctx context.Context, id string, domain string, input string) (*models.RawAVstream, error) {
user, _ := ctx.Value("user").(string) user, _ := ctx.Value("user").(string)
if !r.IAM.Enforce(user, domain, "process:"+id, "read") { if !r.IAM.Enforce(user, domain, "process", id, "read") {
return nil, fmt.Errorf("forbidden") return nil, fmt.Errorf("forbidden")
} }

View File

@@ -21,7 +21,7 @@ func (r *queryResolver) Processes(ctx context.Context, idpattern *string, refpat
procs := []*models.Process{} procs := []*models.Process{}
for _, id := range ids { for _, id := range ids {
if !r.IAM.Enforce(user, id.Domain, "process:"+id.ID, "read") { if !r.IAM.Enforce(user, id.Domain, "process", id.ID, "read") {
continue continue
} }
@@ -40,7 +40,7 @@ func (r *queryResolver) Processes(ctx context.Context, idpattern *string, refpat
func (r *queryResolver) Process(ctx context.Context, id string, domain string) (*models.Process, error) { func (r *queryResolver) Process(ctx context.Context, id string, domain string) (*models.Process, error) {
user, _ := ctx.Value(GraphKey("user")).(string) user, _ := ctx.Value(GraphKey("user")).(string)
if !r.IAM.Enforce(user, domain, "process:"+id, "read") { if !r.IAM.Enforce(user, domain, "process", id, "read") {
return nil, fmt.Errorf("forbidden") return nil, fmt.Errorf("forbidden")
} }
@@ -56,7 +56,7 @@ func (r *queryResolver) Process(ctx context.Context, id string, domain string) (
func (r *queryResolver) Probe(ctx context.Context, id string, domain string) (*models.Probe, error) { func (r *queryResolver) Probe(ctx context.Context, id string, domain string) (*models.Probe, error) {
user, _ := ctx.Value(GraphKey("user")).(string) user, _ := ctx.Value(GraphKey("user")).(string)
if !r.IAM.Enforce(user, domain, "process:"+id, "write") { if !r.IAM.Enforce(user, domain, "process", id, "write") {
return nil, fmt.Errorf("forbidden") return nil, fmt.Errorf("forbidden")
} }

View File

@@ -36,12 +36,12 @@ func (h *ClusterHandler) AddIdentity(c echo.Context) error {
iamuser, iampolicies := user.Unmarshal() iamuser, iampolicies := user.Unmarshal()
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "Not allowed to create user '%s'", iamuser.Name) return api.Err(http.StatusForbidden, "", "Not allowed to create user '%s'", iamuser.Name)
} }
for _, p := range iampolicies { for _, p := range iampolicies {
if !h.iam.Enforce(ctxuser, p.Domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, p.Domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "Not allowed to write policy: %v", p) return api.Err(http.StatusForbidden, "", "Not allowed to write policy: %v", p)
} }
} }
@@ -84,7 +84,7 @@ func (h *ClusterHandler) UpdateIdentity(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
return api.Err(http.StatusForbidden, "", "not allowed to modify this user") return api.Err(http.StatusForbidden, "", "not allowed to modify this user")
} }
@@ -102,7 +102,7 @@ func (h *ClusterHandler) UpdateIdentity(c echo.Context) error {
} }
} }
iampolicies := h.iam.ListPolicies(name, "", "", nil) iampolicies := h.iam.ListPolicies(name, "", nil, "", nil)
user := api.IAMUser{} user := api.IAMUser{}
user.Marshal(iamuser, iampolicies) user.Marshal(iamuser, iampolicies)
@@ -113,12 +113,12 @@ func (h *ClusterHandler) UpdateIdentity(c echo.Context) error {
iamuser, iampolicies = user.Unmarshal() iamuser, iampolicies = user.Unmarshal()
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "not allowed to create user '%s'", iamuser.Name) return api.Err(http.StatusForbidden, "", "not allowed to create user '%s'", iamuser.Name)
} }
for _, p := range iampolicies { for _, p := range iampolicies {
if !h.iam.Enforce(ctxuser, p.Domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, p.Domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "not allowed to write policy: %v", p) return api.Err(http.StatusForbidden, "", "not allowed to write policy: %v", p)
} }
} }
@@ -165,7 +165,7 @@ func (h *ClusterHandler) UpdateIdentityPolicies(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
return api.Err(http.StatusForbidden, "", "not allowed to modify this user") return api.Err(http.StatusForbidden, "", "not allowed to modify this user")
} }
@@ -199,7 +199,7 @@ func (h *ClusterHandler) UpdateIdentityPolicies(c echo.Context) error {
accessPolicies := []access.Policy{} accessPolicies := []access.Policy{}
for _, p := range policies { for _, p := range policies {
if !h.iam.Enforce(ctxuser, p.Domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, p.Domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "not allowed to write policy: %v", p) return api.Err(http.StatusForbidden, "", "not allowed to write policy: %v", p)
} }
@@ -265,17 +265,17 @@ func (h *ClusterHandler) ListIdentities(c echo.Context) error {
users := make([]api.IAMUser, len(identities)+1) users := make([]api.IAMUser, len(identities)+1)
for i, iamuser := range identities { for i, iamuser := range identities {
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "read") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "read") {
continue continue
} }
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "write") {
iamuser = identity.User{ iamuser = identity.User{
Name: iamuser.Name, Name: iamuser.Name,
} }
} }
policies := h.iam.ListPolicies(iamuser.Name, "", "", nil) policies := h.iam.ListPolicies(iamuser.Name, "", nil, "", nil)
users[i].Marshal(iamuser, policies) users[i].Marshal(iamuser, policies)
} }
@@ -284,7 +284,7 @@ func (h *ClusterHandler) ListIdentities(c echo.Context) error {
Name: "$anon", Name: "$anon",
} }
policies := h.iam.ListPolicies("$anon", "", "", nil) policies := h.iam.ListPolicies("$anon", "", nil, "", nil)
users[len(users)-1].Marshal(anon, policies) users[len(users)-1].Marshal(anon, policies)
@@ -307,7 +307,7 @@ func (h *ClusterHandler) ListIdentity(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "read") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "read") {
return api.Err(http.StatusForbidden, "", "Not allowed to access this user") return api.Err(http.StatusForbidden, "", "Not allowed to access this user")
} }
@@ -321,7 +321,7 @@ func (h *ClusterHandler) ListIdentity(c echo.Context) error {
} }
if ctxuser != iamuser.Name { if ctxuser != iamuser.Name {
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
iamuser = identity.User{ iamuser = identity.User{
Name: iamuser.Name, Name: iamuser.Name,
} }
@@ -333,7 +333,7 @@ func (h *ClusterHandler) ListIdentity(c echo.Context) error {
} }
} }
iampolicies := h.iam.ListPolicies(name, "", "", nil) iampolicies := h.iam.ListPolicies(name, "", nil, "", nil)
user := api.IAMUser{} user := api.IAMUser{}
user.Marshal(iamuser, iampolicies) user.Marshal(iamuser, iampolicies)
@@ -351,7 +351,7 @@ func (h *ClusterHandler) ListIdentity(c echo.Context) error {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v3/cluster/iam/policies [get] // @Router /api/v3/cluster/iam/policies [get]
func (h *ClusterHandler) ListPolicies(c echo.Context) error { func (h *ClusterHandler) ListPolicies(c echo.Context) error {
iampolicies := h.iam.ListPolicies("", "", "", nil) iampolicies := h.iam.ListPolicies("", "", nil, "", nil)
policies := []api.IAMPolicy{} policies := []api.IAMPolicy{}
@@ -385,7 +385,7 @@ func (h *ClusterHandler) RemoveIdentity(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "$none") domain := util.DefaultQuery(c, "domain", "$none")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
return api.Err(http.StatusForbidden, "", "Not allowed to delete this user") return api.Err(http.StatusForbidden, "", "Not allowed to delete this user")
} }

View File

@@ -194,7 +194,7 @@ func (h *ClusterHandler) ListNodeProcesses(c echo.Context) error {
processes := []clientapi.Process{} processes := []clientapi.Process{}
for _, p := range procs { for _, p := range procs {
if !h.iam.Enforce(ctxuser, domain, "process:"+p.Config.ID, "read") { if !h.iam.Enforce(ctxuser, domain, "process", p.Config.ID, "read") {
continue continue
} }

View File

@@ -65,7 +65,7 @@ func (h *ClusterHandler) GetAllProcesses(c echo.Context) error {
pmap := map[app.ProcessID]struct{}{} pmap := map[app.ProcessID]struct{}{}
for _, p := range procs { for _, p := range procs {
if !h.iam.Enforce(ctxuser, domain, "process:"+p.ID, "read") { if !h.iam.Enforce(ctxuser, domain, "process", p.ID, "read") {
continue continue
} }
@@ -81,7 +81,7 @@ func (h *ClusterHandler) GetAllProcesses(c echo.Context) error {
filtered := h.getFilteredStoreProcesses(processes, wantids, domain, reference, idpattern, refpattern, ownerpattern, domainpattern) filtered := h.getFilteredStoreProcesses(processes, wantids, domain, reference, idpattern, refpattern, ownerpattern, domainpattern)
for _, p := range filtered { for _, p := range filtered {
if !h.iam.Enforce(ctxuser, domain, "process:"+p.Config.ID, "read") { if !h.iam.Enforce(ctxuser, domain, "process", p.Config.ID, "read") {
continue continue
} }
@@ -313,7 +313,7 @@ func (h *ClusterHandler) GetProcess(c echo.Context) error {
filter := newFilter(util.DefaultQuery(c, "filter", "")) filter := newFilter(util.DefaultQuery(c, "filter", ""))
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -370,12 +370,12 @@ func (h *ClusterHandler) AddProcess(c echo.Context) error {
return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error())
} }
if !h.iam.Enforce(ctxuser, process.Domain, "process:"+process.ID, "write") { if !h.iam.Enforce(ctxuser, process.Domain, "process", process.ID, "write") {
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write this process in domain %s", ctxuser, process.Domain) return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write this process in domain %s", ctxuser, process.Domain)
} }
if !superuser { if !superuser {
if !h.iam.Enforce(process.Owner, process.Domain, "process:"+process.ID, "write") { 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) return api.Err(http.StatusForbidden, "", "user %s is not allowed to write this process in domain %s", process.Owner, process.Domain)
} }
} }
@@ -431,7 +431,7 @@ func (h *ClusterHandler) UpdateProcess(c echo.Context) error {
Autostart: true, Autostart: true,
} }
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write the process in domain: %s", ctxuser, domain) return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write the process in domain: %s", ctxuser, domain)
} }
@@ -449,12 +449,12 @@ func (h *ClusterHandler) UpdateProcess(c echo.Context) error {
return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error())
} }
if !h.iam.Enforce(ctxuser, process.Domain, "process:"+process.ID, "write") { if !h.iam.Enforce(ctxuser, process.Domain, "process", process.ID, "write") {
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write this process", ctxuser) return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write this process", ctxuser)
} }
if !superuser { if !superuser {
if !h.iam.Enforce(process.Owner, process.Domain, "process:"+process.ID, "write") { 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) return api.Err(http.StatusForbidden, "", "user %s is not allowed to write this process", process.Owner)
} }
} }
@@ -499,7 +499,7 @@ func (h *ClusterHandler) SetProcessCommand(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write the process in domain: %s", ctxuser, domain) return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write the process in domain: %s", ctxuser, domain)
} }
@@ -552,7 +552,7 @@ func (h *ClusterHandler) SetProcessMetadata(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write the process in domain: %s", ctxuser, domain) return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write the process in domain: %s", ctxuser, domain)
} }
@@ -599,7 +599,7 @@ func (h *ClusterHandler) GetProcessMetadata(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -633,7 +633,7 @@ func (h *ClusterHandler) ProbeProcess(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -684,7 +684,7 @@ func (h *ClusterHandler) ProbeProcessConfig(c echo.Context) error {
return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error())
} }
if !h.iam.Enforce(ctxuser, process.Domain, "process:"+process.ID, "write") { if !h.iam.Enforce(ctxuser, process.Domain, "process", process.ID, "write") {
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write this process in domain %s", ctxuser, process.Domain) return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write this process in domain %s", ctxuser, process.Domain)
} }
@@ -729,7 +729,7 @@ func (h *ClusterHandler) DeleteProcess(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
id := util.PathParam(c, "id") id := util.PathParam(c, "id")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write the process in domain: %s", ctxuser, domain) return api.Err(http.StatusForbidden, "", "API user %s is not allowed to write the process in domain: %s", ctxuser, domain)
} }

View File

@@ -29,7 +29,7 @@ func (h *ClusterHandler) ListStoreProcesses(c echo.Context) error {
processes := []api.Process{} processes := []api.Process{}
for _, p := range procs { for _, p := range procs {
if !h.iam.Enforce(ctxuser, p.Config.Domain, "process:"+p.Config.ID, "read") { if !h.iam.Enforce(ctxuser, p.Config.Domain, "process", p.Config.ID, "read") {
continue continue
} }
@@ -62,7 +62,7 @@ func (h *ClusterHandler) GetStoreProcess(c echo.Context) error {
Domain: domain, Domain: domain,
} }
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
return api.Err(http.StatusForbidden, "", "API user %s is not allowed to read this process", ctxuser) return api.Err(http.StatusForbidden, "", "API user %s is not allowed to read this process", ctxuser)
} }
@@ -109,11 +109,11 @@ func (h *ClusterHandler) ListStoreIdentities(c echo.Context) error {
users := make([]api.IAMUser, len(identities)) users := make([]api.IAMUser, len(identities))
for i, iamuser := range identities { for i, iamuser := range identities {
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "read") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "read") {
continue continue
} }
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "write") {
iamuser = identity.User{ iamuser = identity.User{
Name: iamuser.Name, Name: iamuser.Name,
} }
@@ -144,7 +144,7 @@ func (h *ClusterHandler) ListStoreIdentity(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "read") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "read") {
return api.Err(http.StatusForbidden, "", "Not allowed to access this user") return api.Err(http.StatusForbidden, "", "Not allowed to access this user")
} }
@@ -159,7 +159,7 @@ func (h *ClusterHandler) ListStoreIdentity(c echo.Context) error {
} }
if ctxuser != iamuser.Name { if ctxuser != iamuser.Name {
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
iamuser = identity.User{ iamuser = identity.User{
Name: iamuser.Name, Name: iamuser.Name,
} }

View File

@@ -49,12 +49,12 @@ func (h *IAMHandler) AddIdentity(c echo.Context) error {
iamuser, iampolicies := user.Unmarshal() iamuser, iampolicies := user.Unmarshal()
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "not allowed to create user '%s'", iamuser.Name) return api.Err(http.StatusForbidden, "", "not allowed to create user '%s'", iamuser.Name)
} }
for _, p := range iampolicies { for _, p := range iampolicies {
if !h.iam.Enforce(ctxuser, p.Domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, p.Domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "not allowed to write policy: %v", p) return api.Err(http.StatusForbidden, "", "not allowed to write policy: %v", p)
} }
} }
@@ -69,7 +69,7 @@ func (h *IAMHandler) AddIdentity(c echo.Context) error {
} }
for _, p := range iampolicies { for _, p := range iampolicies {
h.iam.AddPolicy(p.Name, p.Domain, p.Resource, p.Actions) h.iam.AddPolicy(p.Name, p.Domain, p.Types, p.Resource, p.Actions)
} }
return c.JSON(http.StatusOK, user) return c.JSON(http.StatusOK, user)
@@ -95,7 +95,7 @@ func (h *IAMHandler) RemoveIdentity(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "$none") domain := util.DefaultQuery(c, "domain", "$none")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
return api.Err(http.StatusForbidden, "", "Not allowed to delete this user") return api.Err(http.StatusForbidden, "", "Not allowed to delete this user")
} }
@@ -114,7 +114,7 @@ func (h *IAMHandler) RemoveIdentity(c echo.Context) error {
} }
// Remove all policies of that user // Remove all policies of that user
if err := h.iam.RemovePolicy(name, "", "", nil); err != nil { if err := h.iam.RemovePolicy(name, "", nil, "", nil); err != nil {
return api.Err(http.StatusBadRequest, "", "%s", err.Error()) return api.Err(http.StatusBadRequest, "", "%s", err.Error())
} }
@@ -144,7 +144,7 @@ func (h *IAMHandler) UpdateIdentity(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "$none") domain := util.DefaultQuery(c, "domain", "$none")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
return api.Err(http.StatusForbidden, "", "Not allowed to modify this user") return api.Err(http.StatusForbidden, "", "Not allowed to modify this user")
} }
@@ -162,7 +162,7 @@ func (h *IAMHandler) UpdateIdentity(c echo.Context) error {
} }
} }
iampolicies := h.iam.ListPolicies(name, "", "", nil) iampolicies := h.iam.ListPolicies(name, "", nil, "", nil)
user := api.IAMUser{} user := api.IAMUser{}
user.Marshal(iamuser, iampolicies) user.Marshal(iamuser, iampolicies)
@@ -173,12 +173,12 @@ func (h *IAMHandler) UpdateIdentity(c echo.Context) error {
iamuser, iampolicies = user.Unmarshal() iamuser, iampolicies = user.Unmarshal()
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "Not allowed to create user '%s'", iamuser.Name) return api.Err(http.StatusForbidden, "", "Not allowed to create user '%s'", iamuser.Name)
} }
for _, p := range iampolicies { for _, p := range iampolicies {
if !h.iam.Enforce(ctxuser, p.Domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, p.Domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "Not allowed to write policy: %v", p) return api.Err(http.StatusForbidden, "", "Not allowed to write policy: %v", p)
} }
} }
@@ -194,12 +194,12 @@ func (h *IAMHandler) UpdateIdentity(c echo.Context) error {
} }
} }
if err := h.iam.RemovePolicy(name, "", "", nil); err != nil { if err := h.iam.RemovePolicy(name, "", nil, "", nil); err != nil {
return api.Err(http.StatusBadRequest, "", "%s", err.Error()) return api.Err(http.StatusBadRequest, "", "%s", err.Error())
} }
for _, p := range iampolicies { for _, p := range iampolicies {
h.iam.AddPolicy(p.Name, p.Domain, p.Resource, p.Actions) h.iam.AddPolicy(p.Name, p.Domain, p.Types, p.Resource, p.Actions)
} }
return c.JSON(http.StatusOK, user) return c.JSON(http.StatusOK, user)
@@ -228,7 +228,7 @@ func (h *IAMHandler) UpdateIdentityPolicies(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "$none") domain := util.DefaultQuery(c, "domain", "$none")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
return api.Err(http.StatusForbidden, "", "Not allowed to modify this user") return api.Err(http.StatusForbidden, "", "Not allowed to modify this user")
} }
@@ -260,7 +260,7 @@ func (h *IAMHandler) UpdateIdentityPolicies(c echo.Context) error {
} }
for _, p := range policies { for _, p := range policies {
if !h.iam.Enforce(ctxuser, p.Domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, p.Domain, "iam", iamuser.Name, "write") {
return api.Err(http.StatusForbidden, "", "not allowed to write policy: %v", p) return api.Err(http.StatusForbidden, "", "not allowed to write policy: %v", p)
} }
} }
@@ -269,12 +269,12 @@ func (h *IAMHandler) UpdateIdentityPolicies(c echo.Context) error {
return api.Err(http.StatusForbidden, "", "only superusers can modify superusers") return api.Err(http.StatusForbidden, "", "only superusers can modify superusers")
} }
if err := h.iam.RemovePolicy(name, "", "", nil); err != nil { if err := h.iam.RemovePolicy(name, "", nil, "", nil); err != nil {
return api.Err(http.StatusBadRequest, "", "%s", err.Error()) return api.Err(http.StatusBadRequest, "", "%s", err.Error())
} }
for _, p := range policies { for _, p := range policies {
h.iam.AddPolicy(iamuser.Name, p.Domain, p.Resource, p.Actions) h.iam.AddPolicy(iamuser.Name, p.Domain, p.Types, p.Resource, p.Actions)
} }
return c.JSON(http.StatusOK, policies) return c.JSON(http.StatusOK, policies)
@@ -298,17 +298,17 @@ func (h *IAMHandler) ListIdentities(c echo.Context) error {
users := make([]api.IAMUser, len(identities)+1) users := make([]api.IAMUser, len(identities)+1)
for i, iamuser := range identities { for i, iamuser := range identities {
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "read") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "read") {
continue continue
} }
if !h.iam.Enforce(ctxuser, domain, "iam:"+iamuser.Name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", iamuser.Name, "write") {
iamuser = identity.User{ iamuser = identity.User{
Name: iamuser.Name, Name: iamuser.Name,
} }
} }
policies := h.iam.ListPolicies(iamuser.Name, "", "", nil) policies := h.iam.ListPolicies(iamuser.Name, "", nil, "", nil)
users[i].Marshal(iamuser, policies) users[i].Marshal(iamuser, policies)
} }
@@ -317,7 +317,7 @@ func (h *IAMHandler) ListIdentities(c echo.Context) error {
Name: "$anon", Name: "$anon",
} }
policies := h.iam.ListPolicies("$anon", "", "", nil) policies := h.iam.ListPolicies("$anon", "", nil, "", nil)
users[len(users)-1].Marshal(anon, policies) users[len(users)-1].Marshal(anon, policies)
@@ -342,7 +342,7 @@ func (h *IAMHandler) GetIdentity(c echo.Context) error {
domain := util.DefaultQuery(c, "domain", "$none") domain := util.DefaultQuery(c, "domain", "$none")
name := util.PathParam(c, "name") name := util.PathParam(c, "name")
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "read") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "read") {
return api.Err(http.StatusForbidden, "", "not allowed to access this user") return api.Err(http.StatusForbidden, "", "not allowed to access this user")
} }
@@ -356,7 +356,7 @@ func (h *IAMHandler) GetIdentity(c echo.Context) error {
} }
if ctxuser != iamuser.Name { if ctxuser != iamuser.Name {
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") { if !h.iam.Enforce(ctxuser, domain, "iam", name, "write") {
iamuser = identity.User{ iamuser = identity.User{
Name: iamuser.Name, Name: iamuser.Name,
} }
@@ -368,7 +368,7 @@ func (h *IAMHandler) GetIdentity(c echo.Context) error {
} }
} }
iampolicies := h.iam.ListPolicies(name, "", "", nil) iampolicies := h.iam.ListPolicies(name, "", nil, "", nil)
user := api.IAMUser{} user := api.IAMUser{}
user.Marshal(iamuser, iampolicies) user.Marshal(iamuser, iampolicies)

View File

@@ -35,7 +35,7 @@ func (h *RestreamHandler) PlayoutStatus(c echo.Context) error {
user := util.DefaultContext(c, "user", "") user := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(user, domain, "process:"+id, "read") { if !h.iam.Enforce(user, domain, "process:", id, "read") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -104,7 +104,7 @@ func (h *RestreamHandler) PlayoutKeyframe(c echo.Context) error {
user := util.DefaultContext(c, "user", "") user := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(user, domain, "process:"+id, "read") { if !h.iam.Enforce(user, domain, "process:", id, "read") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -162,7 +162,7 @@ func (h *RestreamHandler) PlayoutEncodeErrorframe(c echo.Context) error {
user := util.DefaultContext(c, "user", "") user := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(user, domain, "process:"+id, "write") { if !h.iam.Enforce(user, domain, "process:", id, "write") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -217,7 +217,7 @@ func (h *RestreamHandler) PlayoutSetErrorframe(c echo.Context) error {
user := util.DefaultContext(c, "user", "") user := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(user, domain, "process:"+id, "write") { if !h.iam.Enforce(user, domain, "process:", id, "write") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -273,7 +273,7 @@ func (h *RestreamHandler) PlayoutReopenInput(c echo.Context) error {
user := util.DefaultContext(c, "user", "") user := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(user, domain, "process:"+id, "write") { if !h.iam.Enforce(user, domain, "process:", id, "write") {
return api.Err(http.StatusForbidden, "Forbidden") return api.Err(http.StatusForbidden, "Forbidden")
} }
@@ -327,7 +327,7 @@ func (h *RestreamHandler) PlayoutSetStream(c echo.Context) error {
user := util.DefaultContext(c, "user", "") user := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(user, domain, "process:"+id, "write") { if !h.iam.Enforce(user, domain, "process:", id, "write") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }

View File

@@ -59,12 +59,12 @@ func (h *RestreamHandler) Add(c echo.Context) error {
return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error())
} }
if !h.iam.Enforce(ctxuser, process.Domain, "process:"+process.ID, "write") { if !h.iam.Enforce(ctxuser, process.Domain, "process", process.ID, "write") {
return api.Err(http.StatusForbidden, "", "You are not allowed to write this process, check the domain and process ID") return api.Err(http.StatusForbidden, "", "You are not allowed to write this process, check the domain and process ID")
} }
if !superuser { if !superuser {
if !h.iam.Enforce(process.Owner, process.Domain, "process:"+process.ID, "write") { 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) return api.Err(http.StatusForbidden, "", "The owner '%s' is not allowed to write this process", process.Owner)
} }
} }
@@ -131,7 +131,7 @@ func (h *RestreamHandler) GetAll(c echo.Context) error {
ids := []app.ProcessID{} ids := []app.ProcessID{}
for _, id := range preids { for _, id := range preids {
if !h.iam.Enforce(ctxuser, domain, "process:"+id.ID, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id.ID, "read") {
continue continue
} }
@@ -184,7 +184,7 @@ func (h *RestreamHandler) Get(c echo.Context) error {
filter := util.DefaultQuery(c, "filter", "") filter := util.DefaultQuery(c, "filter", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
return api.Err(http.StatusForbidden, "Forbidden") return api.Err(http.StatusForbidden, "Forbidden")
} }
@@ -226,7 +226,7 @@ func (h *RestreamHandler) Delete(c echo.Context) error {
} }
if !superuser { if !superuser {
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
} }
@@ -271,7 +271,7 @@ func (h *RestreamHandler) Update(c echo.Context) error {
Autostart: true, Autostart: true,
} }
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "", "You are not allowed to write this process: %s", id) return api.Err(http.StatusForbidden, "", "You are not allowed to write this process: %s", id)
} }
@@ -292,12 +292,12 @@ func (h *RestreamHandler) Update(c echo.Context) error {
return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error())
} }
if !h.iam.Enforce(ctxuser, process.Domain, "process:"+process.ID, "write") { if !h.iam.Enforce(ctxuser, process.Domain, "process", process.ID, "write") {
return api.Err(http.StatusForbidden, "", "You are not allowed to write this process: %s", process.ID) return api.Err(http.StatusForbidden, "", "You are not allowed to write this process: %s", process.ID)
} }
if !superuser { if !superuser {
if !h.iam.Enforce(process.Owner, process.Domain, "process:"+process.ID, "write") { 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) return api.Err(http.StatusForbidden, "", "The owner '%s' is not allowed to write this process: %s", process.Owner, process.ID)
} }
} }
@@ -352,7 +352,7 @@ func (h *RestreamHandler) Command(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -406,7 +406,7 @@ func (h *RestreamHandler) GetConfig(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -445,7 +445,7 @@ func (h *RestreamHandler) GetState(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -507,7 +507,7 @@ func (h *RestreamHandler) GetReport(c echo.Context) error {
} }
} }
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -651,7 +651,7 @@ func (h *RestreamHandler) Probe(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -698,7 +698,7 @@ func (h *RestreamHandler) ProbeConfig(c echo.Context) error {
return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error()) return api.Err(http.StatusBadRequest, "", "invalid JSON: %s", err.Error())
} }
if !h.iam.Enforce(ctxuser, process.Domain, "process:"+process.ID, "write") { if !h.iam.Enforce(ctxuser, process.Domain, "process", process.ID, "write") {
return api.Err(http.StatusForbidden, "", "You are not allowed to probe this process, check the domain and process ID") return api.Err(http.StatusForbidden, "", "You are not allowed to probe this process, check the domain and process ID")
} }
@@ -778,7 +778,7 @@ func (h *RestreamHandler) GetProcessMetadata(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "read") { if !h.iam.Enforce(ctxuser, domain, "process", id, "read") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }
@@ -821,7 +821,7 @@ func (h *RestreamHandler) SetProcessMetadata(c echo.Context) error {
ctxuser := util.DefaultContext(c, "user", "") ctxuser := util.DefaultContext(c, "user", "")
domain := util.DefaultQuery(c, "domain", "") domain := util.DefaultQuery(c, "domain", "")
if !h.iam.Enforce(ctxuser, domain, "process:"+id, "write") { if !h.iam.Enforce(ctxuser, domain, "process", id, "write") {
return api.Err(http.StatusForbidden, "") return api.Err(http.StatusForbidden, "")
} }

View File

@@ -61,9 +61,9 @@ func getDummyRestreamHandler() (*RestreamHandler, error) {
return nil, err return nil, err
} }
iam.AddPolicy("$anon", "$none", "api:/**", []string{"ANY"}) iam.AddPolicy("$anon", "$none", []string{"api"}, "/**", []string{"ANY"})
iam.AddPolicy("$anon", "$none", "fs:/**", []string{"ANY"}) iam.AddPolicy("$anon", "$none", []string{"fs"}, "/**", []string{"ANY"})
iam.AddPolicy("$anon", "$none", "process:**", []string{"ANY"}) iam.AddPolicy("$anon", "$none", []string{"process"}, "**", []string{"ANY"})
handler := NewRestream(rs, iam) handler := NewRestream(rs, iam)

View File

@@ -124,6 +124,7 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
username := "$anon" username := "$anon"
resource := c.Request().URL.Path resource := c.Request().URL.Path
rtype := "fs"
var domain string var domain string
c.Set("user", username) c.Set("user", username)
@@ -184,7 +185,7 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
} }
domain = c.QueryParam("domain") domain = c.QueryParam("domain")
resource = "api:" + resource rtype = "api"
} else { } else {
identity, err = mw.findIdentityFromSession(c) identity, err = mw.findIdentityFromSession(c)
if err != nil { if err != nil {
@@ -215,7 +216,7 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
} }
domain = mw.findDomainFromFilesystem(resource) domain = mw.findDomainFromFilesystem(resource)
resource = "fs:" + resource rtype = "fs"
} }
superuser := false superuser := false
@@ -234,11 +235,11 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
action := c.Request().Method action := c.Request().Method
if username == "$anon" && resource == "api:/api" { if username == "$anon" && rtype == "api" && resource == "/api" {
return next(c) return next(c)
} }
if !config.IAM.Enforce(username, domain, resource, action) { if !config.IAM.Enforce(username, domain, rtype, resource, action) {
return api.Err(http.StatusForbidden, "Forbidden", "access denied") return api.Err(http.StatusForbidden, "Forbidden", "access denied")
} }
@@ -263,7 +264,7 @@ func (m *iammiddleware) findIdentityFromBasicAuth(c echo.Context) (iamidentity.V
domain = "$none" domain = "$none"
} }
if !m.iam.Enforce("$anon", domain, "fs:"+path, c.Request().Method) { if !m.iam.Enforce("$anon", domain, "fs", path, c.Request().Method) {
return nil, ErrAuthRequired return nil, ErrAuthRequired
} }

View File

@@ -101,7 +101,7 @@ func TestBasicAuth(t *testing.T) {
iam, err := getIAM() iam, err := getIAM()
require.NoError(t, err) require.NoError(t, err)
iam.AddPolicy("foobar", "$none", "fs:/**", []string{"ANY"}) iam.AddPolicy("foobar", "$none", []string{"fs"}, "/**", []string{"ANY"})
e := echo.New() e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
@@ -160,7 +160,7 @@ func TestBasicAuthEncoding(t *testing.T) {
iam, err := getIAM() iam, err := getIAM()
require.NoError(t, err) require.NoError(t, err)
iam.AddPolicy("foobar:2", "$none", "fs:/**", []string{"ANY"}) iam.AddPolicy("foobar:2", "$none", []string{"fs"}, "/**", []string{"ANY"})
e := echo.New() e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
@@ -196,9 +196,9 @@ func TestFindDomainFromFilesystem(t *testing.T) {
iam, err := getIAM() iam, err := getIAM()
require.NoError(t, err) require.NoError(t, err)
iam.AddPolicy("$anon", "$none", "fs:/**", []string{"ANY"}) iam.AddPolicy("$anon", "$none", []string{"fs"}, "/**", []string{"ANY"})
iam.AddPolicy("foobar", "group", "fs:/group/**", []string{"ANY"}) iam.AddPolicy("foobar", "group", []string{"fs"}, "/group/**", []string{"ANY"})
iam.AddPolicy("foobar", "anothergroup", "fs:/memfs/anothergroup/**", []string{"ANY"}) iam.AddPolicy("foobar", "anothergroup", []string{"fs"}, "/memfs/anothergroup/**", []string{"ANY"})
mw := &iammiddleware{ mw := &iammiddleware{
iam: iam, iam: iam,
@@ -222,8 +222,8 @@ func TestBasicAuthDomain(t *testing.T) {
iam, err := getIAM() iam, err := getIAM()
require.NoError(t, err) require.NoError(t, err)
iam.AddPolicy("$anon", "$none", "fs:/**", []string{"ANY"}) iam.AddPolicy("$anon", "$none", []string{"fs"}, "/**", []string{"ANY"})
iam.AddPolicy("foobar", "group", "fs:/group/**", []string{"ANY"}) iam.AddPolicy("foobar", "group", []string{"fs"}, "/group/**", []string{"ANY"})
e := echo.New() e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
@@ -255,7 +255,7 @@ func TestBasicAuthDomain(t *testing.T) {
require.NoError(t, h(c)) require.NoError(t, h(c))
// Allow anonymous group read access // Allow anonymous group read access
iam.AddPolicy("$anon", "group", "fs:/group/**", []string{"GET"}) iam.AddPolicy("$anon", "group", []string{"fs"}, "/group/**", []string{"GET"})
req.Header.Del(echo.HeaderAuthorization) req.Header.Del(echo.HeaderAuthorization)
require.NoError(t, h(c)) require.NoError(t, h(c))
@@ -265,7 +265,7 @@ func TestAPILoginAndRefresh(t *testing.T) {
iam, err := getIAM() iam, err := getIAM()
require.NoError(t, err) require.NoError(t, err)
iam.AddPolicy("foobar", "$none", "api:/**", []string{"ANY"}) iam.AddPolicy("foobar", "$none", []string{"api"}, "/**", []string{"ANY"})
jwthandler := apihandler.NewJWT(iam) jwthandler := apihandler.NewJWT(iam)

View File

@@ -1,6 +1,7 @@
package access package access
import ( import (
"sort"
"strings" "strings"
"github.com/datarhei/core/v16/log" "github.com/datarhei/core/v16/log"
@@ -12,12 +13,13 @@ import (
type Policy struct { type Policy struct {
Name string Name string
Domain string Domain string
Types []string
Resource string Resource string
Actions []string Actions []string
} }
type Enforcer interface { type Enforcer interface {
Enforce(name, domain, resource, action string) (bool, string) Enforce(name, domain, rtype, resource, action string) (bool, string)
HasDomain(name string) bool HasDomain(name string) bool
ListDomains() []string ListDomains() []string
@@ -26,10 +28,10 @@ type Enforcer interface {
type Manager interface { type Manager interface {
Enforcer Enforcer
HasPolicy(name, domain, resource string, actions []string) bool HasPolicy(name, domain string, types []string, resource string, actions []string) bool
AddPolicy(name, domain, resource string, actions []string) error AddPolicy(name, domain string, types []string, resource string, actions []string) error
RemovePolicy(name, domain, resource string, actions []string) error RemovePolicy(name, domain string, types []string, resource string, actions []string) error
ListPolicies(name, domain, resource string, actions []string) []Policy ListPolicies(name, domain string, types []string, resource string, actions []string) []Policy
ReloadPolicies() error ReloadPolicies() error
} }
@@ -77,14 +79,14 @@ func New(config Config) (Manager, error) {
return am, nil return am, nil
} }
func (am *access) HasPolicy(name, domain, resource string, actions []string) bool { func (am *access) HasPolicy(name, domain string, types []string, resource string, actions []string) bool {
policy := []string{name, domain, resource, strings.Join(actions, "|")} policy := []string{name, domain, encodeResource(types, resource), encodeActions(actions)}
return am.enforcer.HasPolicy(policy) return am.enforcer.HasPolicy(policy)
} }
func (am *access) AddPolicy(name, domain, resource string, actions []string) error { func (am *access) AddPolicy(name, domain string, types []string, resource string, actions []string) error {
policy := []string{name, domain, resource, strings.Join(actions, "|")} policy := []string{name, domain, encodeResource(types, resource), encodeActions(actions)}
if am.enforcer.HasPolicy(policy) { if am.enforcer.HasPolicy(policy) {
return nil return nil
@@ -95,24 +97,26 @@ func (am *access) AddPolicy(name, domain, resource string, actions []string) err
return err return err
} }
func (am *access) RemovePolicy(name, domain, resource string, actions []string) error { func (am *access) RemovePolicy(name, domain string, types []string, resource string, actions []string) error {
policies := am.enforcer.GetFilteredPolicy(0, name, domain, resource, strings.Join(actions, "|")) policies := am.enforcer.GetFilteredPolicy(0, name, domain, encodeResource(types, resource), encodeActions(actions))
_, err := am.enforcer.RemovePolicies(policies) _, err := am.enforcer.RemovePolicies(policies)
return err return err
} }
func (am *access) ListPolicies(name, domain, resource string, actions []string) []Policy { func (am *access) ListPolicies(name, domain string, types []string, resource string, actions []string) []Policy {
policies := []Policy{} policies := []Policy{}
ps := am.enforcer.GetFilteredPolicy(0, name, domain, resource, strings.Join(actions, "|")) ps := am.enforcer.GetFilteredPolicy(0, name, domain, encodeResource(types, resource), encodeActions(actions))
for _, p := range ps { for _, p := range ps {
types, resource := decodeResource(p[2])
policies = append(policies, Policy{ policies = append(policies, Policy{
Name: p[0], Name: p[0],
Domain: p[1], Domain: p[1],
Resource: p[2], Types: types,
Actions: strings.Split(p[3], "|"), Resource: resource,
Actions: decodeActions(p[3]),
}) })
} }
@@ -133,8 +137,37 @@ func (am *access) ListDomains() []string {
return am.adapter.AllDomains() return am.adapter.AllDomains()
} }
func (am *access) Enforce(name, domain, resource, action string) (bool, string) { func (am *access) Enforce(name, domain, rtype, resource, action string) (bool, string) {
resource = rtype + ":" + resource
ok, rule, _ := am.enforcer.EnforceEx(name, domain, resource, action) ok, rule, _ := am.enforcer.EnforceEx(name, domain, resource, action)
return ok, strings.Join(rule, ", ") return ok, strings.Join(rule, ", ")
} }
func encodeActions(actions []string) string {
return strings.Join(actions, "|")
}
func decodeActions(actions string) []string {
return strings.Split(actions, "|")
}
func encodeResource(types []string, resource string) string {
if len(types) == 0 {
return resource
}
sort.Strings(types)
return strings.Join(types, "|") + ":" + resource
}
func decodeResource(resource string) ([]string, string) {
before, after, found := strings.Cut(resource, ":")
if !found {
return []string{}, resource
}
return strings.Split(before, "|"), after
}

View File

@@ -26,42 +26,47 @@ func TestAccessManager(t *testing.T) {
}) })
require.NoError(t, err) require.NoError(t, err)
policies := am.ListPolicies("", "", "", nil) policies := am.ListPolicies("", "", nil, "", nil)
require.ElementsMatch(t, []Policy{ require.ElementsMatch(t, []Policy{
{ {
Name: "ingo", Name: "ingo",
Domain: "$none", Domain: "$none",
Resource: "rtmp:/bla-*", Types: []string{"rtmp"},
Resource: "/bla-*",
Actions: []string{"play", "publish"}, Actions: []string{"play", "publish"},
}, },
{ {
Name: "ingo", Name: "ingo",
Domain: "igelcamp", Domain: "igelcamp",
Resource: "rtmp:/igelcamp/**", Types: []string{"rtmp"},
Resource: "/igelcamp/**",
Actions: []string{"publish"}, Actions: []string{"publish"},
}, },
}, policies) }, policies)
am.AddPolicy("foobar", "group", "bla:/", []string{"write"}) am.AddPolicy("foobar", "group", []string{"bla"}, "/", []string{"write"})
policies = am.ListPolicies("", "", "", nil) policies = am.ListPolicies("", "", nil, "", nil)
require.ElementsMatch(t, []Policy{ require.ElementsMatch(t, []Policy{
{ {
Name: "ingo", Name: "ingo",
Domain: "$none", Domain: "$none",
Resource: "rtmp:/bla-*", Types: []string{"rtmp"},
Resource: "/bla-*",
Actions: []string{"play", "publish"}, Actions: []string{"play", "publish"},
}, },
{ {
Name: "ingo", Name: "ingo",
Domain: "igelcamp", Domain: "igelcamp",
Resource: "rtmp:/igelcamp/**", Types: []string{"rtmp"},
Resource: "/igelcamp/**",
Actions: []string{"publish"}, Actions: []string{"publish"},
}, },
{ {
Name: "foobar", Name: "foobar",
Domain: "group", Domain: "group",
Resource: "bla:/", Types: []string{"bla"},
Resource: "/",
Actions: []string{"write"}, Actions: []string{"write"},
}, },
}, policies) }, policies)
@@ -70,14 +75,15 @@ func TestAccessManager(t *testing.T) {
require.True(t, am.HasDomain("group")) require.True(t, am.HasDomain("group"))
require.False(t, am.HasDomain("$none")) require.False(t, am.HasDomain("$none"))
am.RemovePolicy("ingo", "", "", nil) am.RemovePolicy("ingo", "", nil, "", nil)
policies = am.ListPolicies("", "", "", nil) policies = am.ListPolicies("", "", nil, "", nil)
require.ElementsMatch(t, []Policy{ require.ElementsMatch(t, []Policy{
{ {
Name: "foobar", Name: "foobar",
Domain: "group", Domain: "group",
Resource: "bla:/", Types: []string{"bla"},
Resource: "/",
Actions: []string{"write"}, Actions: []string{"write"},
}, },
}, policies) }, policies)
@@ -86,9 +92,9 @@ func TestAccessManager(t *testing.T) {
require.True(t, am.HasDomain("group")) require.True(t, am.HasDomain("group"))
require.False(t, am.HasDomain("$none")) require.False(t, am.HasDomain("$none"))
ok, _ := am.Enforce("foobar", "group", "bla:/", "read") ok, _ := am.Enforce("foobar", "group", "bla", "/", "read")
require.False(t, ok) require.False(t, ok)
ok, _ = am.Enforce("foobar", "group", "bla:/", "write") ok, _ = am.Enforce("foobar", "group", "bla", "/", "write")
require.True(t, ok) require.True(t, ok)
} }

View File

@@ -92,7 +92,7 @@ func (a *adapter) loadPolicyFile(model model.Model) error {
rule[1] = "role:" + name rule[1] = "role:" + name
for _, role := range roles { for _, role := range roles {
rule[3] = role.Resource rule[3] = role.Resource
rule[4] = formatActions(role.Actions) rule[4] = formatList(role.Actions)
if err := a.importPolicy(model, rule[0:5]); err != nil { if err := a.importPolicy(model, rule[0:5]); err != nil {
return err return err
@@ -103,7 +103,7 @@ func (a *adapter) loadPolicyFile(model model.Model) error {
for _, policy := range domain.Policies { for _, policy := range domain.Policies {
rule[1] = policy.Username rule[1] = policy.Username
rule[3] = policy.Resource rule[3] = policy.Resource
rule[4] = formatActions(policy.Actions) rule[4] = formatList(policy.Actions)
if err := a.importPolicy(model, rule[0:5]); err != nil { if err := a.importPolicy(model, rule[0:5]); err != nil {
return err return err
@@ -220,7 +220,7 @@ func (a *adapter) addPolicy(ptype string, rule []string) error {
username = rule[0] username = rule[0]
domain = rule[1] domain = rule[1]
resource = rule[2] resource = rule[2]
actions = formatActions(rule[3]) actions = formatList(rule[3])
a.logger.Debug().WithFields(log.Fields{ a.logger.Debug().WithFields(log.Fields{
"subject": username, "subject": username,
@@ -307,7 +307,7 @@ func (a *adapter) hasPolicy(ptype string, rule []string) (bool, error) {
username = rule[0] username = rule[0]
domain = rule[1] domain = rule[1]
resource = rule[2] resource = rule[2]
actions = formatActions(rule[3]) actions = formatList(rule[3])
} else if ptype == "g" { } else if ptype == "g" {
if len(rule) < 3 { if len(rule) < 3 {
return false, fmt.Errorf("invalid rule length. must be 'user, role, domain'") return false, fmt.Errorf("invalid rule length. must be 'user, role, domain'")
@@ -348,13 +348,13 @@ func (a *adapter) hasPolicy(ptype string, rule []string) (bool, error) {
} }
for _, role := range roles { for _, role := range roles {
if role.Resource == resource && formatActions(role.Actions) == actions { if role.Resource == resource && formatList(role.Actions) == actions {
return true, nil return true, nil
} }
} }
} else { } else {
for _, p := range dom.Policies { for _, p := range dom.Policies {
if p.Username == username && p.Resource == resource && formatActions(p.Actions) == actions { if p.Username == username && p.Resource == resource && formatList(p.Actions) == actions {
return true, nil return true, nil
} }
} }
@@ -420,7 +420,7 @@ func (a *adapter) removePolicy(ptype string, rule []string) error {
username = rule[0] username = rule[0]
domain = rule[1] domain = rule[1]
resource = rule[2] resource = rule[2]
actions = formatActions(rule[3]) actions = formatList(rule[3])
a.logger.Debug().WithFields(log.Fields{ a.logger.Debug().WithFields(log.Fields{
"subject": username, "subject": username,
@@ -463,7 +463,7 @@ func (a *adapter) removePolicy(ptype string, rule []string) error {
newRoles := []Role{} newRoles := []Role{}
for _, role := range roles { for _, role := range roles {
if role.Resource == resource && formatActions(role.Actions) == actions { if role.Resource == resource && formatList(role.Actions) == actions {
continue continue
} }
@@ -475,7 +475,7 @@ func (a *adapter) removePolicy(ptype string, rule []string) error {
policies := []DomainPolicy{} policies := []DomainPolicy{}
for _, p := range dom.Policies { for _, p := range dom.Policies {
if p.Username == username && p.Resource == resource && formatActions(p.Actions) == actions { if p.Username == username && p.Resource == resource && formatList(p.Actions) == actions {
continue continue
} }
@@ -579,8 +579,8 @@ type DomainPolicy struct {
Role Role
} }
func formatActions(actions string) string { func formatList(list string) string {
a := strings.Split(actions, "|") a := strings.Split(list, "|")
sort.Strings(a) sort.Strings(a)

View File

@@ -48,7 +48,7 @@ func TestFormatActions(t *testing.T) {
} }
for _, d := range data { for _, d := range data {
require.Equal(t, d[1], formatActions(d[0]), d[0]) require.Equal(t, d[1], formatList(d[0]), d[0])
} }
} }

View File

@@ -10,14 +10,28 @@ func resourceMatch(request, policy string) bool {
reqPrefix, reqResource := getPrefix(request) reqPrefix, reqResource := getPrefix(request)
polPrefix, polResource := getPrefix(policy) polPrefix, polResource := getPrefix(policy)
if reqPrefix != polPrefix { var match bool = false
var err error = nil
reqType := strings.ToLower(reqPrefix)
polTypes := strings.Split(strings.ToLower(polPrefix), "|")
for _, polType := range polTypes {
if reqType != polType {
continue
}
match = true
break
}
if !match {
return false return false
} }
var match bool match = false
var err error
if reqPrefix == "api" || reqPrefix == "fs" || reqPrefix == "rtmp" || reqPrefix == "srt" { if reqType == "api" || reqType == "fs" || reqType == "rtmp" || reqType == "srt" {
match, err = glob.Match(polResource, reqResource, rune('/')) match, err = glob.Match(polResource, reqResource, rune('/'))
if err != nil { if err != nil {
return false return false

View File

@@ -7,7 +7,7 @@ import (
) )
type Enforcer interface { type Enforcer interface {
Enforce(name, domain, resource, action string) bool Enforce(name, domain, rtype, resource, action string) bool
} }
type IAM interface { type IAM interface {
@@ -16,10 +16,10 @@ type IAM interface {
HasDomain(domain string) bool HasDomain(domain string) bool
ListDomains() []string ListDomains() []string
HasPolicy(name, domain, resource string, actions []string) bool HasPolicy(name, domain string, types []string, resource string, actions []string) bool
AddPolicy(name, domain, resource string, actions []string) error AddPolicy(name, domain string, types []string, resource string, actions []string) error
RemovePolicy(name, domain, resource string, actions []string) error RemovePolicy(name, domain string, types []string, resource string, actions []string) error
ListPolicies(name, domain, resource string, actions []string) []access.Policy ListPolicies(name, domain string, types []string, resource string, actions []string) []access.Policy
ReloadPolicies() error ReloadPolicies() error
Validators() []string Validators() []string
@@ -96,7 +96,7 @@ func (i *iam) Close() {
i.am = nil i.am = nil
} }
func (i *iam) Enforce(name, domain, resource, action string) bool { func (i *iam) Enforce(name, domain, rtype, resource, action string) bool {
if len(name) == 0 { if len(name) == 0 {
name = "$anon" name = "$anon"
} }
@@ -116,6 +116,7 @@ func (i *iam) Enforce(name, domain, resource, action string) bool {
l := i.logger.Debug().WithFields(log.Fields{ l := i.logger.Debug().WithFields(log.Fields{
"subject": name, "subject": name,
"domain": domain, "domain": domain,
"type": rtype,
"resource": resource, "resource": resource,
"action": action, "action": action,
"superuser": superuser, "superuser": superuser,
@@ -125,7 +126,7 @@ func (i *iam) Enforce(name, domain, resource, action string) bool {
name = "$superuser" name = "$superuser"
} }
ok, rule := i.am.Enforce(name, domain, resource, action) ok, rule := i.am.Enforce(name, domain, rtype, resource, action)
if !ok { if !ok {
l.Log("no match") l.Log("no match")
@@ -194,7 +195,7 @@ func (i *iam) Validators() []string {
return i.im.Validators() return i.im.Validators()
} }
func (i *iam) HasPolicy(name, domain, resource string, actions []string) bool { func (i *iam) HasPolicy(name, domain string, types []string, resource string, actions []string) bool {
if len(name) == 0 { if len(name) == 0 {
name = "$anon" name = "$anon"
} }
@@ -203,10 +204,10 @@ func (i *iam) HasPolicy(name, domain, resource string, actions []string) bool {
domain = "$none" domain = "$none"
} }
return i.am.HasPolicy(name, domain, resource, actions) return i.am.HasPolicy(name, domain, types, resource, actions)
} }
func (i *iam) AddPolicy(name, domain, resource string, actions []string) error { func (i *iam) AddPolicy(name, domain string, types []string, resource string, actions []string) error {
if len(name) == 0 { if len(name) == 0 {
name = "$anon" name = "$anon"
} }
@@ -222,10 +223,10 @@ func (i *iam) AddPolicy(name, domain, resource string, actions []string) error {
} }
} }
return i.am.AddPolicy(name, domain, resource, actions) return i.am.AddPolicy(name, domain, types, resource, actions)
} }
func (i *iam) RemovePolicy(name, domain, resource string, actions []string) error { func (i *iam) RemovePolicy(name, domain string, types []string, resource string, actions []string) error {
if len(name) != 0 && name != "$anon" { if len(name) != 0 && name != "$anon" {
if user, err := i.im.Get(name); err == nil { if user, err := i.im.Get(name); err == nil {
// Update the "updatedAt" field // Update the "updatedAt" field
@@ -233,11 +234,11 @@ func (i *iam) RemovePolicy(name, domain, resource string, actions []string) erro
} }
} }
return i.am.RemovePolicy(name, domain, resource, actions) return i.am.RemovePolicy(name, domain, types, resource, actions)
} }
func (i *iam) ListPolicies(name, domain, resource string, actions []string) []access.Policy { func (i *iam) ListPolicies(name, domain string, types []string, resource string, actions []string) []access.Policy {
return i.am.ListPolicies(name, domain, resource, actions) return i.am.ListPolicies(name, domain, types, resource, actions)
} }
func (i *iam) ReloadPolicies() error { func (i *iam) ReloadPolicies() error {

View File

@@ -69,7 +69,7 @@ func getDummyRestreamer(portrange net.Portranger, validatorIn, validatorOut ffmp
return nil, err return nil, err
} }
iam.AddPolicy("$anon", "$none", "process:*", []string{"CREATE", "GET", "DELETE", "UPDATE", "COMMAND", "PROBE", "METADATA", "PLAYOUT"}) iam.AddPolicy("$anon", "$none", []string{"process"}, "*", []string{"CREATE", "GET", "DELETE", "UPDATE", "COMMAND", "PROBE", "METADATA", "PLAYOUT"})
rewriter, err := rewrite.New(rewrite.Config{ rewriter, err := rewrite.New(rewrite.Config{
IAM: iam, IAM: iam,

View File

@@ -273,9 +273,9 @@ func (s *server) handlePlay(conn *rtmp.Conn) {
} }
domain := s.findDomainFromPlaypath(playpath) domain := s.findDomainFromPlaypath(playpath)
resource := "rtmp:" + playpath resource := playpath
if !s.iam.Enforce(identity, domain, resource, "PLAY") { if !s.iam.Enforce(identity, domain, "rtmp", resource, "PLAY") {
s.log(identity, "PLAY", "FORBIDDEN", playpath, "access denied", remote) s.log(identity, "PLAY", "FORBIDDEN", playpath, "access denied", remote)
return return
} }
@@ -402,9 +402,9 @@ func (s *server) handlePublish(conn *rtmp.Conn) {
} }
domain := s.findDomainFromPlaypath(playpath) domain := s.findDomainFromPlaypath(playpath)
resource := "rtmp:" + playpath resource := playpath
if !s.iam.Enforce(identity, domain, resource, "PUBLISH") { if !s.iam.Enforce(identity, domain, "rtmp", resource, "PUBLISH") {
s.log(identity, "PUBLISH", "FORBIDDEN", playpath, "access denied", remote) s.log(identity, "PUBLISH", "FORBIDDEN", playpath, "access denied", remote)
return return
} }

View File

@@ -330,13 +330,13 @@ func (s *server) handleConnect(req srt.ConnRequest) srt.ConnType {
} }
domain := s.findDomainFromPlaypath(si.Resource) domain := s.findDomainFromPlaypath(si.Resource)
resource := "srt:" + si.Resource resource := si.Resource
action := "PLAY" action := "PLAY"
if mode == srt.PUBLISH { if mode == srt.PUBLISH {
action = "PUBLISH" action = "PUBLISH"
} }
if !s.iam.Enforce(identity, domain, resource, action) { if !s.iam.Enforce(identity, domain, "srt", resource, action) {
s.log(identity, "CONNECT", "FORBIDDEN", si.Resource, "access denied", client) s.log(identity, "CONNECT", "FORBIDDEN", si.Resource, "access denied", client)
return srt.REJECT return srt.REJECT
} }