mirror of
https://github.com/SigNoz/signoz.git
synced 2026-05-13 21:50:31 +01:00
Compare commits
3 Commits
fix/commit
...
platform-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe0bb30936 | ||
|
|
4369aeaf19 | ||
|
|
79e3340292 |
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/auditor"
|
||||
"github.com/SigNoz/signoz/pkg/authn"
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/authz/authzregistry"
|
||||
"github.com/SigNoz/signoz/pkg/authz/openfgaauthz"
|
||||
"github.com/SigNoz/signoz/pkg/authz/openfgaschema"
|
||||
"github.com/SigNoz/signoz/pkg/authz/openfgaserver"
|
||||
@@ -92,13 +93,14 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
|
||||
func(ctx context.Context, providerSettings factory.ProviderSettings, store authtypes.AuthNStore, licensing licensing.Licensing) (map[authtypes.AuthNProvider]authn.AuthN, error) {
|
||||
return signoz.NewAuthNs(ctx, providerSettings, store, licensing)
|
||||
},
|
||||
func(ctx context.Context, sqlstore sqlstore.SQLStore, _ licensing.Licensing, _ []authz.OnBeforeRoleDelete, _ dashboard.Module) (factory.ProviderFactory[authz.AuthZ, authz.Config], error) {
|
||||
func(ctx context.Context, sqlstore sqlstore.SQLStore, _ licensing.Licensing, _ []authz.OnBeforeRoleDelete) (factory.ProviderFactory[authz.AuthZ, authz.Config], error) {
|
||||
openfgaDataStore, err := openfgaserver.NewSQLStore(sqlstore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return openfgaauthz.NewProviderFactory(sqlstore, openfgaschema.NewSchema().Get(ctx), openfgaDataStore), nil
|
||||
authzRegistry := authzregistry.NewAuthzRegistry()
|
||||
return openfgaauthz.NewProviderFactory(sqlstore, openfgaschema.NewSchema().Get(ctx), openfgaDataStore, authzRegistry), nil
|
||||
},
|
||||
func(store sqlstore.SQLStore, settings factory.ProviderSettings, analytics analytics.Analytics, orgGetter organization.Getter, queryParser queryparser.QueryParser, _ querier.Querier, _ licensing.Licensing) dashboard.Module {
|
||||
return impldashboard.NewModule(impldashboard.NewStore(store), settings, analytics, orgGetter, queryParser)
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/auditor"
|
||||
"github.com/SigNoz/signoz/pkg/authn"
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/authz/authzregistry"
|
||||
"github.com/SigNoz/signoz/pkg/cache"
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
@@ -137,12 +138,14 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
|
||||
|
||||
return authNs, nil
|
||||
},
|
||||
func(ctx context.Context, sqlstore sqlstore.SQLStore, licensing licensing.Licensing, onBeforeRoleDelete []authz.OnBeforeRoleDelete, dashboardModule dashboard.Module) (factory.ProviderFactory[authz.AuthZ, authz.Config], error) {
|
||||
func(ctx context.Context, sqlstore sqlstore.SQLStore, licensing licensing.Licensing, onBeforeRoleDelete []authz.OnBeforeRoleDelete) (factory.ProviderFactory[authz.AuthZ, authz.Config], error) {
|
||||
openfgaDataStore, err := openfgaserver.NewSQLStore(sqlstore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return openfgaauthz.NewProviderFactory(sqlstore, openfgaschema.NewSchema().Get(ctx), openfgaDataStore, licensing, onBeforeRoleDelete, dashboardModule), nil
|
||||
|
||||
authzRegistry := authzregistry.NewAuthzRegistry()
|
||||
return openfgaauthz.NewProviderFactory(sqlstore, openfgaschema.NewSchema().Get(ctx), openfgaDataStore, licensing, onBeforeRoleDelete, authzRegistry), nil
|
||||
},
|
||||
func(store sqlstore.SQLStore, settings factory.ProviderSettings, analytics analytics.Analytics, orgGetter organization.Getter, queryParser queryparser.QueryParser, querier querier.Querier, licensing licensing.Licensing) dashboard.Module {
|
||||
return impldashboard.NewModule(pkgimpldashboard.NewStore(store), settings, analytics, orgGetter, queryParser, querier, licensing)
|
||||
|
||||
198
docs/contributing/go/authz.md
Normal file
198
docs/contributing/go/authz.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# Authorization (FGA)
|
||||
|
||||
SigNoz uses OpenFGA for fine-grained authorization. Resources are modeled as FGA objects — the authz system checks whether a principal (user or service account) has a specific relation (read, update, delete, etc.) on a specific resource.
|
||||
|
||||
This guide explains how to enable FGA for a new entity.
|
||||
|
||||
## Overview
|
||||
|
||||
Enabling FGA for an entity involves four steps:
|
||||
|
||||
1. **Define typeables** — Declare the resource type identities in `authtypes`
|
||||
2. **Register in the authz registry** — Define which managed roles get which permissions
|
||||
3. **Switch routes to the Check middleware** — Replace role-based middleware with resource-level FGA checks
|
||||
4. **Add a migration** — Backfill FGA tuples for existing organizations
|
||||
|
||||
## Step 1: Define typeables in `authtypes`
|
||||
|
||||
Add the typeable vars to the var block in `pkg/types/authtypes/typeable.go`, alongside the existing typeables. Every FGA-managed entity needs two typeables:
|
||||
|
||||
- A **collection typeable** (`metaresources`) — for `create` and `list` operations
|
||||
- An **instance typeable** (`metaresource`) — for `read`, `update`, and `delete` operations
|
||||
|
||||
```go
|
||||
// pkg/types/authtypes/typeable.go — add to the existing var block
|
||||
var (
|
||||
// ... existing typeables ...
|
||||
|
||||
TypeableMetaResourceMyEntity = MustNewTypeableMetaResource(MustNewName("my-entity"))
|
||||
TypeableMetaResourcesMyEntities = MustNewTypeableMetaResources(MustNewName("my-entities"))
|
||||
)
|
||||
```
|
||||
|
||||
These produce FGA objects like:
|
||||
- `metaresource:organization/{orgID}/my-entity/{entityID}` — individual instance
|
||||
- `metaresources:organization/{orgID}/my-entities/*` — collection
|
||||
|
||||
Use kebab-case for names. The collection name is typically the plural form.
|
||||
|
||||
## Step 2: Register in the authz registry
|
||||
|
||||
Create a new file `pkg/authz/authzregistry/myentity.go`. Each registry file exports two functions:
|
||||
|
||||
- `myEntityTypeables()` — returns the typeables for this entity
|
||||
- `myEntityTransactions()` — returns the managed role → transaction mapping
|
||||
|
||||
Use `serviceaccount.go` or `dashboard.go` as a reference. Here is the pattern:
|
||||
|
||||
```go
|
||||
package authzregistry
|
||||
|
||||
import "github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
|
||||
func myEntityTypeables() []authtypes.Typeable {
|
||||
return []authtypes.Typeable{
|
||||
authtypes.TypeableMetaResourceMyEntity,
|
||||
authtypes.TypeableMetaResourcesMyEntities,
|
||||
}
|
||||
}
|
||||
|
||||
func myEntityTransactions() map[string][]*authtypes.Transaction {
|
||||
return map[string][]*authtypes.Transaction{
|
||||
authtypes.SigNozAdminRoleName: {
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcesMyEntities, authtypes.RelationCreate),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcesMyEntities, authtypes.RelationList),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceMyEntity, authtypes.RelationRead),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceMyEntity, authtypes.RelationUpdate),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceMyEntity, authtypes.RelationDelete),
|
||||
},
|
||||
authtypes.SigNozEditorRoleName: {
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcesMyEntities, authtypes.RelationList),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceMyEntity, authtypes.RelationRead),
|
||||
},
|
||||
authtypes.SigNozViewerRoleName: {
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcesMyEntities, authtypes.RelationList),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceMyEntity, authtypes.RelationRead),
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`MustNewWildcardTransaction(typeable, relation)` creates a transaction granting the relation on all instances (`*`) of that resource type. It validates that the relation is valid for the type and generates a unique ID.
|
||||
|
||||
Then wire it into `pkg/authz/authzregistry/registry.go`:
|
||||
|
||||
```go
|
||||
func collectTypeables() []authtypes.Typeable {
|
||||
typeables := make([]authtypes.Typeable, 0)
|
||||
typeables = append(typeables, roleTypeables()...)
|
||||
typeables = append(typeables, dashboardTypeables()...)
|
||||
typeables = append(typeables, serviceAccountTypeables()...)
|
||||
typeables = append(typeables, myEntityTypeables()...) // <-- add this
|
||||
return typeables
|
||||
}
|
||||
|
||||
func collectTransactions() map[string][]*authtypes.Transaction {
|
||||
transactions := make(map[string][]*authtypes.Transaction)
|
||||
|
||||
sources := []map[string][]*authtypes.Transaction{
|
||||
dashboardTransactions(),
|
||||
serviceAccountTransactions(),
|
||||
myEntityTransactions(), // <-- add this
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
for roleName, txns := range source {
|
||||
transactions[roleName] = append(transactions[roleName], txns...)
|
||||
}
|
||||
}
|
||||
|
||||
return transactions
|
||||
}
|
||||
```
|
||||
|
||||
## Step 3: Switch routes to the Check middleware
|
||||
|
||||
In your route file (e.g., `pkg/apiserver/signozapiserver/myentity.go`), replace `AdminAccess` / `EditAccess` / `ViewAccess` with the `Check` middleware:
|
||||
|
||||
```go
|
||||
provider.authZ.Check(
|
||||
handler, // the HTTP handler func
|
||||
authtypes.RelationRead, // the relation to check
|
||||
authtypes.TypeableMetaResourceMyEntity, // the typeable
|
||||
selectorCallback, // extracts resource ID from the request
|
||||
roles, // role names for community edition fallback
|
||||
)
|
||||
```
|
||||
|
||||
### Selector callbacks
|
||||
|
||||
You need two callbacks — one for collection operations, one for instance operations:
|
||||
|
||||
```go
|
||||
// For create/list — wildcard selector on the collection.
|
||||
func myEntityCollectionSelector(_ *http.Request, _ authtypes.Claims) ([]authtypes.Selector, error) {
|
||||
return []authtypes.Selector{
|
||||
authtypes.MustNewSelector(authtypes.TypeMetaResources, authtypes.WildCardSelectorString),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// For read/update/delete — specific instance ID + wildcard.
|
||||
func myEntityInstanceSelector(req *http.Request, _ authtypes.Claims) ([]authtypes.Selector, error) {
|
||||
id := mux.Vars(req)["id"]
|
||||
idSelector, err := authtypes.NewSelector(authtypes.TypeMetaResource, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []authtypes.Selector{
|
||||
idSelector,
|
||||
authtypes.MustNewSelector(authtypes.TypeMetaResource, authtypes.WildCardSelectorString),
|
||||
}, nil
|
||||
}
|
||||
```
|
||||
|
||||
The instance callback includes a wildcard selector so that roles with wildcard permission (`*`) also match. Use `NewSelector` (not `MustNewSelector`) for user-supplied path parameters to avoid panics on malformed input.
|
||||
|
||||
### Role fallback
|
||||
|
||||
The `roles` parameter is used by the **community edition**, where `CheckWithTupleCreation` only checks role membership (ignoring resource selectors). Pass the role names that should have access:
|
||||
|
||||
```go
|
||||
var myEntityAdminRoles = []string{authtypes.SigNozAdminRoleName}
|
||||
var myEntityReadRoles = []string{authtypes.SigNozAdminRoleName, authtypes.SigNozEditorRoleName, authtypes.SigNozViewerRoleName}
|
||||
```
|
||||
|
||||
### OpenAPI security schemes
|
||||
|
||||
Use `newScopedSecuritySchemes` with the exact FGA scope, generated via `Typeable.Scope(relation)`:
|
||||
|
||||
```go
|
||||
SecuritySchemes: newScopedSecuritySchemes([]string{
|
||||
authtypes.TypeableMetaResourceMyEntity.Scope(authtypes.RelationRead),
|
||||
}),
|
||||
// produces: ["my-entity:read"]
|
||||
```
|
||||
|
||||
## Step 4: Add a migration for existing organizations
|
||||
|
||||
New organizations get FGA tuples automatically during bootstrap (via `CreateManagedUserRoleTransactions`). Existing organizations need a SQL migration to backfill the tuples.
|
||||
|
||||
Create a migration file in `pkg/sqlmigration/` (use the next available number). Follow the pattern in `078_add_sa_managed_role_txn.go`:
|
||||
|
||||
1. Select the OpenFGA store ID
|
||||
2. Iterate all organizations
|
||||
3. For each org × tuple, insert into the `tuple` and `changelog` tables
|
||||
4. Use `ON CONFLICT DO NOTHING` for idempotency
|
||||
5. Handle both PostgreSQL and SQLite dialects
|
||||
|
||||
Register the migration in `pkg/signoz/provider.go`.
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Typeable vars added to `pkg/types/authtypes/typeable.go`
|
||||
- [ ] Registry file created in `pkg/authz/authzregistry/` with `*Typeables()` and `*Transactions()` functions
|
||||
- [ ] Functions wired into `collectTypeables()` and `collectTransactions()` in `registry.go`
|
||||
- [ ] Routes switched from `AdminAccess`/`EditAccess`/`ViewAccess` to `Check` middleware
|
||||
- [ ] Selector callbacks use `NewSelector` (not `MustNewSelector`) for user-supplied IDs
|
||||
- [ ] OpenAPI `SecuritySchemes` use `newScopedSecuritySchemes` with exact scope strings
|
||||
- [ ] Migration backfills FGA tuples for existing organizations
|
||||
@@ -11,6 +11,7 @@ We adhere to three primary style guides as our foundation:
|
||||
We **recommend** (almost enforce) reviewing these guides before contributing to the codebase. They provide valuable insights into writing idiomatic Go code and will help you understand our approach to backend development. In addition, we have a few additional rules that make certain areas stricter than the above which can be found in area-specific files in this package:
|
||||
|
||||
- [Abstractions](abstractions.md) - When to introduce new types and intermediate representations
|
||||
- [Authorization](authz.md) - Enabling FGA for new entities
|
||||
- [Errors](errors.md) - Structured error handling
|
||||
- [Endpoint](endpoint.md) - HTTP endpoint patterns
|
||||
- [Flagger](flagger.md) - Feature flag patterns
|
||||
|
||||
@@ -25,19 +25,19 @@ type provider struct {
|
||||
openfgaServer *openfgaserver.Server
|
||||
licensing licensing.Licensing
|
||||
store authtypes.RoleStore
|
||||
registry []authz.RegisterTypeable
|
||||
registry authz.Registry
|
||||
settings factory.ScopedProviderSettings
|
||||
onBeforeRoleDelete []authz.OnBeforeRoleDelete
|
||||
}
|
||||
|
||||
func NewProviderFactory(sqlstore sqlstore.SQLStore, openfgaSchema []openfgapkgtransformer.ModuleFile, openfgaDataStore storage.OpenFGADatastore, licensing licensing.Licensing, onBeforeRoleDelete []authz.OnBeforeRoleDelete, registry ...authz.RegisterTypeable) factory.ProviderFactory[authz.AuthZ, authz.Config] {
|
||||
func NewProviderFactory(sqlstore sqlstore.SQLStore, openfgaSchema []openfgapkgtransformer.ModuleFile, openfgaDataStore storage.OpenFGADatastore, licensing licensing.Licensing, onBeforeRoleDelete []authz.OnBeforeRoleDelete, registry authz.Registry) factory.ProviderFactory[authz.AuthZ, authz.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("openfga"), func(ctx context.Context, ps factory.ProviderSettings, config authz.Config) (authz.AuthZ, error) {
|
||||
return newOpenfgaProvider(ctx, ps, config, sqlstore, openfgaSchema, openfgaDataStore, licensing, onBeforeRoleDelete, registry)
|
||||
})
|
||||
}
|
||||
|
||||
func newOpenfgaProvider(ctx context.Context, settings factory.ProviderSettings, config authz.Config, sqlstore sqlstore.SQLStore, openfgaSchema []openfgapkgtransformer.ModuleFile, openfgaDataStore storage.OpenFGADatastore, licensing licensing.Licensing, onBeforeRoleDelete []authz.OnBeforeRoleDelete, registry []authz.RegisterTypeable) (authz.AuthZ, error) {
|
||||
pkgOpenfgaAuthzProvider := pkgopenfgaauthz.NewProviderFactory(sqlstore, openfgaSchema, openfgaDataStore)
|
||||
func newOpenfgaProvider(ctx context.Context, settings factory.ProviderSettings, config authz.Config, sqlstore sqlstore.SQLStore, openfgaSchema []openfgapkgtransformer.ModuleFile, openfgaDataStore storage.OpenFGADatastore, licensing licensing.Licensing, onBeforeRoleDelete []authz.OnBeforeRoleDelete, registry authz.Registry) (authz.AuthZ, error) {
|
||||
pkgOpenfgaAuthzProvider := pkgopenfgaauthz.NewProviderFactory(sqlstore, openfgaSchema, openfgaDataStore, registry)
|
||||
pkgAuthzService, err := pkgOpenfgaAuthzProvider.New(ctx, settings, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -210,12 +210,7 @@ func (provider *provider) GetOrCreate(ctx context.Context, orgID valuer.UUID, ro
|
||||
|
||||
func (provider *provider) GetResources(_ context.Context) []*authtypes.Resource {
|
||||
resources := make([]*authtypes.Resource, 0)
|
||||
for _, register := range provider.registry {
|
||||
for _, typeable := range register.MustGetTypeables() {
|
||||
resources = append(resources, &authtypes.Resource{Name: typeable.Name(), Type: typeable.Type()})
|
||||
}
|
||||
}
|
||||
for _, typeable := range provider.MustGetTypeables() {
|
||||
for _, typeable := range provider.registry.GetTypeables() {
|
||||
resources = append(resources, &authtypes.Resource{Name: typeable.Name(), Type: typeable.Type()})
|
||||
}
|
||||
|
||||
@@ -234,7 +229,7 @@ func (provider *provider) GetObjects(ctx context.Context, orgID valuer.UUID, id
|
||||
}
|
||||
|
||||
objects := make([]*authtypes.Object, 0)
|
||||
for _, objectType := range provider.getUniqueTypes() {
|
||||
for _, objectType := range provider.registry.GetUniqueTypes() {
|
||||
if !slices.Contains(authtypes.TypeableRelations[objectType], relation) {
|
||||
continue
|
||||
}
|
||||
@@ -318,9 +313,6 @@ func (provider *provider) Delete(ctx context.Context, orgID valuer.UUID, id valu
|
||||
return provider.store.Delete(ctx, orgID, id)
|
||||
}
|
||||
|
||||
func (provider *provider) MustGetTypeables() []authtypes.Typeable {
|
||||
return []authtypes.Typeable{authtypes.TypeableRole, authtypes.TypeableResourcesRoles}
|
||||
}
|
||||
|
||||
func (provider *provider) getManagedRoleGrantTuples(orgID valuer.UUID, userID valuer.UUID) ([]*openfgav1.TupleKey, error) {
|
||||
tuples := []*openfgav1.TupleKey{}
|
||||
@@ -359,15 +351,8 @@ func (provider *provider) getManagedRoleGrantTuples(orgID valuer.UUID, userID va
|
||||
}
|
||||
|
||||
func (provider *provider) getManagedRoleTransactionTuples(orgID valuer.UUID) ([]*openfgav1.TupleKey, error) {
|
||||
transactionsByRole := make(map[string][]*authtypes.Transaction)
|
||||
for _, register := range provider.registry {
|
||||
for roleName, txns := range register.MustGetManagedRoleTransactions() {
|
||||
transactionsByRole[roleName] = append(transactionsByRole[roleName], txns...)
|
||||
}
|
||||
}
|
||||
|
||||
tuples := make([]*openfgav1.TupleKey, 0)
|
||||
for roleName, transactions := range transactionsByRole {
|
||||
for roleName, transactions := range provider.registry.GetManagedRoleTransactions() {
|
||||
for _, txn := range transactions {
|
||||
typeable := authtypes.MustNewTypeableFromType(txn.Object.Resource.Type, txn.Object.Resource.Name)
|
||||
txnTuples, err := typeable.Tuples(
|
||||
@@ -395,7 +380,7 @@ func (provider *provider) deleteTuples(ctx context.Context, roleName string, org
|
||||
subject := authtypes.MustNewSubject(authtypes.TypeableRole, roleName, orgID, &authtypes.RelationAssignee)
|
||||
|
||||
tuples := make([]*openfgav1.TupleKey, 0)
|
||||
for _, objectType := range provider.getUniqueTypes() {
|
||||
for _, objectType := range provider.registry.GetUniqueTypes() {
|
||||
typeTuples, err := provider.ReadTuples(ctx, &openfgav1.ReadRequestTupleKey{
|
||||
User: subject,
|
||||
Object: objectType.StringValue() + ":",
|
||||
@@ -425,27 +410,3 @@ func (provider *provider) deleteTuples(ctx context.Context, roleName string, org
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *provider) getUniqueTypes() []authtypes.Type {
|
||||
seen := make(map[string]struct{})
|
||||
uniqueTypes := make([]authtypes.Type, 0)
|
||||
for _, register := range provider.registry {
|
||||
for _, typeable := range register.MustGetTypeables() {
|
||||
typeKey := typeable.Type().StringValue()
|
||||
if _, ok := seen[typeKey]; ok {
|
||||
continue
|
||||
}
|
||||
seen[typeKey] = struct{}{}
|
||||
uniqueTypes = append(uniqueTypes, typeable.Type())
|
||||
}
|
||||
}
|
||||
for _, typeable := range provider.MustGetTypeables() {
|
||||
typeKey := typeable.Type().StringValue()
|
||||
if _, ok := seen[typeKey]; ok {
|
||||
continue
|
||||
}
|
||||
seen[typeKey] = struct{}{}
|
||||
uniqueTypes = append(uniqueTypes, typeable.Type())
|
||||
}
|
||||
|
||||
return uniqueTypes
|
||||
}
|
||||
|
||||
@@ -217,28 +217,6 @@ func (module *module) LockUnlock(ctx context.Context, orgID valuer.UUID, id valu
|
||||
return module.pkgDashboardModule.LockUnlock(ctx, orgID, id, updatedBy, isAdmin, lock)
|
||||
}
|
||||
|
||||
func (module *module) MustGetTypeables() []authtypes.Typeable {
|
||||
return module.pkgDashboardModule.MustGetTypeables()
|
||||
}
|
||||
|
||||
func (module *module) MustGetManagedRoleTransactions() map[string][]*authtypes.Transaction {
|
||||
return map[string][]*authtypes.Transaction{
|
||||
authtypes.SigNozAnonymousRoleName: {
|
||||
{
|
||||
ID: valuer.GenerateUUID(),
|
||||
Relation: authtypes.RelationRead,
|
||||
Object: *authtypes.MustNewObject(
|
||||
authtypes.Resource{
|
||||
Type: authtypes.TypeMetaResource,
|
||||
Name: dashboardtypes.TypeableMetaResourcePublicDashboard.Name(),
|
||||
},
|
||||
authtypes.MustNewSelector(authtypes.TypeMetaResource, "*"),
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (module *module) deletePublic(ctx context.Context, _ valuer.UUID, dashboardID valuer.UUID) error {
|
||||
return module.store.DeletePublic(ctx, dashboardID.StringValue())
|
||||
}
|
||||
|
||||
@@ -3,20 +3,32 @@ export default {
|
||||
status: 'success',
|
||||
data: {
|
||||
resources: [
|
||||
{
|
||||
name: 'role',
|
||||
type: 'role',
|
||||
},
|
||||
{
|
||||
name: 'roles',
|
||||
type: 'metaresources',
|
||||
},
|
||||
{
|
||||
name: 'dashboard',
|
||||
type: 'metaresource',
|
||||
},
|
||||
{
|
||||
name: 'public-dashboard',
|
||||
type: 'metaresource',
|
||||
},
|
||||
{
|
||||
name: 'dashboards',
|
||||
type: 'metaresources',
|
||||
},
|
||||
{
|
||||
name: 'role',
|
||||
type: 'role',
|
||||
name: 'service-account',
|
||||
type: 'metaresource',
|
||||
},
|
||||
{
|
||||
name: 'roles',
|
||||
name: 'service-accounts',
|
||||
type: 'metaresources',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -84,7 +84,7 @@ func (provider *provider) addDashboardRoutes(router *mux.Router) error {
|
||||
if err := router.Handle("/api/v1/public/dashboards/{id}", handler.New(provider.authZ.CheckWithoutClaims(
|
||||
provider.dashboardHandler.GetPublicData,
|
||||
authtypes.RelationRead,
|
||||
dashboardtypes.TypeableMetaResourcePublicDashboard,
|
||||
authtypes.TypeableMetaResourcePublicDashboard,
|
||||
func(req *http.Request, orgs []*types.Organization) ([]authtypes.Selector, valuer.UUID, error) {
|
||||
id, err := valuer.NewUUID(mux.Vars(req)["id"])
|
||||
if err != nil {
|
||||
@@ -104,7 +104,7 @@ func (provider *provider) addDashboardRoutes(router *mux.Router) error {
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newAnonymousSecuritySchemes([]string{dashboardtypes.TypeableMetaResourcePublicDashboard.Scope(authtypes.RelationRead)}),
|
||||
SecuritySchemes: newAnonymousSecuritySchemes([]string{authtypes.TypeableMetaResourcePublicDashboard.Scope(authtypes.RelationRead)}),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -112,7 +112,7 @@ func (provider *provider) addDashboardRoutes(router *mux.Router) error {
|
||||
if err := router.Handle("/api/v1/public/dashboards/{id}/widgets/{idx}/query_range", handler.New(provider.authZ.CheckWithoutClaims(
|
||||
provider.dashboardHandler.GetPublicWidgetQueryRange,
|
||||
authtypes.RelationRead,
|
||||
dashboardtypes.TypeableMetaResourcePublicDashboard,
|
||||
authtypes.TypeableMetaResourcePublicDashboard,
|
||||
func(req *http.Request, orgs []*types.Organization) ([]authtypes.Selector, valuer.UUID, error) {
|
||||
id, err := valuer.NewUUID(mux.Vars(req)["id"])
|
||||
if err != nil {
|
||||
@@ -132,7 +132,7 @@ func (provider *provider) addDashboardRoutes(router *mux.Router) error {
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newAnonymousSecuritySchemes([]string{dashboardtypes.TypeableMetaResourcePublicDashboard.Scope(authtypes.RelationRead)}),
|
||||
SecuritySchemes: newAnonymousSecuritySchemes([]string{authtypes.TypeableMetaResourcePublicDashboard.Scope(authtypes.RelationRead)}),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -316,10 +316,7 @@ func (provider *provider) AddToRouter(router *mux.Router) error {
|
||||
}
|
||||
|
||||
func newSecuritySchemes(role types.Role) []handler.OpenAPISecurityScheme {
|
||||
return []handler.OpenAPISecurityScheme{
|
||||
{Name: authtypes.IdentNProviderAPIKey.StringValue(), Scopes: []string{role.String()}},
|
||||
{Name: authtypes.IdentNProviderTokenizer.StringValue(), Scopes: []string{role.String()}},
|
||||
}
|
||||
return newScopedSecuritySchemes([]string{role.String()})
|
||||
}
|
||||
|
||||
func newAnonymousSecuritySchemes(scopes []string) []handler.OpenAPISecurityScheme {
|
||||
@@ -327,3 +324,10 @@ func newAnonymousSecuritySchemes(scopes []string) []handler.OpenAPISecuritySchem
|
||||
{Name: authtypes.IdentNProviderAnonymous.StringValue(), Scopes: scopes},
|
||||
}
|
||||
}
|
||||
|
||||
func newScopedSecuritySchemes(scopes []string) []handler.OpenAPISecurityScheme {
|
||||
return []handler.OpenAPISecurityScheme{
|
||||
{Name: authtypes.IdentNProviderAPIKey.StringValue(), Scopes: scopes},
|
||||
{Name: authtypes.IdentNProviderTokenizer.StringValue(), Scopes: scopes},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,10 +90,11 @@ type AuthZ interface {
|
||||
// OnBeforeRoleDelete is a callback invoked before a role is deleted.
|
||||
type OnBeforeRoleDelete func(context.Context, valuer.UUID, valuer.UUID) error
|
||||
|
||||
type RegisterTypeable interface {
|
||||
MustGetTypeables() []authtypes.Typeable
|
||||
|
||||
MustGetManagedRoleTransactions() map[string][]*authtypes.Transaction
|
||||
type Registry interface {
|
||||
GetTypeables() []authtypes.Typeable
|
||||
GetManagedRoleTransactions() map[string][]*authtypes.Transaction
|
||||
GetUniqueTypes() []authtypes.Type
|
||||
GetManagedRolesByTransaction() map[string][]string
|
||||
}
|
||||
|
||||
type Handler interface {
|
||||
|
||||
19
pkg/authz/authzregistry/dashboard.go
Normal file
19
pkg/authz/authzregistry/dashboard.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package authzregistry
|
||||
|
||||
import "github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
|
||||
func dashboardTypeables() []authtypes.Typeable {
|
||||
return []authtypes.Typeable{
|
||||
authtypes.TypeableMetaResourceDashboard,
|
||||
authtypes.TypeableMetaResourcePublicDashboard,
|
||||
authtypes.TypeableMetaResourcesDashboards,
|
||||
}
|
||||
}
|
||||
|
||||
func dashboardTransactions() map[string][]*authtypes.Transaction {
|
||||
return map[string][]*authtypes.Transaction{
|
||||
authtypes.SigNozAnonymousRoleName: {
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcePublicDashboard, authtypes.RelationRead),
|
||||
},
|
||||
}
|
||||
}
|
||||
94
pkg/authz/authzregistry/registry.go
Normal file
94
pkg/authz/authzregistry/registry.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package authzregistry
|
||||
|
||||
import (
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
)
|
||||
|
||||
type registry struct {
|
||||
typeables []authtypes.Typeable
|
||||
transactions map[string][]*authtypes.Transaction
|
||||
uniqueTypes []authtypes.Type
|
||||
managedRolesByTransaction map[string][]string
|
||||
}
|
||||
|
||||
func NewAuthzRegistry() authz.Registry {
|
||||
typeables := collectTypeables()
|
||||
transactions := collectTransactions()
|
||||
|
||||
uniqueTypes := buildUniqueTypes(typeables)
|
||||
managedRolesByTransaction := buildManagedRolesByTransaction(transactions)
|
||||
|
||||
return ®istry{
|
||||
typeables: typeables,
|
||||
transactions: transactions,
|
||||
uniqueTypes: uniqueTypes,
|
||||
managedRolesByTransaction: managedRolesByTransaction,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *registry) GetTypeables() []authtypes.Typeable {
|
||||
return r.typeables
|
||||
}
|
||||
|
||||
func (r *registry) GetManagedRoleTransactions() map[string][]*authtypes.Transaction {
|
||||
return r.transactions
|
||||
}
|
||||
|
||||
func (r *registry) GetUniqueTypes() []authtypes.Type {
|
||||
return r.uniqueTypes
|
||||
}
|
||||
|
||||
func (r *registry) GetManagedRolesByTransaction() map[string][]string {
|
||||
return r.managedRolesByTransaction
|
||||
}
|
||||
|
||||
func collectTypeables() []authtypes.Typeable {
|
||||
typeables := make([]authtypes.Typeable, 0)
|
||||
typeables = append(typeables, roleTypeables()...)
|
||||
typeables = append(typeables, dashboardTypeables()...)
|
||||
typeables = append(typeables, serviceAccountTypeables()...)
|
||||
return typeables
|
||||
}
|
||||
|
||||
func collectTransactions() map[string][]*authtypes.Transaction {
|
||||
transactions := make(map[string][]*authtypes.Transaction)
|
||||
|
||||
sources := []map[string][]*authtypes.Transaction{
|
||||
dashboardTransactions(),
|
||||
serviceAccountTransactions(),
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
for roleName, txns := range source {
|
||||
transactions[roleName] = append(transactions[roleName], txns...)
|
||||
}
|
||||
}
|
||||
|
||||
return transactions
|
||||
}
|
||||
|
||||
func buildUniqueTypes(typeables []authtypes.Typeable) []authtypes.Type {
|
||||
seen := make(map[string]struct{})
|
||||
uniqueTypes := make([]authtypes.Type, 0)
|
||||
for _, typeable := range typeables {
|
||||
typeKey := typeable.Type().StringValue()
|
||||
if _, ok := seen[typeKey]; ok {
|
||||
continue
|
||||
}
|
||||
seen[typeKey] = struct{}{}
|
||||
uniqueTypes = append(uniqueTypes, typeable.Type())
|
||||
}
|
||||
return uniqueTypes
|
||||
}
|
||||
|
||||
func buildManagedRolesByTransaction(transactions map[string][]*authtypes.Transaction) map[string][]string {
|
||||
managedRolesByTransaction := make(map[string][]string)
|
||||
for roleName, txns := range transactions {
|
||||
for _, txn := range txns {
|
||||
key := txn.TransactionKey()
|
||||
managedRolesByTransaction[key] = append(managedRolesByTransaction[key], roleName)
|
||||
}
|
||||
}
|
||||
return managedRolesByTransaction
|
||||
}
|
||||
10
pkg/authz/authzregistry/role.go
Normal file
10
pkg/authz/authzregistry/role.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package authzregistry
|
||||
|
||||
import "github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
|
||||
func roleTypeables() []authtypes.Typeable {
|
||||
return []authtypes.Typeable{
|
||||
authtypes.TypeableRole,
|
||||
authtypes.TypeableResourcesRoles,
|
||||
}
|
||||
}
|
||||
30
pkg/authz/authzregistry/serviceaccount.go
Normal file
30
pkg/authz/authzregistry/serviceaccount.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package authzregistry
|
||||
|
||||
import "github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
|
||||
func serviceAccountTypeables() []authtypes.Typeable {
|
||||
return []authtypes.Typeable{
|
||||
authtypes.TypeableMetaResourceServiceAccount,
|
||||
authtypes.TypeableMetaResourcesServiceAccounts,
|
||||
}
|
||||
}
|
||||
|
||||
func serviceAccountTransactions() map[string][]*authtypes.Transaction {
|
||||
return map[string][]*authtypes.Transaction{
|
||||
authtypes.SigNozAdminRoleName: {
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcesServiceAccounts, authtypes.RelationCreate),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcesServiceAccounts, authtypes.RelationList),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceServiceAccount, authtypes.RelationRead),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceServiceAccount, authtypes.RelationUpdate),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceServiceAccount, authtypes.RelationDelete),
|
||||
},
|
||||
authtypes.SigNozEditorRoleName: {
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcesServiceAccounts, authtypes.RelationList),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceServiceAccount, authtypes.RelationRead),
|
||||
},
|
||||
authtypes.SigNozViewerRoleName: {
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourcesServiceAccounts, authtypes.RelationList),
|
||||
authtypes.MustNewWildcardTransaction(authtypes.TypeableMetaResourceServiceAccount, authtypes.RelationRead),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -18,31 +18,27 @@ import (
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
server *openfgaserver.Server
|
||||
store authtypes.RoleStore
|
||||
registry []authz.RegisterTypeable
|
||||
managedRolesByTransaction map[string][]string
|
||||
server *openfgaserver.Server
|
||||
store authtypes.RoleStore
|
||||
registry authz.Registry
|
||||
}
|
||||
|
||||
func NewProviderFactory(sqlstore sqlstore.SQLStore, openfgaSchema []openfgapkgtransformer.ModuleFile, openfgaDataStore storage.OpenFGADatastore, registry ...authz.RegisterTypeable) factory.ProviderFactory[authz.AuthZ, authz.Config] {
|
||||
func NewProviderFactory(sqlstore sqlstore.SQLStore, openfgaSchema []openfgapkgtransformer.ModuleFile, openfgaDataStore storage.OpenFGADatastore, registry authz.Registry) factory.ProviderFactory[authz.AuthZ, authz.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("openfga"), func(ctx context.Context, ps factory.ProviderSettings, config authz.Config) (authz.AuthZ, error) {
|
||||
return newOpenfgaProvider(ctx, ps, config, sqlstore, openfgaSchema, openfgaDataStore, registry)
|
||||
})
|
||||
}
|
||||
|
||||
func newOpenfgaProvider(ctx context.Context, settings factory.ProviderSettings, config authz.Config, sqlstore sqlstore.SQLStore, openfgaSchema []openfgapkgtransformer.ModuleFile, openfgaDataStore storage.OpenFGADatastore, registry []authz.RegisterTypeable) (authz.AuthZ, error) {
|
||||
func newOpenfgaProvider(ctx context.Context, settings factory.ProviderSettings, config authz.Config, sqlstore sqlstore.SQLStore, openfgaSchema []openfgapkgtransformer.ModuleFile, openfgaDataStore storage.OpenFGADatastore, registry authz.Registry) (authz.AuthZ, error) {
|
||||
server, err := openfgaserver.NewOpenfgaServer(ctx, settings, config, sqlstore, openfgaSchema, openfgaDataStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
managedRolesByTransaction := buildManagedRolesByTransaction(registry)
|
||||
|
||||
return &provider{
|
||||
server: server,
|
||||
store: sqlauthzstore.NewSqlAuthzStore(sqlstore),
|
||||
registry: registry,
|
||||
managedRolesByTransaction: managedRolesByTransaction,
|
||||
server: server,
|
||||
store: sqlauthzstore.NewSqlAuthzStore(sqlstore),
|
||||
registry: registry,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -220,7 +216,7 @@ func (provider *provider) CheckTransactions(ctx context.Context, subject string,
|
||||
return make([]*authtypes.TransactionWithAuthorization, 0), nil
|
||||
}
|
||||
|
||||
tuples, preResolved, roleCorrelations, err := authtypes.NewTuplesFromTransactionsWithManagedRoles(transactions, subject, orgID, provider.managedRolesByTransaction)
|
||||
tuples, preResolved, roleCorrelations, err := authtypes.NewTuplesFromTransactionsWithManagedRoles(transactions, subject, orgID, provider.registry.GetManagedRolesByTransaction())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -237,20 +233,3 @@ func (provider *provider) CheckTransactions(ctx context.Context, subject string,
|
||||
return authtypes.NewTransactionWithAuthorizationFromBatchResults(transactions, batchResults, preResolved, roleCorrelations), nil
|
||||
}
|
||||
|
||||
func buildManagedRolesByTransaction(registry []authz.RegisterTypeable) map[string][]string {
|
||||
managedRolesByTransaction := make(map[string][]string)
|
||||
for _, register := range registry {
|
||||
for roleName, transactions := range register.MustGetManagedRoleTransactions() {
|
||||
for _, txn := range transactions {
|
||||
key := txn.TransactionKey()
|
||||
managedRolesByTransaction[key] = append(managedRolesByTransaction[key], roleName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return managedRolesByTransaction
|
||||
}
|
||||
|
||||
func (provider *provider) MustGetTypeables() []authtypes.Typeable {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/authz"
|
||||
"github.com/SigNoz/signoz/pkg/statsreporter"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
@@ -50,8 +49,6 @@ type Module interface {
|
||||
GetByMetricNames(ctx context.Context, orgID valuer.UUID, metricNames []string) (map[string][]map[string]string, error)
|
||||
|
||||
statsreporter.StatsCollector
|
||||
|
||||
authz.RegisterTypeable
|
||||
}
|
||||
|
||||
type Handler interface {
|
||||
|
||||
@@ -202,14 +202,6 @@ func (module *module) Collect(ctx context.Context, orgID valuer.UUID) (map[strin
|
||||
return dashboardtypes.NewStatsFromStorableDashboards(dashboards), nil
|
||||
}
|
||||
|
||||
func (module *module) MustGetTypeables() []authtypes.Typeable {
|
||||
return []authtypes.Typeable{dashboardtypes.TypeableMetaResourceDashboard, dashboardtypes.TypeableMetaResourcesDashboards}
|
||||
}
|
||||
|
||||
func (module *module) MustGetManagedRoleTransactions() map[string][]*authtypes.Transaction {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreatePublic is not supported.
|
||||
func (module *module) CreatePublic(ctx context.Context, orgID valuer.UUID, publicDashboard *dashboardtypes.PublicDashboard) error {
|
||||
return errors.Newf(errors.TypeUnsupported, dashboardtypes.ErrCodePublicDashboardUnsupported, "not implemented")
|
||||
|
||||
@@ -100,7 +100,7 @@ func New(
|
||||
sqlstoreProviderFactories factory.NamedMap[factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config]],
|
||||
telemetrystoreProviderFactories factory.NamedMap[factory.ProviderFactory[telemetrystore.TelemetryStore, telemetrystore.Config]],
|
||||
authNsCallback func(ctx context.Context, providerSettings factory.ProviderSettings, store authtypes.AuthNStore, licensing licensing.Licensing) (map[authtypes.AuthNProvider]authn.AuthN, error),
|
||||
authzCallback func(context.Context, sqlstore.SQLStore, licensing.Licensing, []authz.OnBeforeRoleDelete, dashboard.Module) (factory.ProviderFactory[authz.AuthZ, authz.Config], error),
|
||||
authzCallback func(context.Context, sqlstore.SQLStore, licensing.Licensing, []authz.OnBeforeRoleDelete) (factory.ProviderFactory[authz.AuthZ, authz.Config], error),
|
||||
dashboardModuleCallback func(sqlstore.SQLStore, factory.ProviderSettings, analytics.Analytics, organization.Getter, queryparser.QueryParser, querier.Querier, licensing.Licensing) dashboard.Module,
|
||||
gatewayProviderFactory func(licensing.Licensing) factory.ProviderFactory[gateway.Gateway, gateway.Config],
|
||||
auditorProviderFactories func(licensing.Licensing) factory.NamedMap[factory.ProviderFactory[auditor.Auditor, auditor.Config]],
|
||||
@@ -322,12 +322,9 @@ func New(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize query parser (needed for dashboard module)
|
||||
// Initialize query parser
|
||||
queryParser := queryparser.New(providerSettings)
|
||||
|
||||
// Initialize dashboard module (needed for authz registry)
|
||||
dashboard := dashboardModuleCallback(sqlstore, providerSettings, analytics, orgGetter, queryParser, querier, licensing)
|
||||
|
||||
// Initialize user getter
|
||||
userGetter := impluser.NewGetter(userStore, userRoleStore, flagger)
|
||||
|
||||
@@ -341,7 +338,7 @@ func New(
|
||||
}
|
||||
|
||||
// Initialize authz
|
||||
authzProviderFactory, err := authzCallback(ctx, sqlstore, licensing, onBeforeRoleDelete, dashboard)
|
||||
authzProviderFactory, err := authzCallback(ctx, sqlstore, licensing, onBeforeRoleDelete)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -350,6 +347,9 @@ func New(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize dashboard module (no longer needs to be before authz — registry is independent)
|
||||
dashboard := dashboardModuleCallback(sqlstore, providerSettings, analytics, orgGetter, queryParser, querier, licensing)
|
||||
|
||||
// Initialize notification manager from the available notification manager provider factories
|
||||
nfManager, err := factory.NewProviderFromNamedMap(
|
||||
ctx,
|
||||
|
||||
@@ -33,6 +33,24 @@ func NewTransaction(relation Relation, object Object) (*Transaction, error) {
|
||||
return &Transaction{ID: valuer.GenerateUUID(), Relation: relation, Object: object}, nil
|
||||
}
|
||||
|
||||
func MustNewTransaction(relation Relation, object Object) *Transaction {
|
||||
txn, err := NewTransaction(relation, object)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return txn
|
||||
}
|
||||
|
||||
// MustNewWildcardTransaction creates a Transaction granting the given relation
|
||||
// on all instances (*) of the given typeable. This is the standard way to
|
||||
// express managed role permissions in the authz registry.
|
||||
func MustNewWildcardTransaction(typeable Typeable, relation Relation) *Transaction {
|
||||
return MustNewTransaction(relation, *MustNewObject(
|
||||
Resource{Type: typeable.Type(), Name: typeable.Name()},
|
||||
MustNewSelector(typeable.Type(), "*"),
|
||||
))
|
||||
}
|
||||
|
||||
func NewGettableTransaction(results []*TransactionWithAuthorization) []*GettableTransaction {
|
||||
gettableTransactions := make([]*GettableTransaction, len(results))
|
||||
for i, result := range results {
|
||||
|
||||
@@ -25,11 +25,17 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
TypeableUser = &typeableUser{}
|
||||
TypeableServiceAccount = &typeableServiceAccount{}
|
||||
TypeableAnonymous = &typeableAnonymous{}
|
||||
TypeableRole = &typeableRole{}
|
||||
TypeableOrganization = &typeableOrganization{}
|
||||
TypeableUser Typeable = new(typeableUser)
|
||||
TypeableServiceAccount Typeable = new(typeableServiceAccount)
|
||||
TypeableAnonymous Typeable = new(typeableAnonymous)
|
||||
TypeableRole Typeable = new(typeableRole)
|
||||
TypeableOrganization Typeable = new(typeableOrganization)
|
||||
|
||||
TypeableMetaResourceDashboard = MustNewTypeableMetaResource(MustNewName("dashboard"))
|
||||
TypeableMetaResourcePublicDashboard = MustNewTypeableMetaResource(MustNewName("public-dashboard"))
|
||||
TypeableMetaResourcesDashboards = MustNewTypeableMetaResources(MustNewName("dashboards"))
|
||||
TypeableMetaResourceServiceAccount = MustNewTypeableMetaResource(MustNewName("service-account"))
|
||||
TypeableMetaResourcesServiceAccounts = MustNewTypeableMetaResources(MustNewName("service-accounts"))
|
||||
)
|
||||
|
||||
type Typeable interface {
|
||||
|
||||
@@ -9,18 +9,11 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/transition"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
var (
|
||||
TypeableMetaResourceDashboard = authtypes.MustNewTypeableMetaResource(authtypes.MustNewName("dashboard"))
|
||||
TypeableMetaResourcePublicDashboard = authtypes.MustNewTypeableMetaResource(authtypes.MustNewName("public-dashboard"))
|
||||
TypeableMetaResourcesDashboards = authtypes.MustNewTypeableMetaResources(authtypes.MustNewName("dashboards"))
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCodeDashboardInvalidInput = errors.MustNewCode("dashboard_invalid_input")
|
||||
ErrCodeDashboardNotFound = errors.MustNewCode("dashboard_not_found")
|
||||
|
||||
Reference in New Issue
Block a user