mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-06 10:21:05 +02:00
authorize: omit client cert rule when not needed (#4386)
Currently we always add an invalid_client_certificate deny rule to all PPL policies. Instead, let's add this rule only when a client CA is configured. This way, if a user is not using client certificates at all, they won't see any reason strings related to client certificates in the authorize logs. Change the "valid-client-certificate-or-none-required" reason string to just "valid-client-certificate" accordingly. Pass the main Evaluator config to NewPolicyEvaluator so that we can determine whether there is a client CA configured or not. Extract the existing default deny rule to a separate method. Add unit tests exercising the new behavior.
This commit is contained in:
parent
219296a875
commit
4698e4661a
10 changed files with 166 additions and 103 deletions
|
@ -119,6 +119,8 @@ func New(ctx context.Context, store *store.Store, options ...Option) (*Evaluator
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.clientCA = cfg.clientCA
|
||||||
|
|
||||||
e.policyEvaluators = make(map[uint64]*PolicyEvaluator)
|
e.policyEvaluators = make(map[uint64]*PolicyEvaluator)
|
||||||
for i := range cfg.policies {
|
for i := range cfg.policies {
|
||||||
configPolicy := cfg.policies[i]
|
configPolicy := cfg.policies[i]
|
||||||
|
@ -126,15 +128,14 @@ func New(ctx context.Context, store *store.Store, options ...Option) (*Evaluator
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("authorize: error computing policy route id: %w", err)
|
return nil, fmt.Errorf("authorize: error computing policy route id: %w", err)
|
||||||
}
|
}
|
||||||
policyEvaluator, err := NewPolicyEvaluator(ctx, store, &configPolicy)
|
clientCA, _ := e.getClientCA(&configPolicy)
|
||||||
|
policyEvaluator, err := NewPolicyEvaluator(ctx, store, &configPolicy, clientCA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
e.policyEvaluators[id] = policyEvaluator
|
e.policyEvaluators[id] = policyEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
e.clientCA = cfg.clientCA
|
|
||||||
|
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package evaluator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -109,10 +110,14 @@ func TestEvaluator(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
To: config.WeightedURLs{{URL: *mustParseURL("https://to11.example.com")}},
|
||||||
|
AllowedUsers: []string{"a@example.com"},
|
||||||
|
TLSDownstreamClientCA: base64.StdEncoding.EncodeToString([]byte(testCA)),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
options := []Option{
|
options := []Option{
|
||||||
WithAuthenticateURL("https://authn.example.com"),
|
WithAuthenticateURL("https://authn.example.com"),
|
||||||
WithClientCA([]byte(testCA)),
|
|
||||||
WithPolicies(policies),
|
WithPolicies(policies),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +127,10 @@ func TestEvaluator(t *testing.T) {
|
||||||
Leaf: testValidCert,
|
Leaf: testValidCert,
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("client certificate", func(t *testing.T) {
|
t.Run("client certificate (default CA)", func(t *testing.T) {
|
||||||
|
// Clone the existing options and add a default client CA.
|
||||||
|
options := append([]Option(nil), options...)
|
||||||
|
options = append(options, WithClientCA([]byte(testCA)))
|
||||||
t.Run("invalid", func(t *testing.T) {
|
t.Run("invalid", func(t *testing.T) {
|
||||||
res, err := eval(t, options, nil, &Request{
|
res, err := eval(t, options, nil, &Request{
|
||||||
Policy: &policies[0],
|
Policy: &policies[0],
|
||||||
|
@ -141,6 +149,25 @@ func TestEvaluator(t *testing.T) {
|
||||||
assert.False(t, res.Deny.Value)
|
assert.False(t, res.Deny.Value)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
t.Run("client certificate (per-policy CA)", func(t *testing.T) {
|
||||||
|
t.Run("invalid", func(t *testing.T) {
|
||||||
|
res, err := eval(t, options, nil, &Request{
|
||||||
|
Policy: &policies[10],
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, NewRuleResult(true, criteria.ReasonInvalidClientCertificate), res.Deny)
|
||||||
|
})
|
||||||
|
t.Run("valid", func(t *testing.T) {
|
||||||
|
res, err := eval(t, options, nil, &Request{
|
||||||
|
Policy: &policies[10],
|
||||||
|
HTTP: RequestHTTP{
|
||||||
|
ClientCertificate: validCertInfo,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.False(t, res.Deny.Value)
|
||||||
|
})
|
||||||
|
})
|
||||||
t.Run("identity_headers", func(t *testing.T) {
|
t.Run("identity_headers", func(t *testing.T) {
|
||||||
t.Run("kubernetes", func(t *testing.T) {
|
t.Run("kubernetes", func(t *testing.T) {
|
||||||
res, err := eval(t, options, []proto.Message{
|
res, err := eval(t, options, []proto.Message{
|
||||||
|
@ -158,9 +185,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -183,9 +209,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -210,9 +235,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -234,9 +258,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -258,9 +281,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -289,9 +311,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session2",
|
ID: "session2",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -314,9 +335,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -338,9 +358,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -367,9 +386,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -390,9 +408,8 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -427,10 +444,9 @@ func TestEvaluator(t *testing.T) {
|
||||||
ID: "session1",
|
ID: "session1",
|
||||||
},
|
},
|
||||||
HTTP: RequestHTTP{
|
HTTP: RequestHTTP{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "https://from.example.com",
|
URL: "https://from.example.com",
|
||||||
ClientCertificate: validCertInfo,
|
Headers: tc.src,
|
||||||
Headers: tc.src,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
|
@ -445,7 +461,7 @@ func TestEvaluator(t *testing.T) {
|
||||||
http.MethodGet,
|
http.MethodGet,
|
||||||
*mustParseURL("https://from.example.com/"),
|
*mustParseURL("https://from.example.com/"),
|
||||||
nil,
|
nil,
|
||||||
validCertInfo,
|
ClientCertificateInfo{},
|
||||||
"",
|
"",
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
@ -459,7 +475,7 @@ func TestEvaluator(t *testing.T) {
|
||||||
"POST",
|
"POST",
|
||||||
*mustParseURL("https://from.example.com/test"),
|
*mustParseURL("https://from.example.com/test"),
|
||||||
nil,
|
nil,
|
||||||
validCertInfo,
|
ClientCertificateInfo{},
|
||||||
"",
|
"",
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
|
@ -107,11 +107,16 @@ type PolicyEvaluator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPolicyEvaluator creates a new PolicyEvaluator.
|
// NewPolicyEvaluator creates a new PolicyEvaluator.
|
||||||
func NewPolicyEvaluator(ctx context.Context, store *store.Store, configPolicy *config.Policy) (*PolicyEvaluator, error) {
|
func NewPolicyEvaluator(
|
||||||
|
ctx context.Context, store *store.Store, configPolicy *config.Policy, clientCA string,
|
||||||
|
) (*PolicyEvaluator, error) {
|
||||||
e := new(PolicyEvaluator)
|
e := new(PolicyEvaluator)
|
||||||
|
|
||||||
// generate the base rego script for the policy
|
// generate the base rego script for the policy
|
||||||
ppl := configPolicy.ToPPL()
|
ppl := configPolicy.ToPPL()
|
||||||
|
if clientCA != "" {
|
||||||
|
ppl.AddDefaultClientCertificateRule()
|
||||||
|
}
|
||||||
base, err := policy.GenerateRegoFromPolicy(ppl)
|
base, err := policy.GenerateRegoFromPolicy(ppl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -32,13 +32,15 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
privateJWK, err := cryptutil.PrivateJWKFromBytes(encodedSigningKey)
|
privateJWK, err := cryptutil.PrivateJWKFromBytes(encodedSigningKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var clientCA string
|
||||||
|
|
||||||
eval := func(t *testing.T, policy *config.Policy, data []proto.Message, input *PolicyRequest) (*PolicyResponse, error) {
|
eval := func(t *testing.T, policy *config.Policy, data []proto.Message, input *PolicyRequest) (*PolicyResponse, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = storage.WithQuerier(ctx, storage.NewStaticQuerier(data...))
|
ctx = storage.WithQuerier(ctx, storage.NewStaticQuerier(data...))
|
||||||
store := store.New()
|
store := store.New()
|
||||||
store.UpdateJWTClaimHeaders(config.NewJWTClaimHeaders("email", "groups", "user", "CUSTOM_KEY"))
|
store.UpdateJWTClaimHeaders(config.NewJWTClaimHeaders("email", "groups", "user", "CUSTOM_KEY"))
|
||||||
store.UpdateSigningKey(privateJWK)
|
store.UpdateSigningKey(privateJWK)
|
||||||
e, err := NewPolicyEvaluator(ctx, store, policy)
|
e, err := NewPolicyEvaluator(ctx, store, policy, clientCA)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return e.Evaluate(ctx, input)
|
return e.Evaluate(ctx, input)
|
||||||
}
|
}
|
||||||
|
@ -66,6 +68,40 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("allowed", func(t *testing.T) {
|
t.Run("allowed", func(t *testing.T) {
|
||||||
|
output, err := eval(t,
|
||||||
|
p1,
|
||||||
|
[]proto.Message{s1, u1, s2, u2},
|
||||||
|
&PolicyRequest{
|
||||||
|
HTTP: RequestHTTP{Method: http.MethodGet, URL: "https://from.example.com/path"},
|
||||||
|
Session: RequestSession{ID: "s1"},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, &PolicyResponse{
|
||||||
|
Allow: NewRuleResult(true, criteria.ReasonEmailOK),
|
||||||
|
Deny: NewRuleResult(false),
|
||||||
|
Traces: []contextutil.PolicyEvaluationTrace{{Allow: true}},
|
||||||
|
}, output)
|
||||||
|
})
|
||||||
|
t.Run("forbidden", func(t *testing.T) {
|
||||||
|
output, err := eval(t,
|
||||||
|
p1,
|
||||||
|
[]proto.Message{s1, u1, s2, u2},
|
||||||
|
&PolicyRequest{
|
||||||
|
HTTP: RequestHTTP{Method: http.MethodGet, URL: "https://from.example.com/path"},
|
||||||
|
Session: RequestSession{ID: "s2"},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, &PolicyResponse{
|
||||||
|
Allow: NewRuleResult(false, criteria.ReasonEmailUnauthorized, criteria.ReasonUserUnauthorized),
|
||||||
|
Deny: NewRuleResult(false),
|
||||||
|
Traces: []contextutil.PolicyEvaluationTrace{{}},
|
||||||
|
}, output)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Enable client certificate validation.
|
||||||
|
clientCA = "---FAKE CA CERTIFICATE---"
|
||||||
|
|
||||||
|
t.Run("allowed with cert", func(t *testing.T) {
|
||||||
output, err := eval(t,
|
output, err := eval(t,
|
||||||
p1,
|
p1,
|
||||||
[]proto.Message{s1, u1, s2, u2},
|
[]proto.Message{s1, u1, s2, u2},
|
||||||
|
@ -78,7 +114,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &PolicyResponse{
|
assert.Equal(t, &PolicyResponse{
|
||||||
Allow: NewRuleResult(true, criteria.ReasonEmailOK),
|
Allow: NewRuleResult(true, criteria.ReasonEmailOK),
|
||||||
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired),
|
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificate),
|
||||||
Traces: []contextutil.PolicyEvaluationTrace{{Allow: true}},
|
Traces: []contextutil.PolicyEvaluationTrace{{Allow: true}},
|
||||||
}, output)
|
}, output)
|
||||||
})
|
})
|
||||||
|
@ -99,7 +135,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
Traces: []contextutil.PolicyEvaluationTrace{{Allow: true, Deny: true}},
|
Traces: []contextutil.PolicyEvaluationTrace{{Allow: true, Deny: true}},
|
||||||
}, output)
|
}, output)
|
||||||
})
|
})
|
||||||
t.Run("forbidden", func(t *testing.T) {
|
t.Run("forbidden with cert", func(t *testing.T) {
|
||||||
output, err := eval(t,
|
output, err := eval(t,
|
||||||
p1,
|
p1,
|
||||||
[]proto.Message{s1, u1, s2, u2},
|
[]proto.Message{s1, u1, s2, u2},
|
||||||
|
@ -112,10 +148,11 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &PolicyResponse{
|
assert.Equal(t, &PolicyResponse{
|
||||||
Allow: NewRuleResult(false, criteria.ReasonEmailUnauthorized, criteria.ReasonUserUnauthorized),
|
Allow: NewRuleResult(false, criteria.ReasonEmailUnauthorized, criteria.ReasonUserUnauthorized),
|
||||||
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired),
|
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificate),
|
||||||
Traces: []contextutil.PolicyEvaluationTrace{{}},
|
Traces: []contextutil.PolicyEvaluationTrace{{}},
|
||||||
}, output)
|
}, output)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ppl", func(t *testing.T) {
|
t.Run("ppl", func(t *testing.T) {
|
||||||
t.Run("allow", func(t *testing.T) {
|
t.Run("allow", func(t *testing.T) {
|
||||||
rego, err := policy.GenerateRegoFromReader(strings.NewReader(`
|
rego, err := policy.GenerateRegoFromReader(strings.NewReader(`
|
||||||
|
@ -143,7 +180,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &PolicyResponse{
|
assert.Equal(t, &PolicyResponse{
|
||||||
Allow: NewRuleResult(true, criteria.ReasonAccept),
|
Allow: NewRuleResult(true, criteria.ReasonAccept),
|
||||||
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired),
|
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificate),
|
||||||
Traces: []contextutil.PolicyEvaluationTrace{{}, {ID: "p1", Allow: true}},
|
Traces: []contextutil.PolicyEvaluationTrace{{}, {ID: "p1", Allow: true}},
|
||||||
}, output)
|
}, output)
|
||||||
})
|
})
|
||||||
|
@ -243,7 +280,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &PolicyResponse{
|
assert.Equal(t, &PolicyResponse{
|
||||||
Allow: NewRuleResult(true),
|
Allow: NewRuleResult(true),
|
||||||
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired),
|
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificate),
|
||||||
Traces: []contextutil.PolicyEvaluationTrace{{}, {ID: "p1", Allow: true}},
|
Traces: []contextutil.PolicyEvaluationTrace{{}, {ID: "p1", Allow: true}},
|
||||||
}, output)
|
}, output)
|
||||||
})
|
})
|
||||||
|
@ -266,7 +303,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &PolicyResponse{
|
assert.Equal(t, &PolicyResponse{
|
||||||
Allow: NewRuleResult(true, criteria.ReasonEmailOK),
|
Allow: NewRuleResult(true, criteria.ReasonEmailOK),
|
||||||
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired),
|
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificate),
|
||||||
Traces: []contextutil.PolicyEvaluationTrace{{Allow: true}},
|
Traces: []contextutil.PolicyEvaluationTrace{{Allow: true}},
|
||||||
}, output)
|
}, output)
|
||||||
})
|
})
|
||||||
|
@ -290,7 +327,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &PolicyResponse{
|
assert.Equal(t, &PolicyResponse{
|
||||||
Allow: NewRuleResult(false, criteria.ReasonUserUnauthenticated),
|
Allow: NewRuleResult(false, criteria.ReasonUserUnauthenticated),
|
||||||
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired),
|
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificate),
|
||||||
Traces: []contextutil.PolicyEvaluationTrace{{Allow: false}},
|
Traces: []contextutil.PolicyEvaluationTrace{{Allow: false}},
|
||||||
}, output)
|
}, output)
|
||||||
})
|
})
|
||||||
|
|
|
@ -79,13 +79,6 @@ func (p *Policy) ToPPL() *parser.Policy {
|
||||||
}
|
}
|
||||||
ppl.Rules = append(ppl.Rules, allowRule)
|
ppl.Rules = append(ppl.Rules, allowRule)
|
||||||
|
|
||||||
denyRule := parser.Rule{Action: parser.ActionDeny}
|
|
||||||
denyRule.Or = append(denyRule.Or,
|
|
||||||
parser.Criterion{
|
|
||||||
Name: "invalid_client_certificate",
|
|
||||||
})
|
|
||||||
ppl.Rules = append(ppl.Rules, denyRule)
|
|
||||||
|
|
||||||
// append embedded PPL policy rules
|
// append embedded PPL policy rules
|
||||||
if p.Policy != nil && p.Policy.Policy != nil {
|
if p.Policy != nil && p.Policy.Policy != nil {
|
||||||
ppl.Rules = append(ppl.Rules, p.Policy.Policy.Rules...)
|
ppl.Rules = append(ppl.Rules, p.Policy.Policy.Rules...)
|
||||||
|
|
|
@ -392,25 +392,6 @@ allow = v {
|
||||||
v := merge_with_or(normalized)
|
v := merge_with_or(normalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
invalid_client_certificate_0 = [true, {"invalid-client-certificate"}] {
|
|
||||||
is_boolean(input.is_valid_client_certificate)
|
|
||||||
not input.is_valid_client_certificate
|
|
||||||
}
|
|
||||||
|
|
||||||
else = [false, {"valid-client-certificate-or-none-required"}]
|
|
||||||
|
|
||||||
or_2 = v {
|
|
||||||
results := [invalid_client_certificate_0]
|
|
||||||
normalized := [normalize_criterion_result(x) | x := results[i]]
|
|
||||||
v := merge_with_or(normalized)
|
|
||||||
}
|
|
||||||
|
|
||||||
deny = v {
|
|
||||||
results := [or_2]
|
|
||||||
normalized := [normalize_criterion_result(x) | x := results[i]]
|
|
||||||
v := merge_with_or(normalized)
|
|
||||||
}
|
|
||||||
|
|
||||||
invert_criterion_result(in) = out {
|
invert_criterion_result(in) = out {
|
||||||
in[0]
|
in[0]
|
||||||
out = array.concat([false], array.slice(in, 1, count(in)))
|
out = array.concat([false], array.slice(in, 1, count(in)))
|
||||||
|
|
|
@ -26,12 +26,13 @@ func (invalidClientCertificateCriterion) Name() string {
|
||||||
|
|
||||||
func (c invalidClientCertificateCriterion) GenerateRule(_ string, _ parser.Value) (*ast.Rule, []*ast.Rule, error) {
|
func (c invalidClientCertificateCriterion) GenerateRule(_ string, _ parser.Value) (*ast.Rule, []*ast.Rule, error) {
|
||||||
rule := NewCriterionRule(c.g, c.Name(),
|
rule := NewCriterionRule(c.g, c.Name(),
|
||||||
ReasonInvalidClientCertificate, ReasonValidClientCertificateOrNoneRequired,
|
ReasonInvalidClientCertificate, ReasonValidClientCertificate,
|
||||||
invalidClientCertificateBody)
|
invalidClientCertificateBody)
|
||||||
return rule, nil, nil
|
return rule, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvalidClientCertificate returns a Criterion which returns true if the client certificate is valid.
|
// InvalidClientCertificate returns a Criterion which returns true if the
|
||||||
|
// client certificate is invalid.
|
||||||
func InvalidClientCertificate(generator *Generator) Criterion {
|
func InvalidClientCertificate(generator *Generator) Criterion {
|
||||||
return invalidClientCertificateCriterion{g: generator}
|
return invalidClientCertificateCriterion{g: generator}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,31 +7,31 @@ type Reason string
|
||||||
|
|
||||||
// Well-known reasons.
|
// Well-known reasons.
|
||||||
const (
|
const (
|
||||||
ReasonAccept = "accept"
|
ReasonAccept = "accept"
|
||||||
ReasonClaimOK = "claim-ok"
|
ReasonClaimOK = "claim-ok"
|
||||||
ReasonClaimUnauthorized = "claim-unauthorized"
|
ReasonClaimUnauthorized = "claim-unauthorized"
|
||||||
ReasonCORSRequest = "cors-request"
|
ReasonCORSRequest = "cors-request"
|
||||||
ReasonDeviceOK = "device-ok"
|
ReasonDeviceOK = "device-ok"
|
||||||
ReasonDeviceUnauthenticated = "device-unauthenticated"
|
ReasonDeviceUnauthenticated = "device-unauthenticated"
|
||||||
ReasonDeviceUnauthorized = "device-unauthorized"
|
ReasonDeviceUnauthorized = "device-unauthorized"
|
||||||
ReasonDomainOK = "domain-ok"
|
ReasonDomainOK = "domain-ok"
|
||||||
ReasonDomainUnauthorized = "domain-unauthorized"
|
ReasonDomainUnauthorized = "domain-unauthorized"
|
||||||
ReasonEmailOK = "email-ok"
|
ReasonEmailOK = "email-ok"
|
||||||
ReasonEmailUnauthorized = "email-unauthorized"
|
ReasonEmailUnauthorized = "email-unauthorized"
|
||||||
ReasonHTTPMethodOK = "http-method-ok"
|
ReasonHTTPMethodOK = "http-method-ok"
|
||||||
ReasonHTTPMethodUnauthorized = "http-method-unauthorized"
|
ReasonHTTPMethodUnauthorized = "http-method-unauthorized"
|
||||||
ReasonHTTPPathOK = "http-path-ok"
|
ReasonHTTPPathOK = "http-path-ok"
|
||||||
ReasonHTTPPathUnauthorized = "http-path-unauthorized"
|
ReasonHTTPPathUnauthorized = "http-path-unauthorized"
|
||||||
ReasonInvalidClientCertificate = "invalid-client-certificate"
|
ReasonInvalidClientCertificate = "invalid-client-certificate"
|
||||||
ReasonNonCORSRequest = "non-cors-request"
|
ReasonNonCORSRequest = "non-cors-request"
|
||||||
ReasonNonPomeriumRoute = "non-pomerium-route"
|
ReasonNonPomeriumRoute = "non-pomerium-route"
|
||||||
ReasonPomeriumRoute = "pomerium-route"
|
ReasonPomeriumRoute = "pomerium-route"
|
||||||
ReasonReject = "reject"
|
ReasonReject = "reject"
|
||||||
ReasonRouteNotFound = "route-not-found"
|
ReasonRouteNotFound = "route-not-found"
|
||||||
ReasonUserOK = "user-ok"
|
ReasonUserOK = "user-ok"
|
||||||
ReasonUserUnauthenticated = "user-unauthenticated" // user needs to log in
|
ReasonUserUnauthenticated = "user-unauthenticated" // user needs to log in
|
||||||
ReasonUserUnauthorized = "user-unauthorized" // user does not have access
|
ReasonUserUnauthorized = "user-unauthorized" // user does not have access
|
||||||
ReasonValidClientCertificateOrNoneRequired = "valid-client-certificate-or-none-required"
|
ReasonValidClientCertificate = "valid-client-certificate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reasons is a collection of reasons.
|
// Reasons is a collection of reasons.
|
||||||
|
|
9
pkg/policy/parser/default.go
Normal file
9
pkg/policy/parser/default.go
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package parser
|
||||||
|
|
||||||
|
// AddDefaultClientCertificateRule adds a deny rule to the policy with the
|
||||||
|
// criterion invalid_client_certificate.
|
||||||
|
func (p *Policy) AddDefaultClientCertificateRule() {
|
||||||
|
denyRule := Rule{Action: ActionDeny}
|
||||||
|
denyRule.Or = append(denyRule.Or, Criterion{Name: "invalid_client_certificate"})
|
||||||
|
p.Rules = append(p.Rules, denyRule)
|
||||||
|
}
|
20
pkg/policy/parser/default_test.go
Normal file
20
pkg/policy/parser/default_test.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddDefaultClientCertificateRule(t *testing.T) {
|
||||||
|
var p Policy
|
||||||
|
p.AddDefaultClientCertificateRule()
|
||||||
|
assert.Equal(t, Policy{
|
||||||
|
Rules: []Rule{{
|
||||||
|
Action: ActionDeny,
|
||||||
|
Or: []Criterion{
|
||||||
|
{Name: "invalid_client_certificate"},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}, p)
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue