further updates

This commit is contained in:
Caleb Doxsey 2024-01-04 12:36:07 -07:00
parent 3215fc4a26
commit 18952b837d
8 changed files with 180 additions and 189 deletions

View file

@ -104,10 +104,11 @@ func NewHeadersEvaluator(ctx context.Context, store *store.Store) (*HeadersEvalu
r := rego.New(
rego.Store(store),
rego.Module("pomerium.headers", opa.HeadersRego),
rego.Query("result = data.pomerium.headers"),
rego.Query("result := data.pomerium.headers"),
getGoogleCloudServerlessHeadersRegoOption,
variableSubstitutionFunctionRegoOption,
store.GetDataBrokerRecordOption(),
rego.SetRegoVersion(ast.RegoV1),
)
q, err := r.PrepareForEval(ctx)

View file

@ -55,104 +55,104 @@ func TestPolicy_ToPPL(t *testing.T) {
import rego.v1
default allow = [false, set()]
default allow := [false, set()]
default deny = [false, set()]
default deny := [false, set()]
accept_0 = [true, {"accept"}]
accept_0 := [true, {"accept"}]
cors_preflight_0 = [true, {"cors-request"}] if {
cors_preflight_0 := [true, {"cors-request"}] if {
input.http.method == "OPTIONS"
count(object.get(input.http.headers, "Access-Control-Request-Method", [])) > 0
count(object.get(input.http.headers, "Origin", [])) > 0
}
else = [false, {"non-cors-request"}]
else := [false, {"non-cors-request"}]
authenticated_user_0 = [true, {"user-ok"}] if {
authenticated_user_0 := [true, {"user-ok"}] if {
session := get_session(input.session.id)
session.user_id != null
session.user_id != ""
}
else = [false, {"user-unauthorized"}] if {
else := [false, {"user-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
domain_0 = [true, {"domain-ok"}] if {
domain_0 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
domain == "a.example.com"
}
else = [false, {"domain-unauthorized"}] if {
else := [false, {"domain-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
domain_1 = [true, {"domain-ok"}] if {
domain_1 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
domain == "b.example.com"
}
else = [false, {"domain-unauthorized"}] if {
else := [false, {"domain-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
domain_2 = [true, {"domain-ok"}] if {
domain_2 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
domain == "c.example.com"
}
else = [false, {"domain-unauthorized"}] if {
else := [false, {"domain-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
domain_3 = [true, {"domain-ok"}] if {
domain_3 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
domain == "d.example.com"
}
else = [false, {"domain-unauthorized"}] if {
else := [false, {"domain-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
domain_4 = [true, {"domain-ok"}] if {
domain_4 := [true, {"domain-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
domain := split(get_user_email(session, user), "@")[1]
domain == "e.example.com"
}
else = [false, {"domain-unauthorized"}] if {
else := [false, {"domain-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
claim_0 = [true, {"claim-ok"}] if {
claim_0 := [true, {"claim-ok"}] if {
rule_data := "Smith"
rule_path := "family_name"
session := get_session(input.session.id)
@ -164,14 +164,14 @@ claim_0 = [true, {"claim-ok"}] if {
rule_data == values[_0]
}
else = [false, {"claim-unauthorized"}] if {
else := [false, {"claim-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
claim_1 = [true, {"claim-ok"}] if {
claim_1 := [true, {"claim-ok"}] if {
rule_data := "Jones"
rule_path := "family_name"
session := get_session(input.session.id)
@ -183,14 +183,14 @@ claim_1 = [true, {"claim-ok"}] if {
rule_data == values[_0]
}
else = [false, {"claim-unauthorized"}] if {
else := [false, {"claim-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
claim_2 = [true, {"claim-ok"}] if {
claim_2 := [true, {"claim-ok"}] if {
rule_data := "John"
rule_path := "given_name"
session := get_session(input.session.id)
@ -202,14 +202,14 @@ claim_2 = [true, {"claim-ok"}] if {
rule_data == values[_0]
}
else = [false, {"claim-unauthorized"}] if {
else := [false, {"claim-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
claim_3 = [true, {"claim-ok"}] if {
claim_3 := [true, {"claim-ok"}] if {
rule_data := "EST"
rule_path := "timezone"
session := get_session(input.session.id)
@ -221,204 +221,204 @@ claim_3 = [true, {"claim-ok"}] if {
rule_data == values[_0]
}
else = [false, {"claim-unauthorized"}] if {
else := [false, {"claim-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
user_0 = [true, {"user-ok"}] if {
user_0 := [true, {"user-ok"}] if {
session := get_session(input.session.id)
user_id := session.user_id
user_id == "user1"
}
else = [false, {"user-unauthorized"}] if {
else := [false, {"user-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
email_0 = [true, {"email-ok"}] if {
email_0 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
email == "user1"
}
else = [false, {"email-unauthorized"}] if {
else := [false, {"email-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
user_1 = [true, {"user-ok"}] if {
user_1 := [true, {"user-ok"}] if {
session := get_session(input.session.id)
user_id := session.user_id
user_id == "user2"
}
else = [false, {"user-unauthorized"}] if {
else := [false, {"user-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
email_1 = [true, {"email-ok"}] if {
email_1 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
email == "user2"
}
else = [false, {"email-unauthorized"}] if {
else := [false, {"email-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
user_2 = [true, {"user-ok"}] if {
user_2 := [true, {"user-ok"}] if {
session := get_session(input.session.id)
user_id := session.user_id
user_id == "user3"
}
else = [false, {"user-unauthorized"}] if {
else := [false, {"user-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
email_2 = [true, {"email-ok"}] if {
email_2 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
email == "user3"
}
else = [false, {"email-unauthorized"}] if {
else := [false, {"email-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
user_3 = [true, {"user-ok"}] if {
user_3 := [true, {"user-ok"}] if {
session := get_session(input.session.id)
user_id := session.user_id
user_id == "user4"
}
else = [false, {"user-unauthorized"}] if {
else := [false, {"user-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
email_3 = [true, {"email-ok"}] if {
email_3 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
email == "user4"
}
else = [false, {"email-unauthorized"}] if {
else := [false, {"email-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
user_4 = [true, {"user-ok"}] if {
user_4 := [true, {"user-ok"}] if {
session := get_session(input.session.id)
user_id := session.user_id
user_id == "user5"
}
else = [false, {"user-unauthorized"}] if {
else := [false, {"user-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
email_4 = [true, {"email-ok"}] if {
email_4 := [true, {"email-ok"}] if {
session := get_session(input.session.id)
user := get_user(session)
email := get_user_email(session, user)
email == "user5"
}
else = [false, {"email-unauthorized"}] if {
else := [false, {"email-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
or_0 = v if {
or_0 := v if {
results := [accept_0, cors_preflight_0, authenticated_user_0, domain_0, domain_1, domain_2, domain_3, domain_4, claim_0, claim_1, claim_2, claim_3, user_0, email_0, user_1, email_1, user_2, email_2, user_3, email_3, user_4, email_4]
normalized := [normalize_criterion_result(x) | x := results[i]]
v := merge_with_or(normalized)
}
user_5 = [true, {"user-ok"}] if {
user_5 := [true, {"user-ok"}] if {
session := get_session(input.session.id)
user_id := session.user_id
user_id == "user6"
}
else = [false, {"user-unauthorized"}] if {
else := [false, {"user-unauthorized"}] if {
session := get_session(input.session.id)
session.id != ""
}
else = [false, {"user-unauthenticated"}]
else := [false, {"user-unauthenticated"}]
or_1 = v if {
or_1 := v if {
results := [user_5]
normalized := [normalize_criterion_result(x) | x := results[i]]
v := merge_with_or(normalized)
}
allow = v if {
allow := v if {
results := [or_0, or_1]
normalized := [normalize_criterion_result(x) | x := results[i]]
v := merge_with_or(normalized)
}
invert_criterion_result(v) = out if {
invert_criterion_result(v) := out if {
v[0]
out = array.concat([false], array.slice(v, 1, count(v)))
}
else = out if {
else := out if {
not v[0]
out = array.concat([true], array.slice(v, 1, count(v)))
}
normalize_criterion_result(result) = v if {
normalize_criterion_result(result) := v if {
is_boolean(result)
v = [result, set()]
}
else = v if {
else := v if {
is_array(result)
v = result
}
else = v if {
else := v if {
v = [false, set()]
}
object_union(xs) = merged if {
object_union(xs) := merged if {
merged = {k: v |
some k
xs[_0][k]
@ -427,38 +427,38 @@ object_union(xs) = merged if {
}
}
merge_with_and(results) = [true, reasons, additional_data] if {
merge_with_and(results) := [true, reasons, additional_data] if {
true_results := [x | x := results[i]; x[0]]
count(true_results) == count(results)
reasons := union({x | x := true_results[i][1]})
additional_data := object_union({x | x := true_results[i][2]})
}
else = [false, reasons, additional_data] if {
else := [false, reasons, additional_data] if {
false_results := [x | x := results[i]; not x[0]]
reasons := union({x | x := false_results[i][1]})
additional_data := object_union({x | x := false_results[i][2]})
}
merge_with_or(results) = [true, reasons, additional_data] if {
merge_with_or(results) := [true, reasons, additional_data] if {
true_results := [x | x := results[i]; x[0]]
count(true_results) > 0
reasons := union({x | x := true_results[i][1]})
additional_data := object_union({x | x := true_results[i][2]})
}
else = [false, reasons, additional_data] if {
else := [false, reasons, additional_data] if {
false_results := [x | x := results[i]; not x[0]]
reasons := union({x | x := false_results[i][1]})
additional_data := object_union({x | x := false_results[i][2]})
}
get_session(id) = v if {
get_session(id) := v if {
v = get_databroker_record("type.googleapis.com/user.ServiceAccount", id)
v != null
}
else = iv if {
else := iv if {
v = get_databroker_record("type.googleapis.com/session.Session", id)
v != null
object.get(v, "impersonate_session_id", "") != ""
@ -467,41 +467,41 @@ else = iv if {
iv != null
}
else = v if {
else := v if {
v = get_databroker_record("type.googleapis.com/session.Session", id)
v != null
object.get(v, "impersonate_session_id", "") == ""
}
else = {}
else := {}
get_user(session) = v if {
get_user(session) := v if {
v = get_databroker_record("type.googleapis.com/user.User", session.user_id)
v != null
}
else = {}
else := {}
get_user_email(session, user) = v if {
get_user_email(session, user) := v if {
v = user.email
}
else = ""
else := ""
object_get(obj, key, def) = value if {
object_get(obj, key, def) := value if {
undefined := "10a0fd35-0f1a-4e5b-97ce-631e89e1bafa"
value = object.get(obj, key, undefined)
value != undefined
}
else = value if {
else := value if {
segments := split(replace(key, ".", "/"), "/")
count(segments) == 2
o1 := object.get(obj, segments[0], {})
value = object.get(o1, segments[1], def)
}
else = value if {
else := value if {
segments := split(replace(key, ".", "/"), "/")
count(segments) == 3
o1 := object.get(obj, segments[0], {})
@ -509,7 +509,7 @@ else = value if {
value = object.get(o2, segments[2], def)
}
else = value if {
else := value if {
segments := split(replace(key, ".", "/"), "/")
count(segments) == 4
o1 := object.get(obj, segments[0], {})
@ -518,7 +518,7 @@ else = value if {
value = object.get(o3, segments[3], def)
}
else = value if {
else := value if {
segments := split(replace(key, ".", "/"), "/")
count(segments) == 5
o1 := object.get(obj, segments[0], {})
@ -528,7 +528,7 @@ else = value if {
value = object.get(o4, segments[4], def)
}
else = value if {
else := value if {
value = object.get(obj, key, def)
}
`, str)

View file

@ -66,9 +66,7 @@ func NewCriterionRule(
r1.Body = body
r2 := &ast.Rule{
Head: &ast.Head{
Value: NewCriterionTerm(false, failReason),
},
Head: generator.NewHead("", NewCriterionTerm(false, failReason)),
Body: ast.Body{
ast.NewExpr(ast.BooleanTerm(true)),
},
@ -107,9 +105,7 @@ func NewCriterionDeviceRule(
// case 2: rule fails, session exists, device exists
r2 := &ast.Rule{
Head: &ast.Head{
Value: NewCriterionTermWithAdditionalData(false, failReason, additionalData),
},
Head: generator.NewHead("", NewCriterionTermWithAdditionalData(false, failReason, additionalData)),
Body: append(sharedBody, ast.Body{
ast.MustParseExpr(`session.id != ""`),
ast.MustParseExpr(`device_credential.id != ""`),
@ -120,9 +116,7 @@ func NewCriterionDeviceRule(
// case 3: device not authenticated, session exists, device does not exist
r3 := &ast.Rule{
Head: &ast.Head{
Value: NewCriterionTermWithAdditionalData(false, ReasonDeviceUnauthenticated, additionalData),
},
Head: generator.NewHead("", NewCriterionTermWithAdditionalData(false, ReasonDeviceUnauthenticated, additionalData)),
Body: append(sharedBody, ast.Body{
ast.MustParseExpr(`session.id != ""`),
}...),
@ -131,9 +125,7 @@ func NewCriterionDeviceRule(
// case 4: user not authenticated, session does not exist
r4 := &ast.Rule{
Head: &ast.Head{
Value: NewCriterionTermWithAdditionalData(false, ReasonUserUnauthenticated, additionalData),
},
Head: generator.NewHead("", NewCriterionTermWithAdditionalData(false, ReasonUserUnauthenticated, additionalData)),
Body: ast.Body{
ast.NewExpr(ast.BooleanTerm(true)),
},
@ -157,9 +149,7 @@ func NewCriterionSessionRule(
r1.Body = body
r2 := &ast.Rule{
Head: &ast.Head{
Value: NewCriterionTerm(false, failReason),
},
Head: generator.NewHead("", NewCriterionTerm(false, failReason)),
Body: ast.Body{
ast.MustParseExpr(`session := get_session(input.session.id)`),
ast.MustParseExpr(`session.id != ""`),
@ -168,9 +158,7 @@ func NewCriterionSessionRule(
r1.Else = r2
r3 := &ast.Rule{
Head: &ast.Head{
Value: NewCriterionTerm(false, ReasonUserUnauthenticated),
},
Head: generator.NewHead("", NewCriterionTerm(false, ReasonUserUnauthenticated)),
Body: ast.Body{
ast.NewExpr(ast.BooleanTerm(true)),
},

View file

@ -121,6 +121,7 @@ func evaluate(t *testing.T,
return nil, nil
}),
rego.Input(input),
rego.SetRegoVersion(ast.RegoV1),
)
preparedQuery, err := r.PrepareForEval(context.Background())
if err != nil {

View file

@ -35,17 +35,13 @@ func (c invalidClientCertificateCriterion) GenerateRule(_ string, _ parser.Value
r1.Body = validClientCertificateBody
r2 := &ast.Rule{
Head: &ast.Head{
Value: NewCriterionTerm(true, ReasonClientCertificateRequired),
},
Head: generator.NewHead("", NewCriterionTerm(true, ReasonClientCertificateRequired)),
Body: noClientCertificateBody,
}
r1.Else = r2
r3 := &ast.Rule{
Head: &ast.Head{
Value: NewCriterionTerm(true, ReasonInvalidClientCertificate),
},
Head: generator.NewHead("", NewCriterionTerm(true, ReasonInvalidClientCertificate)),
}
r2.Else = r3

View file

@ -49,8 +49,8 @@ func (g *Generator) GetCriterion(name string) (Criterion, bool) {
// Generate generates the rego module from a policy.
func (g *Generator) Generate(policy *parser.Policy) (*ast.Module, error) {
rs := ast.NewRuleSet()
rs.Add(ast.MustParseRule(`default allow = [false, set()]`))
rs.Add(ast.MustParseRule(`default deny = [false, set()]`))
rs.Add(rules.MustParse(`default allow := [false, set()]`))
rs.Add(rules.MustParse(`default deny := [false, set()]`))
rs.Add(rules.InvertCriterionResult())
rs.Add(rules.NormalizeCriterionResult())
rs.Add(rules.ObjectUnion())
@ -95,10 +95,7 @@ func (g *Generator) Generate(policy *parser.Policy) (*ast.Module, error) {
}
if len(terms) > 0 {
rule := &ast.Rule{
Head: &ast.Head{
Name: ast.Var(action),
Value: ast.VarTerm("v"),
},
Head: NewHead(ast.Var(action), ast.VarTerm("v")),
Body: append(ast.Body{
ast.Assign.Expr(ast.VarTerm("results"), ast.ArrayTerm(terms...)),
}, orBody...),
@ -151,8 +148,15 @@ func (g *Generator) NewRule(name string) *ast.Rule {
id := g.ids[name]
g.ids[name]++
return &ast.Rule{
Head: &ast.Head{
Name: ast.Var(fmt.Sprintf("%s_%d", name, id)),
},
Head: NewHead(ast.Var(fmt.Sprintf("%s_%d", name, id)), nil),
}
}
// NewHead creates a new AST Head.
func NewHead(name ast.Var, value *ast.Term) *ast.Head {
return &ast.Head{
Name: name,
Value: value,
Assign: true,
}
}

View file

@ -65,9 +65,9 @@ func Test(t *testing.T) {
import rego.v1
default allow = [false, set()]
default allow := [false, set()]
default deny = [false, set()]
default deny := [false, set()]
accept_0 if 1 == 1
@ -75,7 +75,7 @@ accept_1 if 1 == 1
accept_2 if 1 == 1
and_0 = v if {
and_0 := v if {
results := [accept_0, accept_1, accept_2]
normalized := [normalize_criterion_result(x) | x := results[i]]
v := merge_with_and(normalized)
@ -87,7 +87,7 @@ accept_4 if 1 == 1
accept_5 if 1 == 1
or_0 = v if {
or_0 := v if {
results := [accept_3, accept_4, accept_5]
normalized := [normalize_criterion_result(x) | x := results[i]]
v := merge_with_or(normalized)
@ -99,7 +99,7 @@ accept_7 if 1 == 1
accept_8 if 1 == 1
not_0 = v if {
not_0 := v if {
results := [accept_6, accept_7, accept_8]
normalized := [normalize_criterion_result(x) | x := results[i]]
inverted := [invert_criterion_result(x) | x := results[i]]
@ -112,7 +112,7 @@ accept_10 if 1 == 1
accept_11 if 1 == 1
nor_0 = v if {
nor_0 := v if {
results := [accept_9, accept_10, accept_11]
normalized := [normalize_criterion_result(x) | x := results[i]]
inverted := [invert_criterion_result(x) | x := results[i]]
@ -121,13 +121,13 @@ nor_0 = v if {
accept_12 if 1 == 1
and_1 = v if {
and_1 := v if {
results := [accept_12]
normalized := [normalize_criterion_result(x) | x := results[i]]
v := merge_with_and(normalized)
}
allow = v if {
allow := v if {
results := [and_0, or_0, not_0, nor_0, and_1]
normalized := [normalize_criterion_result(x) | x := results[i]]
v := merge_with_or(normalized)
@ -137,44 +137,44 @@ accept_13 if 1 == 1
accept_14 if 1 == 1
nor_1 = v if {
nor_1 := v if {
results := [accept_13, accept_14]
normalized := [normalize_criterion_result(x) | x := results[i]]
inverted := [invert_criterion_result(x) | x := results[i]]
v := merge_with_or(inverted)
}
deny = v if {
deny := v if {
results := [nor_1]
normalized := [normalize_criterion_result(x) | x := results[i]]
v := merge_with_or(normalized)
}
invert_criterion_result(v) = out if {
invert_criterion_result(v) := out if {
v[0]
out = array.concat([false], array.slice(v, 1, count(v)))
}
else = out if {
else := out if {
not v[0]
out = array.concat([true], array.slice(v, 1, count(v)))
}
normalize_criterion_result(result) = v if {
normalize_criterion_result(result) := v if {
is_boolean(result)
v = [result, set()]
}
else = v if {
else := v if {
is_array(result)
v = result
}
else = v if {
else := v if {
v = [false, set()]
}
object_union(xs) = merged if {
object_union(xs) := merged if {
merged = {k: v |
some k
xs[_][k]
@ -183,27 +183,27 @@ object_union(xs) = merged if {
}
}
merge_with_and(results) = [true, reasons, additional_data] if {
merge_with_and(results) := [true, reasons, additional_data] if {
true_results := [x | x := results[i]; x[0]]
count(true_results) == count(results)
reasons := union({x | x := true_results[i][1]})
additional_data := object_union({x | x := true_results[i][2]})
}
else = [false, reasons, additional_data] if {
else := [false, reasons, additional_data] if {
false_results := [x | x := results[i]; not x[0]]
reasons := union({x | x := false_results[i][1]})
additional_data := object_union({x | x := false_results[i][2]})
}
merge_with_or(results) = [true, reasons, additional_data] if {
merge_with_or(results) := [true, reasons, additional_data] if {
true_results := [x | x := results[i]; x[0]]
count(true_results) > 0
reasons := union({x | x := true_results[i][1]})
additional_data := object_union({x | x := true_results[i][2]})
}
else = [false, reasons, additional_data] if {
else := [false, reasons, additional_data] if {
false_results := [x | x := results[i]; not x[0]]
reasons := union({x | x := false_results[i][1]})
additional_data := object_union({x | x := false_results[i][2]})

View file

@ -5,74 +5,74 @@ import "github.com/open-policy-agent/opa/ast"
// GetSession gets the session for the given id.
func GetSession() *ast.Rule {
return mustParseRule(`
get_session(id) = v if {
return MustParse(`
get_session(id) := v if {
v = get_databroker_record("type.googleapis.com/user.ServiceAccount", id)
v != null
} else = iv if {
} else := iv if {
v = get_databroker_record("type.googleapis.com/session.Session", id)
v != null
object.get(v, "impersonate_session_id", "") != ""
iv = get_databroker_record("type.googleapis.com/session.Session", v.impersonate_session_id)
iv != null
} else = v if {
} else := v if {
v = get_databroker_record("type.googleapis.com/session.Session", id)
v != null
object.get(v, "impersonate_session_id", "") == ""
} else = {}
} else := {}
`)
}
// GetUser returns the user for the given session.
func GetUser() *ast.Rule {
return mustParseRule(`
get_user(session) = v if {
return MustParse(`
get_user(session) := v if {
v = get_databroker_record("type.googleapis.com/user.User", session.user_id)
v != null
} else = {}
} else := {}
`)
}
// GetUserEmail gets the user email, either the impersonate email, or the user email.
func GetUserEmail() *ast.Rule {
return mustParseRule(`
get_user_email(session, user) = v if {
return MustParse(`
get_user_email(session, user) := v if {
v = user.email
} else = ""
} else := ""
`)
}
// GetDeviceCredential gets the device credential for the given session.
func GetDeviceCredential() *ast.Rule {
return mustParseRule(`
get_device_credential(session, device_type_id) = v if {
return MustParse(`
get_device_credential(session, device_type_id) := v if {
device_credential_id := [x.Credential.Id|x:=session.device_credentials[_];x.type_id==device_type_id][0]
v = get_databroker_record("type.googleapis.com/pomerium.device.Credential", device_credential_id)
v != null
} else = {}
} else := {}
`)
}
// GetDeviceEnrollment gets the device enrollment for the given device credential.
func GetDeviceEnrollment() *ast.Rule {
return mustParseRule(`
get_device_enrollment(device_credential) = v if {
return MustParse(`
get_device_enrollment(device_credential) := v if {
v = get_databroker_record("type.googleapis.com/pomerium.device.Enrollment", device_credential.enrollment_id)
v != null
} else = {}
} else := {}
`)
}
// MergeWithAnd merges criterion results using `and`.
func MergeWithAnd() *ast.Rule {
return mustParseRule(`
merge_with_and(results) = [true, reasons, additional_data] if {
return MustParse(`
merge_with_and(results) := [true, reasons, additional_data] if {
true_results := [x|x:=results[i];x[0]]
count(true_results) == count(results)
reasons := union({x|x:=true_results[i][1]})
additional_data := object_union({x|x:=true_results[i][2]})
} else = [false, reasons, additional_data] if {
} else := [false, reasons, additional_data] if {
false_results := [x|x:=results[i];not x[0]]
reasons := union({x|x:=false_results[i][1]})
additional_data := object_union({x|x:=false_results[i][2]})
@ -82,13 +82,13 @@ merge_with_and(results) = [true, reasons, additional_data] if {
// MergeWithOr merges criterion results using `or`.
func MergeWithOr() *ast.Rule {
return mustParseRule(`
merge_with_or(results) = [true, reasons, additional_data] if {
return MustParse(`
merge_with_or(results) := [true, reasons, additional_data] if {
true_results := [x|x:=results[i];x[0]]
count(true_results) > 0
reasons := union({x|x:=true_results[i][1]})
additional_data := object_union({x|x:=true_results[i][2]})
} else = [false, reasons, additional_data] if {
} else := [false, reasons, additional_data] if {
false_results := [x|x:=results[i];not x[0]]
reasons := union({x|x:=false_results[i][1]})
additional_data := object_union({x|x:=false_results[i][2]})
@ -99,11 +99,11 @@ merge_with_or(results) = [true, reasons, additional_data] if {
// InvertCriterionResult changes the criterion result's value from false to
// true, or vice-versa.
func InvertCriterionResult() *ast.Rule {
return mustParseRule(`
invert_criterion_result(v) = out if {
return MustParse(`
invert_criterion_result(v) := out if {
v[0]
out = array.concat([false], array.slice(v, 1, count(v)))
} else = out if {
} else := out if {
not v[0]
out = array.concat([true], array.slice(v, 1, count(v)))
}
@ -112,14 +112,14 @@ invert_criterion_result(v) = out if {
// NormalizeCriterionResult converts a criterion result into a standard form.
func NormalizeCriterionResult() *ast.Rule {
return mustParseRule(`
normalize_criterion_result(result) = v if {
return MustParse(`
normalize_criterion_result(result) := v if {
is_boolean(result)
v = [result, set()]
} else = v if {
} else := v if {
is_array(result)
v = result
} else = v if {
} else := v if {
v = [false, set()]
}
`)
@ -127,33 +127,33 @@ normalize_criterion_result(result) = v if {
// ObjectGet recursively gets a value from an object.
func ObjectGet() *ast.Rule {
return mustParseRule(`
return MustParse(`
# object_get is like object.get, but supports converting "/" in keys to separate lookups
# rego doesn't support recursion, so we hard code a limited number of /'s
object_get(obj, key, def) = value if {
object_get(obj, key, def) := value if {
undefined := "10a0fd35-0f1a-4e5b-97ce-631e89e1bafa"
value = object.get(obj, key, undefined)
value != undefined
} else = value if {
} else := value if {
segments := split(replace(key, ".", "/"), "/")
count(segments) == 2
o1 := object.get(obj, segments[0], {})
value = object.get(o1, segments[1], def)
} else = value if {
} else := value if {
segments := split(replace(key, ".", "/"), "/")
count(segments) == 3
o1 := object.get(obj, segments[0], {})
o2 := object.get(o1, segments[1], {})
value = object.get(o2, segments[2], def)
} else = value if {
} else := value if {
segments := split(replace(key, ".", "/"), "/")
count(segments) == 4
o1 := object.get(obj, segments[0], {})
o2 := object.get(o1, segments[1], {})
o3 := object.get(o2, segments[2], {})
value = object.get(o3, segments[3], def)
} else = value if {
} else := value if {
segments := split(replace(key, ".", "/"), "/")
count(segments) == 5
o1 := object.get(obj, segments[0], {})
@ -161,7 +161,7 @@ object_get(obj, key, def) = value if {
o3 := object.get(o2, segments[2], {})
o4 := object.get(o3, segments[3], {})
value = object.get(o4, segments[4], def)
} else = value if {
} else := value if {
value = object.get(obj, key, def)
}
`)
@ -169,8 +169,8 @@ object_get(obj, key, def) = value if {
// ObjectUnion merges objects together. It expects a set of objects.
func ObjectUnion() *ast.Rule {
return mustParseRule(`
object_union(xs) = merged if {
return MustParse(`
object_union(xs) := merged if {
merged = { k: v |
some k
xs[_][k]
@ -181,7 +181,8 @@ object_union(xs) = merged if {
`)
}
func mustParseRule(str string) *ast.Rule {
// MustParse parses an AST rule.
func MustParse(str string) *ast.Rule {
r, err := ast.ParseRuleWithOpts(str, ast.ParserOptions{
RegoVersion: ast.RegoV1,
})