Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions service/integration/attribute_fqns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1647,6 +1647,95 @@ func (s *AttributeFqnSuite) TestGetAttributeByValueFqns_KAS_Keys_Returned() {
}
}

func (s *AttributeFqnSuite) Test_GrantsAreReturned() {
// Create New Namespace
ns, err := s.db.PolicyClient.CreateNamespace(s.ctx, &namespaces.CreateNamespaceRequest{Name: "grants.com"})
s.Require().NoError(err)
s.NotNil(ns)

// Create Attribute
attr, err := s.db.PolicyClient.CreateAttribute(s.ctx, &attributes.CreateAttributeRequest{
Name: "grants",
NamespaceId: ns.GetId(),
Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF,
Values: []string{"value1", "value2"},
})
s.Require().NoError(err)
s.NotNil(attr)

// Create Kas Registry
kas, err := s.db.PolicyClient.CreateKeyAccessServer(s.ctx, &kasregistry.CreateKeyAccessServerRequest{
Uri: "https://grants.com/kas",
PublicKey: &policy.PublicKey{
PublicKey: &policy.PublicKey_Remote{
Remote: "https://grants.com/kas/public_key",
},
},
})
s.Require().NoError(err)
s.NotNil(kas)

// Create NS Grant
nsGrant, err := s.db.PolicyClient.AssignKeyAccessServerToNamespace(s.ctx, policydb.AssignKeyAccessServerToNamespaceParams{
NamespaceID: ns.GetId(),
KeyAccessServerID: kas.GetId(),
})
s.Require().NoError(err)
s.NotNil(nsGrant)

// Create Attribute Grant
attrGrant, err := s.db.PolicyClient.AssignKeyAccessServerToAttribute(s.ctx, policydb.AssignKeyAccessServerToAttributeParams{
AttributeDefinitionID: attr.GetId(),
KeyAccessServerID: kas.GetId(),
})
s.Require().NoError(err)
s.NotNil(attrGrant)

// Create Value Grant
valueGrant, err := s.db.PolicyClient.AssignKeyAccessServerToAttributeValue(s.ctx, policydb.AssignKeyAccessServerToAttributeValueParams{
AttributeValueID: attr.GetValues()[0].GetId(),
KeyAccessServerID: kas.GetId(),
})
s.Require().NoError(err)
s.NotNil(valueGrant)

// Get Namespace check for grant
nsGet, err := s.db.PolicyClient.GetNamespace(s.ctx, ns.GetId())
s.Require().NoError(err)
s.NotNil(nsGet)
s.Len(nsGet.GetGrants(), 1)
s.Equal(ns.GetId(), nsGet.GetId())
s.Equal(kas.GetId(), nsGet.GetGrants()[0].GetId())

// Get Attribute
attrGet, err := s.db.PolicyClient.GetAttribute(s.ctx, attr.GetId())
s.Require().NoError(err)
s.NotNil(attrGet)
s.Len(attrGet.GetGrants(), 1)
s.Equal(attr.GetId(), attrGet.GetId())
s.Equal(kas.GetId(), attrGet.GetGrants()[0].GetId())

// Get Value
valueGet, err := s.db.PolicyClient.GetAttributeValue(s.ctx, attr.GetValues()[0].GetId())
s.Require().NoError(err)
s.NotNil(valueGet)
s.Len(valueGet.GetGrants(), 1)
s.Equal(attr.GetValues()[0].GetId(), valueGet.GetId())
s.Equal(kas.GetId(), valueGet.GetGrants()[0].GetId())

// GetAttributeByFQN Values
fqn := fqnBuilder(ns.GetName(), attr.GetName(), attr.GetValues()[0].GetValue())
v, err := s.db.PolicyClient.GetAttributesByValueFqns(s.ctx, &attributes.GetAttributeValuesByFqnsRequest{
Fqns: []string{fqn},
})
s.Require().NoError(err)
s.NotNil(v)
s.Len(v, 1)
s.Len(v[fqn].GetAttribute().GetNamespace().GetGrants(), 1)
s.Len(v[fqn].GetAttribute().GetGrants(), 1)
s.Len(v[fqn].GetValue().GetGrants(), 1)
}

func validateSimpleKasKey(s *suite.Suite, expected *policy.KasKey, actual *policy.SimpleKasKey) {
s.Equal(expected.GetKey().GetKeyId(), actual.GetPublicKey().GetKid())
s.Equal(expected.GetKasUri(), actual.GetKasUri())
Expand Down
10 changes: 10 additions & 0 deletions service/policy/db/attribute_values.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ func (c PolicyDBClient) GetAttributeValue(ctx context.Context, identifier any) (
return nil, err
}

var grants []*policy.KeyAccessServer
if av.Grants != nil {
grants, err = db.KeyAccessServerProtoJSON(av.Grants)
if err != nil {
c.logger.ErrorContext(ctx, "could not unmarshal key access grants", slog.String("error", err.Error()))
return nil, err
}
}

var keys []*policy.SimpleKasKey
if av.Keys != nil {
keys, err = db.SimpleKasKeysProtoJSON(av.Keys)
Expand All @@ -101,6 +110,7 @@ func (c PolicyDBClient) GetAttributeValue(ctx context.Context, identifier any) (
Id: av.AttributeDefinitionID,
},
Fqn: av.Fqn.String,
Grants: grants,
KasKeys: keys,
}, nil
}
Expand Down
18 changes: 18 additions & 0 deletions service/policy/db/attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type attributeQueryRow struct {
active bool
namespaceName string
valuesJSON []byte
grantsJSON []byte
fqn sql.NullString
}

Expand All @@ -80,6 +81,15 @@ func hydrateAttribute(row *attributeQueryRow) (*policy.Attribute, error) {
values = v
}

var grants []*policy.KeyAccessServer
if row.grantsJSON != nil {
k, err := db.KeyAccessServerProtoJSON(row.grantsJSON)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal grantsJSON [%s]: %w", string(row.grantsJSON), err)
}
grants = k
}

ns := &policy.Namespace{
Id: row.namespaceID,
Name: row.namespaceName,
Expand All @@ -94,6 +104,7 @@ func hydrateAttribute(row *attributeQueryRow) (*policy.Attribute, error) {
Active: &wrapperspb.BoolValue{Value: row.active},
Metadata: metadata,
Namespace: ns,
Grants: grants,
Fqn: row.fqn.String,
}

Expand Down Expand Up @@ -225,6 +236,7 @@ func (c PolicyDBClient) GetAttribute(ctx context.Context, identifier any) (*poli
namespaceID: attr.NamespaceID,
namespaceName: attr.NamespaceName.String,
valuesJSON: attr.Values,
grantsJSON: attr.Grants,
fqn: sql.NullString(attr.Fqn),
})
if err != nil {
Expand Down Expand Up @@ -264,6 +276,12 @@ func (c PolicyDBClient) ListAttributesByFqns(ctx context.Context, fqns []string)

var keys []*policy.SimpleKasKey
var grants []*policy.KeyAccessServer
if len(attr.Grants) > 0 {
grants, err = db.KeyAccessServerProtoJSON(attr.Grants)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal grants [%s]: %w", string(attr.Grants), err)
}
}
if len(attr.Keys) > 0 {
keys, err = db.SimpleKasKeysProtoJSON(attr.Keys)
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions service/policy/db/namespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ func (c PolicyDBClient) GetNamespace(ctx context.Context, identifier any) (*poli
return nil, err
}

var grants []*policy.KeyAccessServer
if ns.Grants != nil {
grants, err = db.KeyAccessServerProtoJSON(ns.Grants)
if err != nil {
c.logger.Error("could not unmarshal grants", slog.String("error", err.Error()))
return nil, err
}
}

var keys []*policy.SimpleKasKey
if len(ns.Keys) > 0 {
keys, err = db.SimpleKasKeysProtoJSON(ns.Keys)
Expand All @@ -65,6 +74,7 @@ func (c PolicyDBClient) GetNamespace(ctx context.Context, identifier any) (*poli
Id: ns.ID,
Name: ns.Name,
Active: &wrapperspb.BoolValue{Value: ns.Active},
Grants: grants,
Metadata: metadata,
Fqn: ns.Fqn.String,
KasKeys: keys,
Expand Down
85 changes: 85 additions & 0 deletions service/policy/db/query.sql
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,19 @@ WITH target_definition AS (
ad.rule,
ad.active,
ad.values_order,
JSONB_AGG(
DISTINCT JSONB_BUILD_OBJECT(
'id', kas.id,
'uri', kas.uri,
'name', kas.name,
'public_key', kas.public_key
)
) FILTER (WHERE kas.id IS NOT NULL) AS grants,
defk.keys AS keys
FROM attribute_fqns fqns
INNER JOIN attribute_definitions ad ON fqns.attribute_id = ad.id
LEFT JOIN attribute_definition_key_access_grants adkag ON ad.id = adkag.attribute_definition_id
LEFT JOIN key_access_servers kas ON adkag.key_access_server_id = kas.id
LEFT JOIN (
SELECT
k.definition_id,
Expand Down Expand Up @@ -491,11 +501,21 @@ namespaces AS (
'name', n.name,
'active', n.active,
'fqn', fqns.fqn,
'grants', JSONB_AGG(
DISTINCT JSONB_BUILD_OBJECT(
'id', kas.id,
'uri', kas.uri,
'name', kas.name,
'public_key', kas.public_key
)
) FILTER (WHERE kas.id IS NOT NULL),
'kas_keys', nmp_keys.keys
) AS namespace
FROM target_definition td
INNER JOIN attribute_namespaces n ON td.namespace_id = n.id
INNER JOIN attribute_fqns fqns ON n.id = fqns.namespace_id
LEFT JOIN attribute_namespace_key_access_grants ankag ON n.id = ankag.namespace_id
LEFT JOIN key_access_servers kas ON ankag.key_access_server_id = kas.id
LEFT JOIN (
SELECT
k.namespace_id,
Expand All @@ -519,6 +539,23 @@ namespaces AS (
AND (fqns.attribute_id IS NULL AND fqns.value_id IS NULL)
GROUP BY n.id, fqns.fqn, nmp_keys.keys
),
value_grants AS (
SELECT
av.id,
JSON_AGG(
DISTINCT JSONB_BUILD_OBJECT(
'id', kas.id,
'uri', kas.uri,
'name', kas.name,
'public_key', kas.public_key
)
) FILTER (WHERE kas.id IS NOT NULL) AS grants
FROM target_definition td
LEFT JOIN attribute_values av on td.id = av.attribute_definition_id
LEFT JOIN attribute_value_key_access_grants avkag ON av.id = avkag.attribute_value_id
LEFT JOIN key_access_servers kas ON avkag.key_access_server_id = kas.id
GROUP BY av.id
),
value_subject_mappings AS (
SELECT
av.id,
Expand Down Expand Up @@ -583,6 +620,7 @@ values AS (
'value', av.value,
'active', av.active,
'fqn', fqns.fqn,
'grants', avg.grants,
'subject_mappings', avsm.sub_maps,
'resource_mappings', avrm.res_maps,
'kas_keys', value_keys.keys
Expand All @@ -592,6 +630,7 @@ values AS (
FROM target_definition td
LEFT JOIN attribute_values av ON td.id = av.attribute_definition_id
LEFT JOIN attribute_fqns fqns ON av.id = fqns.value_id
LEFT JOIN value_grants avg ON av.id = avg.id
LEFT JOIN value_subject_mappings avsm ON av.id = avsm.id
LEFT JOIN value_resource_mappings avrm ON av.id = avrm.id
LEFT JOIN (
Expand Down Expand Up @@ -624,6 +663,7 @@ SELECT
n.namespace,
fqns.fqn,
values.values,
td.grants,
td.keys
FROM target_definition td
INNER JOIN attribute_fqns fqns ON td.id = fqns.attribute_id
Expand All @@ -648,6 +688,14 @@ SELECT
'fqn', CONCAT(fqns.fqn, '/value/', avt.value)
) ORDER BY ARRAY_POSITION(ad.values_order, avt.id)
) AS values,
JSONB_AGG(
DISTINCT JSONB_BUILD_OBJECT(
'id', kas.id,
'uri', kas.uri,
'name', kas.name,
'public_key', kas.public_key
)
) FILTER (WHERE adkag.attribute_definition_id IS NOT NULL) AS grants,
fqns.fqn,
defk.keys as keys
FROM attribute_definitions ad
Expand All @@ -661,6 +709,8 @@ LEFT JOIN (
FROM attribute_values av
GROUP BY av.id
) avt ON avt.attribute_definition_id = ad.id
LEFT JOIN attribute_definition_key_access_grants adkag ON adkag.attribute_definition_id = ad.id
LEFT JOIN key_access_servers kas ON kas.id = adkag.key_access_server_id
LEFT JOIN attribute_fqns fqns ON fqns.attribute_id = ad.id AND fqns.value_id IS NULL
LEFT JOIN (
SELECT
Expand Down Expand Up @@ -758,9 +808,19 @@ SELECT
JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', av.metadata -> 'labels', 'created_at', av.created_at, 'updated_at', av.updated_at)) as metadata,
av.attribute_definition_id,
fqns.fqn,
JSONB_AGG(
DISTINCT JSONB_BUILD_OBJECT(
'id', kas.id,
'uri', kas.uri,
'name', kas.name,
'public_key', kas.public_key
)
) FILTER (WHERE avkag.attribute_value_id IS NOT NULL) AS grants,
value_keys.keys as keys
FROM attribute_values av
LEFT JOIN attribute_fqns fqns ON av.id = fqns.value_id
LEFT JOIN attribute_value_key_access_grants avkag ON av.id = avkag.attribute_value_id
LEFT JOIN key_access_servers kas ON avkag.key_access_server_id = kas.id
LEFT JOIN (
SELECT
k.value_id,
Expand Down Expand Up @@ -983,8 +1043,16 @@ SELECT
ns.active,
fqns.fqn,
JSON_STRIP_NULLS(JSON_BUILD_OBJECT('labels', ns.metadata -> 'labels', 'created_at', ns.created_at, 'updated_at', ns.updated_at)) as metadata,
JSONB_AGG(DISTINCT JSONB_BUILD_OBJECT(
'id', kas.id,
'uri', kas.uri,
'name', kas.name,
'public_key', kas.public_key
)) FILTER (WHERE kas_ns_grants.namespace_id IS NOT NULL) as grants,
nmp_keys.keys as keys
FROM attribute_namespaces ns
LEFT JOIN attribute_namespace_key_access_grants kas_ns_grants ON kas_ns_grants.namespace_id = ns.id
LEFT JOIN key_access_servers kas ON kas.id = kas_ns_grants.key_access_server_id
LEFT JOIN attribute_fqns fqns ON fqns.namespace_id = ns.id
LEFT JOIN (
SELECT
Expand Down Expand Up @@ -1654,3 +1722,20 @@ VALUES ($1);

-- name: deleteAllBaseKeys :execrows
DELETE FROM base_keys;



-------------------------
-- For Testing Only!!!!!!!!!
-------------------------
-- name: AssignKeyAccessServerToAttribute :execrows
INSERT INTO attribute_definition_key_access_grants (attribute_definition_id, key_access_server_id)
VALUES ($1, $2);

-- name: AssignKeyAccessServerToNamespace :execrows
INSERT INTO attribute_namespace_key_access_grants (namespace_id, key_access_server_id)
VALUES ($1, $2);

-- name: AssignKeyAccessServerToAttributeValue :execrows
INSERT INTO attribute_value_key_access_grants (attribute_value_id, key_access_server_id)
VALUES ($1, $2);
Loading
Loading