Create identity and access packages for IAM

This commit is contained in:
Ingo Oppermann
2023-05-25 16:16:29 +02:00
parent 710d5c595f
commit e9034aa171
22 changed files with 514 additions and 286 deletions

View File

@@ -27,6 +27,8 @@ import (
httpfs "github.com/datarhei/core/v16/http/fs"
"github.com/datarhei/core/v16/http/router"
"github.com/datarhei/core/v16/iam"
iamaccess "github.com/datarhei/core/v16/iam/access"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/io/fs"
"github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/math/rand"
@@ -390,14 +392,14 @@ func (a *api) start() error {
}
{
superuser := iam.User{
superuser := iamidentity.User{
Name: cfg.API.Auth.Username,
Superuser: true,
Auth: iam.UserAuth{
API: iam.UserAuthAPI{
Auth0: iam.UserAuthAPIAuth0{},
Auth: iamidentity.UserAuth{
API: iamidentity.UserAuthAPI{
Auth0: iamidentity.UserAuthAPIAuth0{},
},
Services: iam.UserAuthServices{
Services: iamidentity.UserAuthServices{
Token: []string{
cfg.RTMP.Token,
cfg.SRT.Token,
@@ -412,7 +414,7 @@ func (a *api) start() error {
if cfg.API.Auth.Auth0.Enable {
superuser.Auth.API.Auth0.User = cfg.API.Auth.Auth0.Tenants[0].Users[0]
superuser.Auth.API.Auth0.Tenant = iam.Auth0Tenant{
superuser.Auth.API.Auth0.Tenant = iamidentity.Auth0Tenant{
Domain: cfg.API.Auth.Auth0.Tenants[0].Domain,
Audience: cfg.API.Auth.Auth0.Tenants[0].Audience,
ClientID: cfg.API.Auth.Auth0.Tenants[0].ClientID,
@@ -431,12 +433,23 @@ func (a *api) start() error {
secret = cfg.API.Auth.Username + cfg.API.Auth.Password + cfg.API.Auth.JWT.Secret
}
policyAdapter, err := iamaccess.NewJSONAdapter(fs, "./policy.json", nil)
if err != nil {
return err
}
identityAdapter, err := iamidentity.NewJSONAdapter(fs, "./users.json", nil)
if err != nil {
return err
}
manager, err := iam.NewIAM(iam.Config{
FS: fs,
Superuser: superuser,
JWTRealm: "datarhei-core",
JWTSecret: secret,
Logger: a.log.logger.core.WithComponent("IAM"),
PolicyAdapter: policyAdapter,
IdentityAdapter: identityAdapter,
Superuser: superuser,
JWTRealm: "datarhei-core",
JWTSecret: secret,
Logger: a.log.logger.core.WithComponent("IAM"),
})
if err != nil {
return fmt.Errorf("iam: %w", err)
@@ -445,7 +458,7 @@ func (a *api) start() error {
// Check if there are already file created by IAM. If not, create policies
// and users based on the config in order to mimic the behaviour before IAM.
if len(fs.List("/", "/*.json")) == 0 {
policies := []iam.Policy{
policies := []iamaccess.Policy{
{
Name: "$anon",
Domain: "$none",
@@ -466,19 +479,19 @@ func (a *api) start() error {
},
}
users := map[string]iam.User{}
users := map[string]iamidentity.User{}
if cfg.Storage.Memory.Auth.Enable && cfg.Storage.Memory.Auth.Username != superuser.Name {
users[cfg.Storage.Memory.Auth.Username] = iam.User{
users[cfg.Storage.Memory.Auth.Username] = iamidentity.User{
Name: cfg.Storage.Memory.Auth.Username,
Auth: iam.UserAuth{
Services: iam.UserAuthServices{
Auth: iamidentity.UserAuth{
Services: iamidentity.UserAuthServices{
Basic: []string{cfg.Storage.Memory.Auth.Password},
},
},
}
policies = append(policies, iam.Policy{
policies = append(policies, iamaccess.Policy{
Name: cfg.Storage.Memory.Auth.Username,
Domain: "$none",
Resource: "fs:/memfs/**",
@@ -490,10 +503,10 @@ func (a *api) start() error {
if s.Auth.Enable && s.Auth.Username != superuser.Name {
user, ok := users[s.Auth.Username]
if !ok {
users[s.Auth.Username] = iam.User{
users[s.Auth.Username] = iamidentity.User{
Name: s.Auth.Username,
Auth: iam.UserAuth{
Services: iam.UserAuthServices{
Auth: iamidentity.UserAuth{
Services: iamidentity.UserAuthServices{
Basic: []string{s.Auth.Password},
},
},
@@ -503,7 +516,7 @@ func (a *api) start() error {
users[s.Auth.Username] = user
}
policies = append(policies, iam.Policy{
policies = append(policies, iamaccess.Policy{
Name: s.Auth.Username,
Domain: "$none",
Resource: "fs:" + s.Mountpoint + "/**",
@@ -513,7 +526,7 @@ func (a *api) start() error {
}
if cfg.RTMP.Enable && len(cfg.RTMP.Token) == 0 {
policies = append(policies, iam.Policy{
policies = append(policies, iamaccess.Policy{
Name: "$anon",
Domain: "$none",
Resource: "rtmp:/**",
@@ -522,7 +535,7 @@ func (a *api) start() error {
}
if cfg.SRT.Enable && len(cfg.SRT.Token) == 0 {
policies = append(policies, iam.Policy{
policies = append(policies, iamaccess.Policy{
Name: "$anon",
Domain: "$none",
Resource: "srt:**",
@@ -737,7 +750,7 @@ func (a *api) start() error {
}
template += "/{name}"
var identity iam.IdentityVerifier = nil
var identity iamidentity.Verifier = nil
if len(config.Owner) == 0 {
identity = a.iam.GetDefaultVerifier()
@@ -763,7 +776,7 @@ func (a *api) start() error {
template += ",mode:publish"
}
var identity iam.IdentityVerifier = nil
var identity iamidentity.Verifier = nil
if len(config.Owner) == 0 {
identity = a.iam.GetDefaultVerifier()

View File

@@ -1,6 +1,9 @@
package api
import "github.com/datarhei/core/v16/iam"
import (
"github.com/datarhei/core/v16/iam/access"
"github.com/datarhei/core/v16/iam/identity"
)
type IAMUser struct {
Name string `json:"name"`
@@ -9,7 +12,7 @@ type IAMUser struct {
Policies []IAMPolicy `json:"policies"`
}
func (u *IAMUser) Marshal(user iam.User, policies []iam.Policy) {
func (u *IAMUser) Marshal(user identity.User, policies []access.Policy) {
u.Name = user.Name
u.Superuser = user.Superuser
u.Auth = IAMUserAuth{
@@ -39,33 +42,33 @@ func (u *IAMUser) Marshal(user iam.User, policies []iam.Policy) {
}
}
func (u *IAMUser) Unmarshal() (iam.User, []iam.Policy) {
iamuser := iam.User{
func (u *IAMUser) Unmarshal() (identity.User, []access.Policy) {
iamuser := identity.User{
Name: u.Name,
Superuser: u.Superuser,
Auth: iam.UserAuth{
API: iam.UserAuthAPI{
Auth: identity.UserAuth{
API: identity.UserAuthAPI{
Password: u.Auth.API.Password,
Auth0: iam.UserAuthAPIAuth0{
Auth0: identity.UserAuthAPIAuth0{
User: u.Auth.API.Auth0.User,
Tenant: iam.Auth0Tenant{
Tenant: identity.Auth0Tenant{
Domain: u.Auth.API.Auth0.Tenant.Domain,
Audience: u.Auth.API.Auth0.Tenant.Audience,
ClientID: u.Auth.API.Auth0.Tenant.ClientID,
},
},
},
Services: iam.UserAuthServices{
Services: identity.UserAuthServices{
Basic: u.Auth.Services.Basic,
Token: u.Auth.Services.Token,
},
},
}
iampolicies := []iam.Policy{}
iampolicies := []access.Policy{}
for _, p := range u.Policies {
iampolicies = append(iampolicies, iam.Policy{
iampolicies = append(iampolicies, access.Policy{
Name: u.Name,
Domain: p.Domain,
Resource: p.Resource,

View File

@@ -6,6 +6,7 @@ import (
"github.com/datarhei/core/v16/http/api"
"github.com/datarhei/core/v16/http/handler/util"
"github.com/datarhei/core/v16/iam"
"github.com/datarhei/core/v16/iam/identity"
"github.com/labstack/echo/v4"
)
@@ -70,11 +71,6 @@ func (h *IAMHandler) AddUser(c echo.Context) error {
h.iam.AddPolicy(p.Name, p.Domain, p.Resource, p.Actions)
}
err = h.iam.SaveIdentities()
if err != nil {
return api.Err(http.StatusInternalServerError, "Internal server error", "%s", err)
}
return c.JSON(http.StatusOK, user)
}
@@ -116,11 +112,6 @@ func (h *IAMHandler) RemoveUser(c echo.Context) error {
return api.Err(http.StatusBadRequest, "Bad request", "%s", err)
}
err = h.iam.SaveIdentities()
if err != nil {
return api.Err(http.StatusInternalServerError, "Internal server error", "%s", err)
}
// Remove all policies of that user
h.iam.RemovePolicy(name, "", "", nil)
@@ -153,7 +144,7 @@ func (h *IAMHandler) UpdateUser(c echo.Context) error {
return api.Err(http.StatusForbidden, "Forbidden", "Not allowed to modify this user")
}
var iamuser iam.User
var iamuser identity.User
var err error
if name != "$anon" {
@@ -162,7 +153,7 @@ func (h *IAMHandler) UpdateUser(c echo.Context) error {
return api.Err(http.StatusNotFound, "Not found", "%s", err)
}
} else {
iamuser = iam.User{
iamuser = identity.User{
Name: "$anon",
}
}
@@ -205,11 +196,6 @@ func (h *IAMHandler) UpdateUser(c echo.Context) error {
h.iam.AddPolicy(p.Name, p.Domain, p.Resource, p.Actions)
}
err = h.iam.SaveIdentities()
if err != nil {
return api.Err(http.StatusInternalServerError, "Internal server error", "%s", err)
}
return c.JSON(http.StatusOK, user)
}
@@ -239,7 +225,7 @@ func (h *IAMHandler) UpdateUserPolicies(c echo.Context) error {
return api.Err(http.StatusForbidden, "Forbidden", "Not allowed to modify this user")
}
var iamuser iam.User
var iamuser identity.User
var err error
if name != "$anon" {
@@ -248,7 +234,7 @@ func (h *IAMHandler) UpdateUserPolicies(c echo.Context) error {
return api.Err(http.StatusNotFound, "Not found", "%s", err)
}
} else {
iamuser = iam.User{
iamuser = identity.User{
Name: "$anon",
}
}
@@ -300,7 +286,7 @@ func (h *IAMHandler) GetUser(c echo.Context) error {
return api.Err(http.StatusForbidden, "Forbidden", "Not allowed to access this user")
}
var iamuser iam.User
var iamuser identity.User
var err error
if name != "$anon" {
@@ -311,13 +297,13 @@ func (h *IAMHandler) GetUser(c echo.Context) error {
if !superuser && name != iamuser.Name {
if !h.iam.Enforce(ctxuser, domain, "iam:"+name, "write") {
iamuser = iam.User{
iamuser = identity.User{
Name: iamuser.Name,
}
}
}
} else {
iamuser = iam.User{
iamuser = identity.User{
Name: "$anon",
}
}

View File

@@ -10,6 +10,8 @@ import (
"github.com/datarhei/core/v16/http/api"
"github.com/datarhei/core/v16/http/mock"
"github.com/datarhei/core/v16/iam"
"github.com/datarhei/core/v16/iam/access"
"github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/io/fs"
"github.com/labstack/echo/v4"
@@ -33,9 +35,20 @@ func getDummyRestreamHandler() (*RestreamHandler, error) {
return nil, fmt.Errorf("failed to create memory filesystem: %w", err)
}
policyAdapter, err := access.NewJSONAdapter(memfs, "./policy.json", nil)
if err != nil {
return nil, err
}
identityAdapter, err := identity.NewJSONAdapter(memfs, "./users.json", nil)
if err != nil {
return nil, err
}
iam, err := iam.NewIAM(iam.Config{
FS: memfs,
Superuser: iam.User{
PolicyAdapter: policyAdapter,
IdentityAdapter: identityAdapter,
Superuser: identity.User{
Name: "foobar",
},
JWTRealm: "",

View File

@@ -44,6 +44,7 @@ import (
"github.com/datarhei/core/v16/http/api"
"github.com/datarhei/core/v16/http/handler/util"
"github.com/datarhei/core/v16/iam"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/log"
jwtgo "github.com/golang-jwt/jwt/v4"
@@ -117,7 +118,7 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
isAPISuperuser = true
}
var identity iam.IdentityVerifier = nil
var identity iamidentity.Verifier = nil
var err error
username := "$anon"
@@ -231,7 +232,7 @@ var ErrAuthRequired = errors.New("unauthorized")
var ErrUnauthorized = errors.New("unauthorized")
var ErrBadRequest = errors.New("bad request")
func (m *iammiddleware) findIdentityFromBasicAuth(c echo.Context) (iam.IdentityVerifier, error) {
func (m *iammiddleware) findIdentityFromBasicAuth(c echo.Context) (iamidentity.Verifier, error) {
basic := "basic"
auth := c.Request().Header.Get(echo.HeaderAuthorization)
l := len(basic)
@@ -290,7 +291,7 @@ func (m *iammiddleware) findIdentityFromBasicAuth(c echo.Context) (iam.IdentityV
return identity, nil
}
func (m *iammiddleware) findIdentityFromJWT(c echo.Context) (iam.IdentityVerifier, error) {
func (m *iammiddleware) findIdentityFromJWT(c echo.Context) (iamidentity.Verifier, error) {
// Look for an Auth header
values := c.Request().Header.Values("Authorization")
prefix := "Bearer "
@@ -356,7 +357,7 @@ func (m *iammiddleware) findIdentityFromJWT(c echo.Context) (iam.IdentityVerifie
return identity, nil
}
func (m *iammiddleware) findIdentityFromUserpass(c echo.Context) (iam.IdentityVerifier, error) {
func (m *iammiddleware) findIdentityFromUserpass(c echo.Context) (iamidentity.Verifier, error) {
var login api.Login
if err := util.ShouldBindJSON(c, &login); err != nil {
@@ -383,7 +384,7 @@ func (m *iammiddleware) findIdentityFromUserpass(c echo.Context) (iam.IdentityVe
return identity, nil
}
func (m *iammiddleware) findIdentityFromAuth0(c echo.Context) (iam.IdentityVerifier, error) {
func (m *iammiddleware) findIdentityFromAuth0(c echo.Context) (iamidentity.Verifier, error) {
// Look for an Auth header
values := c.Request().Header.Values("Authorization")
prefix := "Bearer "

View File

@@ -14,6 +14,8 @@ import (
apihandler "github.com/datarhei/core/v16/http/handler/api"
"github.com/datarhei/core/v16/http/validator"
"github.com/datarhei/core/v16/iam"
iamaccess "github.com/datarhei/core/v16/iam/access"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/io/fs"
"github.com/labstack/echo/v4"
@@ -28,9 +30,20 @@ func getIAM() (iam.IAM, error) {
return nil, err
}
policyAdapter, err := iamaccess.NewJSONAdapter(dummyfs, "./policy.json", nil)
if err != nil {
return nil, err
}
identityAdapter, err := iamidentity.NewJSONAdapter(dummyfs, "./users.json", nil)
if err != nil {
return nil, err
}
i, err := iam.NewIAM(iam.Config{
FS: dummyfs,
Superuser: iam.User{
PolicyAdapter: policyAdapter,
IdentityAdapter: identityAdapter,
Superuser: iamidentity.User{
Name: "admin",
},
JWTRealm: "datarhei-core",
@@ -41,13 +54,13 @@ func getIAM() (iam.IAM, error) {
return nil, err
}
i.CreateIdentity(iam.User{
i.CreateIdentity(iamidentity.User{
Name: "foobar",
Auth: iam.UserAuth{
API: iam.UserAuthAPI{
Auth: iamidentity.UserAuth{
API: iamidentity.UserAuthAPI{
Password: "secret",
},
Services: iam.UserAuthServices{
Services: iamidentity.UserAuthServices{
Basic: []string{"secret"},
},
},

View File

@@ -17,6 +17,8 @@ import (
"github.com/datarhei/core/v16/http/errorhandler"
"github.com/datarhei/core/v16/http/validator"
"github.com/datarhei/core/v16/iam"
iamaccess "github.com/datarhei/core/v16/iam/access"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/internal/testhelper"
"github.com/datarhei/core/v16/io/fs"
"github.com/datarhei/core/v16/restream"
@@ -53,9 +55,20 @@ func DummyRestreamer(pathPrefix string) (restream.Restreamer, error) {
return nil, err
}
policyAdapter, err := iamaccess.NewJSONAdapter(memfs, "./policy.json", nil)
if err != nil {
return nil, err
}
identityAdapter, err := iamidentity.NewJSONAdapter(memfs, "./users.json", nil)
if err != nil {
return nil, err
}
iam, err := iam.NewIAM(iam.Config{
FS: memfs,
Superuser: iam.User{
PolicyAdapter: policyAdapter,
IdentityAdapter: identityAdapter,
Superuser: iamidentity.User{
Name: "foobar",
},
JWTRealm: "",

View File

@@ -1,10 +1,8 @@
package iam
package access
import (
"fmt"
"strings"
"github.com/datarhei/core/v16/io/fs"
"github.com/datarhei/core/v16/log"
"github.com/casbin/casbin/v2"
@@ -18,43 +16,40 @@ type Policy struct {
Actions []string
}
type AccessEnforcer interface {
type Enforcer interface {
Enforce(name, domain, resource, action string) (bool, string)
HasDomain(name string) bool
ListDomains() []string
}
type AccessManager interface {
AccessEnforcer
type Manager interface {
Enforcer
HasPolicy(name, domain, resource string, actions []string) bool
AddPolicy(name, domain, resource string, actions []string) bool
RemovePolicy(name, domain, resource string, actions []string) bool
ListPolicies(name, domain, resource string, actions []string) []Policy
ReloadPolicies() error
}
type access struct {
fs fs.Filesystem
logger log.Logger
adapter *adapter
adapter Adapter
model model.Model
enforcer *casbin.Enforcer
}
type AccessConfig struct {
FS fs.Filesystem
Logger log.Logger
type Config struct {
Adapter Adapter
Logger log.Logger
}
func NewAccessManager(config AccessConfig) (AccessManager, error) {
func New(config Config) (Manager, error) {
am := &access{
fs: config.FS,
logger: config.Logger,
}
if am.fs == nil {
return nil, fmt.Errorf("a filesystem has to be provided")
adapter: config.Adapter,
logger: config.Logger,
}
if am.logger == nil {
@@ -68,12 +63,7 @@ func NewAccessManager(config AccessConfig) (AccessManager, error) {
m.AddDef("e", "e", "some(where (p.eft == allow))")
m.AddDef("m", "m", `g(r.sub, p.sub, r.dom) && r.dom == p.dom && ResourceMatch(r.obj, r.dom, p.obj) && ActionMatch(r.act, p.act) || r.sub == "$superuser"`)
a, err := newAdapter(am.fs, "./policy.json", am.logger)
if err != nil {
return nil, err
}
e, err := casbin.NewEnforcer(m, a)
e, err := casbin.NewEnforcer(m, am.adapter)
if err != nil {
return nil, err
}
@@ -82,7 +72,7 @@ func NewAccessManager(config AccessConfig) (AccessManager, error) {
e.AddFunction("ActionMatch", actionMatchFunc)
am.enforcer = e
am.adapter = a
am.model = m
return am, nil
}
@@ -129,20 +119,18 @@ func (am *access) ListPolicies(name, domain, resource string, actions []string)
return policies
}
func (am *access) ReloadPolicies() error {
am.model.ClearPolicy()
return am.adapter.LoadPolicy(am.model)
}
func (am *access) HasDomain(name string) bool {
groups := am.adapter.getAllDomains()
for _, g := range groups {
if g == name {
return true
}
}
return false
return am.adapter.HasDomain(name)
}
func (am *access) ListDomains() []string {
return am.adapter.getAllDomains()
return am.adapter.AllDomains()
}
func (am *access) Enforce(name, domain, resource, action string) (bool, string) {

View File

@@ -1,4 +1,4 @@
package iam
package access
import (
"testing"
@@ -7,13 +7,22 @@ import (
"github.com/stretchr/testify/require"
)
func TestAccessManager(t *testing.T) {
func createAdapter() (Adapter, error) {
memfs, err := fs.NewMemFilesystemFromDir("./fixtures", fs.MemConfig{})
if err != nil {
return nil, err
}
return NewJSONAdapter(memfs, "./policy.json", nil)
}
func TestAccessManager(t *testing.T) {
adapter, err := createAdapter()
require.NoError(t, err)
am, err := NewAccessManager(AccessConfig{
FS: memfs,
Logger: nil,
am, err := New(Config{
Adapter: adapter,
Logger: nil,
})
require.NoError(t, err)

View File

@@ -1,4 +1,4 @@
package iam
package access
import (
"encoding/json"
@@ -12,6 +12,7 @@ import (
"github.com/datarhei/core/v16/log"
"github.com/casbin/casbin/v2/model"
"github.com/casbin/casbin/v2/persist"
)
// Adapter is the file adapter for Casbin.
@@ -24,7 +25,14 @@ type adapter struct {
lock sync.Mutex
}
func newAdapter(fs fs.Filesystem, filePath string, logger log.Logger) (*adapter, error) {
type Adapter interface {
persist.BatchAdapter
AllDomains() []string
HasDomain(string) bool
}
func NewJSONAdapter(fs fs.Filesystem, filePath string, logger log.Logger) (Adapter, error) {
a := &adapter{
fs: fs,
filePath: filePath,
@@ -72,6 +80,8 @@ func (a *adapter) loadPolicyFile(model model.Model) error {
return err
}
model.ClearPolicy()
rule := [5]string{}
for _, domain := range domains {
rule[0] = "p"
@@ -511,7 +521,10 @@ func (a *adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int,
return fmt.Errorf("not implemented")
}
func (a *adapter) getAllDomains() []string {
func (a *adapter) AllDomains() []string {
a.lock.Lock()
defer a.lock.Unlock()
names := []string{}
for _, domain := range a.domains {
@@ -525,6 +538,23 @@ func (a *adapter) getAllDomains() []string {
return names
}
func (a *adapter) HasDomain(name string) bool {
a.lock.Lock()
defer a.lock.Unlock()
for _, domain := range a.domains {
if domain.Name[0] == '$' {
continue
}
if domain.Name == name {
return true
}
}
return false
}
type Domain struct {
Name string `json:"name"`
Roles map[string][]Role `json:"roles"`

View File

@@ -1,4 +1,4 @@
package iam
package access
import (
"encoding/json"
@@ -12,9 +12,12 @@ func TestAddPolicy(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
a, err := newAdapter(memfs, "/policy.json", nil)
ai, err := NewJSONAdapter(memfs, "/policy.json", nil)
require.NoError(t, err)
a, ok := ai.(*adapter)
require.True(t, ok)
err = a.AddPolicy("p", "p", []string{"foobar", "group", "resource", "action"})
require.NoError(t, err)
@@ -53,9 +56,12 @@ func TestRemovePolicy(t *testing.T) {
memfs, err := fs.NewMemFilesystem(fs.MemConfig{})
require.NoError(t, err)
a, err := newAdapter(memfs, "/policy.json", nil)
ai, err := NewJSONAdapter(memfs, "/policy.json", nil)
require.NoError(t, err)
a, ok := ai.(*adapter)
require.True(t, ok)
err = a.AddPolicies("p", "p", [][]string{
{"foobar1", "group", "resource1", "action1"},
{"foobar2", "group", "resource2", "action2"},

View File

@@ -1,4 +1,4 @@
package iam
package access
import (
"strings"

View File

@@ -1,7 +1,8 @@
package iam
import (
"github.com/datarhei/core/v16/io/fs"
"github.com/datarhei/core/v16/iam/access"
"github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/log"
)
@@ -18,21 +19,21 @@ type IAM interface {
HasPolicy(name, domain, resource string, actions []string) bool
AddPolicy(name, domain, resource string, actions []string) bool
RemovePolicy(name, domain, resource string, actions []string) bool
ListPolicies(name, domain, resource string, actions []string) []Policy
ListPolicies(name, domain, resource string, actions []string) []access.Policy
ReloadPolicies() error
Validators() []string
CreateIdentity(u User) error
GetIdentity(name string) (User, error)
UpdateIdentity(name string, u User) error
CreateIdentity(u identity.User) error
GetIdentity(name string) (identity.User, error)
UpdateIdentity(name string, u identity.User) error
DeleteIdentity(name string) error
ListIdentities() []User
SaveIdentities() error
ListIdentities() []identity.User
ReloadIndentities() error
GetVerifier(name string) (IdentityVerifier, error)
GetVerfierFromAuth0(name string) (IdentityVerifier, error)
GetDefaultVerifier() IdentityVerifier
GetVerifier(name string) (identity.Verifier, error)
GetVerfierFromAuth0(name string) (identity.Verifier, error)
GetDefaultVerifier() identity.Verifier
CreateJWT(name string) (string, string, error)
@@ -40,23 +41,24 @@ type IAM interface {
}
type iam struct {
im IdentityManager
am AccessManager
im identity.Manager
am access.Manager
logger log.Logger
}
type Config struct {
FS fs.Filesystem
Superuser User
JWTRealm string
JWTSecret string
Logger log.Logger
PolicyAdapter access.Adapter
IdentityAdapter identity.Adapter
Superuser identity.User
JWTRealm string
JWTSecret string
Logger log.Logger
}
func NewIAM(config Config) (IAM, error) {
im, err := NewIdentityManager(IdentityConfig{
FS: config.FS,
im, err := identity.New(identity.Config{
Adapter: config.IdentityAdapter,
Superuser: config.Superuser,
JWTRealm: config.JWTRealm,
JWTSecret: config.JWTSecret,
@@ -66,9 +68,9 @@ func NewIAM(config Config) (IAM, error) {
return nil, err
}
am, err := NewAccessManager(AccessConfig{
FS: config.FS,
Logger: config.Logger,
am, err := access.New(access.Config{
Adapter: config.PolicyAdapter,
Logger: config.Logger,
})
if err != nil {
return nil, err
@@ -138,15 +140,15 @@ func (i *iam) Enforce(name, domain, resource, action string) bool {
return ok
}
func (i *iam) CreateIdentity(u User) error {
func (i *iam) CreateIdentity(u identity.User) error {
return i.im.Create(u)
}
func (i *iam) GetIdentity(name string) (User, error) {
func (i *iam) GetIdentity(name string) (identity.User, error) {
return i.im.Get(name)
}
func (i *iam) UpdateIdentity(name string, u User) error {
func (i *iam) UpdateIdentity(name string, u identity.User) error {
return i.im.Update(name, u)
}
@@ -154,23 +156,23 @@ func (i *iam) DeleteIdentity(name string) error {
return i.im.Delete(name)
}
func (i *iam) ListIdentities() []User {
func (i *iam) ListIdentities() []identity.User {
return nil
}
func (i *iam) SaveIdentities() error {
return i.im.Save()
func (i *iam) ReloadIndentities() error {
return i.im.Reload()
}
func (i *iam) GetVerifier(name string) (IdentityVerifier, error) {
func (i *iam) GetVerifier(name string) (identity.Verifier, error) {
return i.im.GetVerifier(name)
}
func (i *iam) GetVerfierFromAuth0(name string) (IdentityVerifier, error) {
func (i *iam) GetVerfierFromAuth0(name string) (identity.Verifier, error) {
return i.im.GetVerifierFromAuth0(name)
}
func (i *iam) GetDefaultVerifier() IdentityVerifier {
func (i *iam) GetDefaultVerifier() identity.Verifier {
v, _ := i.im.GetDefaultVerifier()
return v
@@ -220,6 +222,10 @@ func (i *iam) RemovePolicy(name, domain, resource string, actions []string) bool
return i.am.RemovePolicy(name, domain, resource, actions)
}
func (i *iam) ListPolicies(name, domain, resource string, actions []string) []Policy {
func (i *iam) ListPolicies(name, domain, resource string, actions []string) []access.Policy {
return i.am.ListPolicies(name, domain, resource, actions)
}
func (i *iam) ReloadPolicies() error {
return i.am.ReloadPolicies()
}

89
iam/identity/adapter.go Normal file
View File

@@ -0,0 +1,89 @@
package identity
import (
"encoding/json"
"fmt"
"os"
"sync"
"github.com/datarhei/core/v16/io/fs"
"github.com/datarhei/core/v16/log"
)
type Adapter interface {
LoadIdentities() ([]User, error)
SaveIdentities(user []User) error
}
type fileAdapter struct {
fs fs.Filesystem
filePath string
logger log.Logger
lock sync.Mutex
}
func NewJSONAdapter(fs fs.Filesystem, filePath string, logger log.Logger) (Adapter, error) {
a := &fileAdapter{
fs: fs,
filePath: filePath,
logger: logger,
}
if a.fs == nil {
return nil, fmt.Errorf("a filesystem must be provided")
}
if a.filePath == "" {
return nil, fmt.Errorf("invalid file path, file path cannot be empty")
}
if a.logger == nil {
a.logger = log.New("")
}
return a, nil
}
func (a *fileAdapter) LoadIdentities() ([]User, error) {
a.lock.Lock()
defer a.lock.Unlock()
if _, err := a.fs.Stat(a.filePath); os.IsNotExist(err) {
return nil, nil
}
data, err := a.fs.ReadFile(a.filePath)
if err != nil {
return nil, err
}
users := []User{}
err = json.Unmarshal(data, &users)
if err != nil {
return nil, err
}
a.logger.Debug().WithField("path", a.filePath).Log("Identity file loaded")
return users, nil
}
func (a *fileAdapter) SaveIdentities(user []User) error {
a.lock.Lock()
defer a.lock.Unlock()
jsondata, err := json.MarshalIndent(user, "", " ")
if err != nil {
return err
}
_, _, err = a.fs.WriteFileSafe(a.filePath, jsondata)
if err != nil {
return err
}
a.logger.Debug().WithField("path", a.filePath).Log("Identity file save")
return nil
}

View File

@@ -1,15 +1,12 @@
package iam
package identity
import (
"encoding/json"
"fmt"
"os"
"regexp"
"sync"
"time"
"github.com/datarhei/core/v16/iam/jwks"
"github.com/datarhei/core/v16/io/fs"
"github.com/datarhei/core/v16/log"
"github.com/google/uuid"
@@ -79,7 +76,7 @@ func (u *User) clone() User {
return user
}
type IdentityVerifier interface {
type Verifier interface {
Name() string
VerifyJWT(jwt string) (bool, error)
@@ -369,21 +366,23 @@ func (i *identity) IsSuperuser() bool {
return i.user.Superuser
}
type IdentityManager interface {
type Manager interface {
Create(identity User) error
Update(name string, identity User) error
Delete(name string) error
Get(name string) (User, error)
GetVerifier(name string) (IdentityVerifier, error)
GetVerifierFromAuth0(name string) (IdentityVerifier, error)
GetDefaultVerifier() (IdentityVerifier, error)
GetVerifier(name string) (Verifier, error)
GetVerifierFromAuth0(name string) (Verifier, error)
GetDefaultVerifier() (Verifier, error)
Reload() error // Reload users from adapter
Save() error // Save users to adapter
List() []User // List all users
Validators() []string
CreateJWT(name string) (string, string, error)
Save() error
Autosave(bool)
Close()
}
@@ -395,8 +394,7 @@ type identityManager struct {
auth0UserIdentityMap map[string]string
fs fs.Filesystem
filePath string
adapter Adapter
autosave bool
logger log.Logger
@@ -406,21 +404,20 @@ type identityManager struct {
lock sync.RWMutex
}
type IdentityConfig struct {
FS fs.Filesystem
type Config struct {
Adapter Adapter
Superuser User
JWTRealm string
JWTSecret string
Logger log.Logger
}
func NewIdentityManager(config IdentityConfig) (IdentityManager, error) {
func New(config Config) (Manager, error) {
im := &identityManager{
identities: map[string]*identity{},
tenants: map[string]*auth0Tenant{},
auth0UserIdentityMap: map[string]string{},
fs: config.FS,
filePath: "./users.json",
adapter: config.Adapter,
jwtRealm: config.JWTRealm,
jwtSecret: []byte(config.JWTSecret),
logger: config.Logger,
@@ -430,13 +427,8 @@ func NewIdentityManager(config IdentityConfig) (IdentityManager, error) {
im.logger = log.New("")
}
if im.fs == nil {
return nil, fmt.Errorf("no filesystem provided")
}
err := im.load(im.filePath)
if err != nil {
return nil, err
if im.adapter == nil {
return nil, fmt.Errorf("no adapter provided")
}
config.Superuser.Superuser = true
@@ -446,7 +438,13 @@ func NewIdentityManager(config IdentityConfig) (IdentityManager, error) {
}
im.root = identity
im.autosave = true
err = im.Reload()
if err != nil {
return nil, err
}
im.Save()
return im, nil
}
@@ -455,7 +453,7 @@ func (im *identityManager) Close() {
im.lock.Lock()
defer im.lock.Unlock()
im.fs = nil
im.adapter = nil
im.auth0UserIdentityMap = map[string]string{}
im.identities = map[string]*identity{}
im.root = nil
@@ -467,6 +465,51 @@ func (im *identityManager) Close() {
im.tenants = map[string]*auth0Tenant{}
}
func (im *identityManager) Reload() error {
users, err := im.adapter.LoadIdentities()
if err != nil {
return fmt.Errorf("load users from adapter: %w", err)
}
im.lock.Lock()
defer im.lock.Unlock()
im.autosave = false
defer func() {
im.autosave = true
}()
names := []string{}
for name := range im.identities {
names = append(names, name)
}
for _, name := range names {
im.delete(name)
}
for _, u := range users {
if im.root != nil && u.Name == im.root.user.Name {
continue
}
_, ok := im.identities[u.Name]
if ok {
continue
}
identity, err := im.create(u)
if err != nil {
continue
}
im.identities[identity.user.Name] = identity
}
return nil
}
func (im *identityManager) Create(u User) error {
if err := u.validate(); err != nil {
return err
@@ -492,7 +535,7 @@ func (im *identityManager) Create(u User) error {
im.identities[identity.user.Name] = identity
if im.autosave {
im.save(im.filePath)
im.save()
}
return nil
@@ -580,7 +623,7 @@ func (im *identityManager) Update(name string, u User) error {
}).Log("Identity updated")
if im.autosave {
im.save(im.filePath)
im.save()
}
return nil
@@ -590,7 +633,12 @@ func (im *identityManager) Delete(name string) error {
im.lock.Lock()
defer im.lock.Unlock()
return im.delete(name)
err := im.delete(name)
if err != nil {
return err
}
return nil
}
func (im *identityManager) delete(name string) error {
@@ -611,7 +659,7 @@ func (im *identityManager) delete(name string) error {
if len(identity.user.Auth.API.Auth0.User) == 0 {
if im.autosave {
im.save(im.filePath)
im.save()
}
return nil
@@ -633,7 +681,7 @@ func (im *identityManager) delete(name string) error {
delete(im.tenants, identity.user.Auth.API.Auth0.Tenant.key())
if im.autosave {
im.save(im.filePath)
im.save()
}
return nil
@@ -657,7 +705,9 @@ func (im *identityManager) delete(name string) error {
}
if im.autosave {
im.save(im.filePath)
if err := im.save(); err != nil {
return err
}
}
return nil
@@ -696,14 +746,14 @@ func (im *identityManager) Get(name string) (User, error) {
return user, nil
}
func (im *identityManager) GetVerifier(name string) (IdentityVerifier, error) {
func (im *identityManager) GetVerifier(name string) (Verifier, error) {
im.lock.RLock()
defer im.lock.RUnlock()
return im.getIdentity(name)
}
func (im *identityManager) GetVerifierFromAuth0(name string) (IdentityVerifier, error) {
func (im *identityManager) GetVerifierFromAuth0(name string) (Verifier, error) {
im.lock.RLock()
defer im.lock.RUnlock()
@@ -715,65 +765,38 @@ func (im *identityManager) GetVerifierFromAuth0(name string) (IdentityVerifier,
return im.getIdentity(name)
}
func (im *identityManager) GetDefaultVerifier() (IdentityVerifier, error) {
func (im *identityManager) GetDefaultVerifier() (Verifier, error) {
return im.root, nil
}
func (im *identityManager) load(filePath string) error {
if _, err := im.fs.Stat(filePath); os.IsNotExist(err) {
return nil
}
data, err := im.fs.ReadFile(filePath)
if err != nil {
return err
}
func (im *identityManager) List() []User {
im.lock.RLock()
defer im.lock.RUnlock()
users := []User{}
err = json.Unmarshal(data, &users)
if err != nil {
return err
for _, identity := range im.identities {
users = append(users, identity.user.clone())
}
for _, u := range users {
err = im.Create(u)
if err != nil {
return err
}
}
return nil
return users
}
func (im *identityManager) Save() error {
im.lock.RLock()
defer im.lock.RUnlock()
return im.save(im.filePath)
return im.save()
}
func (im *identityManager) save(filePath string) error {
if filePath == "" {
return fmt.Errorf("invalid file path, file path cannot be empty")
}
func (im *identityManager) save() error {
users := []User{}
for _, u := range im.identities {
users = append(users, u.user)
}
jsondata, err := json.MarshalIndent(users, "", " ")
if err != nil {
return err
}
_, _, err = im.fs.WriteFileSafe(filePath, jsondata)
im.logger.Debug().WithField("path", filePath).Log("Identity file save")
return err
return im.adapter.SaveIdentities(users)
}
func (im *identityManager) Autosave(auto bool) {

View File

@@ -1,4 +1,4 @@
package iam
package identity
import (
"testing"
@@ -7,6 +7,15 @@ import (
"github.com/stretchr/testify/require"
)
func createAdapter() (Adapter, error) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
if err != nil {
return nil, err
}
return NewJSONAdapter(dummyfs, "./users.json", nil)
}
func TestUserName(t *testing.T) {
user := User{}
@@ -39,11 +48,11 @@ func TestIdentity(t *testing.T) {
identity.user.Superuser = true
require.True(t, identity.IsSuperuser())
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -58,11 +67,11 @@ func TestIdentity(t *testing.T) {
}
func TestDefaultIdentity(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -186,11 +195,11 @@ func TestIdentityServiceTokenAuth(t *testing.T) {
}
func TestJWT(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -239,11 +248,11 @@ func TestJWT(t *testing.T) {
}
func TestCreateUser(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -263,11 +272,11 @@ func TestCreateUser(t *testing.T) {
}
func TestCreateUserAuth0(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -383,11 +392,13 @@ func TestCreateUserAuth0(t *testing.T) {
}
func TestLoadAndSave(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adptr, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
dummyfs := adptr.(*fileAdapter).fs
im, err := New(Config{
Adapter: adptr,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -416,8 +427,8 @@ func TestLoadAndSave(t *testing.T) {
err = im.Save()
require.NoError(t, err)
im, err = NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err = New(Config{
Adapter: adptr,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -432,11 +443,11 @@ func TestLoadAndSave(t *testing.T) {
}
func TestUpdateUser(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -480,11 +491,11 @@ func TestUpdateUser(t *testing.T) {
}
func TestUpdateUserAuth0(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -537,11 +548,11 @@ func TestUpdateUserAuth0(t *testing.T) {
}
func TestRemoveUser(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -633,11 +644,11 @@ func TestRemoveUser(t *testing.T) {
}
func TestRemoveUserAuth0(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adapter, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
im, err := New(Config{
Adapter: adapter,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -716,11 +727,13 @@ func TestRemoveUserAuth0(t *testing.T) {
}
func TestAutosave(t *testing.T) {
dummyfs, err := fs.NewMemFilesystem(fs.MemConfig{})
adptr, err := createAdapter()
require.NoError(t, err)
im, err := NewIdentityManager(IdentityConfig{
FS: dummyfs,
dummyfs := adptr.(*fileAdapter).fs
im, err := New(Config{
Adapter: adptr,
Superuser: User{Name: "foobar"},
JWTRealm: "test-realm",
JWTSecret: "abc123",
@@ -739,8 +752,6 @@ func TestAutosave(t *testing.T) {
require.NoError(t, err)
require.Equal(t, []byte("[]"), data)
im.Autosave(true)
err = im.Create(User{Name: "foobaz"})
require.NoError(t, err)

View File

@@ -7,6 +7,8 @@ import (
"github.com/datarhei/core/v16/ffmpeg"
"github.com/datarhei/core/v16/iam"
iamaccess "github.com/datarhei/core/v16/iam/access"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/internal/testhelper"
"github.com/datarhei/core/v16/io/fs"
"github.com/datarhei/core/v16/net"
@@ -39,9 +41,20 @@ func getDummyRestreamer(portrange net.Portranger, validatorIn, validatorOut ffmp
return nil, err
}
policyAdapter, err := iamaccess.NewJSONAdapter(dummyfs, "./policy.json", nil)
if err != nil {
return nil, err
}
identityAdapter, err := iamidentity.NewJSONAdapter(dummyfs, "./users.json", nil)
if err != nil {
return nil, err
}
iam, err := iam.NewIAM(iam.Config{
FS: dummyfs,
Superuser: iam.User{
PolicyAdapter: policyAdapter,
IdentityAdapter: identityAdapter,
Superuser: iamidentity.User{
Name: "foobar",
},
JWTRealm: "",

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"net/url"
"github.com/datarhei/core/v16/iam"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/rtmp"
srturl "github.com/datarhei/core/v16/srt/url"
)
@@ -25,7 +25,7 @@ type Config struct {
// to a new identity, i.e. adjusting the credentials to the given identity.
type Rewriter interface {
RewriteAddress(address string, identity iam.IdentityVerifier, mode Access) string
RewriteAddress(address string, identity iamidentity.Verifier, mode Access) string
}
type rewrite struct {
@@ -44,7 +44,7 @@ func New(config Config) (Rewriter, error) {
return r, nil
}
func (g *rewrite) RewriteAddress(address string, identity iam.IdentityVerifier, mode Access) string {
func (g *rewrite) RewriteAddress(address string, identity iamidentity.Verifier, mode Access) string {
u, err := url.Parse(address)
if err != nil {
return address
@@ -104,7 +104,7 @@ func (g *rewrite) isLocal(u *url.URL) bool {
return host == base.Host
}
func (g *rewrite) httpURL(u *url.URL, mode Access, identity iam.IdentityVerifier) string {
func (g *rewrite) httpURL(u *url.URL, mode Access, identity iamidentity.Verifier) string {
password := identity.GetServiceBasicAuth()
if len(password) == 0 {
@@ -116,7 +116,7 @@ func (g *rewrite) httpURL(u *url.URL, mode Access, identity iam.IdentityVerifier
return u.String()
}
func (g *rewrite) rtmpURL(u *url.URL, mode Access, identity iam.IdentityVerifier) string {
func (g *rewrite) rtmpURL(u *url.URL, mode Access, identity iamidentity.Verifier) string {
token := identity.GetServiceToken()
// Remove the existing token from the path
@@ -131,7 +131,7 @@ func (g *rewrite) rtmpURL(u *url.URL, mode Access, identity iam.IdentityVerifier
return u.String()
}
func (g *rewrite) srtURL(u *url.URL, mode Access, identity iam.IdentityVerifier) string {
func (g *rewrite) srtURL(u *url.URL, mode Access, identity iamidentity.Verifier) string {
token := identity.GetServiceToken()
q := u.Query()

View File

@@ -4,21 +4,26 @@ import (
"net/url"
"testing"
"github.com/datarhei/core/v16/iam"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/io/fs"
"github.com/stretchr/testify/require"
)
func getIdentityManager(enableBasic bool) iam.IdentityManager {
func getIdentityManager(enableBasic bool) (iamidentity.Manager, error) {
dummyfs, _ := fs.NewMemFilesystem(fs.MemConfig{})
superuser := iam.User{
adapter, err := iamidentity.NewJSONAdapter(dummyfs, "./users.json", nil)
if err != nil {
return nil, err
}
superuser := iamidentity.User{
Name: "foobar",
Superuser: false,
Auth: iam.UserAuth{
API: iam.UserAuthAPI{},
Services: iam.UserAuthServices{
Auth: iamidentity.UserAuth{
API: iamidentity.UserAuthAPI{},
Services: iamidentity.UserAuthServices{
Token: []string{"servicetoken"},
},
},
@@ -28,19 +33,20 @@ func getIdentityManager(enableBasic bool) iam.IdentityManager {
superuser.Auth.Services.Basic = []string{"basicauthpassword"}
}
im, _ := iam.NewIdentityManager(iam.IdentityConfig{
FS: dummyfs,
im, err := iamidentity.New(iamidentity.Config{
Adapter: adapter,
Superuser: superuser,
JWTRealm: "",
JWTSecret: "",
Logger: nil,
})
return im
return im, err
}
func TestRewriteHTTP(t *testing.T) {
im := getIdentityManager(false)
im, err := getIdentityManager(false)
require.NoError(t, err)
rewrite, err := New(Config{
HTTPBase: "http://localhost:8080/",
@@ -70,7 +76,8 @@ func TestRewriteHTTP(t *testing.T) {
}
func TestRewriteHTTPPassword(t *testing.T) {
im := getIdentityManager(true)
im, err := getIdentityManager(true)
require.NoError(t, err)
rewrite, err := New(Config{
HTTPBase: "http://localhost:8080/",
@@ -100,7 +107,8 @@ func TestRewriteHTTPPassword(t *testing.T) {
}
func TestRewriteRTMP(t *testing.T) {
im := getIdentityManager(false)
im, err := getIdentityManager(false)
require.NoError(t, err)
rewrite, err := New(Config{
RTMPBase: "rtmp://localhost:1935/live",
@@ -128,7 +136,8 @@ func TestRewriteRTMP(t *testing.T) {
}
func TestRewriteSRT(t *testing.T) {
im := getIdentityManager(false)
im, err := getIdentityManager(false)
require.NoError(t, err)
rewrite, err := New(Config{
SRTBase: "srt://localhost:6000/",

View File

@@ -13,6 +13,7 @@ import (
"github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/iam"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/session"
@@ -467,7 +468,7 @@ func (s *server) findIdentityFromStreamKey(key string) (string, error) {
return "$anon", nil
}
var identity iam.IdentityVerifier
var identity iamidentity.Verifier
var err error
var token string

View File

@@ -11,6 +11,7 @@ import (
"github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/iam"
iamidentity "github.com/datarhei/core/v16/iam/identity"
"github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/session"
"github.com/datarhei/core/v16/srt/url"
@@ -477,7 +478,7 @@ func (s *server) findIdentityFromToken(key string) (string, error) {
return "$anon", nil
}
var identity iam.IdentityVerifier
var identity iamidentity.Verifier
var err error
var token string