Skip to content
This repository was archived by the owner on Dec 6, 2025. It is now read-only.

Commit ba810a6

Browse files
authored
More Permissions (#880)
1 parent 2fcd785 commit ba810a6

File tree

33 files changed

+821
-86
lines changed

33 files changed

+821
-86
lines changed

libs/hwauthz/commonPerm/userOrg.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package commonPerm
2+
3+
import (
4+
"common/auth"
5+
"context"
6+
7+
"github.com/google/uuid"
8+
)
9+
10+
type User uuid.UUID
11+
12+
func (t User) Type() string { return "user" }
13+
func (t User) ID() string { return uuid.UUID(t).String() }
14+
15+
func UserFromCtx(ctx context.Context) User {
16+
userID := auth.MustGetUserID(ctx)
17+
return User(userID)
18+
}
19+
20+
type Organization uuid.UUID
21+
22+
func (p Organization) Type() string { return "organization" }
23+
func (p Organization) ID() string { return uuid.UUID(p).String() }
24+
25+
func OrganizationFromCtx(ctx context.Context) Organization {
26+
organizationID := auth.MustGetOrganizationID(ctx)
27+
return Organization(organizationID)
28+
}

services/property-svc/cmd/service/main.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
hwspicedb "hwauthz/spicedb"
1414
propertySet "property-svc/internal/property-set/api"
1515
psh "property-svc/internal/property-set/handlers"
16+
propertySetSpiceDBProjection "property-svc/internal/property-set/projections/spiceDBProjection"
1617
propertyValue "property-svc/internal/property-value/api"
1718
pvh "property-svc/internal/property-value/handlers"
1819
"property-svc/internal/property-value/projections/property_value_postgres_projection"
@@ -22,7 +23,7 @@ import (
2223
property "property-svc/internal/property/api"
2324
ph "property-svc/internal/property/handlers"
2425
propertyPostgresProjection "property-svc/internal/property/projections/postgres_projection"
25-
propertySpicedbProjection "property-svc/internal/property/projections/spicedb_projection"
26+
propertySpiceDBProjection "property-svc/internal/property/projections/spiceDBProjection"
2627
)
2728

2829
const ServiceName = "property-svc"
@@ -53,14 +54,15 @@ func Main(version string, ready func()) {
5354
go projections.StartProjections(
5455
ctx,
5556
common.Shutdown,
56-
propertySpicedbProjection.NewProjection(eventStore, ServiceName, authz),
57+
propertySpiceDBProjection.NewProjection(eventStore, ServiceName, authz),
58+
propertySetSpiceDBProjection.NewProjection(eventStore, ServiceName, authz),
5759
propertyPostgresProjection.NewProjection(eventStore, ServiceName, hwdb.GetDB()),
5860
property_value_postgres_projection.NewProjection(eventStore, ServiceName, hwdb.GetDB()),
5961
property_rules_postgres.NewProjection(eventStore, ServiceName),
6062
)
6163

6264
propertyHandlers := ph.NewPropertyHandlers(aggregateStore, authz)
63-
propertySetHandlers := psh.NewPropertySetHandlers(aggregateStore)
65+
propertySetHandlers := psh.NewPropertySetHandlers(aggregateStore, authz)
6466
propertyViewHandlers := pvih.NewPropertyViewHandlers(aggregateStore)
6567
propertyValueHandlers := pvh.NewPropertyValueHandlers(aggregateStore)
6668

services/property-svc/internal/property-set/commands/v1/create_property_set.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ import (
55
"context"
66
"errors"
77
"fmt"
8+
"hwauthz"
9+
"hwauthz/commonPerm"
810
"hwes"
911

12+
"property-svc/internal/property-set/perm"
13+
1014
"github.com/google/uuid"
1115

1216
"property-svc/internal/property-set/aggregate"
@@ -20,8 +24,16 @@ type CreatePropertySetCommandHandler func(
2024
name string,
2125
) (common.ConsistencyToken, error)
2226

23-
func NewCreatePropertySetCommandHandler(as hwes.AggregateStore) CreatePropertySetCommandHandler {
27+
func NewCreatePropertySetCommandHandler(as hwes.AggregateStore, authz hwauthz.AuthZ) CreatePropertySetCommandHandler {
2428
return func(ctx context.Context, propertySetID uuid.UUID, name string) (common.ConsistencyToken, error) {
29+
user := commonPerm.UserFromCtx(ctx)
30+
org := commonPerm.OrganizationFromCtx(ctx)
31+
32+
check := hwauthz.NewPermissionCheck(user, perm.OrganizationCanUserCreatePropertySet, org)
33+
if err := authz.Must(ctx, check); err != nil {
34+
return 0, err
35+
}
36+
2537
a := aggregate.NewPropertySetAggregate(propertySetID)
2638

2739
exists, err := as.Exists(ctx, a)

services/property-svc/internal/property-set/handlers/handlers.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package handlers
22

33
import (
4+
"hwauthz"
45
"hwes"
56

67
commandsV1 "property-svc/internal/property-set/commands/v1"
@@ -20,16 +21,16 @@ type Handlers struct {
2021
Queries *Queries
2122
}
2223

23-
func NewPropertySetHandlers(as hwes.AggregateStore) *Handlers {
24+
func NewPropertySetHandlers(as hwes.AggregateStore, authz hwauthz.AuthZ) *Handlers {
2425
return &Handlers{
2526
Commands: &Commands{
2627
V1: &commandsV1.PropertySetCommands{
27-
CreatePropertySet: commandsV1.NewCreatePropertySetCommandHandler(as),
28+
CreatePropertySet: commandsV1.NewCreatePropertySetCommandHandler(as, authz),
2829
},
2930
},
3031
Queries: &Queries{
3132
V1: &queriesV1.PropertySetQueries{
32-
GetPropertySetByID: queriesV1.NewGetPropertySetByIDQueryHandler(as),
33+
GetPropertySetByID: queriesV1.NewGetPropertySetByIDQueryHandler(as, authz),
3334
},
3435
},
3536
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package perm
2+
3+
import (
4+
"hwauthz"
5+
6+
"github.com/google/uuid"
7+
)
8+
9+
// Types
10+
11+
type PropertySet uuid.UUID
12+
13+
func (t PropertySet) Type() string { return "property_set" }
14+
func (t PropertySet) ID() string { return uuid.UUID(t).String() }
15+
16+
// Direct Relations
17+
18+
const PropertySetOrganization hwauthz.Relation = "organization"
19+
20+
// Permissions
21+
22+
const OrganizationCanUserCreatePropertySet hwauthz.Permission = "create_property_set"
23+
24+
const (
25+
PropertySetCanUserGet hwauthz.Permission = "get"
26+
)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package spiceDBProjection
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"hwauthz"
8+
"hwauthz/commonPerm"
9+
"hwes"
10+
"hwes/eventstoredb/projections/custom"
11+
"hwutil"
12+
13+
"property-svc/internal/property-set/aggregate"
14+
15+
"github.com/EventStore/EventStore-Client-Go/v4/esdb"
16+
"github.com/google/uuid"
17+
zlog "github.com/rs/zerolog/log"
18+
19+
propertySetEventsV1 "property-svc/internal/property-set/events/v1"
20+
"property-svc/internal/property-set/perm"
21+
)
22+
23+
type Projection struct {
24+
*custom.CustomProjection
25+
authz hwauthz.AuthZ
26+
}
27+
28+
func NewProjection(es *esdb.Client, serviceName string, authz hwauthz.AuthZ) *Projection {
29+
subscriptionGroupName := serviceName + "-property-set-spicedb-projection"
30+
p := &Projection{
31+
CustomProjection: custom.NewCustomProjection(
32+
es,
33+
subscriptionGroupName,
34+
&[]string{aggregate.PropertySetAggregateType + "-"},
35+
),
36+
authz: authz,
37+
}
38+
p.initEventListeners()
39+
return p
40+
}
41+
42+
func (p *Projection) initEventListeners() {
43+
p.RegisterEventListener(propertySetEventsV1.PropertySetCreated, p.onPropertySetCreated)
44+
}
45+
46+
func (p *Projection) onPropertySetCreated(ctx context.Context, evt hwes.Event) (error, *esdb.NackAction) {
47+
log := zlog.Ctx(ctx)
48+
49+
// Parse Values
50+
var payload propertySetEventsV1.PropertySetCreatedEvent
51+
if err := evt.GetJsonData(&payload); err != nil {
52+
log.Error().Err(err).Msg("unmarshal failed")
53+
return err, hwutil.PtrTo(esdb.NackActionPark)
54+
}
55+
56+
propertySetID, err := uuid.Parse(payload.ID)
57+
if err != nil {
58+
return err, hwutil.PtrTo(esdb.NackActionPark)
59+
}
60+
61+
if evt.OrganizationID == nil {
62+
return errors.New("organization is missing from event"), hwutil.PtrTo(esdb.NackActionPark)
63+
}
64+
organizationID := *evt.OrganizationID
65+
66+
relationship := hwauthz.NewRelationship(
67+
commonPerm.Organization(organizationID),
68+
perm.PropertySetOrganization,
69+
perm.PropertySet(propertySetID),
70+
)
71+
72+
// add to permission graph
73+
_, err = p.authz.
74+
Create(relationship).
75+
Commit(ctx)
76+
if err != nil {
77+
return fmt.Errorf("could not create spice relationship %s: %w", relationship.DebugString(), err),
78+
hwutil.PtrTo(esdb.NackActionRetry)
79+
}
80+
81+
log.Debug().
82+
Str("relationship", relationship.DebugString()).
83+
Msg("spice relationship created")
84+
85+
return nil, nil
86+
}

services/property-svc/internal/property-set/queries/v1/get_property_set_by_id.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ package v1
33
import (
44
"context"
55
"fmt"
6+
"hwauthz"
7+
"hwauthz/commonPerm"
68
"hwes"
79

10+
"property-svc/internal/property-set/perm"
11+
812
"github.com/google/uuid"
913

1014
"property-svc/internal/property-set/aggregate"
@@ -13,8 +17,16 @@ import (
1317

1418
type GetPropertySetByIDQueryHandler func(ctx context.Context, propertySetID uuid.UUID) (*models.PropertySet, error)
1519

16-
func NewGetPropertySetByIDQueryHandler(as hwes.AggregateStore) GetPropertySetByIDQueryHandler {
20+
func NewGetPropertySetByIDQueryHandler(as hwes.AggregateStore, authz hwauthz.AuthZ) GetPropertySetByIDQueryHandler {
1721
return func(ctx context.Context, propertySetID uuid.UUID) (*models.PropertySet, error) {
22+
user := commonPerm.UserFromCtx(ctx)
23+
set := perm.PropertySet(propertySetID)
24+
check := hwauthz.NewPermissionCheck(user, perm.PropertySetCanUserGet, set)
25+
26+
if err := authz.Must(ctx, check); err != nil {
27+
return nil, err
28+
}
29+
1830
propertySetAggregate, err := aggregate.LoadPropertySetAggregate(ctx, as, propertySetID)
1931
if err != nil {
2032
return nil, fmt.Errorf("GetPropertySetByIDQueryHandler: %w", err)

services/property-svc/internal/property/commands/v1/create_property.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
pb "gen/services/property_svc/v1"
88
"hwauthz"
9+
"hwauthz/commonPerm"
910
"hwes"
1011

1112
"github.com/google/uuid"
@@ -35,8 +36,8 @@ func NewCreatePropertyCommandHandler(as hwes.AggregateStore, authz hwauthz.AuthZ
3536
setID *string,
3637
fieldTypeData *models.FieldTypeData,
3738
) (version common.ConsistencyToken, err error) {
38-
user := perm.UserFromCtx(ctx)
39-
organization := perm.OrganizationFromCtx(ctx)
39+
user := commonPerm.UserFromCtx(ctx)
40+
organization := commonPerm.OrganizationFromCtx(ctx)
4041

4142
check := hwauthz.NewPermissionCheck(user, perm.OrganizationCanUserCreateProperty, organization)
4243
if err = authz.Must(ctx, check); err != nil {

services/property-svc/internal/property/commands/v1/update_property.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
pb "gen/services/property_svc/v1"
77
"hwauthz"
8+
"hwauthz/commonPerm"
89
"hwes"
910

1011
"github.com/google/uuid"
@@ -40,7 +41,7 @@ func NewUpdatePropertyCommandHandler(as hwes.AggregateStore, authz hwauthz.AuthZ
4041
removeOptions []string,
4142
isArchived *bool,
4243
) (common.ConsistencyToken, error) {
43-
user := perm.UserFromCtx(ctx)
44+
user := commonPerm.UserFromCtx(ctx)
4445

4546
check := hwauthz.NewPermissionCheck(user, perm.PropertyCanUserUpdate, perm.Property(propertyID))
4647
if err := authz.Must(ctx, check); err != nil {

services/property-svc/internal/property/perm/permission.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package perm
22

33
import (
4-
"common/auth"
5-
"context"
64
"hwauthz"
75

86
"github.com/google/uuid"
@@ -15,26 +13,6 @@ type Property uuid.UUID
1513
func (t Property) Type() string { return "property" }
1614
func (t Property) ID() string { return uuid.UUID(t).String() }
1715

18-
type User uuid.UUID
19-
20-
func (t User) Type() string { return "user" }
21-
func (t User) ID() string { return uuid.UUID(t).String() }
22-
23-
func UserFromCtx(ctx context.Context) User {
24-
userID := auth.MustGetUserID(ctx)
25-
return User(userID)
26-
}
27-
28-
type Organization uuid.UUID
29-
30-
func (p Organization) Type() string { return "organization" }
31-
func (p Organization) ID() string { return uuid.UUID(p).String() }
32-
33-
func OrganizationFromCtx(ctx context.Context) Organization {
34-
organizationID := auth.MustGetOrganizationID(ctx)
35-
return Organization(organizationID)
36-
}
37-
3816
// Direct Relations
3917

4018
const PropertyOrganization hwauthz.Relation = "organization"

0 commit comments

Comments
 (0)