Files
new-api/service/authz/authz_test.go
T

272 lines
8.5 KiB
Go

package authz
import (
"testing"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/model"
"github.com/glebarez/sqlite"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
)
func newAuthzTestDB(t *testing.T) *gorm.DB {
t.Helper()
wasMaster := common.IsMasterNode
common.IsMasterNode = true
t.Cleanup(func() {
common.IsMasterNode = wasMaster
})
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
sqlDB, err := db.DB()
require.NoError(t, err)
sqlDB.SetMaxOpenConns(1)
require.NoError(t, db.AutoMigrate(&model.CasbinRule{}, &model.AuthzRole{}))
return db
}
func TestInitSeedsBuiltInRolesAndPoliciesOnce(t *testing.T) {
db := newAuthzTestDB(t)
require.NoError(t, Init(db))
require.NoError(t, Init(db))
// root is a superuser role and is granted everything implicitly, so only the
// admin baseline is written as explicit policy rows.
var count int64
require.NoError(t, db.Model(&model.CasbinRule{}).Count(&count).Error)
assert.Equal(t, int64(len(PermissionsForRole(BuiltInRoleAdmin))), count)
var roles []model.AuthzRole
require.NoError(t, db.Order("sort asc").Find(&roles).Error)
require.Len(t, roles, 2)
assert.Equal(t, BuiltInRoleRoot, roles[0].Key)
assert.Equal(t, BuiltInRoleAdmin, roles[1].Key)
assert.True(t, Can(1, common.RoleRootUser, ChannelSensitiveWrite))
assert.True(t, Can(2, common.RoleAdminUser, ChannelRead))
assert.True(t, Can(2, common.RoleAdminUser, ChannelOperate))
assert.True(t, Can(2, common.RoleAdminUser, ChannelWrite))
assert.False(t, Can(2, common.RoleAdminUser, ChannelSensitiveWrite))
assert.False(t, Can(3, common.RoleCommonUser, ChannelRead))
}
func TestInitOnSlaveOnlyLoadsPolicies(t *testing.T) {
wasMaster := common.IsMasterNode
common.IsMasterNode = false
t.Cleanup(func() {
common.IsMasterNode = wasMaster
})
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
sqlDB, err := db.DB()
require.NoError(t, err)
sqlDB.SetMaxOpenConns(1)
require.NoError(t, db.AutoMigrate(&model.CasbinRule{}, &model.AuthzRole{}))
require.NoError(t, Init(db))
var roleCount int64
require.NoError(t, db.Model(&model.AuthzRole{}).Count(&roleCount).Error)
assert.Equal(t, int64(0), roleCount)
var policyCount int64
require.NoError(t, db.Model(&model.CasbinRule{}).Count(&policyCount).Error)
assert.Equal(t, int64(0), policyCount)
assert.False(t, Can(2, common.RoleAdminUser, ChannelRead))
}
func TestSetUserPermissionsStoresOnlyOverrides(t *testing.T) {
db := newAuthzTestDB(t)
require.NoError(t, Init(db))
require.NoError(t, SetUserPermissions(42, PermissionsMap{
ResourceChannel: {
ActionRead: true,
ActionOperate: true,
ActionWrite: false,
ActionSensitiveWrite: true,
ActionSecretView: false,
"unknown": true,
},
"unknown": {
ActionRead: true,
},
}))
assert.True(t, Can(42, common.RoleAdminUser, ChannelSensitiveWrite))
assert.False(t, Can(42, common.RoleAdminUser, ChannelWrite))
assert.Equal(t, PermissionsMap{
ResourceChannel: {
ActionRead: true,
ActionOperate: true,
ActionWrite: false,
ActionSensitiveWrite: true,
ActionSecretView: false,
},
ResourceTaskPlugin: {
ActionBind: false,
},
}, ExplicitUserPermissions(42))
assert.Equal(t, PermissionsMap{
ResourceChannel: {
ActionSensitiveWrite: true,
ActionWrite: false,
},
}, ExplicitUserOverrides(42))
var userPolicyCount int64
require.NoError(t, db.Model(&model.CasbinRule{}).Where("v0 = ?", UserSubject(42)).Count(&userPolicyCount).Error)
assert.Equal(t, int64(2), userPolicyCount)
require.NoError(t, SetUserPermissions(42, PermissionsMap{ResourceChannel: {
ActionRead: true,
ActionOperate: true,
ActionWrite: true,
ActionSensitiveWrite: false,
ActionSecretView: false,
}}))
assert.False(t, Can(42, common.RoleAdminUser, ChannelSensitiveWrite))
assert.Equal(t, PermissionsMap{
ResourceChannel: {
ActionRead: true,
ActionOperate: true,
ActionWrite: true,
ActionSensitiveWrite: false,
ActionSecretView: false,
},
ResourceTaskPlugin: {
ActionBind: false,
},
}, ExplicitUserPermissions(42))
assert.Empty(t, ExplicitUserOverrides(42))
}
func TestClearUserAuthorizationRemovesOverrides(t *testing.T) {
db := newAuthzTestDB(t)
require.NoError(t, Init(db))
require.NoError(t, SetUserPermissions(90, PermissionsMap{ResourceChannel: {
ActionWrite: false,
ActionSensitiveWrite: true,
}}))
assert.True(t, Can(90, common.RoleAdminUser, ChannelSensitiveWrite))
assert.False(t, Can(90, common.RoleAdminUser, ChannelWrite))
require.NoError(t, ClearUserAuthorization(90))
assert.Empty(t, ExplicitUserOverrides(90))
assert.True(t, Can(90, common.RoleAdminUser, ChannelRead))
assert.True(t, Can(90, common.RoleAdminUser, ChannelWrite))
assert.False(t, Can(90, common.RoleAdminUser, ChannelSensitiveWrite))
assert.False(t, Can(90, common.RoleCommonUser, ChannelRead))
}
func TestSetUserPermissionsInTxDoesNotMutateEnforcerBeforeReload(t *testing.T) {
db := newAuthzTestDB(t)
require.NoError(t, Init(db))
require.NoError(t, db.Transaction(func(tx *gorm.DB) error {
return SetUserPermissionsInTx(tx, 42, PermissionsMap{ResourceChannel: {
ActionRead: true,
ActionOperate: true,
ActionWrite: true,
ActionSensitiveWrite: true,
ActionSecretView: false,
}})
}))
assert.False(t, Can(42, common.RoleAdminUser, ChannelSensitiveWrite))
require.NoError(t, ReloadPolicy())
assert.True(t, Can(42, common.RoleAdminUser, ChannelSensitiveWrite))
}
func TestSetUserPermissionsInTxRollbackLeavesNoPolicy(t *testing.T) {
db := newAuthzTestDB(t)
require.NoError(t, Init(db))
tx := db.Begin()
require.NoError(t, tx.Error)
require.NoError(t, SetUserPermissionsInTx(tx, 43, PermissionsMap{ResourceChannel: {
ActionSensitiveWrite: true,
}}))
require.NoError(t, tx.Rollback().Error)
require.NoError(t, ReloadPolicy())
assert.False(t, Can(43, common.RoleAdminUser, ChannelSensitiveWrite))
var count int64
require.NoError(t, db.Model(&model.CasbinRule{}).Where("v0 = ?", UserSubject(43)).Count(&count).Error)
assert.Equal(t, int64(0), count)
}
func TestAdapterAddPolicyIsIdempotent(t *testing.T) {
db := newAuthzTestDB(t)
adapter := newGormAdapter(db)
rule := []string{UserSubject(55), ResourceChannel, ActionSensitiveWrite, EffectAllow}
require.NoError(t, adapter.AddPolicy("p", "p", rule))
require.NoError(t, adapter.AddPolicy("p", "p", rule))
var count int64
require.NoError(t, db.Model(&model.CasbinRule{}).Where(
"ptype = ? AND v0 = ? AND v1 = ? AND v2 = ? AND v3 = ?",
"p",
UserSubject(55),
ResourceChannel,
ActionSensitiveWrite,
EffectAllow,
).Count(&count).Error)
assert.Equal(t, int64(1), count)
}
func TestCapabilitiesUseCatalogShape(t *testing.T) {
db := newAuthzTestDB(t)
require.NoError(t, Init(db))
capabilities := Capabilities(7, common.RoleAdminUser)
assert.True(t, capabilities[ResourceChannel][ActionRead])
assert.True(t, capabilities[ResourceChannel][ActionOperate])
assert.True(t, capabilities[ResourceChannel][ActionWrite])
assert.False(t, capabilities[ResourceChannel][ActionSensitiveWrite])
assert.False(t, capabilities[ResourceChannel][ActionSecretView])
assert.False(t, capabilities[ResourceTaskPlugin][ActionBind])
}
func TestTaskPluginBindIsRootOnlyUntilGranted(t *testing.T) {
db := newAuthzTestDB(t)
require.NoError(t, Init(db))
var bindAction *ActionDefinition
for _, resource := range Catalog() {
if resource.Resource != ResourceTaskPlugin {
continue
}
assert.Equal(t, "Task Plugin", resource.LabelKey)
for i := range resource.Actions {
if resource.Actions[i].Action == ActionBind {
bindAction = &resource.Actions[i]
}
}
}
require.NotNil(t, bindAction)
assert.Equal(t, "Bind task plugins", bindAction.LabelKey)
assert.Equal(t, "List registered task plugins and bind them when creating or editing task plugin channels.", bindAction.DescriptionKey)
assert.Empty(t, bindAction.DefaultRoles)
assert.False(t, Can(2, common.RoleAdminUser, TaskPluginBind))
assert.True(t, Can(1, common.RoleRootUser, TaskPluginBind))
enforcer := currentEnforcer()
require.NotNil(t, enforcer)
_, err := enforcer.AddPolicy(RoleSubject(BuiltInRoleAdmin), ResourceTaskPlugin, ActionBind, EffectAllow)
require.NoError(t, err)
assert.True(t, Can(2, common.RoleAdminUser, TaskPluginBind))
_, err = enforcer.RemovePolicy(RoleSubject(BuiltInRoleAdmin), ResourceTaskPlugin, ActionBind, EffectAllow)
require.NoError(t, err)
assert.False(t, Can(2, common.RoleAdminUser, TaskPluginBind))
}